blob: 99d135bf3e1748d2cf2328d79088b45b423022ba [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.apache.ofbiz.accounting.thirdparty.gosoftware;
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import org.apache.ofbiz.accounting.payment.PaymentGatewayServices;
import org.apache.ofbiz.base.util.Debug;
import org.apache.ofbiz.base.util.GeneralException;
import org.apache.ofbiz.base.util.StringUtil;
import org.apache.ofbiz.base.util.UtilMisc;
import org.apache.ofbiz.base.util.UtilNumber;
import org.apache.ofbiz.base.util.UtilProperties;
import org.apache.ofbiz.base.util.UtilValidate;
import org.apache.ofbiz.entity.Delegator;
import org.apache.ofbiz.entity.GenericEntityException;
import org.apache.ofbiz.entity.GenericValue;
import org.apache.ofbiz.entity.util.EntityQuery;
import org.apache.ofbiz.entity.util.EntityUtilProperties;
import org.apache.ofbiz.service.DispatchContext;
import org.apache.ofbiz.service.GenericServiceException;
import org.apache.ofbiz.service.LocalDispatcher;
import org.apache.ofbiz.service.ServiceUtil;
public class RitaServices {
public static final String module = RitaServices.class.getName();
private static int decimals = UtilNumber.getBigDecimalScale("invoice.decimals");
private static int rounding = UtilNumber.getBigDecimalRoundingMode("invoice.rounding");
public final static String resource = "AccountingUiLabels";
public static final String resourceOrder = "OrderUiLabels";
public static Map<String, Object> ccAuth(DispatchContext dctx, Map<String, ? extends Object> context) {
Locale locale = (Locale) context.get("locale");
Delegator delegator = dctx.getDelegator();
Properties props = buildPccProperties(context, delegator);
RitaApi api = getApi(props, "CREDIT");
if (api == null) {
return ServiceUtil.returnError(UtilProperties.getMessage(resource,
"AccountingRitaErrorGettingPaymentGatewayConfig", locale));
}
try {
RitaServices.setCreditCardInfo(api, dctx.getDelegator(), context);
} catch (GeneralException e) {
return ServiceUtil.returnError(e.getMessage());
}
// basic tx info
api.set(RitaApi.TRANS_AMOUNT, getAmountString(context, "processAmount"));
api.set(RitaApi.INVOICE, context.get("orderId"));
// command setting
if ("1".equals(props.getProperty("autoBill"))) {
// sale
api.set(RitaApi.COMMAND, "SALE");
} else {
// pre-auth
api.set(RitaApi.COMMAND, "PRE_AUTH");
}
// send the transaction
RitaApi out = null;
try {
Debug.logInfo("Sending request to RiTA", module);
out = api.send();
} catch (IOException e) {
Debug.logError(e, module);
return ServiceUtil.returnError(e.getMessage());
} catch (GeneralException e) {
Debug.logError(e, module);
return ServiceUtil.returnError(e.getMessage());
}
if (out != null) {
Map<String, Object> result = ServiceUtil.returnSuccess();
String resultCode = out.get(RitaApi.RESULT);
boolean passed = false;
if ("CAPTURED".equals(resultCode)) {
result.put("authResult", Boolean.TRUE);
result.put("captureResult", Boolean.TRUE);
passed = true;
} else if ("APPROVED".equals(resultCode)) {
result.put("authCode", out.get(RitaApi.AUTH_CODE));
result.put("authResult", Boolean.TRUE);
passed = true;
} else if ("PROCESSED".equals(resultCode)) {
result.put("authResult", Boolean.TRUE);
} else {
result.put("authResult", Boolean.FALSE);
}
result.put("authRefNum", out.get(RitaApi.INTRN_SEQ_NUM) != null ? out.get(RitaApi.INTRN_SEQ_NUM) : "");
result.put("processAmount", context.get("processAmount"));
result.put("authCode", out.get(RitaApi.AUTH_CODE));
result.put("authFlag", out.get(RitaApi.REFERENCE));
result.put("authMessage", out.get(RitaApi.RESULT));
result.put("cvCode", out.get(RitaApi.CVV2_CODE));
result.put("avsCode", out.get(RitaApi.AVS_CODE));
if (!passed) {
String respMsg = out.get(RitaApi.RESULT) + " / " + out.get(RitaApi.INTRN_SEQ_NUM);
result.put("customerRespMsgs", UtilMisc.toList(respMsg));
}
if (result.get("captureResult") != null) {
result.put("captureCode", out.get(RitaApi.AUTH_CODE));
result.put("captureFlag", out.get(RitaApi.REFERENCE));
result.put("captureRefNum", out.get(RitaApi.INTRN_SEQ_NUM));
result.put("captureMessage", out.get(RitaApi.RESULT));
}
return result;
} else {
return ServiceUtil.returnError(UtilProperties.getMessage(resource,
"AccountingRitaResultIsNull", locale));
}
}
public static Map<String, Object> ccCapture(DispatchContext dctx, Map<String, ? extends Object> context) {
GenericValue orderPaymentPreference = (GenericValue) context.get("orderPaymentPreference");
Locale locale = (Locale) context.get("locale");
Delegator delegator = dctx.getDelegator();
//lets see if there is a auth transaction already in context
GenericValue authTransaction = (GenericValue) context.get("authTrans");
if (authTransaction == null) {
authTransaction = PaymentGatewayServices.getAuthTransaction(orderPaymentPreference);
}
if (authTransaction == null) {
return ServiceUtil.returnError(UtilProperties.getMessage(resource,
"AccountingPaymentTransactionAuthorizationNotFoundCannotCapture", locale));
}
// setup the RiTA Interface
Properties props = buildPccProperties(context, delegator);
RitaApi api = getApi(props, "CREDIT");
if (api == null) {
return ServiceUtil.returnError(UtilProperties.getMessage(resource,
"AccountingRitaErrorGettingPaymentGatewayConfig", locale));
}
api.set(RitaApi.ORIG_SEQ_NUM, authTransaction.getString("referenceNum"));
api.set(RitaApi.COMMAND, "COMPLETION");
// send the transaction
RitaApi out = null;
try {
out = api.send();
} catch (IOException e) {
Debug.logError(e, module);
return ServiceUtil.returnError(e.getMessage());
} catch (GeneralException e) {
Debug.logError(e, module);
return ServiceUtil.returnError(e.getMessage());
}
if (out != null) {
Map<String, Object> result = ServiceUtil.returnSuccess();
String resultCode = out.get(RitaApi.RESULT);
if ("CAPTURED".equals(resultCode)) {
result.put("captureResult", Boolean.TRUE);
} else {
result.put("captureResult", Boolean.FALSE);
}
result.put("captureAmount", context.get("captureAmount"));
result.put("captureRefNum", out.get(RitaApi.INTRN_SEQ_NUM) != null ? out.get(RitaApi.INTRN_SEQ_NUM) : "");
result.put("captureCode", out.get(RitaApi.AUTH_CODE));
result.put("captureFlag", out.get(RitaApi.REFERENCE));
result.put("captureMessage", out.get(RitaApi.RESULT));
return result;
} else {
return ServiceUtil.returnError(UtilProperties.getMessage(resource,
"AccountingRitaResultIsNull", locale));
}
}
public static Map<String, Object> ccVoidRelease(DispatchContext dctx, Map<String, ? extends Object> context) {
return ccVoid(dctx, context, false);
}
public static Map<String, Object> ccVoidRefund(DispatchContext dctx, Map<String, ? extends Object> context) {
return ccVoid(dctx, context, true);
}
private static Map<String, Object> ccVoid(DispatchContext dctx, Map<String, ? extends Object> context, boolean isRefund) {
GenericValue orderPaymentPreference = (GenericValue) context.get("orderPaymentPreference");
Locale locale = (Locale) context.get("locale");
Delegator delegator = dctx.getDelegator();
//lets see if there is a auth transaction already in context
GenericValue authTransaction = (GenericValue) context.get("authTrans");
if (authTransaction == null) {
authTransaction = PaymentGatewayServices.getAuthTransaction(orderPaymentPreference);
}
if (authTransaction == null) {
return ServiceUtil.returnError(UtilProperties.getMessage(resource,
"AccountingPaymentTransactionAuthorizationNotFoundCannotRelease", locale));
}
// setup the RiTA Interface
Properties props = buildPccProperties(context, delegator);
RitaApi api = getApi(props, "CREDIT");
if (api == null) {
return ServiceUtil.returnError(UtilProperties.getMessage(resource,
"AccountingRitaErrorGettingPaymentGatewayConfig", locale));
}
api.set(RitaApi.TRANS_AMOUNT, getAmountString(context, isRefund ? "refundAmount" : "releaseAmount"));
api.set(RitaApi.ORIG_SEQ_NUM, authTransaction.getString("referenceNum"));
api.set(RitaApi.COMMAND, "VOID");
// check to make sure we are configured for SALE mode
if (!"1".equals(props.getProperty("autoBill"))) {
return ServiceUtil.returnError(UtilProperties.getMessage(resource,
"AccountingRitaCannotSupportReleasingPreAuth", locale));
}
// send the transaction
RitaApi out = null;
try {
out = api.send();
} catch (IOException e) {
Debug.logError(e, module);
return ServiceUtil.returnError(e.getMessage());
} catch (GeneralException e) {
Debug.logError(e, module);
return ServiceUtil.returnError(e.getMessage());
}
if (out != null) {
Map<String, Object> result = ServiceUtil.returnSuccess();
String resultCode = out.get(RitaApi.RESULT);
if ("VOIDED".equals(resultCode)) {
result.put(isRefund ? "refundResult" : "releaseResult", Boolean.TRUE);
} else {
result.put(isRefund ? "refundResult" : "releaseResult", Boolean.FALSE);
}
result.put(isRefund ? "refundAmount" : "releaseAmount", context.get(isRefund ? "refundAmount" : "releaseAmount"));
result.put(isRefund ? "refundRefNum" : "releaseRefNum", out.get(RitaApi.INTRN_SEQ_NUM) != null ? out.get(RitaApi.INTRN_SEQ_NUM) : "");
result.put(isRefund ? "refundCode" : "releaseCode", out.get(RitaApi.AUTH_CODE));
result.put(isRefund ? "refundFlag" : "releaseFlag", out.get(RitaApi.REFERENCE));
result.put(isRefund ? "refundMessage" : "releaseMessage", out.get(RitaApi.RESULT));
return result;
} else {
return ServiceUtil.returnError(UtilProperties.getMessage(resource,
"AccountingRitaResultIsNull", locale));
}
}
public static Map<String, Object> ccCreditRefund(DispatchContext dctx, Map<String, ? extends Object> context) {
GenericValue orderPaymentPreference = (GenericValue) context.get("orderPaymentPreference");
Locale locale = (Locale) context.get("locale");
Delegator delegator = dctx.getDelegator();
//lets see if there is a auth transaction already in context
GenericValue authTransaction = (GenericValue) context.get("authTrans");
if (authTransaction == null) {
authTransaction = PaymentGatewayServices.getAuthTransaction(orderPaymentPreference);
}
if (authTransaction == null) {
return ServiceUtil.returnError(UtilProperties.getMessage(resource,
"AccountingPaymentTransactionAuthorizationNotFoundCannotRefund", locale));
}
// setup the RiTA Interface
Properties props = buildPccProperties(context, delegator);
RitaApi api = getApi(props, "CREDIT");
if (api == null) {
return ServiceUtil.returnError(UtilProperties.getMessage(resource,
"AccountingRitaErrorGettingPaymentGatewayConfig", locale));
}
// set the required cc info
try {
RitaServices.setCreditCardInfo(api, dctx.getDelegator(), context);
} catch (GeneralException e) {
return ServiceUtil.returnError(e.getMessage());
}
api.set(RitaApi.TRANS_AMOUNT, getAmountString(context, "refundAmount"));
api.set(RitaApi.ORIG_SEQ_NUM, authTransaction.getString("referenceNum"));
api.set(RitaApi.COMMAND, "CREDIT");
// send the transaction
RitaApi out = null;
try {
out = api.send();
} catch (IOException e) {
Debug.logError(e, module);
return ServiceUtil.returnError(e.getMessage());
} catch (GeneralException e) {
Debug.logError(e, module);
return ServiceUtil.returnError(e.getMessage());
}
if (out != null) {
Map<String, Object> result = ServiceUtil.returnSuccess();
String resultCode = out.get(RitaApi.RESULT);
if ("CAPTURED".equals(resultCode)) {
result.put("refundResult", Boolean.TRUE);
} else {
result.put("refundResult", Boolean.FALSE);
}
result.put("refundAmount", context.get("refundAmount"));
result.put("refundRefNum", out.get(RitaApi.INTRN_SEQ_NUM) != null ? out.get(RitaApi.INTRN_SEQ_NUM) : "");
result.put("refundCode", out.get(RitaApi.AUTH_CODE));
result.put("refundFlag", out.get(RitaApi.REFERENCE));
result.put("refundMessage", out.get(RitaApi.RESULT));
return result;
} else {
return ServiceUtil.returnError(UtilProperties.getMessage(resource,
"AccountingRitaResultIsNull", locale));
}
}
public static Map<String, Object> ccRefund(DispatchContext dctx, Map<String, ? extends Object> context) {
LocalDispatcher dispatcher = dctx.getDispatcher();
Delegator delegator = dctx.getDelegator();
GenericValue orderPaymentPreference = (GenericValue) context.get("orderPaymentPreference");
Locale locale = (Locale) context.get("locale");
GenericValue orderHeader = null;
try {
orderHeader = orderPaymentPreference.getRelatedOne("OrderHeader", false);
} catch (GenericEntityException e) {
Debug.logError(e, module);
return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrder,
"OrderOrderNotFound", UtilMisc.toMap("orderId", orderPaymentPreference.getString("orderId")), locale));
}
if (orderHeader != null) {
String terminalId = orderHeader.getString("terminalId");
boolean isVoid = false;
if (terminalId != null) {
Timestamp orderDate = orderHeader.getTimestamp("orderDate");
GenericValue terminalState = null;
try {
terminalState = EntityQuery.use(delegator).from("PosTerminalState")
.where("posTerminalId", terminalId).filterByDate("openedDate", "closedDate").queryFirst();
} catch (GenericEntityException e) {
Debug.logError(e, module);
}
// this is the current opened terminal
if (terminalState != null) {
Timestamp openDate = terminalState.getTimestamp("openedDate");
// if the order date is after the open date of the current state
// the order happend within the current open/close of the terminal
if (orderDate.after(openDate)) {
isVoid = true;
}
}
}
Map<String, Object> refundResp = null;
try {
if (isVoid) {
refundResp = dispatcher.runSync("ritaCCVoidRefund", context);
} else {
refundResp = dispatcher.runSync("ritaCCCreditRefund", context);
}
} catch (GenericServiceException e) {
Debug.logError(e, module);
return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrder,
"AccountingRitaErrorServiceException", locale));
}
return refundResp;
} else {
return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrder,
"OrderOrderNotFound", UtilMisc.toMap("orderId", orderPaymentPreference.getString("orderId")), locale));
}
}
private static void setCreditCardInfo(RitaApi api, Delegator delegator, Map<String, ? extends Object> context) throws GeneralException {
GenericValue orderPaymentPreference = (GenericValue) context.get("orderPaymentPreference");
GenericValue creditCard = (GenericValue) context.get("creditCard");
if (creditCard == null) {
creditCard = EntityQuery.use(delegator).from("CreditCard").where("paymentMethodId", orderPaymentPreference.getString("paymentMethodId")).queryOne();
}
if (creditCard != null) {
List<String> expDateList = StringUtil.split(creditCard.getString("expireDate"), "/");
String month = expDateList.get(0);
String year = expDateList.get(1);
String y2d = year.substring(2);
String title = creditCard.getString("titleOnCard");
String fname = creditCard.getString("firstNameOnCard");
String mname = creditCard.getString("middleNameOnCard");
String lname = creditCard.getString("lastNameOnCard");
String sufix = creditCard.getString("suffixOnCard");
StringBuilder name = new StringBuilder();
if (UtilValidate.isNotEmpty(title)) {
name.append(title).append(" ");
}
if (UtilValidate.isNotEmpty(fname)) {
name.append(fname).append(" ");
}
if (UtilValidate.isNotEmpty(mname)) {
name.append(mname).append(" ");
}
if (UtilValidate.isNotEmpty(lname)) {
name.append(lname).append(" ");
}
if (UtilValidate.isNotEmpty(sufix)) {
name.append(sufix);
}
String nameOnCard = name.toString().trim();
String acctNumber = creditCard.getString("cardNumber");
String cvNum = (String) context.get("cardSecurityCode");
api.set(RitaApi.ACCT_NUM, acctNumber);
api.set(RitaApi.EXP_MONTH, month);
api.set(RitaApi.EXP_YEAR, y2d);
api.set(RitaApi.CARDHOLDER, nameOnCard);
if (UtilValidate.isNotEmpty(cvNum)) {
api.set(RitaApi.CVV2, cvNum);
}
// billing address information
GenericValue billingAddress = (GenericValue) context.get("billingAddress");
if (billingAddress != null) {
api.set(RitaApi.CUSTOMER_STREET, billingAddress.getString("address1"));
api.set(RitaApi.CUSTOMER_ZIP, billingAddress.getString("postalCode"));
} else {
String zipCode = orderPaymentPreference.getString("billingPostalCode");
if (UtilValidate.isNotEmpty(zipCode)) {
api.set(RitaApi.CUSTOMER_ZIP, zipCode);
}
}
// set the present flag
String presentFlag = orderPaymentPreference.getString("presentFlag");
if (presentFlag == null) {
presentFlag = "N";
}
api.set(RitaApi.PRESENT_FLAG, presentFlag.equals("Y") ? "3" : "1"); // 1, no present, 2 present, 3 swiped
} else {
throw new GeneralException("No CreditCard object found");
}
}
private static RitaApi getApi(Properties props) {
if (props == null) {
Debug.logError("Cannot load API w/ null properties", module);
return null;
}
String host = props.getProperty("host");
int port = 0;
try {
port = Integer.parseInt(props.getProperty("port"));
} catch (Exception e) {
Debug.logError(e, module);
}
boolean ssl = props.getProperty("ssl", "N").equals("Y") ? true : false;
RitaApi api = null;
if (port > 0 && host != null) {
api = new RitaApi(host, port, ssl);
} else {
api = new RitaApi();
}
api.set(RitaApi.CLIENT_ID, props.getProperty("clientID"));
api.set(RitaApi.USER_ID, props.getProperty("userID"));
api.set(RitaApi.USER_PW, props.getProperty("userPW"));
api.set(RitaApi.FORCE_FLAG, props.getProperty("forceTx"));
return api;
}
private static RitaApi getApi(Properties props, String paymentType) {
RitaApi api = getApi(props);
api.set(RitaApi.FUNCTION_TYPE, "PAYMENT");
api.set(RitaApi.PAYMENT_TYPE, paymentType);
return api;
}
private static Properties buildPccProperties(Map<String, ? extends Object> context, Delegator delegator) {
String configString = (String) context.get("paymentConfig");
if (configString == null) {
configString = "payment.properties";
}
String clientId = EntityUtilProperties.getPropertyValue(configString, "payment.rita.clientID", delegator);
String userId = EntityUtilProperties.getPropertyValue(configString, "payment.rita.userID", delegator);
String userPw = EntityUtilProperties.getPropertyValue(configString, "payment.rita.userPW", delegator);
String host = EntityUtilProperties.getPropertyValue(configString, "payment.rita.host", delegator);
String port = EntityUtilProperties.getPropertyValue(configString, "payment.rita.port", delegator);
String ssl = EntityUtilProperties.getPropertyValue(configString, "payment.rita.ssl", "N", delegator);
String autoBill = EntityUtilProperties.getPropertyValue(configString, "payment.rita.autoBill", "0", delegator);
String forceTx = EntityUtilProperties.getPropertyValue(configString, "payment.rita.forceTx", "0", delegator);
// some property checking
if (UtilValidate.isEmpty(clientId)) {
Debug.logWarning("The clientID property in [" + configString + "] is not configured", module);
return null;
}
if (UtilValidate.isEmpty(userId)) {
Debug.logWarning("The userID property in [" + configString + "] is not configured", module);
return null;
}
if (UtilValidate.isEmpty(userPw)) {
Debug.logWarning("The userPW property in [" + configString + "] is not configured", module);
return null;
}
// create some properties for CS Client
Properties props = new Properties();
props.put("clientID", clientId);
props.put("userID", userId);
props.put("userPW", userPw);
props.put("host", host);
props.put("port", port);
props.put("ssl", ssl);
props.put("autoBill", autoBill);
props.put("forceTx", forceTx);
Debug.logInfo("Returning properties - " + props, module);
return props;
}
private static String getAmountString(Map<String, ? extends Object> context, String amountField) {
BigDecimal processAmount = (BigDecimal) context.get(amountField);
return processAmount.setScale(decimals, rounding).toPlainString();
}
}