com.konakart.bl.modules.payment.cyberpac.Cyberpac.java Source code

Java tutorial

Introduction

Here is the source code for com.konakart.bl.modules.payment.cyberpac.Cyberpac.java

Source

//
// (c) 2013 DS Data Systems UK Ltd, All rights reserved.
//
// DS Data Systems and KonaKart and their respective logos, are 
// trademarks of DS Data Systems UK Ltd. All rights reserved.
//
// The information in this document is free software; you can redistribute 
// it and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// 
// This software is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
// 
//
package com.konakart.bl.modules.payment.cyberpac;

import java.math.BigDecimal;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;

import org.apache.commons.codec.binary.Hex;

import com.konakart.app.KKException;
import com.konakart.app.NameValue;
import com.konakart.app.Order;
import com.konakart.app.OrderTotal;
import com.konakart.app.PaymentDetails;
import com.konakart.app.SSOToken;
import com.konakart.appif.KKEngIf;
import com.konakart.appif.SSOTokenIf;
import com.konakart.bl.modules.BaseModule;
import com.konakart.bl.modules.ordertotal.OrderTotalMgr;
import com.konakart.bl.modules.payment.BasePaymentModule;
import com.konakart.bl.modules.payment.PaymentInfo;
import com.konakart.bl.modules.payment.PaymentInterface;

/**
 * La Caixa Cyberpac module
 */
public class Cyberpac extends BasePaymentModule implements PaymentInterface {
    // Module name must be the same as the class name although it can be all in lowercase
    private static String code = "cyberpac";

    private static String bundleName = BaseModule.basePackage + ".payment.cyberpac.Cyberpac";

    private static HashMap<Locale, ResourceBundle> resourceBundleMap = new HashMap<Locale, ResourceBundle>();

    /** Hash Map that contains the static data */
    private static Map<String, StaticData> staticDataHM = Collections
            .synchronizedMap(new HashMap<String, StaticData>());

    private static String mutex = "cyberpacMutex";

    // Configuration Keys

    /**
     * Used to put the gateway online / offline
     */
    private final static String MODULE_PAYMENT_CYBERPAC_STATUS = "MODULE_PAYMENT_CYBERPAC_STATUS";

    /**
     * The Cyberpac zone, if greater than zero, should reference a GeoZone. If the DeliveryAddress
     * of the order isn't within that GeoZone, then we throw an exception
     */
    private final static String MODULE_PAYMENT_CYBERPAC_ZONE = "MODULE_PAYMENT_CYBERPAC_ZONE";

    /**
     * The order for displaying this payment gateway on the UI
     */
    private final static String MODULE_PAYMENT_CYBERPAC_SORT_ORDER = "MODULE_PAYMENT_CYBERPAC_SORT_ORDER";

    /**
     * The Cyberpac Url used to POST the payment request. "https://sis.sermepa.es/sis/realizarPago"
     */
    private final static String MODULE_PAYMENT_CYBERPAC_REQUEST_URL = "MODULE_PAYMENT_CYBERPAC_REQUEST_URL";

    /**
     * Callback username and password
     */
    private static final String MODULE_PAYMENT_CYBERPAC_CALLBACK_USERNAME = "MODULE_PAYMENT_CYBERPAC_CALLBACK_USERNAME";

    private static final String MODULE_PAYMENT_CYBERPAC_CALLBACK_PASSWORD = "MODULE_PAYMENT_CYBERPAC_CALLBACK_PASSWORD";

    /**
     * FUC code assigned to the merchant.
     */
    private final static String MODULE_PAYMENT_CYBERPAC_MERCHANT_CODE = "MODULE_PAYMENT_CYBERPAC_MERCHANT_CODE";

    /**
     * Merchant URL where transaction data will be sent by POST.
     */
    private final static String MODULE_PAYMENT_CYBERPAC_CALLBACK_URL = "MODULE_PAYMENT_CYBERPAC_CALLBACK_URL";

    /**
     * Customer is redirected to this URL when the payment completes successfully
     */
    private final static String MODULE_PAYMENT_CYBERPAC_MERCHANT_URL_OK = "MODULE_PAYMENT_CYBERPAC_MERCHANT_URL_OK";

    /**
     * Customer is redirected to this URL when the payment doesn't complete successfully
     */
    private final static String MODULE_PAYMENT_CYBERPAC_MERCHANT_URL_KO = "MODULE_PAYMENT_CYBERPAC_MERCHANT_URL_KO";

