001: /*******************************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *******************************************************************************/package org.ofbiz.accounting.thirdparty.gosoftware;
019:
020: import java.util.Map;
021: import java.util.Properties;
022: import java.util.List;
023: import java.io.IOException;
024: import java.text.DecimalFormat;
025: import java.sql.Timestamp;
026:
027: import org.ofbiz.service.DispatchContext;
028: import org.ofbiz.service.ServiceUtil;
029: import org.ofbiz.service.LocalDispatcher;
030: import org.ofbiz.service.GenericServiceException;
031: import org.ofbiz.base.util.GeneralException;
032: import org.ofbiz.base.util.Debug;
033: import org.ofbiz.base.util.UtilMisc;
034: import org.ofbiz.base.util.StringUtil;
035: import org.ofbiz.base.util.UtilValidate;
036: import org.ofbiz.base.util.UtilProperties;
037: import org.ofbiz.base.util.UtilDateTime;
038: import org.ofbiz.entity.GenericValue;
039: import org.ofbiz.entity.GenericDelegator;
040: import org.ofbiz.entity.GenericEntityException;
041: import org.ofbiz.entity.util.EntityUtil;
042: import org.ofbiz.accounting.payment.PaymentGatewayServices;
043:
044: public class RitaServices {
045:
046: public static final String module = RitaServices.class.getName();
047:
048: public static Map ccAuth(DispatchContext dctx, Map context) {
049: Properties props = buildPccProperties(context);
050: RitaApi api = getApi(props, "CREDIT");
051: if (api == null) {
052: return ServiceUtil
053: .returnError("RiTA is not configured properly");
054: }
055:
056: try {
057: RitaServices.setCreditCardInfo(api, dctx.getDelegator(),
058: context);
059: } catch (GeneralException e) {
060: return ServiceUtil.returnError(e.getMessage());
061: }
062:
063: // basic tx info
064: api.set(RitaApi.TRANS_AMOUNT, getAmountString(context,
065: "processAmount"));
066: api.set(RitaApi.INVOICE, context.get("orderId"));
067:
068: // command setting
069: if ("1".equals(props.getProperty("autoBill"))) {
070: // sale
071: api.set(RitaApi.COMMAND, "SALE");
072: } else {
073: // pre-auth
074: api.set(RitaApi.COMMAND, "PRE_AUTH");
075: }
076:
077: // send the transaction
078: RitaApi out = null;
079: try {
080: Debug.log("Sending request to RiTA", module);
081: out = api.send();
082: } catch (IOException e) {
083: Debug.logError(e, module);
084: return ServiceUtil.returnError(e.getMessage());
085: } catch (GeneralException e) {
086: Debug.logError(e, module);
087: return ServiceUtil.returnError(e.getMessage());
088: }
089:
090: if (out != null) {
091: Map result = ServiceUtil.returnSuccess();
092: String resultCode = out.get(RitaApi.RESULT);
093: boolean passed = false;
094: if ("CAPTURED".equals(resultCode)) {
095: result.put("authResult", Boolean.TRUE);
096: result.put("captureResult", Boolean.TRUE);
097: passed = true;
098: } else if ("APPROVED".equals(resultCode)) {
099: result.put("authCode", out.get(RitaApi.AUTH_CODE));
100: result.put("authResult", Boolean.TRUE);
101: passed = true;
102: } else if ("PROCESSED".equals(resultCode)) {
103: result.put("authResult", Boolean.TRUE);
104: } else {
105: result.put("authResult", Boolean.FALSE);
106: }
107:
108: result.put("authRefNum",
109: out.get(RitaApi.INTRN_SEQ_NUM) != null ? out
110: .get(RitaApi.INTRN_SEQ_NUM) : "");
111: result.put("processAmount", context.get("processAmount"));
112: result.put("authCode", out.get(RitaApi.AUTH_CODE));
113: result.put("authFlag", out.get(RitaApi.REFERENCE));
114: result.put("authMessage", out.get(RitaApi.RESULT));
115: result.put("cvCode", out.get(RitaApi.CVV2_CODE));
116: result.put("avsCode", out.get(RitaApi.AVS_CODE));
117:
118: if (!passed) {
119: String respMsg = out.get(RitaApi.RESULT) + " / "
120: + out.get(RitaApi.INTRN_SEQ_NUM);
121: result
122: .put("customerRespMsgs", UtilMisc
123: .toList(respMsg));
124: }
125:
126: if (result.get("captureResult") != null) {
127: result.put("captureCode", out.get(RitaApi.AUTH_CODE));
128: result.put("captureFlag", out.get(RitaApi.REFERENCE));
129: result.put("captureRefNum", out
130: .get(RitaApi.INTRN_SEQ_NUM));
131: result.put("captureMessage", out.get(RitaApi.RESULT));
132: }
133:
134: return result;
135:
136: } else {
137: return ServiceUtil
138: .returnError("Receive a null result from RiTA");
139: }
140: }
141:
142: public static Map ccCapture(DispatchContext dctx, Map context) {
143: GenericValue orderPaymentPreference = (GenericValue) context
144: .get("orderPaymentPreference");
145:
146: //lets see if there is a auth transaction already in context
147: GenericValue authTransaction = (GenericValue) context
148: .get("authTrans");
149:
150: if (authTransaction == null) {
151: authTransaction = PaymentGatewayServices
152: .getAuthTransaction(orderPaymentPreference);
153: }
154:
155: if (authTransaction == null) {
156: return ServiceUtil
157: .returnError("No authorization transaction found for the OrderPaymentPreference; cannot capture");
158: }
159:
160: // setup the RiTA Interface
161: Properties props = buildPccProperties(context);
162: RitaApi api = getApi(props, "CREDIT");
163: if (api == null) {
164: return ServiceUtil
165: .returnError("RiTA is not configured properly");
166: }
167:
168: api.set(RitaApi.ORIG_SEQ_NUM, authTransaction
169: .getString("referenceNum"));
170: api.set(RitaApi.COMMAND, "COMPLETION");
171:
172: // send the transaction
173: RitaApi out = null;
174: try {
175: out = api.send();
176: } catch (IOException e) {
177: Debug.logError(e, module);
178: return ServiceUtil.returnError(e.getMessage());
179: } catch (GeneralException e) {
180: Debug.logError(e, module);
181: return ServiceUtil.returnError(e.getMessage());
182: }
183:
184: if (out != null) {
185: Map result = ServiceUtil.returnSuccess();
186: String resultCode = out.get(RitaApi.RESULT);
187: if ("CAPTURED".equals(resultCode)) {
188: result.put("captureResult", Boolean.TRUE);
189: } else {
190: result.put("captureResult", Boolean.FALSE);
191: }
192: result.put("captureAmount", context.get("captureAmount"));
193: result.put("captureRefNum",
194: out.get(RitaApi.INTRN_SEQ_NUM) != null ? out
195: .get(RitaApi.INTRN_SEQ_NUM) : "");
196: result.put("captureCode", out.get(RitaApi.AUTH_CODE));
197: result.put("captureFlag", out.get(RitaApi.REFERENCE));
198: result.put("captureMessage", out.get(RitaApi.RESULT));
199:
200: return result;
201: } else {
202: return ServiceUtil
203: .returnError("Receive a null result from RiTA");
204: }
205: }
206:
207: public static Map ccVoidRelease(DispatchContext dctx, Map context) {
208: return ccVoid(dctx, context, false);
209: }
210:
211: public static Map ccVoidRefund(DispatchContext dctx, Map context) {
212: return ccVoid(dctx, context, true);
213: }
214:
215: private static Map ccVoid(DispatchContext dctx, Map context,
216: boolean isRefund) {
217: GenericValue orderPaymentPreference = (GenericValue) context
218: .get("orderPaymentPreference");
219:
220: //lets see if there is a auth transaction already in context
221: GenericValue authTransaction = (GenericValue) context
222: .get("authTrans");
223:
224: if (authTransaction == null) {
225: authTransaction = PaymentGatewayServices
226: .getAuthTransaction(orderPaymentPreference);
227: }
228:
229: if (authTransaction == null) {
230: return ServiceUtil
231: .returnError("No authorization transaction found for the OrderPaymentPreference; cannot release");
232: }
233:
234: // setup the RiTA Interface
235: Properties props = buildPccProperties(context);
236: RitaApi api = getApi(props, "CREDIT");
237: if (api == null) {
238: return ServiceUtil
239: .returnError("RiTA is not configured properly");
240: }
241:
242: api.set(RitaApi.TRANS_AMOUNT, getAmountString(context,
243: isRefund ? "refundAmount" : "releaseAmount"));
244: api.set(RitaApi.ORIG_SEQ_NUM, authTransaction
245: .getString("referenceNum"));
246: api.set(RitaApi.COMMAND, "VOID");
247:
248: // check to make sure we are configured for SALE mode
249: if (!"1".equals(props.getProperty("autoBill"))) {
250: return ServiceUtil
251: .returnError("RiTA does not support releasing pre-auths.");
252: }
253:
254: // send the transaction
255: RitaApi out = null;
256: try {
257: out = api.send();
258: } catch (IOException e) {
259: Debug.logError(e, module);
260: return ServiceUtil.returnError(e.getMessage());
261: } catch (GeneralException e) {
262: Debug.logError(e, module);
263: return ServiceUtil.returnError(e.getMessage());
264: }
265:
266: if (out != null) {
267: Map result = ServiceUtil.returnSuccess();
268: String resultCode = out.get(RitaApi.RESULT);
269: if ("VOIDED".equals(resultCode)) {
270: result.put(isRefund ? "refundResult" : "releaseResult",
271: Boolean.TRUE);
272: } else {
273: result.put(isRefund ? "refundResult" : "releaseResult",
274: Boolean.FALSE);
275: }
276: result.put(isRefund ? "refundAmount" : "releaseAmount",
277: context.get(isRefund ? "refundAmount"
278: : "releaseAmount"));
279: result.put(isRefund ? "refundRefNum" : "releaseRefNum", out
280: .get(RitaApi.INTRN_SEQ_NUM) != null ? out
281: .get(RitaApi.INTRN_SEQ_NUM) : "");
282: result.put(isRefund ? "refundCode" : "releaseCode", out
283: .get(RitaApi.AUTH_CODE));
284: result.put(isRefund ? "refundFlag" : "releaseFlag", out
285: .get(RitaApi.REFERENCE));
286: result.put(isRefund ? "refundMessage" : "releaseMessage",
287: out.get(RitaApi.RESULT));
288:
289: return result;
290: } else {
291: return ServiceUtil
292: .returnError("Receive a null result from RiTA");
293: }
294: }
295:
296: public static Map ccCreditRefund(DispatchContext dctx, Map context) {
297: GenericValue orderPaymentPreference = (GenericValue) context
298: .get("orderPaymentPreference");
299:
300: //lets see if there is a auth transaction already in context
301: GenericValue authTransaction = (GenericValue) context
302: .get("authTrans");
303:
304: if (authTransaction == null) {
305: authTransaction = PaymentGatewayServices
306: .getAuthTransaction(orderPaymentPreference);
307: }
308:
309: if (authTransaction == null) {
310: return ServiceUtil
311: .returnError("No authorization transaction found for the OrderPaymentPreference; cannot refund");
312: }
313:
314: // setup the RiTA Interface
315: Properties props = buildPccProperties(context);
316: RitaApi api = getApi(props, "CREDIT");
317: if (api == null) {
318: return ServiceUtil
319: .returnError("RiTA is not configured properly");
320: }
321:
322: // set the required cc info
323: try {
324: RitaServices.setCreditCardInfo(api, dctx.getDelegator(),
325: context);
326: } catch (GeneralException e) {
327: return ServiceUtil.returnError(e.getMessage());
328: }
329:
330: api.set(RitaApi.TRANS_AMOUNT, getAmountString(context,
331: "refundAmount"));
332: api.set(RitaApi.ORIG_SEQ_NUM, authTransaction
333: .getString("referenceNum"));
334: api.set(RitaApi.COMMAND, "CREDIT");
335:
336: // send the transaction
337: RitaApi out = null;
338: try {
339: out = api.send();
340: } catch (IOException e) {
341: Debug.logError(e, module);
342: return ServiceUtil.returnError(e.getMessage());
343: } catch (GeneralException e) {
344: Debug.logError(e, module);
345: return ServiceUtil.returnError(e.getMessage());
346: }
347:
348: if (out != null) {
349: Map result = ServiceUtil.returnSuccess();
350: String resultCode = out.get(RitaApi.RESULT);
351: if ("CAPTURED".equals(resultCode)) {
352: result.put("refundResult", Boolean.TRUE);
353: } else {
354: result.put("refundResult", Boolean.FALSE);
355: }
356: result.put("refundAmount", context.get("refundAmount"));
357: result.put("refundRefNum",
358: out.get(RitaApi.INTRN_SEQ_NUM) != null ? out
359: .get(RitaApi.INTRN_SEQ_NUM) : "");
360: result.put("refundCode", out.get(RitaApi.AUTH_CODE));
361: result.put("refundFlag", out.get(RitaApi.REFERENCE));
362: result.put("refundMessage", out.get(RitaApi.RESULT));
363:
364: return result;
365: } else {
366: return ServiceUtil
367: .returnError("Receive a null result from RiTA");
368: }
369: }
370:
371: public static Map ccRefund(DispatchContext dctx, Map context) {
372: LocalDispatcher dispatcher = dctx.getDispatcher();
373: GenericDelegator delegator = dctx.getDelegator();
374: GenericValue orderPaymentPreference = (GenericValue) context
375: .get("orderPaymentPreference");
376: GenericValue orderHeader = null;
377: try {
378: orderHeader = orderPaymentPreference
379: .getRelatedOne("OrderHeader");
380: } catch (GenericEntityException e) {
381: Debug.logError(e, module);
382: return ServiceUtil
383: .returnError("Unable to obtain order header information from payment preference");
384: }
385:
386: if (orderHeader != null) {
387: String terminalId = orderHeader.getString("terminalId");
388: boolean isVoid = false;
389: if (terminalId != null) {
390: Timestamp orderDate = orderHeader
391: .getTimestamp("orderDate");
392: GenericValue terminalState = null;
393: try {
394: List states = delegator.findByAnd(
395: "PosTerminalState", UtilMisc.toMap(
396: "posTerminalId", terminalId));
397: states = EntityUtil.filterByDate(states,
398: UtilDateTime.nowTimestamp(), "openedDate",
399: "closedDate", true);
400: terminalState = EntityUtil.getFirst(states);
401: } catch (GenericEntityException e) {
402: Debug.logError(e, module);
403: }
404:
405: // this is the current opened terminal
406: if (terminalState != null) {
407: Timestamp openDate = terminalState
408: .getTimestamp("openedDate");
409: // if the order date is after the open date of the current state
410: // the order happend within the current open/close of the terminal
411: if (orderDate.after(openDate)) {
412: isVoid = true;
413: }
414: }
415: }
416:
417: Map refundResp = null;
418: try {
419: if (isVoid) {
420: refundResp = dispatcher.runSync("ritaCCVoidRefund",
421: context);
422: } else {
423: refundResp = dispatcher.runSync(
424: "ritaCCCreditRefund", context);
425: }
426: } catch (GenericServiceException e) {
427: Debug.logError(e, module);
428: return ServiceUtil
429: .returnError("Service invocation exception");
430: }
431: return refundResp;
432: } else {
433: return ServiceUtil
434: .returnError("Unable to find order information; cannot complete the refund");
435: }
436: }
437:
438: private static void setCreditCardInfo(RitaApi api,
439: GenericDelegator delegator, Map context)
440: throws GeneralException {
441: GenericValue orderPaymentPreference = (GenericValue) context
442: .get("orderPaymentPreference");
443: GenericValue creditCard = (GenericValue) context
444: .get("creditCard");
445: if (creditCard == null) {
446: creditCard = delegator.findByPrimaryKey("CreditCard",
447: UtilMisc.toMap("paymentMethodId",
448: orderPaymentPreference
449: .getString("paymentMethodId")));
450: }
451: if (creditCard != null) {
452: List expDateList = StringUtil.split(creditCard
453: .getString("expireDate"), "/");
454: String month = (String) expDateList.get(0);
455: String year = (String) expDateList.get(1);
456: String y2d = year.substring(2);
457:
458: String title = creditCard.getString("titleOnCard");
459: String fname = creditCard.getString("firstNameOnCard");
460: String mname = creditCard.getString("middleNameOnCard");
461: String lname = creditCard.getString("lastNameOnCard");
462: String sufix = creditCard.getString("suffixOnCard");
463: StringBuffer name = new StringBuffer();
464: if (UtilValidate.isNotEmpty(title)) {
465: name.append(title + " ");
466: }
467: if (UtilValidate.isNotEmpty(fname)) {
468: name.append(fname + " ");
469: }
470: if (UtilValidate.isNotEmpty(mname)) {
471: name.append(mname + " ");
472: }
473: if (UtilValidate.isNotEmpty(lname)) {
474: name.append(lname + " ");
475: }
476: if (UtilValidate.isNotEmpty(sufix)) {
477: name.append(sufix);
478: }
479: String nameOnCard = name.toString().trim();
480: String acctNumber = creditCard.getString("cardNumber");
481: String cvNum = (String) context.get("cardSecurityCode");
482:
483: api.set(RitaApi.ACCT_NUM, acctNumber);
484: api.set(RitaApi.EXP_MONTH, month);
485: api.set(RitaApi.EXP_YEAR, y2d);
486: api.set(RitaApi.CARDHOLDER, nameOnCard);
487: if (UtilValidate.isNotEmpty(cvNum)) {
488: api.set(RitaApi.CVV2, cvNum);
489: }
490:
491: // billing address information
492: GenericValue billingAddress = (GenericValue) context
493: .get("billingAddress");
494: if (billingAddress != null) {
495: api.set(RitaApi.CUSTOMER_STREET, billingAddress
496: .getString("address1"));
497: api.set(RitaApi.CUSTOMER_ZIP, billingAddress
498: .getString("postalCode"));
499: } else {
500: String zipCode = orderPaymentPreference
501: .getString("billingPostalCode");
502: if (UtilValidate.isNotEmpty(zipCode)) {
503: api.set(RitaApi.CUSTOMER_ZIP, zipCode);
504: }
505: }
506:
507: // set the present flag
508: String presentFlag = orderPaymentPreference
509: .getString("presentFlag");
510: if (presentFlag == null) {
511: presentFlag = "N";
512: }
513: api.set(RitaApi.PRESENT_FLAG, presentFlag.equals("Y") ? "3"
514: : "1"); // 1, no present, 2 present, 3 swiped
515: } else {
516: throw new GeneralException("No CreditCard object found");
517: }
518: }
519:
520: private static RitaApi getApi(Properties props) {
521: if (props == null) {
522: Debug
523: .logError("Cannot load API w/ null properties",
524: module);
525: return null;
526: }
527: String host = props.getProperty("host");
528: int port = 0;
529: try {
530: port = Integer.parseInt(props.getProperty("port"));
531: } catch (Exception e) {
532: Debug.logError(e, module);
533: }
534: boolean ssl = props.getProperty("ssl", "N").equals("Y") ? true
535: : false;
536:
537: RitaApi api = null;
538: if (port > 0 && host != null) {
539: api = new RitaApi(host, port, ssl);
540: } else {
541: api = new RitaApi();
542: }
543:
544: api.set(RitaApi.CLIENT_ID, props.getProperty("clientID"));
545: api.set(RitaApi.USER_ID, props.getProperty("userID"));
546: api.set(RitaApi.USER_PW, props.getProperty("userPW"));
547: api.set(RitaApi.FORCE_FLAG, props.getProperty("forceTx"));
548:
549: return api;
550: }
551:
552: private static RitaApi getApi(Properties props, String paymentType) {
553: RitaApi api = getApi(props);
554: api.set(RitaApi.FUNCTION_TYPE, "PAYMENT");
555: api.set(RitaApi.PAYMENT_TYPE, paymentType);
556: return api;
557: }
558:
559: private static Properties buildPccProperties(Map context) {
560: String configString = (String) context.get("paymentConfig");
561: if (configString == null) {
562: configString = "payment.properties";
563: }
564:
565: String clientId = UtilProperties.getPropertyValue(configString,
566: "payment.rita.clientID");
567: String userId = UtilProperties.getPropertyValue(configString,
568: "payment.rita.userID");
569: String userPw = UtilProperties.getPropertyValue(configString,
570: "payment.rita.userPW");
571: String host = UtilProperties.getPropertyValue(configString,
572: "payment.rita.host");
573: String port = UtilProperties.getPropertyValue(configString,
574: "payment.rita.port");
575: String ssl = UtilProperties.getPropertyValue(configString,
576: "payment.rita.ssl", "N");
577: String autoBill = UtilProperties.getPropertyValue(configString,
578: "payment.rita.autoBill", "0");
579: String forceTx = UtilProperties.getPropertyValue(configString,
580: "payment.rita.forceTx", "0");
581:
582: // some property checking
583: if (UtilValidate.isEmpty(clientId)) {
584: Debug.logWarning("The clientID property in ["
585: + configString + "] is not configured", module);
586: return null;
587: }
588: if (UtilValidate.isEmpty(userId)) {
589: Debug.logWarning("The userID property in [" + configString
590: + "] is not configured", module);
591: return null;
592: }
593: if (UtilValidate.isEmpty(userPw)) {
594: Debug.logWarning("The userPW property in [" + configString
595: + "] is not configured", module);
596: return null;
597: }
598:
599: // create some properties for CS Client
600: Properties props = new Properties();
601: props.put("clientID", clientId);
602: props.put("userID", userId);
603: props.put("userPW", userPw);
604: props.put("host", host);
605: props.put("port", port);
606: props.put("ssl", ssl);
607: props.put("autoBill", autoBill);
608: props.put("forceTx", forceTx);
609: Debug.log("Returning properties - " + props, module);
610:
611: return props;
612: }
613:
614: private static String getAmountString(Map context,
615: String amountField) {
616: String currencyFormat = UtilProperties.getPropertyValue(
617: "general.properties", "currency.decimal.format",
618: "##0.00");
619: DecimalFormat formatter = new DecimalFormat(currencyFormat);
620: Double processAmount = (Double) context.get(amountField);
621: return formatter.format(processAmount);
622: }
623: }
|