Ejemplo n.º 1
0
  // base payment integration services
  public static Map<String, Object> finAccountPreAuth(
      DispatchContext dctx, Map<String, Object> context) {
    LocalDispatcher dispatcher = dctx.getDispatcher();
    Delegator delegator = dctx.getDelegator();
    GenericValue userLogin = (GenericValue) context.get("userLogin");
    Locale locale = (Locale) context.get("locale");
    GenericValue paymentPref = (GenericValue) context.get("orderPaymentPreference");
    String finAccountCode = (String) context.get("finAccountCode");
    String finAccountPin = (String) context.get("finAccountPin");
    String finAccountId = (String) context.get("finAccountId");
    String orderId = (String) context.get("orderId");
    BigDecimal amount = (BigDecimal) context.get("processAmount");

    // check for an existing auth trans and cancel it
    GenericValue authTrans = PaymentGatewayServices.getAuthTransaction(paymentPref);
    if (authTrans != null) {
      Map<String, Object> input =
          UtilMisc.toMap("userLogin", userLogin, "finAccountAuthId", authTrans.get("referenceNum"));
      try {
        dispatcher.runSync("expireFinAccountAuth", input);
      } catch (GenericServiceException e) {
        Debug.logError(e, module);
        return ServiceUtil.returnError(e.getMessage());
      }
    }
    if (finAccountId == null && paymentPref != null) {
      finAccountId = paymentPref.getString("finAccountId");
    }

    // obtain the order information
    OrderReadHelper orh = new OrderReadHelper(delegator, orderId);

    // NOTE DEJ20070808: this means that we want store related settings for where the item is being
    // purchased,
    // NOT where the account was setup; should this be changed to use settings from the store where
    // the account was setup?
    String productStoreId = orh.getProductStoreId();

    // TODO, NOTE DEJ20070808: why is this setup this way anyway? for the allowAuthToNegative
    // wouldn't that be better setup
    // on the FinAccount and not on the ProductStoreFinActSetting? maybe an override on the
    // FinAccount would be good...

    // get the financial account
    GenericValue finAccount;
    if (finAccountId != null) {
      try {
        finAccount =
            EntityQuery.use(delegator)
                .from("FinAccount")
                .where("finAccountId", finAccountId)
                .queryOne();
      } catch (GenericEntityException e) {
        Debug.logError(e, module);
        return ServiceUtil.returnError(e.getMessage());
      }
    } else {
      if (finAccountCode != null) {
        try {
          finAccount = FinAccountHelper.getFinAccountFromCode(finAccountCode, delegator);
        } catch (GenericEntityException e) {
          Debug.logError(e, module);
          return ServiceUtil.returnError(
              UtilProperties.getMessage(
                  resourceError, "AccountingFinAccountCannotLocateItFromAccountCode", locale));
        }
      } else {
        return ServiceUtil.returnError(
            UtilProperties.getMessage(
                resourceError, "AccountingFinAccountIdAndFinAccountCodeAreNull", locale));
      }
    }
    if (finAccount == null) {
      return ServiceUtil.returnError(
          UtilProperties.getMessage(resourceError, "AccountingFinAccountIdInvalid", locale));
    }

    String finAccountTypeId = finAccount.getString("finAccountTypeId");
    finAccountId = finAccount.getString("finAccountId");
    String statusId = finAccount.getString("statusId");

    try {
      // fin the store requires a pin number; validate the PIN with the code
      Map<String, Object> findProductStoreFinActSettingMap =
          UtilMisc.<String, Object>toMap(
              "productStoreId", productStoreId, "finAccountTypeId", finAccountTypeId);
      GenericValue finAccountSettings =
          EntityQuery.use(delegator)
              .from("ProductStoreFinActSetting")
              .where(findProductStoreFinActSettingMap)
              .cache()
              .queryOne();

      if (finAccountSettings == null) {
        Debug.logWarning(
            "In finAccountPreAuth could not find ProductStoreFinActSetting record, values searched by: "
                + findProductStoreFinActSettingMap,
            module);
      }
      if (Debug.verboseOn())
        Debug.logVerbose("In finAccountPreAuth finAccountSettings=" + finAccountSettings, module);

      BigDecimal minBalance = FinAccountHelper.ZERO;
      String allowAuthToNegative = "N";

      if (finAccountSettings != null) {
        allowAuthToNegative = finAccountSettings.getString("allowAuthToNegative");
        minBalance = finAccountSettings.getBigDecimal("minBalance");
        if (minBalance == null) {
          minBalance = FinAccountHelper.ZERO;
        }

        // validate the PIN if the store requires it
        if ("Y".equals(finAccountSettings.getString("requirePinCode"))) {
          if (!FinAccountHelper.validatePin(delegator, finAccountCode, finAccountPin)) {
            Map<String, Object> result = ServiceUtil.returnSuccess();
            result.put(
                "authMessage",
                UtilProperties.getMessage(
                    resourceError, "AccountingFinAccountPinCodeCombinatorNotFound", locale));
            result.put("authResult", Boolean.FALSE);
            result.put("processAmount", amount);
            result.put("authFlag", "0");
            result.put("authCode", "A");
            result.put("authRefNum", "0");
            Debug.logWarning("Unable to auth FinAccount: " + result, module);
            return result;
          }
        }
      }

      // check for expiration date
      if ((finAccount.getTimestamp("thruDate") != null)
          && (finAccount.getTimestamp("thruDate").before(UtilDateTime.nowTimestamp()))) {
        Map<String, Object> result = ServiceUtil.returnSuccess();
        result.put(
            "authMessage",
            UtilProperties.getMessage(
                resourceError,
                "AccountingFinAccountExpired",
                UtilMisc.toMap("thruDate", finAccount.getTimestamp("thruDate")),
                locale));
        result.put("authResult", Boolean.FALSE);
        result.put("processAmount", amount);
        result.put("authFlag", "0");
        result.put("authCode", "A");
        result.put("authRefNum", "0");
        Debug.logWarning("Unable to auth FinAccount: " + result, module);
        return result;
      }

      // check for account being in bad standing somehow
      if ("FNACT_NEGPENDREPL".equals(statusId)
          || "FNACT_MANFROZEN".equals(statusId)
          || "FNACT_CANCELLED".equals(statusId)) {
        // refresh the finaccount
        finAccount.refresh();
        statusId = finAccount.getString("statusId");

        if ("FNACT_NEGPENDREPL".equals(statusId)
            || "FNACT_MANFROZEN".equals(statusId)
            || "FNACT_CANCELLED".equals(statusId)) {
          Map<String, Object> result = ServiceUtil.returnSuccess();
          if ("FNACT_NEGPENDREPL".equals(statusId)) {
            result.put(
                "authMessage",
                UtilProperties.getMessage(resourceError, "AccountingFinAccountNegative", locale));
          } else if ("FNACT_MANFROZEN".equals(statusId)) {
            result.put(
                "authMessage",
                UtilProperties.getMessage(resourceError, "AccountingFinAccountFrozen", locale));
          } else if ("FNACT_CANCELLED".equals(statusId)) {
            result.put(
                "authMessage",
                UtilProperties.getMessage(resourceError, "AccountingFinAccountCancelled", locale));
          }
          result.put("authResult", Boolean.FALSE);
          result.put("processAmount", amount);
          result.put("authFlag", "0");
          result.put("authCode", "A");
          result.put("authRefNum", "0");
          Debug.logWarning("Unable to auth FinAccount: " + result, module);
          return result;
        }
      }

      // 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");
      if (availableBalance == null) {
        availableBalance = FinAccountHelper.ZERO;
      } else {
        BigDecimal availableBalanceOriginal = availableBalance;
        availableBalance =
            availableBalance.setScale(FinAccountHelper.decimals, FinAccountHelper.rounding);
        if (availableBalance.compareTo(availableBalanceOriginal) != 0) {
          Debug.logWarning(
              "In finAccountPreAuth for finAccountId ["
                  + finAccountId
                  + "] availableBalance ["
                  + availableBalanceOriginal
                  + "] was different after rounding ["
                  + availableBalance
                  + "]; it should never have made it into the database this way, so check whatever put it there.",
              module);
        }
      }

      Map<String, Object> result = ServiceUtil.returnSuccess();
      String authMessage = null;
      Boolean processResult;
      String refNum;

      // make sure to round and scale it to the same as availableBalance
      amount = amount.setScale(FinAccountHelper.decimals, FinAccountHelper.rounding);

      Debug.logInfo(
          "Allow auth to negative: "
              + allowAuthToNegative
              + " :: available: "
              + availableBalance
              + " comp: "
              + minBalance
              + " = "
              + availableBalance.compareTo(minBalance)
              + " :: req: "
              + amount,
          module);
      // check the available balance to see if we can auth this tx
      if (("Y".equals(allowAuthToNegative) && availableBalance.compareTo(minBalance) > -1)
          || (availableBalance.compareTo(amount) > -1)) {
        Timestamp thruDate;

        if (finAccountSettings != null && finAccountSettings.getLong("authValidDays") != null) {
          thruDate =
              UtilDateTime.getDayEnd(
                  UtilDateTime.nowTimestamp(), finAccountSettings.getLong("authValidDays"));
        } else {
          thruDate =
              UtilDateTime.getDayEnd(
                  UtilDateTime.nowTimestamp(), Long.valueOf(30)); // default 30 days for an auth
        }

        Map<String, Object> tmpResult =
            dispatcher.runSync(
                "createFinAccountAuth",
                UtilMisc.<String, Object>toMap(
                    "finAccountId",
                    finAccountId,
                    "amount",
                    amount,
                    "thruDate",
                    thruDate,
                    "userLogin",
                    userLogin));

        if (ServiceUtil.isError(tmpResult)) {
          return tmpResult;
        }
        refNum = (String) tmpResult.get("finAccountAuthId");
        processResult = Boolean.TRUE;

        // refresh the account
        finAccount.refresh();
      } else {
        Debug.logWarning(
            "Attempted to authorize ["
                + amount
                + "] against a balance of only ["
                + availableBalance
                + "] for finAccountId ["
                + finAccountId
                + "]",
            module);
        refNum = "0"; // a refNum is always required from authorization
        authMessage = "Insufficient funds";
        processResult = Boolean.FALSE;
      }

      result.put("processAmount", amount);
      result.put("authMessage", authMessage);
      result.put("authResult", processResult);
      result.put("processAmount", amount);
      result.put("authFlag", "1");
      result.put("authCode", "A");
      result.put("authRefNum", refNum);
      Debug.logInfo("FinAccont Auth: " + result, module);

      return result;
    } catch (GenericEntityException ex) {
      Debug.logError(ex, "Cannot authorize financial account", module);
      return ServiceUtil.returnError(
          UtilProperties.getMessage(
              resourceError,
              "AccountingFinAccountCannotBeAuthorized",
              UtilMisc.toMap("errorString", ex.getMessage()),
              locale));
    } catch (GenericServiceException ex) {
      Debug.logError(ex, "Cannot authorize financial account", module);
      return ServiceUtil.returnError(
          UtilProperties.getMessage(
              resourceError,
              "AccountingFinAccountCannotBeAuthorized",
              UtilMisc.toMap("errorString", ex.getMessage()),
              locale));
    }
  }