    /**
     * Terminal number assigned by bank
     */
    private final static String MODULE_PAYMENT_CYBERPAC_MERCHANT_TERMINAL_NUMBER = "MODULE_PAYMENT_CYBERPAC_MERCHANT_TERMINAL_NUMBER";

    /**
     * Defaults to 2 (confirmation)
     */
    private final static String MODULE_PAYMENT_CYBERPAC_TRANSACTION_TYPE = "MODULE_PAYMENT_CYBERPAC_TRANSACTION_TYPE";

    /**
     * The secret code used to digitally sign messages
     */
    private final static String MODULE_PAYMENT_CYBERPAC_SECRET_SIGNING_CODE = "MODULE_PAYMENT_CYBERPAC_SECRET_SIGNING_CODE";

    // Message Catalogue Keys
    private final static String MODULE_PAYMENT_CYBERPAC_TEXT_TITLE = "module.payment.cyberpac.text.title";

    private final static String MODULE_PAYMENT_CYBERPAC_TEXT_DESCRIPTION = "module.payment.cyberpac.text.description";

    private final static String MODULE_PAYMENT_CYBERPAC_CUSTOMER_MSG = "module.payment.cyberpac.customer.message";

    /**
     * Constructor
     * 
     * @param eng
     * 
     * @throws KKException
     */
    public Cyberpac(KKEngIf eng) throws KKException {
        super.init(eng);

        StaticData sd = staticDataHM.get(getStoreId());

        if (sd == null) {
            synchronized (mutex) {
                sd = staticDataHM.get(getStoreId());
                if (sd == null) {
                    setStaticVariables();
                }
            }
        }
    }

    /**
     * Sets some static variables during setup
     * 
     * @throws KKException
     * 
     */
    public void setStaticVariables() throws KKException {

        String val;
        int valInt;
        StaticData staticData = staticDataHM.get(getStoreId());
        if (staticData == null) {
            staticData = new StaticData();
            staticDataHM.put(getStoreId(), staticData);
        }

        val = getConfigurationValue(MODULE_PAYMENT_CYBERPAC_REQUEST_URL);
        if (val == null || val.length() == 0) {
            throw new KKException("The Configuration MODULE_PAYMENT_CYBERPAC_REQUEST_URL must be set to the URL for"
                    + " sending the request to Cyberpac. (i.e. https://sis.sermepa.es/sis/services/realizarPago"
                    + " for a live system or https://sis-t.sermepa.es:25443/sis/realizarPago for testing");
        }
        staticData.setRequestUrl(val);

        val = getConfigurationValue(MODULE_PAYMENT_CYBERPAC_CALLBACK_URL);
        if (val == null || val.length() == 0) {
            throw new KKException("The Configuration MODULE_PAYMENT_CYBERPAC_CALLBACK_URL must be set to the URL of"
                    + " the action class used to manage the callback from Cyberpac");
        }
        staticData.setCallbackUrl(val);

        // Not mandatory since it may be configured in the Admin acct
        val = getConfigurationValue(MODULE_PAYMENT_CYBERPAC_MERCHANT_URL_OK);
        staticData.setRedirectOKUrl(val);

        // Not mandatory since it may be configured in the Admin acct
        val = getConfigurationValue(MODULE_PAYMENT_CYBERPAC_MERCHANT_URL_KO);
        staticData.setRedirectKOUrl(val);

        val = getConfigurationValue(MODULE_PAYMENT_CYBERPAC_CALLBACK_USERNAME);
        if (val == null || val.length() == 0) {
            throw new KKException(
                    "The Configuration MODULE_PAYMENT_CYBERPAC_CALLBACK_USERNAME must be set to a valid engine Username for the"
                            + " callback functionality.");
        }
        staticData.setCallbackUsername(val);

        val = getConfigurationValue(MODULE_PAYMENT_CYBERPAC_CALLBACK_PASSWORD);
        if (val == null || val.length() == 0) {
            throw new KKException(
                    "The Configuration MODULE_PAYMENT_CYBERPAC_CALLBACK_PASSWORD must be set to a valid engine Password for the"
                            + " callback functionality.");
        }
        staticData.setCallbackPassword(val);

        valInt = getConfigurationValueAsIntWithDefault(MODULE_PAYMENT_CYBERPAC_ZONE, 0);
        staticData.setZone(valInt);

        valInt = getConfigurationValueAsIntWithDefault(MODULE_PAYMENT_CYBERPAC_SORT_ORDER, 0);
        staticData.setSortOrder(valInt);

        val = getConfigurationValue(MODULE_PAYMENT_CYBERPAC_MERCHANT_CODE);
        if (val == null || val.length() == 0) {
            throw new KKException(
                    "The Configuration MODULE_PAYMENT_CYBERPAC_MERCHANT_CODE must be set to a valid merchant code.");
        }
        staticData.setMerchantCode(val);

        val = getConfigurationValue(MODULE_PAYMENT_CYBERPAC_MERCHANT_TERMINAL_NUMBER);
        if (val == null || val.length() == 0) {
            throw new KKException(
                    "The Configuration MODULE_PAYMENT_CYBERPAC_MERCHANT_TERMINAL_NUMBER must be set to a valid terminal number");
        }
        staticData.setTerminalNumber(val);

        val = getConfigurationValue(MODULE_PAYMENT_CYBERPAC_TRANSACTION_TYPE);
        if (val == null || val.length() == 0) {
            val = "2";
        }
        staticData.setTransactionType(val);

        val = getConfigurationValue(MODULE_PAYMENT_CYBERPAC_SECRET_SIGNING_CODE);
        if (val == null || val.length() == 0) {
            throw new KKException(
                    "The Configuration MODULE_PAYMENT_CYBERPAC_SECRET_SIGNING_CODE must be set with the secret code"
                            + " used to digitally sign messages.");
        }
        staticData.setSecretSigningCode(val);

    }

