serviceName = paymentSettings.getString("paymentService");
}
paymentConfig = paymentSettings.getString("paymentPropertiesPath");
paymentGatewayConfigId = paymentSettings.getString("paymentGatewayConfigId");
} else {
throw new GeneralException("Could not find any valid payment settings for order with ID [" + orh.getOrderId() + "], and payment operation (serviceType) [" + serviceType + "]");
}
// make sure the service name is not null
if (serviceName == null) {
throw new GeneralException("Invalid payment processor, serviceName is null: " + paymentSettings);
}
// make the process context
Map<String, Object> processContext = FastMap.newInstance();
// get the visit record to obtain the client's IP address
GenericValue orderHeader = orh.getOrderHeader();
//if (orderHeader == null) {}
String visitId = orderHeader.getString("visitId");
GenericValue visit = null;
if (visitId != null) {
try {
visit = orderHeader.getDelegator().findByPrimaryKey("Visit", UtilMisc.toMap("visitId", visitId));
} catch (GenericEntityException e) {
Debug.logError(e, module);
}
}
if (visit != null && visit.get("clientIpAddress") != null) {
processContext.put("customerIpAddress", visit.getString("clientIpAddress"));
}
GenericValue productStore = orderHeader.getRelatedOne("ProductStore");
processContext.put("userLogin", userLogin);
processContext.put("orderId", orh.getOrderId());
processContext.put("orderItems", orh.getOrderItems());
processContext.put("shippingAddress", EntityUtil.getFirst(orh.getShippingLocations())); // TODO refactor the payment API to handle support all addresses
processContext.put("paymentConfig", paymentConfig);
processContext.put("paymentGatewayConfigId", paymentGatewayConfigId);
processContext.put("currency", orh.getCurrency());
processContext.put("orderPaymentPreference", paymentPreference);
if (paymentPreference.get("securityCode") != null) {
processContext.put("cardSecurityCode", paymentPreference.get("securityCode"));
}
// get the billing information
getBillingInformation(orh, paymentPreference, processContext);
// default charge is totalRemaining
BigDecimal processAmount = totalRemaining;
// use override or max amount available
if (overrideAmount != null) {
processAmount = overrideAmount;
} else if (paymentPreference.get("maxAmount") != null) {
processAmount = paymentPreference.getBigDecimal("maxAmount");
}
// Check if the order is a replacement order
boolean replacementOrderFlag = isReplacementOrder(orderHeader);
// don't authorized more then what is required
if (!replacementOrderFlag && processAmount.compareTo(totalRemaining) > 0) {
processAmount = totalRemaining;
}
// format the decimal
processAmount = processAmount.setScale(decimals, rounding);
if (Debug.verboseOn()) Debug.logVerbose("Charging amount: " + processAmount, module);
processContext.put("processAmount", processAmount);
// invoke the processor
Map<String, Object> processorResult = null;
try {
// invoke the payment processor; allow 5 minute transaction timeout and require a new tx; we'll capture the error and pass back nicely
GenericValue creditCard = (GenericValue) processContext.get("creditCard");
// only try other exp dates if orderHeader.autoOrderShoppingListId is not empty, productStore.autoOrderCcTryExp=Y and this payment is a creditCard
boolean tryOtherExpDates = "Y".equals(productStore.getString("autoOrderCcTryExp")) && creditCard != null && UtilValidate.isNotEmpty(orderHeader.getString("autoOrderShoppingListId"));
// if we are not trying other expire dates OR if we are and the date is after today, then run the service
if (!tryOtherExpDates || UtilValidate.isDateAfterToday(creditCard.getString("expireDate"))) {
processorResult = dispatcher.runSync(serviceName, processContext, TX_TIME, true);
}
// try other expire dates if the expireDate is not after today, or if we called the auth service and resultBadExpire = true
if (tryOtherExpDates && (!UtilValidate.isDateAfterToday(creditCard.getString("expireDate")) || (processorResult != null && Boolean.TRUE.equals(processorResult.get("resultBadExpire"))))) {
// try adding 2, 3, 4 years later with the same month
String expireDate = creditCard.getString("expireDate");
int dateSlash1 = expireDate.indexOf("/");
String month = expireDate.substring(0, dateSlash1);
String year = expireDate.substring(dateSlash1 + 1);
// start adding 2 years, if comes back with resultBadExpire try again up to twice incrementing one year
year = StringUtil.addToNumberString(year, 2);
// note that this is set in memory only for now, not saved to the database unless successful
creditCard.set("expireDate", month + "/" + year);
// don't need to set back in the processContext, it's already there: processContext.put("creditCard", creditCard);
processorResult = dispatcher.runSync(serviceName, processContext, TX_TIME, true);
// note that these additional tries will only be done if the service return is not an error, in that case we let it pass through to the normal error handling
if (!ServiceUtil.isError(processorResult) && Boolean.TRUE.equals(processorResult.get("resultBadExpire"))) {
// okay, try one more year...
year = StringUtil.addToNumberString(year, 1);
creditCard.set("expireDate", month + "/" + year);
processorResult = dispatcher.runSync(serviceName, processContext, TX_TIME, true);
}
if (!ServiceUtil.isError(processorResult) && Boolean.TRUE.equals(processorResult.get("resultBadExpire"))) {
// okay, try one more year... and this is the last try
year = StringUtil.addToNumberString(year, 1);
creditCard.set("expireDate", month + "/" + year);
processorResult = dispatcher.runSync(serviceName, processContext, TX_TIME, true);
}
// at this point if we have a successful result, let's save the new creditCard expireDate
if (!ServiceUtil.isError(processorResult) && Boolean.TRUE.equals(processorResult.get("authResult"))) {
// TODO: this is bad; we should be expiring the old card and creating a new one instead of editing it
creditCard.store();
}
}
} catch (GenericServiceException e) {
Debug.logError(e, "Error occurred on: " + serviceName + " => " + processContext, module);
throw new GeneralException("Problems invoking payment processor! Will retry later. Order ID is: [" + orh.getOrderId() + "", e);
}
if (processorResult != null) {
// check for errors from the processor implementation
if (ServiceUtil.isError(processorResult)) {