001: /*
002: * $Id: CCPaymentServices.java,v 1.1 2003/08/18 19:37:43 jonesde Exp $
003: *
004: * Copyright (c) 2003 The Open For Business Project - www.ofbiz.org
005: *
006: * Permission is hereby granted, free of charge, to any person obtaining a
007: * copy of this software and associated documentation files (the "Software"),
008: * to deal in the Software without restriction, including without limitation
009: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
010: * and/or sell copies of the Software, and to permit persons to whom the
011: * Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included
014: * in all copies or substantial portions of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
017: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
021: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
022: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023: *
024: */
025: package org.ofbiz.accounting.thirdparty.clearcommerce;
026:
027: import java.io.StringWriter;
028: import java.io.Writer;
029: import java.text.DecimalFormat;
030: import java.text.NumberFormat;
031: import java.util.ArrayList;
032: import java.util.HashMap;
033: import java.util.Iterator;
034: import java.util.List;
035: import java.util.Map;
036:
037: import org.ofbiz.base.util.Debug;
038: import org.ofbiz.base.util.UtilProperties;
039: import org.ofbiz.entity.GenericEntityException;
040: import org.ofbiz.entity.GenericValue;
041: import org.ofbiz.service.DispatchContext;
042: import org.ofbiz.service.ServiceUtil;
043:
044: import com.clearcommerce.ccxclientapi.CcApiDocument;
045: import com.clearcommerce.ccxclientapi.CcApiException;
046: import com.clearcommerce.ccxclientapi.CcApiMoney;
047: import com.clearcommerce.ccxclientapi.CcApiRecord;
048:
049: /**
050: * ClearCommerce Integration Services
051: *
052: * @author <a href="mailto:joe.eckard@redrocketcorp.com">Joe Eckard</a>
053: * @version $Revision: 1.1 $
054: * @since 2.2
055: */
056: public class CCPaymentServices {
057:
058: public static final String module = CCPaymentServices.class
059: .getName();
060:
061: public static final String TYPE_AUTH = "PreAuth";
062: public static final String TYPE_CAPTURE = "PostAuth";
063:
064: public static Map ccAuthProcessor(DispatchContext dctx, Map context) {
065: return ccProcessor(dctx, context, TYPE_AUTH);
066: }
067:
068: public static Map ccCaptureProcessor(DispatchContext dctx,
069: Map context) {
070: return ccProcessor(dctx, context, TYPE_CAPTURE);
071: }
072:
073: private static Map ccProcessor(DispatchContext dctx, Map context,
074: String txType) {
075: Map result = new HashMap();
076:
077: // quick parameter check
078: if (!txType.matches(TYPE_AUTH + "|" + TYPE_CAPTURE)) {
079: return ServiceUtil
080: .returnError("Invalid transaction type specified.");
081: }
082:
083: try {
084: CcApiDocument requestDoc = new CcApiDocument();
085:
086: if (txType.equals(TYPE_AUTH)) {
087: buildAuthRequest(requestDoc, context);
088: } else if (txType.equals(TYPE_CAPTURE)) {
089: buildCaptureRequest(requestDoc, context);
090: }
091:
092: if (Debug.verboseOn()) {
093: Writer requestWriter = new StringWriter();
094:
095: requestDoc.writeTo(requestWriter);
096: Debug.logVerbose("---- ClearCommerce Request ----",
097: module);
098: Debug.logVerbose("\n\n" + requestWriter, module);
099: Debug.logVerbose("---- End Request ----", module);
100: }
101:
102: CcApiDocument responseDoc = requestDoc.process();
103:
104: if (Debug.verboseOn()) {
105: Writer responseWriter = new StringWriter();
106:
107: responseDoc.writeTo(responseWriter);
108: Debug.logVerbose("---- ClearCommerce Response ----",
109: module);
110: Debug.logVerbose("\n\n" + responseWriter, module);
111: Debug.logVerbose("---- End Response ----", module);
112: }
113:
114: CcApiRecord recEngineDoc = responseDoc
115: .getFirstRecord("EngineDoc");
116:
117: if (recEngineDoc == null) {
118: return ServiceUtil
119: .returnError("ERROR: ClearCommerce response did not contain an EngineDoc record.");
120: }
121:
122: // check for messages
123: CcApiRecord recMessageList = recEngineDoc
124: .getFirstRecord("MessageList");
125:
126: if (recMessageList != null) {
127: CcApiRecord recMessage = recMessageList
128: .getFirstRecord("Message");
129: List ccApiMessageList = new ArrayList();
130:
131: while (recMessage != null) {
132: StringBuffer ccApiMessage = new StringBuffer();
133:
134: ccApiMessage.append("Audience="
135: + recMessage.getFieldString("Audience")
136: + ", ");
137: ccApiMessage.append("ContextId="
138: + recMessage.getFieldString("ContextId")
139: + ", ");
140: ccApiMessage.append("Component="
141: + recMessage.getFieldString("Component")
142: + ", ");
143: ccApiMessage.append("Sev="
144: + recMessage.getFieldS32("Sev") + ", ");
145: ccApiMessage.append("Text="
146: + recMessage.getFieldString("Text"));
147: ccApiMessageList.add(ccApiMessage.toString());
148: recMessage = recMessageList
149: .getNextRecord("Message");
150: }
151:
152: if (!ccApiMessageList.isEmpty()) {
153: Debug.logWarning(
154: "ClearCommerce response message(s): "
155: + ccApiMessageList, module);
156: Integer maxSeverity = recMessageList
157: .getFieldS32("MaxSev");
158:
159: if (maxSeverity.intValue() > 4) {
160: return ServiceUtil
161: .returnError(ccApiMessageList);
162: }
163: }
164: }
165:
166: CcApiRecord recOrderFormDoc = recEngineDoc
167: .getFirstRecord("OrderFormDoc");
168:
169: if (recOrderFormDoc == null) {
170: return ServiceUtil
171: .returnError("ERROR: ClearCommerce response did not contain an OrderFormDoc record.");
172: }
173: CcApiRecord recTransaction = recOrderFormDoc
174: .getFirstRecord("Transaction");
175:
176: if (recTransaction == null) {
177: return ServiceUtil
178: .returnError("ERROR: ClearCommerce response did not contain a Transaction record.");
179: }
180: CcApiRecord recProcResponse = recTransaction
181: .getFirstRecord("CardProcResp");
182:
183: if (recProcResponse == null) {
184: return ServiceUtil
185: .returnError("ERROR: ClearCommerce response did not contain a CardProcResp record.");
186: }
187:
188: if (txType.equals(TYPE_AUTH)) {
189: processAuthResponse(responseDoc, result);
190: } else if (txType.equals(TYPE_CAPTURE)) {
191: processCaptureResponse(responseDoc, result);
192: }
193:
194: } catch (CcApiException ce) {
195: ce.printStackTrace();
196: return ServiceUtil
197: .returnError("ERROR: ClearCommerce Problem ("
198: + ce.getMessage() + ").");
199: } catch (GenericEntityException gee) {
200: gee.printStackTrace();
201: return ServiceUtil
202: .returnError("ERROR: Could not get order information ("
203: + gee.getMessage() + ").");
204: }
205:
206: return result;
207: }
208:
209: private static void buildAuthRequest(CcApiDocument doc, Map context)
210: throws CcApiException, GenericEntityException {
211: String configString = (String) context.get("paymentConfig");
212:
213: if (configString == null) {
214: configString = "payment.properties";
215: }
216:
217: initDoc(doc, context);
218:
219: CcApiRecord recEngineDoc = doc.getFirstRecord("EngineDoc");
220:
221: // EngineDocList.EngineDoc.Instructions
222: CcApiRecord recInstructions = recEngineDoc
223: .addRecord("Instructions");
224:
225: recInstructions.setFieldString("Pipeline", "PaymentNoFraud");
226:
227: // EngineDocList.EngineDoc.OrderFormDoc
228: CcApiRecord recOrderFormDoc = recEngineDoc
229: .getFirstRecord("OrderFormDoc");
230: recOrderFormDoc.setFieldString("Comments", (String) context
231: .get("orderId"));
232:
233: // EngineDocList.EngineDoc.OrderFormDoc.Consumer
234: CcApiRecord recConsumer = recOrderFormDoc.addRecord("Consumer");
235: GenericValue contactEmail = (GenericValue) context
236: .get("contactEmail");
237:
238: recConsumer.setFieldString("Email", contactEmail
239: .getString("infoString"));
240:
241: // EngineDocList.EngineDoc.OrderFormDoc.Consumer.PaymentMech
242: CcApiRecord recPaymentMech = recConsumer
243: .addRecord("PaymentMech");
244:
245: recPaymentMech.setFieldString("Type", "CreditCard");
246:
247: // EngineDocList.EngineDoc.OrderFormDoc.Consumer.PaymentMech.CreditCard
248: CcApiRecord recCreditCard = recPaymentMech
249: .addRecord("CreditCard");
250: GenericValue creditCard = (GenericValue) context
251: .get("creditCard");
252:
253: recCreditCard.setFieldString("Number", creditCard
254: .getString("cardNumber"));
255: String expDate = creditCard.getString("expireDate");
256:
257: recCreditCard.setFieldExpirationDate("Expires", expDate
258: .substring(0, 3)
259: + expDate.substring(5));
260:
261: boolean enableCVM = UtilProperties
262: .propertyValueEqualsIgnoreCase(configString,
263: "payment.clearcommerce.enableCVM", "Y");
264: String cvmCode = (String) context.get("cardSecurityCode");
265:
266: if (enableCVM && (cvmCode != null)) {
267: if (cvmCode.length() < 4) {
268: StringBuffer sb = new StringBuffer(cvmCode);
269:
270: while (sb.length() < 4) {
271: sb.append(" ");
272: }
273: cvmCode = sb.toString();
274: }
275: recCreditCard.setFieldString("Cvv2Val", cvmCode.substring(
276: 0, 4)); // this must be exactly 4 characters
277: recCreditCard.setFieldString("Cvv2Indicator", "1");
278: }
279:
280: // EngineDocList.EngineDoc.OrderFormDoc.Consumer.BillTo
281: CcApiRecord recBillTo = recConsumer.addRecord("BillTo");
282:
283: // EngineDocList.EngineDoc.OrderFormDoc.Consumer.BillTo.Location
284: CcApiRecord recLocation = recBillTo.addRecord("Location");
285:
286: // EngineDocList.EngineDoc.OrderFormDoc.Consumer.BillTo.Location.Address
287: CcApiRecord recAddress = recLocation.addRecord("Address");
288: GenericValue contactPerson = (GenericValue) context
289: .get("contactPerson");
290: String billToName = new String(contactPerson
291: .getString("firstName")
292: + " " + contactPerson.getString("lastName"));
293:
294: recAddress.setFieldString("Name", billToName);
295: GenericValue billingAddress = (GenericValue) context
296: .get("billingAddress");
297:
298: recAddress.setFieldString("Street1", billingAddress
299: .getString("address1"));
300: if (billingAddress.get("address2") != null) {
301: recAddress.setFieldString("Street2", billingAddress
302: .getString("address2"));
303: }
304: recAddress.setFieldString("City", billingAddress
305: .getString("city"));
306: if (billingAddress.get("stateProvinceGeoId") != null) {
307: recAddress.setFieldString("StateProv", billingAddress
308: .getString("stateProvinceGeoId"));
309: }
310: recAddress.setFieldString("PostalCode", billingAddress
311: .getString("postalCode"));
312: GenericValue geo = billingAddress
313: .getRelatedOneCache("CountryGeo");
314:
315: recAddress.setFieldString("Country", geo
316: .getString("geoSecCode"));
317:
318: // EngineDocList.EngineDoc.OrderFormDoc.Transaction
319: CcApiRecord recTransaction = recOrderFormDoc
320: .addRecord("Transaction");
321:
322: recTransaction.setFieldString("Type", TYPE_AUTH);
323:
324: // EngineDocList.EngineDoc.OrderFormDoc.Transaction.CurrentTotals
325: CcApiRecord recCurrentTotals = recTransaction
326: .addRecord("CurrentTotals");
327:
328: // Used in the following code to format for CcApiMoney
329: NumberFormat nf = new DecimalFormat("#");
330:
331: // EngineDocList.EngineDoc.OrderFormDoc.Transaction.CurrentTotals.Totals
332: CcApiRecord recTotals = recCurrentTotals.addRecord("Totals");
333: Double processAmount = (Double) context.get("processAmount");
334: CcApiMoney total = new CcApiMoney(nf.format(processAmount
335: .doubleValue() * 100), "840");
336:
337: recTotals.setFieldMoney("Total", total);
338:
339: List orderItems = (List) context.get("orderItems");
340: Iterator itemIterator = orderItems.iterator();
341: CcApiRecord recOrderItemList = recOrderFormDoc
342: .addRecord("OrderItemList");
343:
344: while (itemIterator.hasNext()) {
345: GenericValue item = (GenericValue) itemIterator.next();
346: GenericValue product = item.getRelatedOneCache("Product");
347: CcApiRecord recOrderItem = recOrderItemList
348: .addRecord("OrderItem");
349: Integer orderItemSeqId = new Integer(item
350: .getString("orderItemSeqId"));
351:
352: recOrderItem.setFieldS32("ItemNumber", orderItemSeqId
353: .intValue());
354: recOrderItem.setFieldString("Id", product
355: .getString("productId"));
356: Double qty = new Double(item.getString("quantity"));
357:
358: recOrderItem.setFieldS32("Qty", qty.intValue());
359: recOrderItem.setFieldString("Desc", item
360: .getString("itemDescription"));
361: CcApiMoney unitPrice = new CcApiMoney(nf.format(item
362: .getDouble("unitPrice").doubleValue() * 100), "840");
363:
364: recOrderItem.setFieldMoney("Price", unitPrice);
365: }
366:
367: return;
368:
369: }
370:
371: private static void buildCaptureRequest(CcApiDocument doc,
372: Map context) throws CcApiException, GenericEntityException {
373: initDoc(doc, context);
374:
375: CcApiRecord recEngineDoc = doc.getFirstRecord("EngineDoc");
376:
377: // EngineDocList.EngineDoc.Instructions
378: CcApiRecord recInstructions = recEngineDoc
379: .addRecord("Instructions");
380:
381: recInstructions.setFieldString("Pipeline", "PaymentNoFraud");
382:
383: // EngineDocList.EngineDoc.OrderFormDoc
384: CcApiRecord recOrderFormDoc = recEngineDoc
385: .getFirstRecord("OrderFormDoc");
386: GenericValue paymentPref = (GenericValue) context
387: .get("orderPaymentPreference");
388:
389: recOrderFormDoc.setFieldString("Id", paymentPref
390: .getString("authRefNum"));
391:
392: // EngineDocList.EngineDoc.OrderFormDoc.Transaction
393: CcApiRecord recTransaction = recOrderFormDoc
394: .addRecord("Transaction");
395:
396: recTransaction.setFieldString("Type", TYPE_CAPTURE);
397:
398: // EngineDocList.EngineDoc.OrderFormDoc.Transaction.CurrentTotals
399: CcApiRecord recCurrentTotals = recTransaction
400: .addRecord("CurrentTotals");
401:
402: // EngineDocList.EngineDoc.OrderFormDoc.Transaction.CurrentTotals.Totals
403: CcApiRecord recTotals = recCurrentTotals.addRecord("Totals");
404: Double captureAmount = (Double) context.get("captureAmount");
405: NumberFormat nf = new DecimalFormat("#");
406: CcApiMoney total = new CcApiMoney(nf.format(captureAmount
407: .doubleValue() * 100), "840");
408:
409: recTotals.setFieldMoney("Total", total);
410:
411: return;
412: }
413:
414: private static void processAuthResponse(CcApiDocument response,
415: Map result) throws CcApiException {
416: CcApiRecord recEngineDoc = response.getFirstRecord("EngineDoc");
417: CcApiRecord recOrderFormDoc = recEngineDoc
418: .getFirstRecord("OrderFormDoc");
419: CcApiRecord recTransaction = recOrderFormDoc
420: .getFirstRecord("Transaction");
421: CcApiRecord recProcResponse = recTransaction
422: .getFirstRecord("CardProcResp");
423:
424: Integer errCode = recProcResponse.getFieldS32("CcErrCode");
425:
426: if (errCode.intValue() == 1) {
427: result.put("authCode", recTransaction
428: .getFieldString("AuthCode"));
429: result.put("authResult", new Boolean(true));
430: CcApiRecord recCurrentTotals = recTransaction
431: .getFirstRecord("CurrentTotals");
432: CcApiRecord recTotals = recCurrentTotals
433: .getFirstRecord("Totals");
434: CcApiMoney authAmount = recTotals.getFieldMoney("Total");
435: Double authAmountDouble = new Double(authAmount.getAmount());
436:
437: result.put("processAmount", new Double(authAmountDouble
438: .doubleValue() / 100));
439: } else {
440: result.put("authResult", new Boolean(false));
441: result.put("processAmount", new Double(0.00));
442: }
443: result.put("authRefNum", recOrderFormDoc.getFieldString("Id"));
444: result
445: .put("authFlag", recProcResponse
446: .getFieldString("Status"));
447: result.put("authMessage", recProcResponse
448: .getFieldString("CcReturnMsg"));
449: String avsDisplay = recProcResponse
450: .getFieldString("AvsDisplay");
451:
452: if (avsDisplay != null) {
453: result.put("avsCode", avsDisplay);
454: }
455: }
456:
457: private static void processCaptureResponse(CcApiDocument response,
458: Map result) throws CcApiException {
459: CcApiRecord recEngineDoc = response.getFirstRecord("EngineDoc");
460: CcApiRecord recOrderFormDoc = recEngineDoc
461: .getFirstRecord("OrderFormDoc");
462: CcApiRecord recTransaction = recOrderFormDoc
463: .getFirstRecord("Transaction");
464: CcApiRecord recProcResponse = recTransaction
465: .getFirstRecord("CardProcResp");
466:
467: Integer errCode = recProcResponse.getFieldS32("CcErrCode");
468:
469: if (errCode.intValue() == 1) {
470: CcApiRecord recCurrentTotals = recTransaction
471: .getFirstRecord("CurrentTotals");
472: CcApiRecord recTotals = recCurrentTotals
473: .getFirstRecord("Totals");
474: CcApiMoney captureAmount = recTotals.getFieldMoney("Total");
475: Double captureAmountDouble = new Double(captureAmount
476: .getAmount());
477:
478: result.put("captureAmount", new Double(captureAmountDouble
479: .doubleValue() / 100));
480: result.put("captureResult", new Boolean(true));
481: } else {
482: result.put("captureAmount", new Double(0.00));
483: result.put("captureResult", new Boolean(false));
484: }
485: result.put("captureRefNum", recOrderFormDoc
486: .getFieldString("Id"));
487: }
488:
489: private static void initDoc(CcApiDocument doc, Map context)
490: throws CcApiException {
491: String configString = (String) context.get("paymentConfig");
492:
493: if (configString == null) {
494: configString = "payment.properties";
495: }
496:
497: // Some default values
498: String sourceId = UtilProperties.getPropertyValue(configString,
499: "payment.clearcommerce.sourceId", "mySourceId");
500: String groupId = UtilProperties.getPropertyValue(configString,
501: "payment.clearcommerce.groupId", "myGroup");
502: String userName = UtilProperties.getPropertyValue(configString,
503: "payment.clearcommerce.username", "myUsername");
504: String userPassword = UtilProperties.getPropertyValue(
505: configString, "payment.clearcommerce.password",
506: "myPassword");
507: String alias = UtilProperties.getPropertyValue(configString,
508: "payment.clearcommerce.alias", "myAlias");
509: String effectiveAlias = UtilProperties.getPropertyValue(
510: configString, "payment.clearcommerce.effectiveAlias",
511: "");
512: String processMode = UtilProperties.getPropertyValue(
513: configString, "payment.clearcommerce.processMode", "Y");
514: String hostAddress = UtilProperties.getPropertyValue(
515: configString, "payment.clearcommerce.hostAddress",
516: "test5x.clearcommerce.com");
517: String hostPort = UtilProperties.getPropertyValue(configString,
518: "payment.clearcommerce.hostPort", "12000");
519:
520: // Connection params
521: doc.setHost(hostAddress);
522: doc.setPort(Short.parseShort(hostPort));
523: doc.useCRYPTO();
524:
525: // EngineDocList
526: doc.setFieldString("DocVersion", "1.0");
527:
528: // EngineDocList.EngineDoc
529: CcApiRecord engineDoc = doc.addRecord("EngineDoc");
530:
531: engineDoc.setFieldString("DocumentId", "1");
532: engineDoc.setFieldString("ContentType", "OrderFormDoc");
533: engineDoc.setFieldString("SourceId", sourceId);
534:
535: // EngineDocList.EngineDoc.User
536: CcApiRecord user = engineDoc.addRecord("User");
537:
538: user.setFieldString("Name", userName);
539: user.setFieldString("Password", userPassword);
540: user.setFieldString("Alias", alias);
541: if (!effectiveAlias.equals("")) {
542: user.setFieldString("EffectiveAlias", effectiveAlias);
543: }
544:
545: // EngineDocList.EngineDoc.OrderFormDoc
546: CcApiRecord orderFormDoc = engineDoc.addRecord("OrderFormDoc");
547:
548: orderFormDoc.setFieldString("Mode", processMode);
549: orderFormDoc.setFieldString("GroupId", groupId);
550:
551: return;
552: }
553:
554: }
|