    /**
     * Return a payment details object for Cyberpac
     * 
     * @param order
     * @param info
     * @return Returns information in a PaymentDetails object
     * @throws Exception
     */
    public PaymentDetails getPaymentDetails(Order order, PaymentInfo info) throws Exception {
        StaticData sd = staticDataHM.get(getStoreId());
        /*
         * The CyberpacZone zone, if greater than zero, should reference a GeoZone. If the
         * DeliveryAddress of the order isn't within that GeoZone, then we throw an exception
         */
        if (sd.getZone() > 0) {
            checkZone(info, sd.getZone());
        }

        // Get the scale for currency calculations
        int scale = new Integer(order.getCurrency().getDecimalPlaces()).intValue();

        // Get the resource bundle
        ResourceBundle rb = getResourceBundle(mutex, bundleName, resourceBundleMap, info.getLocale());
        if (rb == null) {
            throw new KKException(
                    "A resource file cannot be found for the country " + info.getLocale().getCountry());
        }

        PaymentDetails pDetails = new PaymentDetails();
        pDetails.setCode(code);
        pDetails.setSortOrder(sd.getSortOrder());
        pDetails.setPaymentType(PaymentDetails.BROWSER_PAYMENT_GATEWAY);
        pDetails.setDescription(rb.getString(MODULE_PAYMENT_CYBERPAC_TEXT_DESCRIPTION));
        pDetails.setTitle(rb.getString(MODULE_PAYMENT_CYBERPAC_TEXT_TITLE));

        // Return now if the full payment details aren't required. This happens when the manager
        // just wants a list of payment gateways to display in the UI.
        if (info.isReturnDetails() == false) {
            return pDetails;
        }

        pDetails.setPostOrGet("post");
        pDetails.setRequestUrl(sd.getRequestUrl());

        List<NameValue> parmList = new ArrayList<NameValue>();

        /*
         * Parameters posted to gateway
         */

        // Total
        BigDecimal total = null;
        for (int i = 0; i < order.getOrderTotals().length; i++) {
            OrderTotal ot = (OrderTotal) order.getOrderTotals()[i];
            if (ot.getClassName().equals(OrderTotalMgr.ot_total)) {
                total = ot.getValue().setScale(scale, BigDecimal.ROUND_HALF_UP);
            }
        }
        if (total == null) {
            throw new KKException("An Order Total was not found in the order id = " + order.getId());
        }
        parmList.add(new NameValue("Ds_Merchant_Amount", total.toString()));

        // Currency
        String currCode = null;
        if (order.getCurrency().getCode().equalsIgnoreCase("EUR")) {
            currCode = "978";
        } else if (order.getCurrency().getCode().equalsIgnoreCase("USD")) {
            currCode = "840";
        } else if (order.getCurrency().getCode().equalsIgnoreCase("GBP")) {
            currCode = "826";
        } else if (order.getCurrency().getCode().equalsIgnoreCase("JPY")) {
            currCode = "392";
        } else {
            throw new KKException("The currency with code = " + order.getCurrency().getCode()
                    + " is not supported by the Cyberpac payment gateway.");
        }
        String ds_Merchant_Currency = currCode;
        parmList.add(new NameValue("Ds_Merchant_Currency", ds_Merchant_Currency));

        // Various
        String ds_Merchant_Order = Integer.toString(order.getId());
        parmList.add(new NameValue("Ds_Merchant_Order", ds_Merchant_Order));
        parmList.add(new NameValue("Ds_Merchant_ProductDescription",
                rb.getString(MODULE_PAYMENT_CYBERPAC_CUSTOMER_MSG) + " " + order.getId()));
        parmList.add(new NameValue("Ds_Merchant_Cardholder", order.getBillingName()));
        String ds_Merchant_MerchantCode = sd.getMerchantCode();
        parmList.add(new NameValue("Ds_Merchant_MerchantCode", ds_Merchant_MerchantCode));
        parmList.add(new NameValue("Ds_Merchant_MerchantURL", sd.getCallbackUrl()));
        if (sd.getRedirectKOUrl() != null && sd.getRedirectKOUrl().length() > 0) {
            parmList.add(new NameValue("Ds_Merchant_UrlKO", sd.getRedirectKOUrl()));
        }
        if (sd.getRedirectOKUrl() != null && sd.getRedirectOKUrl().length() > 0) {
            parmList.add(new NameValue("Ds_Merchant_UrlOK", sd.getRedirectOKUrl()));
        }

        String lang = "001"; // Default Spanish Castellano
        String langCode = order.getLocale().substring(0, 2);
        if (order.getLocale().equalsIgnoreCase("ca_ES")) {
            lang = "003";
        } else if (langCode.equalsIgnoreCase("en")) {
            lang = "002";
        } else if (langCode.equalsIgnoreCase("fr")) {
            lang = "004";
        } else if (langCode.equalsIgnoreCase("de")) {
            lang = "005";
        } else if (langCode.equalsIgnoreCase("it")) {
            lang = "007";
        } else if (langCode.equalsIgnoreCase("pt")) {
            lang = "009";
        } else if (order.getLocale().equalsIgnoreCase("eu_ES")) {
            lang = "013";
        } else if (langCode.equalsIgnoreCase("ru")) {
            lang = "014";
        }
        parmList.add(new NameValue("Ds_Merchant_ConsumerLanguage", lang));

        parmList.add(new NameValue("Ds_Merchant_Terminal", sd.getTerminalNumber()));

        if (sd.getTransactionType() != null && sd.getTransactionType().length() > 0) {
            parmList.add(new NameValue("Ds_Merchant_TransactionType", sd.getTransactionType()));
        } else {
            parmList.add(new NameValue("Ds_Merchant_TransactionType", "2"));
        }

        // Data passed to us in callback. Need to create a session
        SSOTokenIf ssoToken = new SSOToken();
        String sessionId = getEng().login(sd.getCallbackUsername(), sd.getCallbackPassword());
        if (sessionId == null) {
            throw new KKException(
                    "Unable to log into the engine using the Cyberpac Callback Username and Password");
        }
        ssoToken.setSessionId(sessionId);
        ssoToken.setCustom1(String.valueOf(order.getId()));
        // Save the SSOToken with a valid sessionId and the order id in custom1
        String uuid = getEng().saveSSOToken(ssoToken);
        parmList.add(new NameValue("Ds_Merchant_MerchantData", uuid));

        // Sign the data
        // Digest=SHA-1(Ds_Merchant_Amount + Ds_Merchant_Order +Ds_Merchant_MerchantCode
        // + DS_Merchant_Currency + SECRET CODE)
        String ds_Merchant_Amount = (total.multiply(new BigDecimal(100))).toString();
        String stringToSign = ds_Merchant_Amount + ds_Merchant_Order + ds_Merchant_MerchantCode
                + ds_Merchant_Currency + sd.getSecretSigningCode();
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        byte[] digest = md.digest(stringToSign.getBytes("UTF8"));
        String hexEncodedDigest = (Hex.encodeHex(digest)).toString();
        parmList.add(new NameValue("Ds_Merchant_MerchantSignature", hexEncodedDigest));
        if (log.isDebugEnabled()) {
            StringBuffer str = new StringBuffer();
            str.append("Parameters to sign:").append("\n");
            str.append("Ds_Merchant_Amount        = ").append(ds_Merchant_Amount).append("\n");
            str.append("Ds_Merchant_Order         = ").append(ds_Merchant_Order).append("\n");
            str.append("Ds_Merchant_MerchantCode  = ").append(ds_Merchant_MerchantCode).append("\n");
            str.append("Ds_Merchant_Currency      = ").append(ds_Merchant_Currency).append("\n");
            str.append("Secret Code               = ").append(sd.getSecretSigningCode()).append("\n");
            str.append("String to sign            = ").append(stringToSign).append("\n");
            str.append("SHA-1 result              = ").append(hexEncodedDigest).append("\n");
            log.debug(str);
        }

        // Put the parameters into an array
        NameValue[] nvArray = new NameValue[parmList.size()];
        parmList.toArray(nvArray);
        pDetails.setParameters(nvArray);

        if (log.isDebugEnabled()) {
            log.debug(pDetails.toString());
        }

        return pDetails;
    }

