blob: fc0c442cb83ca714359ae0cf59378dd29f3317ca [file] [log] [blame]
/*******************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*******************************************************************************/
package org.ofbiz.accounting.thirdparty.sagepay;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javolution.util.FastMap;
import org.ofbiz.accounting.payment.PaymentGatewayServices;
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.UtilDateTime;
import org.ofbiz.base.util.UtilFormatOut;
import org.ofbiz.base.util.UtilMisc;
import org.ofbiz.base.util.UtilProperties;
import org.ofbiz.entity.Delegator;
import org.ofbiz.entity.GenericEntityException;
import org.ofbiz.entity.GenericValue;
import org.ofbiz.entity.condition.EntityCondition;
import org.ofbiz.entity.util.EntityUtil;
import org.ofbiz.service.DispatchContext;
import org.ofbiz.service.GenericServiceException;
import org.ofbiz.service.LocalDispatcher;
import org.ofbiz.service.ServiceUtil;
public class SagePayPaymentServices {
public static final String module = SagePayPaymentServices.class.getName();
public final static String resource = "AccountingUiLabels";
private static Map<String, String> buildCustomerBillingInfo(Map<String, Object> context) {
Debug.logInfo("SagePay - Entered buildCustomerBillingInfo", module);
Debug.logInfo("SagePay buildCustomerBillingInfo context : " + context, module);
Map<String, String> billingInfo = FastMap.newInstance();
String orderId = null;
BigDecimal processAmount = null;
String currency = null;
String cardNumber = null;
String cardType = null;
String nameOnCard = null;
String expireDate = null;
String securityCode = null;
String postalCode = null;
String address = null;
try {
GenericValue opp = (GenericValue) context.get("orderPaymentPreference");
if (opp != null) {
if ("CREDIT_CARD".equals(opp.getString("paymentMethodTypeId"))) {
GenericValue creditCard = (GenericValue) context.get("creditCard");
if (creditCard == null || !(opp.get("paymentMethodId").equals(creditCard.get("paymentMethodId")))) {
creditCard = opp.getRelatedOne("CreditCard", false);
}
securityCode = opp.getString("securityCode");
//getting billing address
GenericValue billingAddress = (GenericValue) context.get("billingAddress");
postalCode = billingAddress.getString("postalCode");
String address2 = billingAddress.getString("address2");
if (address2 == null){
address2 = "";
}
address = billingAddress.getString("address1") + " " + address2;
//getting card details
cardNumber = creditCard.getString("cardNumber");
String firstName = creditCard.getString("firstNameOnCard");
String middleName = creditCard.getString("middleNameOnCard");
String lastName = creditCard.getString("lastNameOnCard");
if (middleName == null){
middleName = "";
}
nameOnCard = firstName + " " + middleName + " " + lastName;
cardType = creditCard.getString("cardType");
if (cardType != null) {
if ("CCT_MASTERCARD".equals(cardType)) {
cardType = "MC";
}
if ("CCT_VISAELECTRON".equals(cardType)) {
cardType = "UKE";
}
if ("CCT_DINERSCLUB".equals(cardType)) {
cardType = "DC";
}
if ("CCT_SWITCH".equals(cardType)) {
cardType = "MAESTRO";
}
}
expireDate = creditCard.getString("expireDate");
String month = expireDate.substring(0,2);
String year = expireDate.substring(5);
expireDate = month + year;
//getting order details
orderId = UtilFormatOut.checkNull((String) context.get("orderId"));
processAmount = (BigDecimal) context.get("processAmount");
currency = (String) context.get("currency");
} else {
Debug.logWarning("Payment preference " + opp + " is not a credit card", module);
}
}
} catch (GenericEntityException ex) {
Debug.logError("Cannot build customer information for " + context + " due to error: " + ex.getMessage(), module);
return null;
}
billingInfo.put("orderId", orderId);
billingInfo.put("amount", processAmount.toString());
billingInfo.put("currency", currency);
billingInfo.put("description", orderId);
billingInfo.put("cardNumber", cardNumber);
billingInfo.put("cardHolder", nameOnCard);
billingInfo.put("expiryDate", expireDate);
billingInfo.put("cardType", cardType);
billingInfo.put("cv2", securityCode);
billingInfo.put("billingPostCode", postalCode);
billingInfo.put("billingAddress", address);
Debug.logInfo("SagePay billingInfo : " + billingInfo, module);
Debug.logInfo("SagePay - Exiting buildCustomerBillingInfo", module);
return billingInfo;
}
public static Map<String, Object> ccAuth(DispatchContext dctx, Map<String, Object> context) {
Debug.logInfo("SagePay - Entered ccAuth", module);
Debug.logInfo("SagePay ccAuth context : " + context, module);
Map<String, Object> response = null;
String orderId = (String) context.get("orderId");
Locale locale = (Locale) context.get("locale");
GenericValue orderPaymentPreference = (GenericValue) context.get("orderPaymentPreference");
if (orderPaymentPreference == null) {
response = ServiceUtil.returnError(UtilProperties.getMessage(resource, "AccountingSagePayOrderPaymenPreferenceIsNull", UtilMisc.toMap("orderId", orderId, "orderPaymentPreference", orderPaymentPreference), locale));
} else {
response = processCardAuthorisationPayment(dctx, context);
}
Debug.logInfo("SagePay ccAuth response : " + response, module);
Debug.logInfo("SagePay - Exiting ccAuth", module);
return response;
}
private static Map<String, Object> processCardAuthorisationPayment(DispatchContext ctx, Map<String, Object> context) {
Map<String, Object> result = ServiceUtil.returnSuccess();
LocalDispatcher dispatcher = ctx.getDispatcher();
Locale locale = (Locale) context.get("locale");
Map<String, String> billingInfo = buildCustomerBillingInfo(context);
String paymentGatewayConfigId = (String) context.get("paymentGatewayConfigId");
try {
Map<String, Object> paymentResult = dispatcher.runSync("SagePayPaymentAuthentication",
UtilMisc.toMap(
"paymentGatewayConfigId", paymentGatewayConfigId,
"vendorTxCode", billingInfo.get("orderId"),
"cardHolder", billingInfo.get("cardHolder"),
"cardNumber", billingInfo.get("cardNumber"),
"expiryDate", billingInfo.get("expiryDate"),
"cardType", billingInfo.get("cardType"),
"cv2", billingInfo.get("cv2"),
"description", billingInfo.get("description"),
"amount", billingInfo.get("amount"),
"currency", billingInfo.get("currency"),
"billingAddress", billingInfo.get("billingAddress"),
"billingPostCode", billingInfo.get("billingPostCode")
)
);
Debug.logInfo("SagePay - SagePayPaymentAuthentication result : " + paymentResult, module);
String transactionType = (String) paymentResult.get("transactionType");
String status = (String) paymentResult.get("status");
String statusDetail = (String) paymentResult.get("statusDetail");
String vpsTxId = (String) paymentResult.get("vpsTxId");
String securityKey = (String) paymentResult.get("securityKey");
String txAuthNo = (String) paymentResult.get("txAuthNo");
String vendorTxCode = (String) paymentResult.get("vendorTxCode");
String amount = (String) paymentResult.get("amount");
if (status != null && "OK".equals(status)) {
Debug.logInfo("SagePay - Payment authorized for order : " + vendorTxCode, module);
result = SagePayUtil.buildCardAuthorisationPaymentResponse(Boolean.TRUE, txAuthNo, securityKey, new BigDecimal(amount), vpsTxId, vendorTxCode, statusDetail);
if ("PAYMENT".equals(transactionType)) {
Map<String,Object> captureResult = SagePayUtil.buildCardCapturePaymentResponse(Boolean.TRUE, txAuthNo, securityKey, new BigDecimal(amount), vpsTxId, vendorTxCode, statusDetail);
result.putAll(captureResult);
}
} else if (status != null && "INVALID".equals(status)) {
Debug.logInfo("SagePay - Invalid authorisation request for order : " + vendorTxCode, module);
result = SagePayUtil.buildCardAuthorisationPaymentResponse(Boolean.FALSE, null, null, BigDecimal.ZERO, "INVALID", vendorTxCode, statusDetail);
} else if (status != null && "MALFORMED".equals(status)) {
Debug.logInfo("SagePay - Malformed authorisation request for order : " + vendorTxCode, module);
result = SagePayUtil.buildCardAuthorisationPaymentResponse(Boolean.FALSE, null, null, BigDecimal.ZERO, "MALFORMED", vendorTxCode, statusDetail);
} else if (status != null && "NOTAUTHED".equals(status)) {
Debug.logInfo("SagePay - NotAuthed authorisation request for order : " + vendorTxCode, module);
result = SagePayUtil.buildCardAuthorisationPaymentResponse(Boolean.FALSE, null, securityKey, BigDecimal.ZERO, vpsTxId, vendorTxCode, statusDetail);
} else if (status != null && "REJECTED".equals(status)) {
Debug.logInfo("SagePay - Rejected authorisation request for order : " + vendorTxCode, module);
result = SagePayUtil.buildCardAuthorisationPaymentResponse(Boolean.FALSE, null, securityKey, new BigDecimal(amount), vpsTxId, vendorTxCode, statusDetail);
} else {
Debug.logInfo("SagePay - Invalid status " + status + " received for order : " + vendorTxCode, module);
result = SagePayUtil.buildCardAuthorisationPaymentResponse(Boolean.FALSE, null, null, BigDecimal.ZERO, "ERROR", vendorTxCode, statusDetail);
}
} catch(GenericServiceException e) {
Debug.logError(e, "Error in calling SagePayPaymentAuthentication", module);
result = ServiceUtil.returnError(UtilProperties.getMessage(resource, "AccountingSagePayPaymentAuthorisationException", UtilMisc.toMap("errorString", e.getMessage()), locale));
}
return result;
}
public static Map<String, Object> ccCapture(DispatchContext ctx, Map<String, Object> context) {
Debug.logInfo("SagePay - Entered ccCapture", module);
Debug.logInfo("SagePay ccCapture context : " + context, module);
GenericValue orderPaymentPreference = (GenericValue) context.get("orderPaymentPreference");
GenericValue authTransaction = PaymentGatewayServices.getAuthTransaction(orderPaymentPreference);
context.put("authTransaction", authTransaction);
Map<String, Object> response = processCardCapturePayment(ctx, context);
Debug.logInfo("SagePay ccCapture response : " + response, module);
Debug.logInfo("SagePay - Exiting ccCapture", module);
return response;
}
private static Map<String, Object> processCardCapturePayment(DispatchContext ctx, Map<String, Object> context) {
Map<String, Object> result = ServiceUtil.returnSuccess();
LocalDispatcher dispatcher = ctx.getDispatcher();
Locale locale = (Locale) context.get("locale");
String paymentGatewayConfigId = (String) context.get("paymentGatewayConfigId");
GenericValue authTransaction = (GenericValue) context.get("authTransaction");
BigDecimal amount = (BigDecimal) context.get("captureAmount");
String vendorTxCode = (String) authTransaction.get("altReference");
String vpsTxId = (String) authTransaction.get("referenceNum");
String securityKey = (String) authTransaction.get("gatewayFlag");
String txAuthCode = (String) authTransaction.get("gatewayCode");
try {
Map<String, Object> paymentResult = dispatcher.runSync("SagePayPaymentAuthorisation",
UtilMisc.toMap(
"paymentGatewayConfigId", paymentGatewayConfigId,
"vendorTxCode", vendorTxCode,
"vpsTxId", vpsTxId,
"securityKey", securityKey,
"txAuthNo", txAuthCode,
"amount", amount.toString()
)
);
Debug.logInfo("SagePay - SagePayPaymentAuthorisation result : " + paymentResult, module);
String status = (String) paymentResult.get("status");
String statusDetail = (String) paymentResult.get("statusDetail");
if (status != null && "OK".equals(status)) {
Debug.logInfo("SagePay Payment Released for Order : " + vendorTxCode, module);
result = SagePayUtil.buildCardCapturePaymentResponse(Boolean.TRUE, txAuthCode, securityKey, amount, vpsTxId, vendorTxCode, statusDetail);
} else {
Debug.logInfo("SagePay - Invalid status " + status + " received for order : " + vendorTxCode, module);
result = SagePayUtil.buildCardCapturePaymentResponse(Boolean.FALSE, txAuthCode, securityKey, amount, vpsTxId, vendorTxCode, statusDetail);
}
} catch(GenericServiceException e) {
Debug.logError(e, "Error in calling SagePayPaymentAuthorisation", module);
result = ServiceUtil.returnError(UtilProperties.getMessage(resource, "AccountingSagePayPaymentAuthorisationException", UtilMisc.toMap("errorString", e.getMessage()), locale));
}
return result;
}
public static Map<String, Object> ccRefund(DispatchContext ctx, Map<String, Object> context) {
Debug.logInfo("SagePay - Entered ccRefund", module);
Debug.logInfo("SagePay ccRefund context : " + context, module);
Locale locale = (Locale) context.get("locale");
Delegator delegator = ctx.getDelegator();
GenericValue orderPaymentPreference = (GenericValue) context.get("orderPaymentPreference");
GenericValue captureTransaction = PaymentGatewayServices.getCaptureTransaction(orderPaymentPreference);
if (captureTransaction == null) {
return ServiceUtil.returnError(UtilProperties.getMessage(resource, "AccountingPaymentTransactionAuthorizationNotFoundCannotRefund", locale));
}
Debug.logInfo("SagePay ccRefund captureTransaction : " + captureTransaction, module);
GenericValue creditCard = null;
try {
creditCard = orderPaymentPreference.getRelatedOne("CreditCard", false);
} catch (GenericEntityException e) {
Debug.logError(e, "Error getting CreditCard for OrderPaymentPreference : " + orderPaymentPreference, module);
return ServiceUtil.returnError(UtilProperties.getMessage(resource, "AccountingPaymentUnableToGetCCInfo", locale) + " " + orderPaymentPreference);
}
context.put("creditCard",creditCard);
context.put("captureTransaction", captureTransaction);
List<GenericValue> authTransactions = PaymentGatewayServices.getAuthTransactions(orderPaymentPreference);
EntityCondition authCondition = EntityCondition.makeCondition("paymentServiceTypeEnumId", "PRDS_PAY_AUTH");
List<GenericValue> authTransactions1 = EntityUtil.filterByCondition(authTransactions, authCondition);
GenericValue authTransaction = EntityUtil.getFirst(authTransactions1);
Timestamp authTime = authTransaction.getTimestamp("transactionDate");
Calendar authCal = Calendar.getInstance();
authCal.setTimeInMillis(authTime.getTime());
Timestamp nowTime = UtilDateTime.nowTimestamp();
Calendar nowCal = Calendar.getInstance();
nowCal.setTimeInMillis(nowTime.getTime());
Calendar yesterday = Calendar.getInstance();
yesterday.set(nowCal.get(Calendar.YEAR), nowCal.get(Calendar.MONTH), nowCal.get(Calendar.DATE), 23, 59, 59);
yesterday.add(Calendar.DAY_OF_YEAR, -1);
Map<String, Object> response = null;
if (authCal.before(yesterday)) {
Debug.logInfo("SagePay - Calling Refund for Refund", module);
response = processCardRefundPayment(ctx, context);
} else {
Calendar cal = Calendar.getInstance();
cal.set(nowCal.get(Calendar.YEAR), nowCal.get(Calendar.MONTH), nowCal.get(Calendar.DATE), 23, 49, 59);
if (authCal.before(cal)) {
Debug.logInfo("SagePay - Calling Void for Refund", module);
response = processCardVoidPayment(ctx, context);
} else {
Debug.logInfo("SagePay - Calling Refund for Refund", module);
response = processCardRefundPayment(ctx, context);
}
}
Debug.logInfo("SagePay ccRefund response : " + response, module);
return response;
}
private static Map<String, Object> processCardRefundPayment(DispatchContext ctx, Map<String, Object> context) {
Map<String, Object> result = ServiceUtil.returnSuccess();
LocalDispatcher dispatcher = ctx.getDispatcher();
Locale locale = (Locale) context.get("locale");
String paymentGatewayConfigId = (String) context.get("paymentGatewayConfigId");
GenericValue captureTransaction = (GenericValue) context.get("captureTransaction");
BigDecimal amount = (BigDecimal) context.get("refundAmount");
String orderId = (String) captureTransaction.get("altReference");
orderId = "R" + orderId;
try {
Map<String, Object> paymentResult = dispatcher.runSync("SagePayPaymentRefund",
UtilMisc.toMap(
"paymentGatewayConfigId", paymentGatewayConfigId,
"vendorTxCode", orderId,
"amount", amount.toString(),
"currency", "GBP",
"description", orderId,
"relatedVPSTxId", captureTransaction.get("referenceNum"),
"relatedVendorTxCode", captureTransaction.get("altReference"),
"relatedSecurityKey", captureTransaction.get("gatewayFlag"),
"relatedTxAuthNo", captureTransaction.get("gatewayCode")
)
);
Debug.logInfo("SagePay - SagePayPaymentRefund result : " + paymentResult, module);
String status = (String) paymentResult.get("status");
String statusDetail = (String) paymentResult.get("statusDetail");
String vpsTxId = (String) paymentResult.get("vpsTxId");
String txAuthNo = (String) paymentResult.get("txAuthNo");
if (status != null && "OK".equals(status)) {
Debug.logInfo("SagePay Payment Refunded for Order : " + orderId, module);
result = SagePayUtil.buildCardRefundPaymentResponse(Boolean.TRUE, txAuthNo, amount, vpsTxId, orderId, statusDetail);
} else {
Debug.logInfo("SagePay - Invalid status " + status + " received for order : " + orderId, module);
result = SagePayUtil.buildCardRefundPaymentResponse(Boolean.FALSE, null, BigDecimal.ZERO, status, orderId, statusDetail);
}
} catch(GenericServiceException e) {
Debug.logError(e, "Error in calling SagePayPaymentRefund", module);
result = ServiceUtil.returnError(UtilProperties.getMessage(resource, "AccountingSagePayPaymentRefundException", UtilMisc.toMap("errorString", e.getMessage()), locale));
}
return result;
}
private static Map<String, Object> processCardVoidPayment(DispatchContext ctx, Map<String, Object> context) {
Map<String, Object> result = ServiceUtil.returnSuccess();
LocalDispatcher dispatcher = ctx.getDispatcher();
Locale locale = (Locale) context.get("locale");
String paymentGatewayConfigId = (String) context.get("paymentGatewayConfigId");
GenericValue captureTransaction = (GenericValue) context.get("captureTransaction");
BigDecimal amount = (BigDecimal) context.get("refundAmount");
String orderId = (String) captureTransaction.get("altReference");
try {
Map<String, Object> paymentResult = dispatcher.runSync("SagePayPaymentVoid",
UtilMisc.toMap(
"paymentGatewayConfigId", paymentGatewayConfigId,
"vendorTxCode", captureTransaction.get("altReference"),
"vpsTxId", captureTransaction.get("referenceNum"),
"securityKey", captureTransaction.get("gatewayFlag"),
"txAuthNo", captureTransaction.get("gatewayCode")
)
);
Debug.logInfo("SagePay - SagePayPaymentVoid result : " + paymentResult, module);
String status = (String) paymentResult.get("status");
String statusDetail = (String) paymentResult.get("statusDetail");
if (status != null && "OK".equals(status)) {
Debug.logInfo("SagePay Payment Voided for Order : " + orderId, module);
result = SagePayUtil.buildCardVoidPaymentResponse(Boolean.TRUE, amount, "SUCCESS", orderId, statusDetail);
} else if (status != null && "MALFORMED".equals(status)) {
Debug.logInfo("SagePay - Malformed void request for order : " + orderId, module);
result = SagePayUtil.buildCardVoidPaymentResponse(Boolean.FALSE, BigDecimal.ZERO, "MALFORMED", orderId, statusDetail);
} else if (status != null && "INVALID".equals(status)){
Debug.logInfo("SagePay - Invalid void request for order : " + orderId, module);
result = SagePayUtil.buildCardVoidPaymentResponse(Boolean.FALSE, BigDecimal.ZERO, "INVALID", orderId, statusDetail);
} else if (status != null && "ERROR".equals(status)){
Debug.logInfo("SagePay - Error in void request for order : " + orderId, module);
result = SagePayUtil.buildCardVoidPaymentResponse(Boolean.FALSE, BigDecimal.ZERO, "ERROR", orderId, statusDetail);
}
} catch(GenericServiceException e) {
Debug.logError(e, "Error in calling SagePayPaymentVoid", module);
result = ServiceUtil.returnError(UtilProperties.getMessage(resource, "AccountingSagePayPaymentVoidException", UtilMisc.toMap("errorString", e.getMessage()), locale));
}
return result;
}
public static Map<String, Object> ccRelease(DispatchContext ctx, Map<String, Object> context) {
Debug.logInfo("SagePay - Entered ccRelease", module);
Debug.logInfo("SagePay ccRelease context : " + context, module);
Locale locale = (Locale) context.get("locale");
GenericValue orderPaymentPreference = (GenericValue) context.get("orderPaymentPreference");
GenericValue authTransaction = PaymentGatewayServices.getAuthTransaction(orderPaymentPreference);
if (authTransaction == null) {
return ServiceUtil.returnError(UtilProperties.getMessage(resource, "AccountingPaymentTransactionAuthorizationNotFoundCannotRelease", locale));
}
context.put("authTransaction", authTransaction);
Map<String, Object> response = processCardReleasePayment(ctx, context);
Debug.logInfo("SagePay ccRelease response : " + response, module);
return response;
}
private static Map<String, Object> processCardReleasePayment(DispatchContext ctx, Map<String, Object> context) {
Map<String, Object> result = ServiceUtil.returnSuccess();
Locale locale = (Locale) context.get("locale");
LocalDispatcher dispatcher = ctx.getDispatcher();
String paymentGatewayConfigId = (String) context.get("paymentGatewayConfigId");
BigDecimal amount = (BigDecimal) context.get("releaseAmount");
GenericValue authTransaction = (GenericValue) context.get("authTransaction");
String orderId = (String) authTransaction.get("altReference");
String refNum = (String) authTransaction.get("referenceNum");
try {
Map<String, Object> paymentResult = dispatcher.runSync("SagePayPaymentRelease",
UtilMisc.toMap(
"paymentGatewayConfigId", paymentGatewayConfigId,
"vendorTxCode", orderId,
"releaseAmount", amount.toString(),
"vpsTxId", refNum,
"securityKey", authTransaction.get("gatewayFlag"),
"txAuthNo", authTransaction.get("gatewayCode")
)
);
Debug.logInfo("SagePay - SagePayPaymentRelease result : " + paymentResult, module);
String status = (String) paymentResult.get("status");
String statusDetail = (String) paymentResult.get("statusDetail");
if (status != null && "OK".equals(status)) {
Debug.logInfo("SagePay Payment Released for Order : " + orderId, module);
result = SagePayUtil.buildCardReleasePaymentResponse(Boolean.TRUE, null, amount, refNum, orderId, statusDetail);
} else {
Debug.logInfo("SagePay - Invalid status " + status + " received for order : " + orderId, module);
result = SagePayUtil.buildCardReleasePaymentResponse(Boolean.FALSE, null, amount, refNum, orderId, statusDetail);
}
} catch(GenericServiceException e) {
Debug.logError(e, "Error in calling SagePayPaymentRelease", module);
result = ServiceUtil.returnError(UtilProperties.getMessage(resource, "AccountingSagePayPaymentReleaseException", UtilMisc.toMap("errorString", e.getMessage()), locale));
}
return result;
}
}