/******************************************************************************* * 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.payment; import java.math.BigDecimal; import java.security.SecureRandom; import java.sql.Timestamp; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Random; import org.apache.ofbiz.base.util.Debug; import org.apache.ofbiz.base.util.GeneralException; import org.apache.ofbiz.base.util.UtilDateTime; import org.apache.ofbiz.base.util.UtilMisc; 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.order.finaccount.FinAccountHelper; import org.apache.ofbiz.order.order.OrderReadHelper; import org.apache.ofbiz.product.store.ProductStoreWorker; 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 GiftCertificateServices { public static final String module = GiftCertificateServices.class.getName(); public static final String resourceError = "AccountingErrorUiLabels"; public static final String resourceOrderError = "OrderErrorUiLabels"; // These are default settings, in case ProductStoreFinActSetting does not have them public static final int CARD_NUMBER_LENGTH = 14; public static final int PIN_NUMBER_LENGTH = 6; public static BigDecimal ZERO = BigDecimal.ZERO; // Base Gift Certificate Services public static Map<String, Object> createGiftCertificate(DispatchContext dctx, Map<String, ? extends Object> context) { LocalDispatcher dispatcher = dctx.getDispatcher(); Delegator delegator = dctx.getDelegator(); Locale locale = (Locale) context.get("locale"); GenericValue userLogin = (GenericValue) context.get("userLogin"); String productStoreId = (String) context.get("productStoreId"); BigDecimal initialAmount = (BigDecimal) context.get("initialAmount"); String partyId = (String) context.get("partyId"); if (UtilValidate.isEmpty(partyId)) { partyId = "_NA_"; } String currencyUom = (String) context.get("currency"); if (UtilValidate.isEmpty(currencyUom)) { currencyUom = EntityUtilProperties.getPropertyValue("general", "currency.uom.id.default", "USD", delegator); } String cardNumber = null; String pinNumber = null; String refNum = null; String finAccountId = null; try { final String accountName = "Gift Certificate Account"; final String deposit = "DEPOSIT"; GenericValue giftCertSettings = EntityQuery.use(delegator).from("ProductStoreFinActSetting") .where("productStoreId", productStoreId, "finAccountTypeId", FinAccountHelper.giftCertFinAccountTypeId) .cache().queryOne(); Map<String, Object> acctResult = null; if ("Y".equals(giftCertSettings.getString("requirePinCode"))) { // TODO: move this code to createFinAccountForStore as well int cardNumberLength = CARD_NUMBER_LENGTH; int pinNumberLength = PIN_NUMBER_LENGTH; if (giftCertSettings.getLong("accountCodeLength") != null) { cardNumberLength = giftCertSettings.getLong("accountCodeLength").intValue(); } if (giftCertSettings.getLong("pinCodeLength") != null) { pinNumberLength = giftCertSettings.getLong("pinCodeLength").intValue(); } cardNumber = generateNumber(delegator, cardNumberLength, true); pinNumber = generateNumber(delegator, pinNumberLength, false); // in this case, the card number is the finAccountId finAccountId = cardNumber; // create the FinAccount Map<String, Object> acctCtx = UtilMisc.<String, Object>toMap("finAccountId", finAccountId); acctCtx.put("finAccountTypeId", FinAccountHelper.giftCertFinAccountTypeId); acctCtx.put("finAccountName", accountName); acctCtx.put("finAccountCode", pinNumber); acctCtx.put("userLogin", userLogin); acctResult = dispatcher.runSync("createFinAccount", acctCtx); } else { acctResult = dispatcher.runSync("createFinAccountForStore", UtilMisc.<String, Object>toMap("productStoreId", productStoreId, "finAccountTypeId", FinAccountHelper.giftCertFinAccountTypeId, "userLogin", userLogin)); if (acctResult.get("finAccountId") != null) { finAccountId = cardNumber = (String) acctResult.get("finAccountId"); } if (acctResult.get("finAccountCode") != null) { cardNumber = (String) acctResult.get("finAccountCode"); } } if (ServiceUtil.isError(acctResult)) { String error = ServiceUtil.getErrorMessage(acctResult); return ServiceUtil.returnError(error); } // create the initial (deposit) transaction // do something tricky here: run as the "system" user // that can actually create a financial account transaction GenericValue permUserLogin = EntityQuery.use(delegator).from("UserLogin").where("userLoginId", "system").cache().queryOne(); refNum = createTransaction(delegator, dispatcher, permUserLogin, initialAmount, productStoreId, partyId, currencyUom, deposit, finAccountId, locale); } catch (GenericEntityException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCreationError", locale)); } catch (GenericServiceException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCreationError", locale)); } catch (GeneralException e) { Debug.logError(e, module); return ServiceUtil.returnError(e.getMessage()); } Map<String, Object> result = ServiceUtil.returnSuccess(); result.put("cardNumber", cardNumber); result.put("pinNumber", pinNumber); result.put("initialAmount", initialAmount); result.put("processResult", Boolean.TRUE); result.put("responseCode", "1"); result.put("referenceNum", refNum); Debug.logInfo("Create GC Result - " + result, module); return result; } public static Map<String, Object> addFundsToGiftCertificate(DispatchContext dctx, Map<String, ? extends Object> context) { LocalDispatcher dispatcher = dctx.getDispatcher(); Delegator delegator = dctx.getDelegator(); Locale locale = (Locale) context.get("locale"); final String deposit = "DEPOSIT"; GenericValue userLogin = (GenericValue) context.get("userLogin"); String productStoreId = (String) context.get("productStoreId"); String cardNumber = (String) context.get("cardNumber"); String pinNumber = (String) context.get("pinNumber"); BigDecimal amount = (BigDecimal) context.get("amount"); String partyId = (String) context.get("partyId"); if (UtilValidate.isEmpty(partyId)) { partyId = "_NA_"; } String currencyUom = (String) context.get("currency"); if (UtilValidate.isEmpty(currencyUom)) { currencyUom = EntityUtilProperties.getPropertyValue("general", "currency.uom.id.default", "USD", delegator); } String finAccountId = null; GenericValue finAccount = null; // validate the pin if the store requires it and figure out the finAccountId from card number try { GenericValue giftCertSettings = EntityQuery.use(delegator).from("ProductStoreFinActSetting") .where("productStoreId", productStoreId, "finAccountTypeId", FinAccountHelper.giftCertFinAccountTypeId) .cache().queryOne(); if ("Y".equals(giftCertSettings.getString("requirePinCode"))) { if (!validatePin(delegator, cardNumber, pinNumber)) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberPinNotValid", locale)); } finAccountId = cardNumber; } else { finAccount = FinAccountHelper.getFinAccountFromCode(cardNumber, delegator); if (finAccount != null) { finAccountId = finAccount.getString("finAccountId"); } } } catch (GenericEntityException e) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingFinAccountSetting", UtilMisc.toMap("productStoreId", productStoreId, "finAccountTypeId", FinAccountHelper.giftCertFinAccountTypeId), locale)); } if (finAccountId == null) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingFinAccountNotFound", UtilMisc.toMap("finAccountId", ""), locale)); } if (finAccount == null) { try { finAccount = EntityQuery.use(delegator).from("FinAccount").where("finAccountId", finAccountId).queryOne(); } catch (GenericEntityException e) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingFinAccountNotFound", UtilMisc.toMap("finAccountId", finAccountId), locale)); } } // get the previous balance BigDecimal previousBalance = ZERO; if (finAccount.get("availableBalance") != null) { previousBalance = finAccount.getBigDecimal("availableBalance"); } // create the transaction BigDecimal balance = ZERO; String refNum = null; try { refNum = GiftCertificateServices.createTransaction(delegator, dispatcher, userLogin, amount, productStoreId, partyId, currencyUom, deposit, finAccountId, locale); finAccount.refresh(); balance = finAccount.getBigDecimal("availableBalance"); } catch (GeneralException e) { Debug.logError(e, module); return ServiceUtil.returnError(e.getMessage()); } Map<String, Object> result = ServiceUtil.returnSuccess(); result.put("previousBalance", previousBalance); result.put("balance", balance); result.put("amount", amount); result.put("processResult", Boolean.TRUE); result.put("responseCode", "1"); result.put("referenceNum", refNum); Debug.logInfo("Add Funds GC Result - " + result, module); return result; } public static Map<String, Object> redeemGiftCertificate(DispatchContext dctx, Map<String, ? extends Object> context) { LocalDispatcher dispatcher = dctx.getDispatcher(); Delegator delegator = dctx.getDelegator(); final String withdrawl = "WITHDRAWAL"; Locale locale = (Locale) context.get("locale"); GenericValue userLogin = (GenericValue) context.get("userLogin"); String productStoreId = (String) context.get("productStoreId"); String cardNumber = (String) context.get("cardNumber"); String pinNumber = (String) context.get("pinNumber"); BigDecimal amount = (BigDecimal) context.get("amount"); String partyId = (String) context.get("partyId"); if (UtilValidate.isEmpty(partyId)) { partyId = "_NA_"; } String currencyUom = (String) context.get("currency"); if (UtilValidate.isEmpty(currencyUom)) { currencyUom = EntityUtilProperties.getPropertyValue("general", "currency.uom.id.default", "USD", delegator); } // validate the amount if (amount.compareTo(BigDecimal.ZERO) < 0) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingFinAccountMustBePositive", locale)); } // validate the pin if the store requires it try { GenericValue giftCertSettings = EntityQuery.use(delegator).from("ProductStoreFinActSetting") .where("productStoreId", productStoreId, "finAccountTypeId", FinAccountHelper.giftCertFinAccountTypeId) .cache().queryOne(); if ("Y".equals(giftCertSettings.getString("requirePinCode")) && !validatePin(delegator, cardNumber, pinNumber)) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberPinNotValid", locale)); } } catch (GenericEntityException ex) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingFinAccountSetting", UtilMisc.toMap("productStoreId", productStoreId, "finAccountTypeId", FinAccountHelper.giftCertFinAccountTypeId), locale)); } Debug.logInfo("Attempting to redeem GC for " + amount, module); GenericValue finAccount = null; try { finAccount = EntityQuery.use(delegator).from("FinAccount").where("finAccountId", cardNumber).queryOne(); } catch (GenericEntityException e) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingFinAccountNotFound", UtilMisc.toMap("finAccountId", cardNumber), locale)); } // check the actual balance (excluding authorized amounts) and create the transaction if it is sufficient BigDecimal previousBalance = finAccount.get("actualBalance") == null ? BigDecimal.ZERO : finAccount.getBigDecimal("actualBalance"); BigDecimal balance = BigDecimal.ZERO; String refNum = null; Boolean procResult; if (previousBalance.compareTo(amount) >= 0) { try { refNum = GiftCertificateServices.createTransaction(delegator, dispatcher, userLogin, amount, productStoreId, partyId, currencyUom, withdrawl, cardNumber, locale); finAccount.refresh(); balance = finAccount.get("availableBalance") == null ? BigDecimal.ZERO : finAccount.getBigDecimal("availableBalance"); procResult = Boolean.TRUE; } catch (GeneralException e) { Debug.logError(e, module); return ServiceUtil.returnError(e.getMessage()); } } else { procResult = Boolean.FALSE; balance = previousBalance; refNum = "N/A"; } Map<String, Object> result = ServiceUtil.returnSuccess(); result.put("previousBalance", previousBalance); result.put("balance", balance); result.put("amount", amount); result.put("processResult", procResult); result.put("responseCode", "2"); result.put("referenceNum", refNum); Debug.logInfo("Redeem GC Result - " + result, module); return result; } public static Map<String, Object> checkGiftCertificateBalance(DispatchContext dctx, Map<String, ? extends Object> context) { Delegator delegator = dctx.getDelegator(); String cardNumber = (String) context.get("cardNumber"); String pinNumber = (String) context.get("pinNumber"); Locale locale = (Locale) context.get("locale"); // validate the pin if (!validatePin(delegator, cardNumber, pinNumber)) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberPinNotValid", locale)); } GenericValue finAccount = null; try { finAccount = EntityQuery.use(delegator).from("FinAccount").where("finAccountId", cardNumber).queryOne(); } catch (GenericEntityException e) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingFinAccountNotFound", UtilMisc.toMap("finAccountId", cardNumber), locale)); } // TODO: get the real currency from context // get the balance BigDecimal balance = finAccount.get("availableBalance") == null ? BigDecimal.ZERO : finAccount.getBigDecimal("availableBalance"); Map<String, Object> result = ServiceUtil.returnSuccess(); result.put("balance", balance); Debug.logInfo("GC Balance Result - " + result, module); return result; } // Fullfilment Services public static Map<String, Object> giftCertificateProcessor(DispatchContext dctx, Map<String, ? extends Object> context) { LocalDispatcher dispatcher = dctx.getDispatcher(); Delegator delegator = dctx.getDelegator(); GenericValue userLogin = (GenericValue) context.get("userLogin"); Locale locale = (Locale) context.get("locale"); BigDecimal amount = (BigDecimal) context.get("processAmount"); String currency = (String) context.get("currency"); // make sure we have a currency if (currency == null) { currency = EntityUtilProperties.getPropertyValue("general", "currency.uom.id.default", "USD", delegator); } // get the authorizations GenericValue orderPaymentPreference = (GenericValue) context.get("orderPaymentPreference"); GenericValue authTransaction = (GenericValue) context.get("authTrans"); if (authTransaction == null) { authTransaction = PaymentGatewayServices.getAuthTransaction(orderPaymentPreference); } if (authTransaction == null) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingFinAccountCannotCapture", locale)); } // get the gift certificate and its authorization from the authorization String finAccountAuthId = authTransaction.getString("referenceNum"); try { GenericValue finAccountAuth = EntityQuery.use(delegator).from("FinAccountAuth").where("finAccountAuthId", finAccountAuthId).queryOne(); GenericValue giftCard = finAccountAuth.getRelatedOne("FinAccount", false); // make sure authorization has not expired Timestamp authExpiration = finAccountAuth.getTimestamp("thruDate"); if ((authExpiration != null) && (authExpiration.before(UtilDateTime.nowTimestamp()))) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingFinAccountAuthorizationExpired", UtilMisc.toMap("paymentGatewayResponseId", authTransaction.getString("paymentGatewayResponseId"), "authExpiration", authExpiration), locale)); } // make sure the fin account itself has not expired if ((giftCard.getTimestamp("thruDate") != null) && (giftCard.getTimestamp("thruDate").before(UtilDateTime.nowTimestamp()))) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberExpired", UtilMisc.toMap("thruDate", giftCard.getTimestamp("thruDate")), locale)); } // obtain the order information OrderReadHelper orh = new OrderReadHelper(delegator, orderPaymentPreference.getString("orderId")); Map<String, Object> redeemCtx = new HashMap<String, Object>(); redeemCtx.put("userLogin", userLogin); redeemCtx.put("productStoreId", orh.getProductStoreId()); redeemCtx.put("cardNumber", giftCard.get("finAccountId")); redeemCtx.put("pinNumber", giftCard.get("finAccountCode")); redeemCtx.put("currency", currency); if (orh.getBillToParty() != null) { redeemCtx.put("partyId", orh.getBillToParty().get("partyId")); } redeemCtx.put("amount", amount); // invoke the redeem service Map<String, Object> redeemResult = null; redeemResult = dispatcher.runSync("redeemGiftCertificate", redeemCtx); if (ServiceUtil.isError(redeemResult)) { return redeemResult; } // now release the authorization should this use the gift card release service? Map<String, Object> releaseResult = dispatcher.runSync("expireFinAccountAuth", UtilMisc.<String, Object>toMap("userLogin", userLogin, "finAccountAuthId", finAccountAuthId)); if (ServiceUtil.isError(releaseResult)) { return releaseResult; } String authRefNum = authTransaction.getString("referenceNum"); Map<String, Object> result = ServiceUtil.returnSuccess(); if (redeemResult != null) { Boolean processResult = (Boolean) redeemResult.get("processResult"); result.put("processAmount", amount); result.put("captureResult", processResult); result.put("captureCode", "C"); result.put("captureRefNum", redeemResult.get("referenceNum")); result.put("authRefNum", authRefNum); } return result; } catch (GenericEntityException ex) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotProcess", UtilMisc.toMap("errorString", ex.getMessage()), locale)); } catch (GenericServiceException ex) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotProcess", UtilMisc.toMap("errorString", ex.getMessage()), locale)); } } public static Map<String, Object> giftCertificateAuthorize(DispatchContext dctx, Map<String, ? extends Object> context) { LocalDispatcher dispatcher = dctx.getDispatcher(); Delegator delegator = dctx.getDelegator(); GenericValue userLogin = (GenericValue) context.get("userLogin"); Locale locale = (Locale) context.get("locale"); GenericValue giftCard = (GenericValue) context.get("giftCard"); String currency = (String) context.get("currency"); String orderId = (String) context.get("orderId"); BigDecimal amount = (BigDecimal) context.get("processAmount"); // make sure we have a currency if (currency == null) { currency = EntityUtilProperties.getPropertyValue("general", "currency.uom.id.default", "USD", delegator); } // obtain the order information OrderReadHelper orh = new OrderReadHelper(delegator, orderId); String productStoreId = orh.getProductStoreId(); try { // if the store requires pin codes, then validate pin code against card number, and the gift certificate's finAccountId is the gift card's card number // otherwise, the gift card's card number is an ecrypted string, which must be decoded to find the FinAccount GenericValue giftCertSettings = EntityQuery.use(delegator).from("ProductStoreFinActSetting") .where("productStoreId", productStoreId, "finAccountTypeId", FinAccountHelper.giftCertFinAccountTypeId) .cache().queryOne(); GenericValue finAccount = null; String finAccountId = null; if (UtilValidate.isNotEmpty(giftCertSettings)) { if ("Y".equals(giftCertSettings.getString("requirePinCode"))) { if (validatePin(delegator, giftCard.getString("cardNumber"), giftCard.getString("pinNumber"))) { finAccountId = giftCard.getString("cardNumber"); finAccount = EntityQuery.use(delegator).from("FinAccount").where("finAccountId", finAccountId).queryOne(); } } else { finAccount = FinAccountHelper.getFinAccountFromCode(giftCard.getString("cardNumber"), delegator); if (finAccount == null) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberNotFound", UtilMisc.toMap("finAccountId", ""), locale)); } finAccountId = finAccount.getString("finAccountId"); } } else { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingFinAccountSetting", UtilMisc.toMap("productStoreId", productStoreId, "finAccountTypeId", FinAccountHelper.giftCertFinAccountTypeId), locale)); } if (finAccountId == null) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberPinNotValid", locale)); } // check for expiration date if ((finAccount.getTimestamp("thruDate") != null) && (finAccount.getTimestamp("thruDate").before(UtilDateTime.nowTimestamp()))) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberExpired", UtilMisc.toMap("thruDate", finAccount.getTimestamp("thruDate")), locale)); } // check the amount to authorize against the available balance of fin account, which includes active authorizations as well as transactions BigDecimal availableBalance = finAccount.getBigDecimal("availableBalance"); Boolean processResult = null; String refNum = null; Map<String, Object> result = ServiceUtil.returnSuccess(); // make sure to round and scale it to the same as availableBalance amount = amount.setScale(FinAccountHelper.decimals, FinAccountHelper.rounding); // if availableBalance equal to or greater than amount, then auth if (UtilValidate.isNotEmpty(availableBalance) && availableBalance.compareTo(amount) >= 0) { Timestamp thruDate = null; if (giftCertSettings.getLong("authValidDays") != null) { thruDate = UtilDateTime.getDayEnd(UtilDateTime.nowTimestamp(), giftCertSettings.getLong("authValidDays")); } Map<String, Object> tmpResult = dispatcher.runSync("createFinAccountAuth", UtilMisc.<String, Object>toMap("finAccountId", finAccountId, "amount", amount, "currencyUomId", currency, "thruDate", thruDate, "userLogin", userLogin)); if (ServiceUtil.isError(tmpResult)) { return tmpResult; } else { refNum = (String) tmpResult.get("finAccountAuthId"); processResult = Boolean.TRUE; } } else { Debug.logError("Attempted to authorize [" + amount + "] against a balance of only [" + availableBalance + "]", module); refNum = "N/A"; // a refNum is always required from authorization processResult = Boolean.FALSE; } result.put("processAmount", amount); result.put("authResult", processResult); result.put("processAmount", amount); result.put("authFlag", "2"); result.put("authCode", "A"); result.put("captureCode", "C"); result.put("authRefNum", refNum); return result; } catch (GenericEntityException ex) { Debug.logError(ex, "Cannot authorize gift certificate", module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotAuthorize", UtilMisc.toMap("errorString", ex.getMessage()), locale)); } catch (GenericServiceException ex) { Debug.logError(ex, "Cannot authorize gift certificate", module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotAuthorize", UtilMisc.toMap("errorString", ex.getMessage()), locale)); } } public static Map<String, Object> giftCertificateRefund(DispatchContext dctx, Map<String, ? extends Object> context) { GenericValue userLogin = (GenericValue) context.get("userLogin"); GenericValue paymentPref = (GenericValue) context.get("orderPaymentPreference"); String currency = (String) context.get("currency"); BigDecimal amount = (BigDecimal) context.get("refundAmount"); Locale locale = (Locale) context.get("locale"); return giftCertificateRestore(dctx, userLogin, paymentPref, amount, currency, "refund", locale); } public static Map<String, Object> giftCertificateRelease(DispatchContext dctx, Map<String, ? extends Object> context) { LocalDispatcher dispatcher = dctx.getDispatcher(); GenericValue userLogin = (GenericValue) context.get("userLogin"); GenericValue paymentPref = (GenericValue) context.get("orderPaymentPreference"); Locale locale = (Locale) context.get("locale"); String err = UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotBeExpired", locale); try { // expire the related financial authorization transaction GenericValue authTransaction = PaymentGatewayServices.getAuthTransaction(paymentPref); if (authTransaction == null) { return ServiceUtil.returnError(err + UtilProperties.getMessage(resourceError, "AccountingFinAccountCannotFindAuthorization", locale)); } Map<String, Object> input = UtilMisc.<String, Object>toMap("userLogin", userLogin, "finAccountAuthId", authTransaction.get("referenceNum")); Map<String, Object> serviceResults = dispatcher.runSync("expireFinAccountAuth", input); Map<String, Object> result = ServiceUtil.returnSuccess(); result.put("releaseRefNum", authTransaction.getString("referenceNum")); result.put("releaseAmount", authTransaction.getBigDecimal("amount")); result.put("releaseResult", Boolean.TRUE); // if there's an error, don't release if (ServiceUtil.isError(serviceResults)) { return ServiceUtil.returnError(err + ServiceUtil.getErrorMessage(serviceResults)); } return result; } catch (GenericServiceException e) { Debug.logError(e, e.getMessage(), module); return ServiceUtil.returnError(err + e.getMessage()); } } private static Map<String, Object> giftCertificateRestore(DispatchContext dctx, GenericValue userLogin, GenericValue paymentPref, BigDecimal amount, String currency, String resultPrefix, Locale locale) { LocalDispatcher dispatcher = dctx.getDispatcher(); Delegator delegator = dctx.getDelegator(); // get the orderId for tracking String orderId = paymentPref.getString("orderId"); OrderReadHelper orh = new OrderReadHelper(delegator, orderId); String productStoreId = orh.getProductStoreId(); // party ID for tracking GenericValue placingParty = orh.getPlacingParty(); String partyId = null; if (placingParty != null) { partyId = placingParty.getString("partyId"); } // get the GiftCard VO GenericValue giftCard = null; try { giftCard = paymentPref.getRelatedOne("GiftCard", false); } catch (GenericEntityException e) { Debug.logError(e, "Unable to get GiftCard from OrderPaymentPreference", module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotLocateItFromOrderPaymentPreference", locale)); } if (giftCard == null) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotRelease", locale)); } // make sure we have a currency if (currency == null) { currency = EntityUtilProperties.getPropertyValue("general", "currency.uom.id.default", "USD", delegator); } Map<String, Object> refundCtx = new HashMap<String, Object>(); refundCtx.put("productStoreId", productStoreId); refundCtx.put("currency", currency); refundCtx.put("partyId", partyId); refundCtx.put("cardNumber", giftCard.get("cardNumber")); refundCtx.put("pinNumber", giftCard.get("pinNumber")); refundCtx.put("amount", amount); refundCtx.put("userLogin", userLogin); Map<String, Object> restoreGcResult = null; try { restoreGcResult = dispatcher.runSync("addFundsToGiftCertificate", refundCtx); } catch (GenericServiceException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberRefundCallError", locale)); } if (ServiceUtil.isError(restoreGcResult)) { return ServiceUtil.returnError(ServiceUtil.getErrorMessage(restoreGcResult)); } Map<String, Object> result = ServiceUtil.returnSuccess(); if (restoreGcResult != null) { Boolean processResult = (Boolean) restoreGcResult.get("processResult"); result.put(resultPrefix + "Amount", amount); result.put(resultPrefix + "Result", processResult); result.put(resultPrefix + "Code", "R"); result.put(resultPrefix + "Flag", restoreGcResult.get("responseCode")); result.put(resultPrefix + "RefNum", restoreGcResult.get("referenceNum")); } return result; } public static Map<String, Object> giftCertificatePurchase(DispatchContext dctx, Map<String, ? extends Object> context) { // this service should always be called via FULFILLMENT_EXTASYNC LocalDispatcher dispatcher = dctx.getDispatcher(); Delegator delegator = dctx.getDelegator(); GenericValue userLogin = (GenericValue) context.get("userLogin"); GenericValue orderItem = (GenericValue) context.get("orderItem"); Locale locale = (Locale) context.get("locale"); // order ID for tracking String orderId = orderItem.getString("orderId"); // the order header for store info GenericValue orderHeader = null; try { orderHeader = orderItem.getRelatedOne("OrderHeader", false); } catch (GenericEntityException e) { Debug.logError(e, "Unable to get OrderHeader from OrderItem",module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrderError, "OrderCannotGetOrderHeader", UtilMisc.toMap("orderId", orderId), locale)); } // get the order read helper OrderReadHelper orh = new OrderReadHelper(orderHeader); // get the currency String currency = orh.getCurrency(); // make sure we have a currency if (currency == null) { currency = EntityUtilProperties.getPropertyValue("general", "currency.uom.id.default", "USD", delegator); } // get the product store String productStoreId = null; if (orderHeader != null) { productStoreId = orh.getProductStoreId(); } if (productStoreId == null) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotProcess", UtilMisc.toMap("orderId", orderId), locale)); } // party ID for tracking GenericValue placingParty = orh.getPlacingParty(); String partyId = null; if (placingParty != null) { partyId = placingParty.getString("partyId"); } // amount/quantity of the gift card(s) BigDecimal amount = orderItem.getBigDecimal("unitPrice"); BigDecimal quantity = orderItem.getBigDecimal("quantity"); // the product entity needed for information GenericValue product = null; try { product = orderItem.getRelatedOne("Product", false); } catch (GenericEntityException e) { Debug.logError(e, "Unable to get Product from OrderItem", module); } if (product == null) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotFulfill", locale)); } // Gift certificate settings are per store in this entity GenericValue giftCertSettings = null; try { giftCertSettings = EntityQuery.use(delegator).from("ProductStoreFinActSetting") .where("productStoreId", productStoreId, "finAccountTypeId", FinAccountHelper.giftCertFinAccountTypeId) .cache().queryOne(); } catch (GenericEntityException e) { Debug.logError(e, "Unable to get Product Store FinAccount settings for " + FinAccountHelper.giftCertFinAccountTypeId, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingFinAccountSetting", UtilMisc.toMap("productStoreId", productStoreId, "finAccountTypeId", FinAccountHelper.giftCertFinAccountTypeId), locale) + ": " + e.getMessage()); } // survey information String surveyId = giftCertSettings.getString("purchaseSurveyId"); // get the survey response GenericValue surveyResponse = null; try { // there should be only one surveyResponse = EntityQuery.use(delegator).from("SurveyResponse") .where("orderId", orderId, "orderItemSeqId", orderItem.get("orderItemSeqId"), "surveyId", surveyId) .orderBy("-responseDate").queryFirst(); } catch (GenericEntityException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotFulfill", locale)); } if (surveyResponse == null) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotFulfill", locale)); } // get the response answers List<GenericValue> responseAnswers = null; try { responseAnswers = surveyResponse.getRelated("SurveyResponseAnswer", null, null, false); } catch (GenericEntityException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotFulfillFromSurveyAnswers", locale)); } // make a map of answer info Map<String, Object> answerMap = new HashMap<String, Object>(); if (responseAnswers != null) { for (GenericValue answer : responseAnswers) { GenericValue question = null; try { question = answer.getRelatedOne("SurveyQuestion", false); } catch (GenericEntityException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotFulfillFromSurveyAnswers", locale)); } if (question != null) { String desc = question.getString("description"); String ans = answer.getString("textResponse"); // only support text response types for now answerMap.put(desc, ans); } } } // get the send to email address - key defined in product store settings entity String sendToKey = giftCertSettings.getString("purchSurveySendTo"); String sendToEmail = (String) answerMap.get(sendToKey); // get the copyMe flag and set the order email address String orderEmails = orh.getOrderEmailString(); String copyMeField = giftCertSettings.getString("purchSurveyCopyMe"); String copyMeResp = copyMeField != null ? (String) answerMap.get(copyMeField) : null; boolean copyMe = (UtilValidate.isNotEmpty(copyMeField) && UtilValidate.isNotEmpty(copyMeResp) && "true".equalsIgnoreCase(copyMeResp)) ? true : false; int qtyLoop = quantity.intValue(); for (int i = 0; i < qtyLoop; i++) { // create a gift certificate Map<String, Object> createGcCtx = new HashMap<String, Object>(); createGcCtx.put("productStoreId", productStoreId); createGcCtx.put("currency", currency); createGcCtx.put("partyId", partyId); createGcCtx.put("initialAmount", amount); createGcCtx.put("userLogin", userLogin); Map<String, Object> createGcResult = null; try { createGcResult = dispatcher.runSync("createGiftCertificate", createGcCtx); } catch (GenericServiceException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCreationError", locale) + e.getMessage()); } if (ServiceUtil.isError(createGcResult)) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCreationError", locale) + ServiceUtil.getErrorMessage(createGcResult)); } // create the fulfillment record Map<String, Object> gcFulFill = new HashMap<String, Object>(); gcFulFill.put("typeEnumId", "GC_ACTIVATE"); gcFulFill.put("partyId", partyId); gcFulFill.put("orderId", orderId); gcFulFill.put("orderItemSeqId", orderItem.get("orderItemSeqId")); gcFulFill.put("surveyResponseId", surveyResponse.get("surveyResponseId")); gcFulFill.put("cardNumber", createGcResult.get("cardNumber")); gcFulFill.put("pinNumber", createGcResult.get("pinNumber")); gcFulFill.put("amount", createGcResult.get("initialAmount")); gcFulFill.put("responseCode", createGcResult.get("responseCode")); gcFulFill.put("referenceNum", createGcResult.get("referenceNum")); gcFulFill.put("userLogin", userLogin); try { dispatcher.runAsync("createGcFulFillmentRecord", gcFulFill, true); } catch (GenericServiceException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotStoreFulfillmentInfo", UtilMisc.toMap("errorString", e.getMessage()), locale)); } // add some information to the answerMap for the email answerMap.put("cardNumber", createGcResult.get("cardNumber")); answerMap.put("pinNumber", createGcResult.get("pinNumber")); answerMap.put("amount", createGcResult.get("initialAmount")); // get the email setting for this email type GenericValue productStoreEmail = null; String emailType = "PRDS_GC_PURCHASE"; try { productStoreEmail = EntityQuery.use(delegator).from("ProductStoreEmailSetting").where("productStoreId", productStoreId, "emailType", emailType).queryOne(); } catch (GenericEntityException e) { Debug.logError(e, "Unable to get product store email setting for gift card purchase", module); } if (productStoreEmail == null) { Debug.logError("No gift card purchase email setting found for this store; cannot send gift card information", module); } else { answerMap.put("locale", locale); // set the bcc address(s) String bcc = productStoreEmail.getString("bccAddress"); if (copyMe) { if (UtilValidate.isNotEmpty(bcc)) { bcc = bcc + "," + orderEmails; } else { bcc = orderEmails; } } Map<String, Object> emailCtx = new HashMap<String, Object>(); String bodyScreenLocation = productStoreEmail.getString("bodyScreenLocation"); if (UtilValidate.isEmpty(bodyScreenLocation)) { bodyScreenLocation = ProductStoreWorker.getDefaultProductStoreEmailScreenLocation(emailType); } emailCtx.put("bodyScreenUri", bodyScreenLocation); emailCtx.put("bodyParameters", answerMap); emailCtx.put("sendTo", sendToEmail); emailCtx.put("contentType", productStoreEmail.get("contentType")); emailCtx.put("sendFrom", productStoreEmail.get("fromAddress")); emailCtx.put("sendCc", productStoreEmail.get("ccAddress")); emailCtx.put("sendBcc", bcc); emailCtx.put("subject", productStoreEmail.getString("subject")); emailCtx.put("userLogin", userLogin); // send off the email async so we will retry on failed attempts // SC 20060405: Changed to runSync because runAsync kept getting an error: // Problem serializing service attributes (Cannot serialize object of class java.util.PropertyResourceBundle) try { dispatcher.runSync("sendMailFromScreen", emailCtx); } catch (GenericServiceException e) { Debug.logError(e, "Problem sending mail", module); // this is fatal; we will rollback and try again later return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotSendEmailNotice", UtilMisc.toMap("errorString", e.toString()), locale)); } } } return ServiceUtil.returnSuccess(); } public static Map<String, Object> giftCertificateReload(DispatchContext dctx, Map<String, ? extends Object> context) { // this service should always be called via FULFILLMENT_EXTSYNC LocalDispatcher dispatcher = dctx.getDispatcher(); Delegator delegator = dctx.getDelegator(); GenericValue userLogin = (GenericValue) context.get("userLogin"); GenericValue orderItem = (GenericValue) context.get("orderItem"); Locale locale = (Locale) context.get("locale"); // order ID for tracking String orderId = orderItem.getString("orderId"); // the order header for store info GenericValue orderHeader = null; try { orderHeader = orderItem.getRelatedOne("OrderHeader", false); } catch (GenericEntityException e) { Debug.logError(e, "Unable to get OrderHeader from OrderItem",module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrderError, "OrderCannotGetOrderHeader", UtilMisc.toMap("orderId", orderId), locale)); } // get the order read helper OrderReadHelper orh = new OrderReadHelper(orderHeader); // get the currency String currency = orh.getCurrency(); // make sure we have a currency if (currency == null) { currency = EntityUtilProperties.getPropertyValue("general", "currency.uom.id.default", "USD", delegator); } // get the product store String productStoreId = null; if (orderHeader != null) { productStoreId = orh.getProductStoreId(); } if (productStoreId == null) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrderError, "AccountingGiftCerticateNumberCannotReload", UtilMisc.toMap("orderId", orderId), locale)); } // payment config GenericValue paymentSetting = ProductStoreWorker.getProductStorePaymentSetting(delegator, productStoreId, "GIFT_CARD", null, true); String paymentConfig = null; if (paymentSetting != null) { paymentConfig = paymentSetting.getString("paymentPropertiesPath"); } if (paymentConfig == null) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrderError, "AccountingGiftCerticateNumberCannotGetPaymentConfiguration", locale)); } // party ID for tracking GenericValue placingParty = orh.getPlacingParty(); String partyId = null; if (placingParty != null) { partyId = placingParty.getString("partyId"); } // amount of the gift card reload BigDecimal amount = orderItem.getBigDecimal("unitPrice"); // survey information String surveyId = EntityUtilProperties.getPropertyValue(paymentConfig, "payment.giftcert.reload.surveyId", delegator); // get the survey response GenericValue surveyResponse = null; try { // there should be only one surveyResponse = EntityQuery.use(delegator).from("SurveyResponse") .where("orderId", orderId, "orderItemSeqId", orderItem.get("orderItemSeqId"), "surveyId", surveyId) .orderBy("-responseDate").queryFirst(); } catch (GenericEntityException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrderError, "AccountingGiftCerticateNumberCannotReload", locale)); } // get the response answers List<GenericValue> responseAnswers = null; try { responseAnswers = surveyResponse.getRelated("SurveyResponseAnswer", null, null, false); } catch (GenericEntityException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrderError, "AccountingGiftCerticateNumberCannotReloadFromSurveyAnswers", locale)); } // make a map of answer info Map<String, Object> answerMap = new HashMap<String, Object>(); if (responseAnswers != null) { for (GenericValue answer : responseAnswers) { GenericValue question = null; try { question = answer.getRelatedOne("SurveyQuestion", false); } catch (GenericEntityException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrderError, "AccountingGiftCerticateNumberCannotReloadFromSurveyAnswers", locale)); } if (question != null) { String desc = question.getString("description"); String ans = answer.getString("textResponse"); // only support text response types for now answerMap.put(desc, ans); } } } String cardNumberKey = EntityUtilProperties.getPropertyValue(paymentConfig, "payment.giftcert.reload.survey.cardNumber", delegator); String pinNumberKey = EntityUtilProperties.getPropertyValue(paymentConfig, "payment.giftcert.reload.survey.pinNumber", delegator); String cardNumber = (String) answerMap.get(cardNumberKey); String pinNumber = (String) answerMap.get(pinNumberKey); // reload the gift card Map<String, Object> reloadCtx = new HashMap<String, Object>(); reloadCtx.put("productStoreId", productStoreId); reloadCtx.put("currency", currency); reloadCtx.put("partyId", partyId); reloadCtx.put("cardNumber", cardNumber); reloadCtx.put("pinNumber", pinNumber); reloadCtx.put("amount", amount); reloadCtx.put("userLogin", userLogin); String errorMessage = null; Map<String, Object> reloadGcResult = null; try { reloadGcResult = dispatcher.runSync("addFundsToGiftCertificate", reloadCtx); } catch (GenericServiceException e) { Debug.logError(e, module); errorMessage = "Unable to call reload service!"; } if (ServiceUtil.isError(reloadGcResult)) { errorMessage = ServiceUtil.getErrorMessage(reloadGcResult); } // create the fulfillment record Map<String, Object> gcFulFill = new HashMap<String, Object>(); gcFulFill.put("typeEnumId", "GC_RELOAD"); gcFulFill.put("userLogin", userLogin); gcFulFill.put("partyId", partyId); gcFulFill.put("orderId", orderId); gcFulFill.put("orderItemSeqId", orderItem.get("orderItemSeqId")); gcFulFill.put("surveyResponseId", surveyResponse.get("surveyResponseId")); gcFulFill.put("cardNumber", cardNumber); gcFulFill.put("pinNumber", pinNumber); gcFulFill.put("amount", amount); if (reloadGcResult != null) { gcFulFill.put("responseCode", reloadGcResult.get("responseCode")); gcFulFill.put("referenceNum", reloadGcResult.get("referenceNum")); } try { dispatcher.runAsync("createGcFulFillmentRecord", gcFulFill, true); } catch (GenericServiceException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotStoreFulfillmentInfo", UtilMisc.toMap("errorString", e.getMessage()), locale)); } if (errorMessage != null) { // there was a problem Debug.logError("Reload Failed Need to Refund : " + reloadGcResult, module); // process the return try { Map<String, Object> refundCtx = UtilMisc.toMap("orderItem", orderItem, "partyId", partyId, "userLogin", userLogin); dispatcher.runAsync("refundGcPurchase", refundCtx, null, true, 300, true); } catch (GenericServiceException e) { Debug.logError(e, "ERROR! Unable to call create refund service; this failed reload will NOT be refunded", module); } return ServiceUtil.returnError(errorMessage); } // add some information to the answerMap for the email answerMap.put("processResult", reloadGcResult.get("processResult")); answerMap.put("responseCode", reloadGcResult.get("responseCode")); answerMap.put("previousAmount", reloadGcResult.get("previousBalance")); answerMap.put("amount", reloadGcResult.get("amount")); // get the email setting for this email type GenericValue productStoreEmail = null; String emailType = "PRDS_GC_RELOAD"; try { productStoreEmail = EntityQuery.use(delegator).from("ProductStoreEmailSetting").where("productStoreId", productStoreId, "emailType", emailType).queryOne(); } catch (GenericEntityException e) { Debug.logError(e, "Unable to get product store email setting for gift card purchase", module); } if (productStoreEmail == null) { Debug.logError("No gift card purchase email setting found for this store; cannot send gift card information", module); } else { answerMap.put("locale", locale); Map<String, Object> emailCtx = new HashMap<String, Object>(); String bodyScreenLocation = productStoreEmail.getString("bodyScreenLocation"); if (UtilValidate.isEmpty(bodyScreenLocation)) { bodyScreenLocation = ProductStoreWorker.getDefaultProductStoreEmailScreenLocation(emailType); } emailCtx.put("bodyScreenUri", bodyScreenLocation); emailCtx.put("bodyParameters", answerMap); emailCtx.put("sendTo", orh.getOrderEmailString()); emailCtx.put("contentType", productStoreEmail.get("contentType")); emailCtx.put("sendFrom", productStoreEmail.get("fromAddress")); emailCtx.put("sendCc", productStoreEmail.get("ccAddress")); emailCtx.put("sendBcc", productStoreEmail.get("bccAddress")); emailCtx.put("subject", productStoreEmail.getString("subject")); emailCtx.put("userLogin", userLogin); // send off the email async so we will retry on failed attempts try { dispatcher.runAsync("sendMailFromScreen", emailCtx); } catch (GenericServiceException e) { Debug.logError(e, "Problem sending mail", module); // this is fatal; we will rollback and try again later return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotSendEmailNotice", UtilMisc.toMap("errorString", e.toString()), locale)); } } return ServiceUtil.returnSuccess(); } // Tracking Service public static Map<String, Object> createFulfillmentRecord(DispatchContext dctx, Map<String, ? extends Object> context) { Delegator delegator = dctx.getDelegator(); Locale locale = (Locale) context.get("locale"); // create the fulfillment record GenericValue gcFulFill = delegator.makeValue("GiftCardFulfillment"); gcFulFill.set("fulfillmentId", delegator.getNextSeqId("GiftCardFulfillment")); gcFulFill.set("typeEnumId", context.get("typeEnumId")); gcFulFill.set("merchantId", context.get("merchantId")); gcFulFill.set("partyId", context.get("partyId")); gcFulFill.set("orderId", context.get("orderId")); gcFulFill.set("orderItemSeqId", context.get("orderItemSeqId")); gcFulFill.set("surveyResponseId", context.get("surveyResponseId")); gcFulFill.set("cardNumber", context.get("cardNumber")); gcFulFill.set("pinNumber", context.get("pinNumber")); gcFulFill.set("amount", context.get("amount")); gcFulFill.set("responseCode", context.get("responseCode")); gcFulFill.set("referenceNum", context.get("referenceNum")); gcFulFill.set("authCode", context.get("authCode")); gcFulFill.set("fulfillmentDate", UtilDateTime.nowTimestamp()); try { delegator.create(gcFulFill); } catch (GenericEntityException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "AccountingGiftCerticateNumberCannotStoreFulfillmentInfo", UtilMisc.toMap("errorString", e.toString()), locale)); } return ServiceUtil.returnSuccess(); } // Refund Service public static Map<String, Object> refundGcPurchase(DispatchContext dctx, Map<String, ? extends Object> context) { LocalDispatcher dispatcher = dctx.getDispatcher(); Delegator delegator = dctx.getDelegator(); GenericValue userLogin = (GenericValue) context.get("userLogin"); GenericValue orderItem = (GenericValue) context.get("orderItem"); String partyId = (String) context.get("partyId"); Locale locale = (Locale) context.get("locale"); // refresh the item object for status changes try { orderItem.refresh(); } catch (GenericEntityException e) { Debug.logError(e, module); } Map<String, Object> returnableInfo = null; try { returnableInfo = dispatcher.runSync("getReturnableQuantity", UtilMisc.toMap("orderItem", orderItem, "userLogin", userLogin)); } catch (GenericServiceException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrderError, "OrderErrorUnableToGetReturnItemInformation", locale)); } if (returnableInfo != null) { BigDecimal returnableQuantity = (BigDecimal) returnableInfo.get("returnableQuantity"); BigDecimal returnablePrice = (BigDecimal) returnableInfo.get("returnablePrice"); Debug.logInfo("Returnable INFO : " + returnableQuantity + " @ " + returnablePrice + " :: " + orderItem, module); // create the return header Map<String, Object> returnHeaderInfo = new HashMap<String, Object>(); returnHeaderInfo.put("fromPartyId", partyId); returnHeaderInfo.put("userLogin", userLogin); Map<String, Object> returnHeaderResp = null; try { returnHeaderResp = dispatcher.runSync("createReturnHeader", returnHeaderInfo); } catch (GenericServiceException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrderError, "OrderErrorUnableToCreateReturnHeader", locale)); } if (returnHeaderResp != null) { String errorMessage = ServiceUtil.getErrorMessage(returnHeaderResp); if (errorMessage != null) { return ServiceUtil.returnError(errorMessage); } } String returnId = null; if (returnHeaderResp != null) { returnId = (String) returnHeaderResp.get("returnId"); } if (returnId == null) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrderError, "OrderErrorCreateReturnHeaderWithoutId", locale)); } // create the return item Map<String, Object> returnItemInfo = new HashMap<String, Object>(); returnItemInfo.put("returnId", returnId); returnItemInfo.put("returnReasonId", "RTN_DIG_FILL_FAIL"); returnItemInfo.put("returnTypeId", "RTN_REFUND"); returnItemInfo.put("returnItemType", "ITEM"); returnItemInfo.put("description", orderItem.get("itemDescription")); returnItemInfo.put("orderId", orderItem.get("orderId")); returnItemInfo.put("orderItemSeqId", orderItem.get("orderItemSeqId")); returnItemInfo.put("returnQuantity", returnableQuantity); returnItemInfo.put("returnPrice", returnablePrice); returnItemInfo.put("userLogin", userLogin); Map<String, Object> returnItemResp = null; try { returnItemResp = dispatcher.runSync("createReturnItem", returnItemInfo); } catch (GenericServiceException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrderError, "OrderErrorUnableToCreateReturnItem", locale)); } if (returnItemResp != null) { String errorMessage = ServiceUtil.getErrorMessage(returnItemResp); if (errorMessage != null) { return ServiceUtil.returnError(errorMessage); } } String returnItemSeqId = null; if (returnItemResp != null) { returnItemSeqId = (String) returnItemResp.get("returnItemSeqId"); } if (returnItemSeqId == null) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrderError, "OrderErrorCreateReturnItemWithoutId", locale)); } else { Debug.logVerbose("Created return item : " + returnId + " / " + returnItemSeqId, module); } // need the system userLogin to "fake" out the update service GenericValue admin = null; try { admin = EntityQuery.use(delegator).from("UserLogin").where("userLoginId", "system").queryOne(); } catch (GenericEntityException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrderError, "OrderErrorUnableToUpdateReturnHeaderStatusWithoutUserLogin", locale)); } // update the status to received so it can process Map<String, Object> updateReturnInfo = new HashMap<String, Object>(); updateReturnInfo.put("returnId", returnId); updateReturnInfo.put("statusId", "RETURN_RECEIVED"); updateReturnInfo.put("currentStatusId", "RETURN_REQUESTED"); updateReturnInfo.put("userLogin", admin); Map<String, Object> updateReturnResp = null; try { updateReturnResp = dispatcher.runSync("updateReturnHeader", updateReturnInfo); } catch (GenericServiceException e) { Debug.logError(e, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrderError, "OrderErrorUnableToUpdateReturnHeaderStatus", locale)); } if (updateReturnResp != null) { String errorMessage = ServiceUtil.getErrorMessage(updateReturnResp); if (errorMessage != null) { return ServiceUtil.returnError(errorMessage); } } } return ServiceUtil.returnSuccess(); } // Private worker methods private static boolean validatePin(Delegator delegator, String cardNumber, String pinNumber) { GenericValue finAccount = null; try { finAccount = EntityQuery.use(delegator).from("FinAccount").where("finAccountId", cardNumber).queryOne(); } catch (GenericEntityException e) { Debug.logError(e, module); } if (finAccount != null) { String dbPin = finAccount.getString("finAccountCode"); Debug.logInfo("GC Pin Validation: [Sent: " + pinNumber + "] [Actual: " + dbPin + "]", module); if (dbPin != null && dbPin.equals(pinNumber)) { return true; } } else { Debug.logInfo("GC FinAccount record not found (" + cardNumber + ")", module); } return false; } private static String createTransaction(Delegator delegator, LocalDispatcher dispatcher, GenericValue userLogin, BigDecimal amount, String productStoreId, String partyId, String currencyUom, String txType, String finAccountId, Locale locale) throws GeneralException { final String coParty = getPayToPartyId(delegator, productStoreId); final String paymentMethodType = "GIFT_CERTIFICATE"; if (UtilValidate.isEmpty(partyId)) { partyId = "_NA_"; } String paymentType = null; String partyIdFrom = null; String partyIdTo = null; if ("DEPOSIT".equals(txType)) { paymentType = "GC_DEPOSIT"; partyIdFrom = partyId; partyIdTo = coParty; } else if ("WITHDRAWAL".equals(txType)) { paymentType = "GC_WITHDRAWAL"; partyIdFrom = coParty; partyIdTo = partyId; } else { throw new GeneralException(UtilProperties.getMessage(resourceError, "AccountingFinAccountCannotCreateTransaction", locale)); } // create the payment for the transaction Map<String, Object> paymentCtx = UtilMisc.<String, Object>toMap("paymentTypeId", paymentType); paymentCtx.put("paymentMethodTypeId", paymentMethodType); paymentCtx.put("partyIdTo", partyIdTo); paymentCtx.put("partyIdFrom", partyIdFrom); paymentCtx.put("statusId", "PMNT_RECEIVED"); paymentCtx.put("currencyUomId", currencyUom); paymentCtx.put("amount", amount); paymentCtx.put("userLogin", userLogin); paymentCtx.put("paymentRefNum", "N/A"); String paymentId = null; Map<String, Object> payResult = null; try { payResult = dispatcher.runSync("createPayment", paymentCtx); } catch (GenericServiceException e) { throw new GeneralException(e); } if (payResult == null) { throw new GeneralException("Unknow error in creating financial account transaction!"); } if (ServiceUtil.isError(payResult)) { throw new GeneralException(ServiceUtil.getErrorMessage(payResult)); } else { paymentId = (String) payResult.get("paymentId"); } // create the initial transaction Map<String, Object> transCtx = UtilMisc.<String, Object>toMap("finAccountTransTypeId", txType); transCtx.put("finAccountId", finAccountId); transCtx.put("partyId", userLogin.getString("partyId")); transCtx.put("userLogin", userLogin); transCtx.put("paymentId", paymentId); transCtx.put("amount", amount); Map<String, Object> transResult = null; String txId = null; try { transResult = dispatcher.runSync("createFinAccountTrans", transCtx); } catch (GenericServiceException e) { throw new GeneralException(e); } if (transResult == null) { throw new GeneralException("Unknown error in creating financial account transaction!"); } if (ServiceUtil.isError(transResult)) { throw new GeneralException(ServiceUtil.getErrorMessage(transResult)); } else { txId = (String) transResult.get("finAccountTransId"); } return txId; } private static String generateNumber(Delegator delegator, int length, boolean isId) throws GenericEntityException { if (length > 19) { length = 19; } Random rand = new SecureRandom(); boolean isValid = false; StringBuilder number = null; while (!isValid) { number = new StringBuilder(""); for (int i = 0; i < length; i++) { int randInt = rand.nextInt(9); number.append(randInt); } if (isId) { number.append(UtilValidate.getLuhnCheckDigit(number.toString())); // validate the number if (checkCardNumber(number.toString())) { // make sure this number doens't already exist isValid = checkNumberInDatabase(delegator, number.toString()); } } else { isValid = true; } } return number.toString(); } private static boolean checkNumberInDatabase(Delegator delegator, String number) throws GenericEntityException { GenericValue finAccount = EntityQuery.use(delegator).from("FinAccount").where("finAccountId", number).queryOne(); if (finAccount == null) { return true; } return false; } private static boolean checkCardNumber(String number) { number = number.replaceAll("\\D", ""); return UtilValidate.sumIsMod10(UtilValidate.getLuhnSum(number)); } private static String getPayToPartyId(Delegator delegator, String productStoreId) { String payToPartyId = "Company"; // default value GenericValue productStore = null; try { productStore = EntityQuery.use(delegator).from("ProductStore").where("productStoreId", productStoreId).queryOne(); } catch (GenericEntityException e) { Debug.logError(e, "Unable to locate ProductStore (" + productStoreId + ")", module); return null; } if (productStore != null && productStore.get("payToPartyId") != null) { payToPartyId = productStore.getString("payToPartyId"); } return payToPartyId; } }