    /**
     * Returns true or false
     * 
     * @throws KKException
     */
    public boolean isAvailable() throws KKException {
        return isAvailable(MODULE_PAYMENT_CYBERPAC_STATUS);
    }

    /**
     * Used to store the static data of this module
     */
    protected class StaticData {
        private int sortOrder = -1;

        private String requestUrl;

        private String callbackUrl;

        private String redirectOKUrl;

        private String redirectKOUrl;

        private String callbackUsername;

        private String callbackPassword;

        private String merchantCode;

        private String terminalNumber;

        private String transactionType;

        private String secretSigningCode;

        private int zone;

        /**
         * @return the sortOrder
         */
        public int getSortOrder() {
            return sortOrder;
        }

        /**
         * @param sortOrder
         *            the sortOrder to set
         */
        public void setSortOrder(int sortOrder) {
            this.sortOrder = sortOrder;
        }

        /**
         * @return the zone
         */
        public int getZone() {
            return zone;
        }

        /**
         * @param zone
         *            the zone to set
         */
        public void setZone(int zone) {
            this.zone = zone;
        }

        /**
         * @return the callbackUsername
         */
        public String getCallbackUsername() {
            return callbackUsername;
        }

        /**
         * @param callbackUsername
         *            the callbackUsername to set
         */
        public void setCallbackUsername(String callbackUsername) {
            this.callbackUsername = callbackUsername;
        }

