You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by jl...@apache.org on 2007/09/21 21:53:56 UTC
svn commit: r578246 -
/ofbiz/branches/release4.0/applications/accounting/src/org/ofbiz/accounting/thirdparty/authorizedotnet/AIMPaymentServices.java
Author: jleroux
Date: Fri Sep 21 12:53:56 2007
New Revision: 578246
URL: http://svn.apache.org/viewvc?rev=578246&view=rev
Log:
Applied fix from trunk for revision: 571249
Modified:
ofbiz/branches/release4.0/applications/accounting/src/org/ofbiz/accounting/thirdparty/authorizedotnet/AIMPaymentServices.java
Modified: ofbiz/branches/release4.0/applications/accounting/src/org/ofbiz/accounting/thirdparty/authorizedotnet/AIMPaymentServices.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/release4.0/applications/accounting/src/org/ofbiz/accounting/thirdparty/authorizedotnet/AIMPaymentServices.java?rev=578246&r1=578245&r2=578246&view=diff
==============================================================================
--- ofbiz/branches/release4.0/applications/accounting/src/org/ofbiz/accounting/thirdparty/authorizedotnet/AIMPaymentServices.java (original)
+++ ofbiz/branches/release4.0/applications/accounting/src/org/ofbiz/accounting/thirdparty/authorizedotnet/AIMPaymentServices.java Fri Sep 21 12:53:56 2007
@@ -19,21 +19,50 @@
package org.ofbiz.accounting.thirdparty.authorizedotnet;
-import java.util.*;
-
+import org.ofbiz.accounting.payment.PaymentGatewayServices;
import org.ofbiz.base.util.*;
-import org.ofbiz.entity.*;
-import org.ofbiz.service.*;
+import org.ofbiz.entity.GenericDelegator;
+import org.ofbiz.entity.GenericEntityException;
+import org.ofbiz.entity.GenericValue;
+import org.ofbiz.service.DispatchContext;
+import org.ofbiz.service.ModelService;
+import org.ofbiz.service.ServiceUtil;
-import org.ofbiz.accounting.payment.PaymentGatewayServices;
+import java.sql.Timestamp;
+import java.util.*;
public class AIMPaymentServices {
public static final String module = AIMPaymentServices.class.getName();
+ // TODO: Reformat the comments below to fit JavaDocs specs
+
+ // The list of refund failure response codes that would cause the ccRefund service
+ // to attempt to void the refund's associated authorization transaction. This list
+ // contains the responses where the voiding does not need to be done within a certain
+ // time limit
+ private static final List VOIDABLE_RESPONSES_NO_TIME_LIMIT = UtilMisc.toList("50");
+
+ // A list of refund failure response codes that would cause the ccRefund service
+ // to first check whether the refund's associated authorization transaction has occurred
+ // within a certain time limit, and if so, cause it to void the transaction
+ private static final List VOIDABLE_RESPONSES_TIME_LIMIT = UtilMisc.toList("54");
+
+ // The number of days in the time limit when one can safely consider an unsettled
+ // transaction to be still valid
+ private static int TIME_LIMIT_VERIFICATION_DAYS = 120;
+
private static Properties AIMProperties = null;
+ // A routine to check whether a given refund failure response code will cause the
+ // ccRefund service to attempt to void the refund's associated authorization transaction
+ private static boolean isVoidableResponse(String responseCode) {
+ return
+ VOIDABLE_RESPONSES_NO_TIME_LIMIT.contains(responseCode) ||
+ VOIDABLE_RESPONSES_TIME_LIMIT.contains(responseCode);
+ }
+
public static Map ccAuth(DispatchContext ctx, Map context) {
Map results = ServiceUtil.returnSuccess();
Map request = new HashMap();
@@ -112,13 +141,6 @@
return results;
}
- public static Map ccRelease(DispatchContext ctx, Map context) {
- Map results = new HashMap();
- results.put(ModelService.RESPONSE_MESSAGE, ModelService.RESPOND_ERROR);
- results.put(ModelService.ERROR_MESSAGE, "Authorize.net ccRelease unsupported with version 3.0");
- return results;
- }
-
public static Map ccRefund(DispatchContext ctx, Map context) {
GenericDelegator delegator = ctx.getDelegator();
GenericValue orderPaymentPreference = (GenericValue) context.get("orderPaymentPreference");
@@ -160,11 +182,110 @@
}
Map reply = processCard(request, props);
+ results.putAll( processRefundTransResult(reply) );
+
+ boolean refundResult = ((Boolean)results.get("refundResult")).booleanValue();
+ String refundFlag = (String)results.get("refundFlag");
+
+ // Since the refund failed, we are going to void the previous authorization against
+ // which ccRefunds attempted to issue the refund. This happens because Authorize.NET requires
+ // that settled transactions need to be voided the same day. unfortunately they provide no method for
+ // determining what transactions can be voided and what can be refunded, so we'll have to try it with timestamps
+ if (!refundResult && isVoidableResponse(refundFlag)) {
+ boolean canDoVoid = false;
+
+ if (VOIDABLE_RESPONSES_TIME_LIMIT.contains(refundFlag)) {
+ // We are calculating the timestamp that is at the beginning of a time limit,
+ // since we can safely assume that, within this time limit, an unsettled transaction
+ // can still be considered valid
+ Calendar startCalendar = UtilDateTime.toCalendar(UtilDateTime.nowTimestamp());
+ startCalendar.add(Calendar.DATE, -TIME_LIMIT_VERIFICATION_DAYS);
+ Timestamp startTimestamp = new java.sql.Timestamp(startCalendar.getTime().getTime());
+
+ Timestamp authTimestamp = authTransaction.getTimestamp("transactionDate");
+
+ if (startTimestamp.before(authTimestamp)) {
+ canDoVoid = true;
+ }
+ } else {
+ // Since there's no time limit to check, the voiding of the transaction will go
+ // through as usual
+ canDoVoid = true;
+ }
+
+ if (canDoVoid) {
+ Double authAmountObj = authTransaction.getDouble("amount");
+ Double refundAmountObj = (Double)context.get("refundAmount");
+
+ double authAmount = authAmountObj != null? authAmountObj.doubleValue() : 0.0;
+ double refundAmount = refundAmountObj != null? refundAmountObj.doubleValue() : 0.0;
+
+ if (authAmount == refundAmount) {
+ reply = voidTransaction(authTransaction, context);
+ if (ServiceUtil.isError(reply)) return reply;
+
+ results = ServiceUtil.returnSuccess();
+ results.putAll( processRefundTransResult(reply) );
+ return results;
+ } else {
+ // TODO: Modify the code to (a) do a void of the whole transaction, and (b)
+ // create a new auth-capture of the difference.
+ return ServiceUtil.returnError("Cannot perform a VOID transaction: authAmount [" + authAmount + "] is different than refundAmount [" + refundAmount + "]");
+ }
+ }
+ }
- processRefundTransResult(reply,results);
return results;
}
+ public static Map ccRelease(DispatchContext ctx, Map context) {
+ GenericValue orderPaymentPreference = (GenericValue) context.get("orderPaymentPreference");
+
+ GenericValue creditCard = null;
+ try {
+ creditCard = orderPaymentPreference.getRelatedOne("CreditCard");
+ } catch (GenericEntityException e) {
+ Debug.logError(e, module);
+ return ServiceUtil.returnError("Unable to obtain cc information from payment preference [ID = " + orderPaymentPreference.getString("orderPaymentPreferenceId") + "]");
+ }
+
+ GenericValue authTransaction = PaymentGatewayServices.getAuthTransaction(orderPaymentPreference);
+ if (authTransaction == null) {
+ return ServiceUtil.returnError("No authorization transaction found for the OrderPaymentPreference [ID = " + orderPaymentPreference.getString("orderPaymentPreferenceId") + "]; cannot void");
+ }
+
+ Map reply = voidTransaction(authTransaction, context);
+ if (ServiceUtil.isError(reply)) return reply;
+
+ Map results = ServiceUtil.returnSuccess();
+ results.putAll( processReleaseTransResult(reply) );
+ return results;
+ }
+
+ private static Map voidTransaction(GenericValue authTransaction, Map context) {
+ context.put("authTransaction",authTransaction);
+ Map results = ServiceUtil.returnSuccess();
+ Map request = new HashMap();
+
+ Properties props = buildAIMProperties(context);
+ buildMerchantInfo(context,props,request);
+ buildGatewayResponeConfig(context,props,request);
+ buildEmailSettings(context,props,request);
+ props.put("transType","VOID");
+ buildVoidTransaction(context,props,request);
+
+ Map validateResults = validateRequest(context,props,request);
+ String respMsg = (String)validateResults.get(ModelService.RESPONSE_MESSAGE);
+ if(respMsg != null) {
+ if(respMsg.equals(ModelService.RESPOND_ERROR)) {
+ results.put(ModelService.ERROR_MESSAGE, "Validation Failed - invalid values");
+ return results;
+ }
+ }
+
+ return processCard(request, props);
+ }
+
public static Map ccCredit(DispatchContext ctx, Map context) {
Map results = new HashMap();
results.put(ModelService.RESPONSE_MESSAGE, ModelService.RESPOND_ERROR);
@@ -460,6 +581,19 @@
Debug.logInfo("buildCaptureTransaction. " + at.toString(),module);
}
+ private static void buildVoidTransaction(Map params, Properties props, Map AIMRequest) {
+ GenericValue at = (GenericValue)params.get("authTransaction");
+ String currency = (String) params.get("currency");
+
+ AIMRequest.put("x_Currency_Code",currency);
+ AIMRequest.put("x_Method", props.getProperty("method"));
+ AIMRequest.put("x_Type", props.getProperty("transType"));
+ AIMRequest.put("x_Trans_ID",at.get("referenceNum"));
+ AIMRequest.put("x_Auth_Code",at.get("gatewayCode"));
+
+ Debug.logInfo("buildVoidTransaction. " + at.toString(),module);
+ }
+
private static Map validateRequest(Map params, Properties props, Map AIMRequest) {
Map result = new HashMap();
result.put(ModelService.RESPONSE_MESSAGE, ModelService.RESPOND_SUCCESS);
@@ -510,23 +644,45 @@
Debug.logInfo("processCaptureTransResult: " + results.toString(),module);
}
- private static void processRefundTransResult(Map reply, Map results) {
+ private static Map processRefundTransResult(Map reply) {
+ Map results = new HashMap();
AuthorizeResponse ar = (AuthorizeResponse)reply.get("authorizeResponse");
Boolean captureResult = (Boolean)reply.get("authResult");
results.put("refundResult", new Boolean(captureResult.booleanValue()));
results.put("refundFlag",ar.getReasonCode());
results.put("refundMessage",ar.getReasonText());
+ results.put("refundRefNum", ar.getResponseField(AuthorizeResponse.TRANSACTION_ID));
if(captureResult.booleanValue()) { //passed
results.put("refundCode", ar.getResponseField(AuthorizeResponse.AUTHORIZATION_CODE));
- results.put("refundRefNum", ar.getResponseField(AuthorizeResponse.TRANSACTION_ID));
results.put("refundAmount", new Double(ar.getResponseField(AuthorizeResponse.AMOUNT)));
} else {
results.put("refundAmount", new Double("0.00"));
-
}
Debug.logInfo("processRefundTransResult: " + results.toString(),module);
+ return results;
+ }
+
+ private static Map processReleaseTransResult(Map reply) {
+ Map results = new HashMap();
+ AuthorizeResponse ar = (AuthorizeResponse)reply.get("authorizeResponse");
+ Boolean captureResult = (Boolean)reply.get("authResult");
+ results.put("releaseResult", new Boolean(captureResult.booleanValue()));
+ results.put("releaseFlag",ar.getReasonCode());
+ results.put("releaseMessage",ar.getReasonText());
+ results.put("releaseRefNum", ar.getResponseField(AuthorizeResponse.TRANSACTION_ID));
+
+ if(captureResult.booleanValue()) { //passed
+ results.put("releaseCode", ar.getResponseField(AuthorizeResponse.AUTHORIZATION_CODE));
+ results.put("releaseAmount", new Double(ar.getResponseField(AuthorizeResponse.AMOUNT)));
+ } else {
+ results.put("releaseAmount", new Double("0.00"));
+
+ }
+
+ Debug.logInfo("processReleaseTransResult: " + results.toString(),module);
+ return results;
}
private static void processAuthCaptureTransResult(Map reply, Map results) {