| /******************************************************************************* |
| * 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.ideal; |
| |
| import java.io.IOException; |
| import java.math.BigDecimal; |
| import java.sql.Timestamp; |
| import java.util.Iterator; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.Random; |
| import java.util.Set; |
| |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| |
| import org.apache.ofbiz.base.util.Debug; |
| import org.apache.ofbiz.base.util.StringUtil; |
| import org.apache.ofbiz.base.util.UtilDateTime; |
| import org.apache.ofbiz.base.util.UtilHttp; |
| 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.transaction.GenericTransactionException; |
| import org.apache.ofbiz.entity.transaction.TransactionUtil; |
| import org.apache.ofbiz.entity.util.EntityQuery; |
| import org.apache.ofbiz.entity.util.EntityUtilProperties; |
| import org.apache.ofbiz.order.order.OrderChangeHelper; |
| import org.apache.ofbiz.product.store.ProductStoreWorker; |
| import org.apache.ofbiz.service.GenericServiceException; |
| import org.apache.ofbiz.service.LocalDispatcher; |
| import org.apache.ofbiz.service.ModelService; |
| |
| import com.ing.ideal.connector.IdealConnector; |
| import com.ing.ideal.connector.IdealException; |
| import com.ing.ideal.connector.Issuer; |
| import com.ing.ideal.connector.Issuers; |
| import com.ing.ideal.connector.Transaction; |
| |
| |
| public class IdealEvents { |
| |
| public static final String resource = "AccountingUiLabels"; |
| public static final String resourceErr = "AccountingErrorUiLabels"; |
| public static final String module = IdealEvents.class.getName(); |
| private static int decimals = UtilNumber.getBigDecimalScale("invoice.decimals"); |
| private static int rounding = UtilNumber.getBigDecimalRoundingMode("invoice.rounding"); |
| |
| /** Initiate iDEAL Request */ |
| public static String callIdeal(HttpServletRequest request, HttpServletResponse response) { |
| Locale locale = UtilHttp.getLocale(request); |
| Delegator delegator = (Delegator) request.getAttribute("delegator"); |
| |
| // get the orderId |
| String orderId = (String) request.getAttribute("orderId"); |
| String issuerId = (String) request.getAttribute("issuerId"); |
| |
| // get the order header |
| GenericValue orderHeader = null; |
| List<GenericValue> orderItemList = null; |
| try { |
| orderHeader = EntityQuery.use(delegator).from("OrderHeader").where("orderId", orderId).queryOne(); |
| orderItemList = EntityQuery.use(delegator).from("OrderItem").where("orderId", orderId).queryList(); |
| } catch (GenericEntityException e) { |
| Debug.logError(e, "Cannot get the order header for order: " + orderId, module); |
| request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resourceErr, "idealEvents.problemsGettingOrderHeader", locale)); |
| return "error"; |
| } |
| |
| // get the order total |
| BigDecimal orderTotal = orderHeader.getBigDecimal("grandTotal"); |
| |
| // get the product store |
| GenericValue productStore = ProductStoreWorker.getProductStore(request); |
| |
| if (productStore == null) { |
| Debug.logError("ProductStore is null", module); |
| request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resourceErr, "idealEvents.problemsGettingMerchantConfiguration", locale)); |
| return "error"; |
| } |
| |
| // get the payment properties file |
| GenericValue paymentConfig = ProductStoreWorker.getProductStorePaymentSetting(delegator, productStore.getString("productStoreId"), "EXT_IDEAL", null, true); |
| String configString = null; |
| String paymentGatewayConfigId = null; |
| if (paymentConfig != null) { |
| paymentGatewayConfigId = paymentConfig.getString("paymentGatewayConfigId"); |
| configString = paymentConfig.getString("paymentPropertiesPath"); |
| } |
| |
| if (configString == null) { |
| configString = "payment.properties"; |
| } |
| |
| String merchantId = getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "merchantId", configString, "merchantId"); |
| String merchantSubId = getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "merchantSubId", configString, "merchantSubId"); |
| String merchantReturnURL = getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "merchantReturnURL", configString, "merchantReturnURL"); |
| String acquirerURL = getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "acquirerURL", configString, "acquirerURL"); |
| String acquirerTimeout = getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "acquirerTimeout", configString, "acquirerTimeout"); |
| String privateCert = getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "privateCert", configString, "privateCert"); |
| String acquirerKeyStoreFilename = getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "acquirerKeyStoreFilename", configString, "acquirerKeyStoreFilename"); |
| String acquirerKeyStorePassword = getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "acquirerKeyStorePassword", configString, "acquirerKeyStorePassword"); |
| String merchantKeyStoreFilename = getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "merchantKeyStoreFilename", configString, "merchantKeyStoreFilename"); |
| String merchantKeyStorePassword = getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "merchantKeyStorePassword", configString, "merchantKeyStorePassword"); |
| String expirationPeriod = getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "expirationPeriod", configString, "expirationPeriod"); |
| |
| if (UtilValidate.isEmpty(merchantId) |
| || UtilValidate.isEmpty(merchantReturnURL) |
| || UtilValidate.isEmpty(privateCert) |
| || UtilValidate.isEmpty(merchantKeyStoreFilename) |
| || UtilValidate.isEmpty(merchantKeyStoreFilename)) { |
| Debug.logError("Payment properties is not configured properly, some notify URL from iDEAL is not correctly defined!", module); |
| request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resourceErr, "idealEvents.problemsGettingMerchantConfiguration", locale)); |
| return "error"; |
| } |
| |
| List<String> descriptionList = new LinkedList<String>(); |
| for (GenericValue orderItem : orderItemList) { |
| if (UtilValidate.isNotEmpty(orderItem.get("itemDescription"))){ |
| descriptionList.add((String) orderItem.get("itemDescription")); |
| } |
| } |
| |
| String orderDescription = StringUtil.join(descriptionList, ","); |
| String amount = orderTotal.setScale(decimals, rounding).movePointRight(2).toPlainString(); |
| |
| String redirectString = null; |
| |
| try { |
| IdealConnector connector = new IdealConnector("payment"); |
| Transaction transaction = new Transaction(); |
| transaction.setIssuerID(issuerId); |
| transaction.setAmount(amount); |
| transaction.setPurchaseID(orderId); |
| transaction.setDescription(orderDescription); |
| |
| String returnURL = merchantReturnURL + "?orderId=" + orderId; |
| Random random = new SecureRandom(); |
| String EntranceCode = Long.toString(Math.abs(random.nextLong()), 36); |
| transaction.setEntranceCode(EntranceCode); |
| transaction.setMerchantReturnURL(returnURL); |
| Transaction trx = connector.requestTransaction(transaction); |
| redirectString = trx.getIssuerAuthenticationURL(); |
| request.getSession().setAttribute("purchaseID", orderId); |
| request.getSession().setAttribute("payAmount", orderTotal.toPlainString()); |
| } catch (IdealException ex) { |
| Debug.logError(ex.getMessage(), module); |
| request.setAttribute("_ERROR_MESSAGE_", ex.getConsumerMessage()); |
| return "error"; |
| } |
| |
| // redirect to iDEAL |
| try { |
| response.sendRedirect(redirectString); |
| } catch (IOException e) { |
| Debug.logError(e, "Problems redirecting to iDEAL", module); |
| request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resourceErr, "idealEvents.problemsConnectingWithIdeal", locale)); |
| return "error"; |
| } |
| |
| return "success"; |
| } |
| |
| /** iDEAL notification */ |
| public static String idealNotify(HttpServletRequest request, HttpServletResponse response) { |
| Locale locale = UtilHttp.getLocale(request); |
| Delegator delegator = (Delegator) request.getAttribute("delegator"); |
| LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher"); |
| GenericValue userLogin = (GenericValue) request.getSession().getAttribute("userLogin"); |
| Map <String, Object> parametersMap = UtilHttp.getParameterMap(request); |
| String transactionId = request.getParameter("trxid"); |
| for (String name : parametersMap.keySet()) { |
| String value = request.getParameter(name); |
| Debug.logError("### Param: " + name + " => " + value, module); |
| } |
| |
| String orderId = null; |
| String paymentStatus = null; |
| try { |
| IdealConnector connector = new IdealConnector("payment"); |
| Transaction transaction = connector.requestTransactionStatus(transactionId); |
| orderId = transaction.getPurchaseID(); |
| if (orderId == null) { |
| orderId = (String) request.getSession().getAttribute("purchaseID"); |
| } |
| String payAmount = transaction.getAmount(); |
| if (payAmount == null) { |
| payAmount = (String) request.getSession().getAttribute("payAmount"); |
| } |
| paymentStatus = transaction.getStatus(); |
| request.setAttribute("transactionId", transactionId); |
| request.setAttribute("paymentStatus", paymentStatus); |
| request.setAttribute("paymentAmount", payAmount); |
| } catch (IdealException ex) { |
| Debug.logError(ex.getMessage(), module); |
| request.setAttribute("_ERROR_MESSAGE_", ex.getConsumerMessage()); |
| return "error"; |
| } |
| |
| // get the user |
| if (userLogin == null) { |
| String userLoginId = "system"; |
| try { |
| userLogin = EntityQuery.use(delegator).from("UserLogin").where("userLoginId", userLoginId).queryOne(); |
| } catch (GenericEntityException e) { |
| Debug.logError(e, "Cannot get UserLogin for: " + userLoginId + "; cannot continue", module); |
| request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resourceErr, "idealEvents.problemsGettingAuthenticationUser", locale)); |
| return "error"; |
| } |
| } |
| // get the order header |
| GenericValue orderHeader = null; |
| if (UtilValidate.isNotEmpty(orderId)) { |
| try { |
| orderHeader = EntityQuery.use(delegator).from("OrderHeader").where("orderId", orderId).queryOne(); |
| } catch (GenericEntityException e) { |
| Debug.logError(e, "Cannot get the order header for order: " + orderId, module); |
| request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resourceErr, "idealEvents.problemsGettingOrderHeader", locale)); |
| return "error"; |
| } |
| } else { |
| Debug.logError("iDEAL did not callback with a valid orderId!", module); |
| request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resourceErr, "idealEvents.noValidOrderIdReturned", locale)); |
| return "error"; |
| } |
| if (orderHeader == null) { |
| Debug.logError("Cannot get the order header for order: " + orderId, module); |
| request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resourceErr, "idealEvents.problemsGettingOrderHeader", locale)); |
| return "error"; |
| } |
| |
| // attempt to start a transaction |
| boolean okay = true; |
| boolean beganTransaction = false; |
| try { |
| beganTransaction = TransactionUtil.begin(); |
| // authorized |
| if ("Success".equals(paymentStatus)) { |
| okay = OrderChangeHelper.approveOrder(dispatcher, userLogin, orderId); |
| // cancelled |
| } else if ("Cancelled".equals(paymentStatus)) { |
| okay = OrderChangeHelper.cancelOrder(dispatcher, userLogin, orderId); |
| } |
| if (okay) { |
| // set the payment preference |
| okay = setPaymentPreferences(delegator, dispatcher, userLogin, orderId, request); |
| } |
| } catch (Exception e) { |
| String errMsg = "Error handling iDEAL notification"; |
| Debug.logError(e, errMsg, module); |
| try { |
| TransactionUtil.rollback(beganTransaction, errMsg, e); |
| } catch (GenericTransactionException gte2) { |
| Debug.logError(gte2, "Unable to rollback transaction", module); |
| } |
| } finally { |
| if (!okay) { |
| try { |
| TransactionUtil.rollback(beganTransaction, "Failure in processing iDEAL callback", null); |
| } catch (GenericTransactionException gte) { |
| Debug.logError(gte, "Unable to rollback transaction", module); |
| } |
| } else { |
| try { |
| TransactionUtil.commit(beganTransaction); |
| } catch (GenericTransactionException gte) { |
| Debug.logError(gte, "Unable to commit transaction", module); |
| } |
| } |
| } |
| if (okay) { |
| request.setAttribute("_EVENT_MESSAGE_", UtilProperties.getMessage(resource, "IdealSuccessful", locale)); |
| // attempt to release the offline hold on the order (workflow) |
| OrderChangeHelper.releaseInitialOrderHold(dispatcher, orderId); |
| // call the email confirm service |
| Map<String, String> emailContext = UtilMisc.toMap("orderId", orderId, "userLogin", userLogin); |
| try { |
| dispatcher.runSync("sendOrderConfirmation", emailContext); |
| } catch (GenericServiceException e) { |
| Debug.logError(e, "Problems sending email confirmation", module); |
| } |
| } |
| return "success"; |
| } |
| |
| private static boolean setPaymentPreferences(Delegator delegator, LocalDispatcher dispatcher, GenericValue userLogin, String orderId, HttpServletRequest request) { |
| Debug.logVerbose("Setting payment prefrences..", module); |
| List <GenericValue> paymentPrefs = null; |
| try { |
| paymentPrefs = EntityQuery.use(delegator).from("OrderPaymentPreference") |
| .where("orderId", orderId, "statusId", "PAYMENT_NOT_RECEIVED").queryList(); |
| } catch (GenericEntityException e) { |
| Debug.logError(e, "Cannot get payment preferences for order #" + orderId, module); |
| return false; |
| } |
| if (paymentPrefs.size() > 0) { |
| for (GenericValue pref : paymentPrefs) { |
| boolean okay = setPaymentPreference(dispatcher, userLogin, pref, request); |
| if (!okay) |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| private static boolean setPaymentPreference(LocalDispatcher dispatcher, GenericValue userLogin, GenericValue paymentPreference, HttpServletRequest request) { |
| Locale locale = UtilHttp.getLocale(request); |
| String paymentAmount = (String) request.getAttribute("paymentAmount"); |
| String paymentStatus = (String) request.getAttribute("paymentStatus"); |
| String transactionId = (String) request.getAttribute("transactionId"); |
| |
| List <GenericValue> toStore = new LinkedList <GenericValue> (); |
| java.sql.Timestamp authDate = UtilDateTime.nowTimestamp(); |
| |
| paymentPreference.set("maxAmount", new BigDecimal(paymentAmount)); |
| if ("Success".equals(paymentStatus)) { |
| paymentPreference.set("statusId", "PAYMENT_RECEIVED"); |
| } else if ("Cancelled".equals(paymentStatus)) { |
| paymentPreference.set("statusId", "PAYMENT_CANCELLED"); |
| } else { |
| paymentPreference.set("statusId", "PAYMENT_NOT_RECEIVED"); |
| } |
| toStore.add(paymentPreference); |
| Delegator delegator = paymentPreference.getDelegator(); |
| |
| // create the PaymentGatewayResponse |
| String responseId = delegator.getNextSeqId("PaymentGatewayResponse"); |
| GenericValue response = delegator.makeValue("PaymentGatewayResponse"); |
| response.set("paymentGatewayResponseId", responseId); |
| response.set("paymentServiceTypeEnumId", "PRDS_PAY_EXTERNAL"); |
| response.set("orderPaymentPreferenceId", paymentPreference.get("orderPaymentPreferenceId")); |
| response.set("paymentMethodTypeId", paymentPreference.get("paymentMethodTypeId")); |
| response.set("paymentMethodId", paymentPreference.get("paymentMethodId")); |
| |
| // set the auth info |
| response.set("amount", new BigDecimal(paymentAmount)); |
| response.set("currencyUomId", "EUR"); |
| response.set("referenceNum", transactionId); |
| response.set("gatewayCode", paymentStatus); |
| response.set("gatewayFlag", paymentStatus.substring(0,1)); |
| response.set("transactionDate", authDate); |
| toStore.add(response); |
| |
| try { |
| delegator.storeAll(toStore); |
| } catch (GenericEntityException e) { |
| Debug.logError(e, "Cannot set payment preference/payment info", module); |
| return false; |
| } |
| |
| GenericValue userLoginId = null; |
| try { |
| userLoginId = EntityQuery.use(delegator).from("UserLogin").where("userLoginId", "system").queryOne(); |
| } catch (GenericEntityException e) { |
| return false; |
| } |
| |
| // create a payment record too |
| Map <String, Object> results = null; |
| try { |
| String comment = UtilProperties.getMessage(resource, "AccountingPaymentReceiveViaiDEAL", locale); |
| results = dispatcher.runSync("createPaymentFromPreference", UtilMisc.toMap("userLogin", userLoginId, |
| "orderPaymentPreferenceId", paymentPreference.get("orderPaymentPreferenceId"), "comments", comment)); |
| } catch (GenericServiceException e) { |
| Debug.logError(e, "Failed to execute service createPaymentFromPreference", module); |
| request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resourceErr, "idealEvents.failedToExecuteServiceCreatePaymentFromPreference", locale)); |
| return false; |
| } |
| |
| if ((results == null) || (results.get(ModelService.RESPONSE_MESSAGE).equals(ModelService.RESPOND_ERROR))) { |
| Debug.logError((String) results.get(ModelService.ERROR_MESSAGE), module); |
| request.setAttribute("_ERROR_MESSAGE_", results.get(ModelService.ERROR_MESSAGE)); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| private static String getPaymentGatewayConfigValue(Delegator delegator, String paymentGatewayConfigId, String paymentGatewayConfigParameterName, |
| String resource, String parameterName) { |
| String returnValue = ""; |
| if (UtilValidate.isNotEmpty(paymentGatewayConfigId)) { |
| try { |
| GenericValue ideal = EntityQuery.use(delegator).from("PaymentGatewayiDEAL").where("paymentGatewayConfigId", paymentGatewayConfigId).queryOne(); |
| if (ideal != null) { |
| Object idealField = ideal.get(paymentGatewayConfigParameterName); |
| if (idealField != null) { |
| returnValue = idealField.toString().trim(); |
| } |
| } |
| } catch (GenericEntityException e) { |
| Debug.logError(e, module); |
| } |
| } else { |
| String value = EntityUtilProperties.getPropertyValue(resource, parameterName, delegator); |
| if (value != null) { |
| returnValue = value.trim(); |
| } |
| } |
| return returnValue; |
| } |
| |
| public static List<Issuer> getIssuerList() { |
| List<Issuer> issuerList = new LinkedList<Issuer>(); |
| try { |
| IdealConnector connector = new IdealConnector("payment"); |
| Issuers issuers = connector.getIssuerList(); |
| List<Issuer> shortList = issuers.getShortList(); |
| List<Issuer> longList = issuers.getLongList(); |
| for (Iterator<Issuer> iter = shortList.iterator(); iter.hasNext();) { |
| Issuer issuer = (Issuer) iter.next(); |
| issuerList.add(issuer); |
| } |
| for (Iterator<Issuer> iter = longList.iterator(); iter.hasNext();) { |
| Issuer issuer = (Issuer) iter.next(); |
| issuerList.add(issuer); |
| } |
| } catch (IdealException ex){ |
| Debug.logError(ex.getMessage(), module); |
| } |
| |
| return issuerList; |
| } |
| } |