        /**
         * @return the callbackPassword
         */
        public String getCallbackPassword() {
            return callbackPassword;
        }

        /**
         * @param callbackPassword
         *            the callbackPassword to set
         */
        public void setCallbackPassword(String callbackPassword) {
            this.callbackPassword = callbackPassword;
        }

        /**
         * @return the requestUrl
         */
        public String getRequestUrl() {
            return requestUrl;
        }

        /**
         * @param requestUrl
         *            the requestUrl to set
         */
        public void setRequestUrl(String requestUrl) {
            this.requestUrl = requestUrl;
        }

        /**
         * @return the callbackUrl
         */
        public String getCallbackUrl() {
            return callbackUrl;
        }

        /**
         * @param callbackUrl
         *            the callbackUrl to set
         */
        public void setCallbackUrl(String callbackUrl) {
            this.callbackUrl = callbackUrl;
        }

        /**
         * @return the redirectOKUrl
         */
        public String getRedirectOKUrl() {
            return redirectOKUrl;
        }

        /**
         * @param redirectOKUrl
         *            the redirectOKUrl to set
         */
        public void setRedirectOKUrl(String redirectOKUrl) {
            this.redirectOKUrl = redirectOKUrl;
        }

        /**
         * @return the redirectKOUrl
         */
        public String getRedirectKOUrl() {
            return redirectKOUrl;
        }

        /**
         * @param redirectKOUrl
         *            the redirectKOUrl to set
         */
        public void setRedirectKOUrl(String redirectKOUrl) {
            this.redirectKOUrl = redirectKOUrl;
        }

        /**
         * @return the merchantCode
         */
        public String getMerchantCode() {
            return merchantCode;
        }

        /**
         * @param merchantCode
         *            the merchantCode to set
         */
        public void setMerchantCode(String merchantCode) {
            this.merchantCode = merchantCode;
        }

        /**
         * @return the terminalNumber
         */
        public String getTerminalNumber() {
            return terminalNumber;
        }

        /**
         * @param terminalNumber
         *            the terminalNumber to set
         */
        public void setTerminalNumber(String terminalNumber) {
            this.terminalNumber = terminalNumber;
        }

        /**
         * @return the transactionType
         */
        public String getTransactionType() {
            return transactionType;
        }

        /**
         * @param transactionType
         *            the transactionType to set
         */
        public void setTransactionType(String transactionType) {
            this.transactionType = transactionType;
        }

        /**
         * @return the secretSigningCode
         */
        public String getSecretSigningCode() {
            return secretSigningCode;
        }

        /**
         * @param secretSigningCode
         *            the secretSigningCode to set
         */
        public void setSecretSigningCode(String secretSigningCode) {
            this.secretSigningCode = secretSigningCode;
        }
    }

}