OFBiz
  1. OFBiz
  2. OFBIZ-767

Complete support for OrderPaymentPreference.securityCode

    Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Trivial Trivial
    • Resolution: Fixed
    • Affects Version/s: Trunk
    • Fix Version/s: None
    • Component/s: accounting
    • Labels:
      None

      Description

      Hi,

      I have added support for cvvNumber field in CreditCard entity.
      In future , If somebody wants to use this field in his/her custom form/application.

      Any comments are most welcome.

      Thanks & Regards
      Ashish Vijaywargiya

        Activity

        Hide
        David E. Jones added a comment -

        Before we add anything that writes to this field, we need to also add code to clear out the field after the initial auth operation is complete.

        Show
        David E. Jones added a comment - Before we add anything that writes to this field, we need to also add code to clear out the field after the initial auth operation is complete.
        Hide
        Jacopo Cappellato added a comment -

        Am I wrong or OFBiz already supports this?
        I think that the code is already written in the OrderPaymentPreference.securityCode field and then removed by the sysytem alter the transaction is done.
        One quick way to enamble it is this:

        1) add the following input field to the billsettings.ftl file (order component):
        <input type="text" size="4" class="inputBox" name="securityCode_$

        {paymentMethod.paymentMethodId}

        " value=""/>

        2) add the following code to the CheckOutEvents.getSelectedPaymentMethods(...):
        String securityCode = request.getParameter("securityCode_" + paymentMethods[i]);
        if (securityCode != null && securityCode.length() > 0)

        { paymentMethodInfo.put("securityCode", securityCode); }

        the trick here is that you'll have to change the paymentMethodInfo from a list to a map

        3) in CheckOutHelper.setCheckOutPaymentInternal(...) you'll have to retrieve the cvv value from the above map; here is the method from an older modified version of OFBiz:

        public List setCheckOutPaymentInternal(Map selectedPaymentMethods, List singleUsePayments, String billingAccountId, Double billingAccountAmt) {
        List errorMessages = new ArrayList();
        String errMsg = null;

        if (singleUsePayments == null)

        { singleUsePayments = new ArrayList(); }

        // set the payment method option
        if (selectedPaymentMethods != null && selectedPaymentMethods.size() > 0) {
        // clear out the old payments
        cart.clearPayments();

        if (billingAccountId != null && billingAccountAmt != null && !billingAccountId.equals("NA"))

        { // set cart billing account data and generate a payment method containing the amount we will be charging cart.setBillingAccount(billingAccountId, billingAccountAmt.doubleValue()); }

        else if ("NA".equals(billingAccountId))

        { // if _NA_ was supplied, erase all billing account data cart.setBillingAccount(null, 0.0); }

        // TODO: the following code needs some review (JAC20061213)
        // if checkoutPaymentId == EXT_BILLACT, then we have billing account only, so make sure we have enough credit
        if (selectedPaymentMethods.containsKey("EXT_BILLACT") && selectedPaymentMethods.size() == 1) {
        double accountCredit = this.availableAccountBalance(cart.getBillingAccountId());
        double amountToUse = cart.getBillingAccountAmount();

        // if an amount was entered, check that it doesn't exceed availalble amount
        if (amountToUse > 0 && amountToUse > accountCredit)

        { errMsg = UtilProperties.getMessage(resource,"checkhelper.insufficient_credit_available_on_account", (cart != null ? cart.getLocale() : Locale.getDefault())); errorMessages.add(errMsg); }

        else

        { // otherwise use the available account credit (The user might enter 10.00 for an order worth 20.00 from an account with 30.00. This makes sure that the 30.00 is used) amountToUse = accountCredit; }

        // check that the amount to use is enough to fulfill the order
        double grandTotal = cart.getGrandTotal();
        if (grandTotal > amountToUse)

        { cart.setBillingAccount(null, 0.0); // erase existing billing account data errMsg = UtilProperties.getMessage(resource,"checkhelper.insufficient_credit_available_on_account", (cart != null ? cart.getLocale() : Locale.getDefault())); errorMessages.add(errMsg); }

        else

        { // since this is the only selected payment method, let's make this amount the grand total for convenience amountToUse = grandTotal; }

        // associate the cart billing account amount and EXT_BILLACT selected payment method with whatever amount we have now
        // XXX: Note that this step is critical for the billing account to be charged correctly
        if (amountToUse > 0)

        { cart.setBillingAccount(billingAccountId, amountToUse); selectedPaymentMethods.put("EXT_BILLACT", new Double(amountToUse)); }

        }

        Set paymentMethods = selectedPaymentMethods.keySet();
        Iterator i = paymentMethods.iterator();
        while (i.hasNext()) {
        String checkOutPaymentId = (String) i.next();

        // get the selected amount to use
        Double paymentAmount = null;
        String securityCode = null;
        if (selectedPaymentMethods.get(checkOutPaymentId) != null)

        { Map checkOutPaymentInfo = (Map) selectedPaymentMethods.get(checkOutPaymentId); paymentAmount = (Double) checkOutPaymentInfo.get("amount"); securityCode = (String) checkOutPaymentInfo.get("securityCode"); }

        boolean singleUse = singleUsePayments.contains(checkOutPaymentId);
        cart.addPaymentAmount(checkOutPaymentId, paymentAmount, singleUse);

        ShoppingCart.CartPaymentInfo cpi = cart.getPaymentInfo(cart.selectedPayments() - 1);
        cpi.securityCode = securityCode;
        }
        } else if (cart.getGrandTotal() != 0.00)

        { // only return an error if the order total is not 0.00 errMsg = UtilProperties.getMessage(resource,"checkhelper.select_method_of_payment", (cart != null ? cart.getLocale() : Locale.getDefault())); errorMessages.add(errMsg); }

        return errorMessages;
        }

        Hope it helps

        Show
        Jacopo Cappellato added a comment - Am I wrong or OFBiz already supports this? I think that the code is already written in the OrderPaymentPreference.securityCode field and then removed by the sysytem alter the transaction is done. One quick way to enamble it is this: 1) add the following input field to the billsettings.ftl file (order component): <input type="text" size="4" class="inputBox" name="securityCode_$ {paymentMethod.paymentMethodId} " value=""/> 2) add the following code to the CheckOutEvents.getSelectedPaymentMethods(...): String securityCode = request.getParameter("securityCode_" + paymentMethods [i] ); if (securityCode != null && securityCode.length() > 0) { paymentMethodInfo.put("securityCode", securityCode); } the trick here is that you'll have to change the paymentMethodInfo from a list to a map 3) in CheckOutHelper.setCheckOutPaymentInternal(...) you'll have to retrieve the cvv value from the above map; here is the method from an older modified version of OFBiz: public List setCheckOutPaymentInternal(Map selectedPaymentMethods, List singleUsePayments, String billingAccountId, Double billingAccountAmt) { List errorMessages = new ArrayList(); String errMsg = null; if (singleUsePayments == null) { singleUsePayments = new ArrayList(); } // set the payment method option if (selectedPaymentMethods != null && selectedPaymentMethods.size() > 0) { // clear out the old payments cart.clearPayments(); if (billingAccountId != null && billingAccountAmt != null && !billingAccountId.equals(" NA ")) { // set cart billing account data and generate a payment method containing the amount we will be charging cart.setBillingAccount(billingAccountId, billingAccountAmt.doubleValue()); } else if (" NA ".equals(billingAccountId)) { // if _NA_ was supplied, erase all billing account data cart.setBillingAccount(null, 0.0); } // TODO: the following code needs some review (JAC20061213) // if checkoutPaymentId == EXT_BILLACT, then we have billing account only, so make sure we have enough credit if (selectedPaymentMethods.containsKey("EXT_BILLACT") && selectedPaymentMethods.size() == 1) { double accountCredit = this.availableAccountBalance(cart.getBillingAccountId()); double amountToUse = cart.getBillingAccountAmount(); // if an amount was entered, check that it doesn't exceed availalble amount if (amountToUse > 0 && amountToUse > accountCredit) { errMsg = UtilProperties.getMessage(resource,"checkhelper.insufficient_credit_available_on_account", (cart != null ? cart.getLocale() : Locale.getDefault())); errorMessages.add(errMsg); } else { // otherwise use the available account credit (The user might enter 10.00 for an order worth 20.00 from an account with 30.00. This makes sure that the 30.00 is used) amountToUse = accountCredit; } // check that the amount to use is enough to fulfill the order double grandTotal = cart.getGrandTotal(); if (grandTotal > amountToUse) { cart.setBillingAccount(null, 0.0); // erase existing billing account data errMsg = UtilProperties.getMessage(resource,"checkhelper.insufficient_credit_available_on_account", (cart != null ? cart.getLocale() : Locale.getDefault())); errorMessages.add(errMsg); } else { // since this is the only selected payment method, let's make this amount the grand total for convenience amountToUse = grandTotal; } // associate the cart billing account amount and EXT_BILLACT selected payment method with whatever amount we have now // XXX: Note that this step is critical for the billing account to be charged correctly if (amountToUse > 0) { cart.setBillingAccount(billingAccountId, amountToUse); selectedPaymentMethods.put("EXT_BILLACT", new Double(amountToUse)); } } Set paymentMethods = selectedPaymentMethods.keySet(); Iterator i = paymentMethods.iterator(); while (i.hasNext()) { String checkOutPaymentId = (String) i.next(); // get the selected amount to use Double paymentAmount = null; String securityCode = null; if (selectedPaymentMethods.get(checkOutPaymentId) != null) { Map checkOutPaymentInfo = (Map) selectedPaymentMethods.get(checkOutPaymentId); paymentAmount = (Double) checkOutPaymentInfo.get("amount"); securityCode = (String) checkOutPaymentInfo.get("securityCode"); } boolean singleUse = singleUsePayments.contains(checkOutPaymentId); cart.addPaymentAmount(checkOutPaymentId, paymentAmount, singleUse); ShoppingCart.CartPaymentInfo cpi = cart.getPaymentInfo(cart.selectedPayments() - 1); cpi.securityCode = securityCode; } } else if (cart.getGrandTotal() != 0.00) { // only return an error if the order total is not 0.00 errMsg = UtilProperties.getMessage(resource,"checkhelper.select_method_of_payment", (cart != null ? cart.getLocale() : Locale.getDefault())); errorMessages.add(errMsg); } return errorMessages; } Hope it helps
        Hide
        Jacques Le Roux added a comment -

        Jacopo,

        I have no personnal use for the moment but thanks a bunch for this snippets, they will surely help !

        I was asking about creatin an OFBiz FAQ. This one could be in

        How to use cvv codes in OFBiz ? (alright rather technical for a FAQ perhaps ?)

        Show
        Jacques Le Roux added a comment - Jacopo, I have no personnal use for the moment but thanks a bunch for this snippets, they will surely help ! I was asking about creatin an OFBiz FAQ. This one could be in How to use cvv codes in OFBiz ? (alright rather technical for a FAQ perhaps ?)
        Hide
        David E. Jones added a comment -

        Thanks for your comments on this Jacopo, I didn't realize the support for that was this far along.

        In SVN rev 515393 I removed the CreditCard.cvvNumber field as we really should just use the OrderPaymentPreference.securityCode, which is probably a better place for that data anyway.

        Ashish: please forget what I said before and follow Jacopo's advice here to use the securityCode field.

        Show
        David E. Jones added a comment - Thanks for your comments on this Jacopo, I didn't realize the support for that was this far along. In SVN rev 515393 I removed the CreditCard.cvvNumber field as we really should just use the OrderPaymentPreference.securityCode, which is probably a better place for that data anyway. Ashish: please forget what I said before and follow Jacopo's advice here to use the securityCode field.
        Hide
        Jacopo Cappellato added a comment -

        Implemented in rev. 585172

        Show
        Jacopo Cappellato added a comment - Implemented in rev. 585172
        Hide
        BJ Freeman added a comment -

        C v v should not be stored by the PCI standards.
        this leaves using ecas to process the
        https://localhost:8443/webtools/control/availableServices
        processAuthResult->cvCode

        so any processing of this field needs to be on the fly at the time the payment is processed.
        Just having the field in entity could cause a PCI audit to disqualify the program.

        Show
        BJ Freeman added a comment - C v v should not be stored by the PCI standards. this leaves using ecas to process the https://localhost:8443/webtools/control/availableServices processAuthResult->cvCode so any processing of this field needs to be on the fly at the time the payment is processed. Just having the field in entity could cause a PCI audit to disqualify the program.
        Hide
        David E. Jones added a comment -

        BJ I think you are incorrect about this. I've read the PCI guidelines to research just this, and communicated with others familiar with PCI about this, and my understanding Persisting the CVV code is allowed by the PCI requirements, but only within the scope of the initial card authorization. This is a common need for asynchronous payment authorization and such, which is an option though not the default in OFBiz.

        Show
        David E. Jones added a comment - BJ I think you are incorrect about this. I've read the PCI guidelines to research just this, and communicated with others familiar with PCI about this, and my understanding Persisting the CVV code is allowed by the PCI requirements, but only within the scope of the initial card authorization. This is a common need for asynchronous payment authorization and such, which is an option though not the default in OFBiz.
        Hide
        BJ Freeman added a comment -

        Believe the misunderstanding is on my part.
        did not read the code thouroughly.
        thought the cpi.securityCode
        was an entify field not a value passed in the session.
        and I did not see any code to flush the field once finished.
        yes as long as it is not stored in an entity field that is appropriate.

        Show
        BJ Freeman added a comment - Believe the misunderstanding is on my part. did not read the code thouroughly. thought the cpi.securityCode was an entify field not a value passed in the session. and I did not see any code to flush the field once finished. yes as long as it is not stored in an entity field that is appropriate.

          People

          • Assignee:
            Jacopo Cappellato
            Reporter:
            Ashish Vijaywargiya
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development