Subversion Repositories SmartDukaan

Rev

Rev 2334 | Rev 2899 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

package in.shop2020.serving.services;

import in.shop2020.config.ConfigException;
import in.shop2020.payments.Attribute;
import in.shop2020.payments.Payment;
import in.shop2020.payments.PaymentStatus;
import in.shop2020.payments.PaymentService.Client;
import in.shop2020.serving.services.IPaymentService.Errors;
import in.shop2020.thrift.clients.PaymentServiceClient;
import in.shop2020.thrift.clients.config.ConfigClient;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.log4j.Logger;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

public class EbsPaymentService implements IPaymentService{
        
        private static Logger log = Logger.getLogger(Class.class);
        
        public static final String TXN_ID = "transactionId";
        public static final String PAYMENT_ID = "paymentId";
        public static final String AMOUNT = "amount";
        public static final String DATE_TIME = "dateTime";
        public static final String MODE = "mode";
        public static final String REF_NO = "referenceNo";
        public static final String TXN_TYPE = "transactionType";
        
    private static String accountId;
    private static String secretKey;
    
        static{
                try {
                        accountId = ConfigClient.getClient().get("ebs_account_id");
                        secretKey = ConfigClient.getClient().get("ebs_secret_key");
                } catch (ConfigException e) {
                        log.error("Unable to get EBS payment configuration.");
                }
        }
        
        private static int gatewayId=2;
        private long paymentId;
        
        @Override
        public long createPayment(long currentCartId, long userId, long txnId, String paymentOption){
                log.info("Creating payment for the txn#: " + txnId + " for the user: " + userId + " for processing through EBS");
                CommonPaymentService cps = new CommonPaymentService();
                if(!cps.createPayment(currentCartId, userId, txnId, gatewayId)){
                        log.error("Error while creating the basic payment");
                        return PAYMENT_NOT_CREATED;
                }
                paymentId = cps.getPaymentId();
                
                if(paymentOption != null){
                        List<Attribute> attributes = new ArrayList<Attribute>();
                        attributes.add(new Attribute(IPaymentService.PAYMENT_METHOD, paymentOption));
                        
                        try {
                                PaymentServiceClient paymentServiceClient = new PaymentServiceClient();
                                paymentServiceClient.getClient().updatePaymentDetails(paymentId, null, null, null, null, null, null, null, null, PaymentStatus.INIT, null, attributes);
                        } catch (Exception e) {
                                log.error("Error while saving payment option attribute", e);
                                // TODO: We've already created the payment. We could allow the
                                // payment to go through. The customer will be a little
                                // annoyed to have to select from a host of options again but
                                // will be better than completely disallowing him.
                                return PAYMENT_NOT_CREATED;
                        }
                }

                return paymentId;
        }

        /**
         * Capture the amount which was authorized for this payment Id. Makes
         * requests over the network and so internet connectivity is must for it to
         * succeed.
         * 
         * @param amount
         *            The amount to be captured. Must be the same value which was
         *            authorized for this payment.
         * @param gatewayPaymentId
         *            The payment ID generated by the gateway.
         * @return A Map. The Map will definitely have status and will have error
         *         information in case of error and txn information in case of
         *         success. In case there is an error in processing, the returned
         *         result map will be empty.
         */
        public static Map<String, String> capturePayment(Payment payment, String gatewayPaymentId){
                String amount = "" + payment.getAmount();
                log.info("Capturing amount: Rs " + amount + " for payment Id: " + gatewayPaymentId);
            Map<String, String> resultMap = new HashMap<String, String>();

            //Prepare resultMap to elicit failure behaviour in case anything goes wrong.
            resultMap.put(STATUS, "");
            
                try {
                        PaymentServiceClient paymentServiceClient = new PaymentServiceClient();
                        Client paymentClient = paymentServiceClient.getClient();
                        resultMap = paymentClient.captureEbsPayment(payment.getPaymentId());
                } catch (Exception e) {
                        log.error("Unable to capture payment", e);
                        resultMap.put(ERR_CODE, Errors.CONN_FAILURE.code);
                        resultMap.put(ERROR, "Unable to capture transaction.");
                }
            
                return resultMap;
                
//              /*
//               * HDFC Insanity
//               * 
//               * If we don't set this property, all payments through HDFC will fail if
//               * the first payment is made through EBS.
//               * 
//               * The JAR file provided by HDFC requires that the instances of
//               * HttpsURLConnection returned by a call to URL.openConnection be an
//               * instance of com.sun.net.ssl.HttpsURLConnection. Java versions before
//               * 1.4 used to return an instance of this class which goes against the
//               * current policy of using instances of undocumented internal classes of
//               * JDK since they can change at any time. This behaviour was changed in
//               * JAVA 1.4 to return instances of javax.net.ssl.HttpsURLConnection.
//               * However, it appears, that to allow clients with JDK 1.4 and earlier,
//               * HDFC favours the use of the deprecated class.
//               */
//          System.setProperty("java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol");
//          
//          try {
//                  // URL of CGI-Bin script.
//                      url = new URL("https://secure.ebs.in/api/1_0");
//                  // URL connection channel.
//                  urlConn = url.openConnection();
//                  //urlConn.setRequestMethod("POST");
//          } catch (MalformedURLException e1) {
//                      log.error(Errors.CONN_FAILURE.message, e1);
//                      resultMap.put(ERR_CODE, Errors.CONN_FAILURE.code);
//                      resultMap.put(ERROR, Errors.CONN_FAILURE.message);
//                      return resultMap;
//              } catch (IOException e) {
//                      log.error("Unable to initialize connection to EBS API server", e);
//                      resultMap.put(ERR_CODE, Errors.CONN_FAILURE.code);
//                      resultMap.put(ERROR, Errors.CONN_FAILURE.message);
//                      return resultMap;
//              }
//
//          // Let the run-time system (RTS) know that we want input.
//          urlConn.setDoInput (true);
//          // Let the RTS know that we want to do output.
//          urlConn.setDoOutput (true);
//          // No caching, we want the real thing.
//          urlConn.setUseCaches (false);
//          // Specify the content type.
//          urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
//          // Send POST output.
//          try {
//                      printout = new DataOutputStream (urlConn.getOutputStream ());
//                  String content =
//                          "Action=" + URLEncoder.encode("capture", "UTF-8") +
//                          "&AccountID=" + URLEncoder.encode(accountId, "UTF-8") +
//                          "&SecretKey=" + URLEncoder.encode(secretKey, "UTF-8") +
//                          "&Amount=" + URLEncoder.encode(""+amount, "UTF-8") +
//                          "&PaymentID=" + URLEncoder.encode(paymentId, "UTF-8") +
//                          "&submitted=Submit";
//                  printout.writeBytes (content);
//                  printout.flush ();
//                  printout.close ();
//
//                  // Get response data.
//                  reader = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
//                  resultMap = parseCaptureOutput(reader);
//                  reader.close ();
//          } catch (IOException e) {
//                      log.error(Errors.CAPTURE_FAILURE.message, e);
//                      resultMap.clear();
//                      resultMap.put(STATUS, "");
//                      resultMap.put(ERR_CODE, Errors.CAPTURE_FAILURE.code);
//                      resultMap.put(ERROR, Errors.CAPTURE_FAILURE.message);
//              }
//          return resultMap;
        }

        /**
         * Parses the given input stream and returns a map containing the
         * transaction details
         * 
         * @param reader The reader containing the response of the capture request.
         * @return A Map. The Map will definitely have status and will have error
         *         information in case of error and txn information in case of
         *         success.
         */
        private static Map<String, String> parseCaptureOutput(BufferedReader reader){
                Map<String, String> resultMap = new HashMap<String, String>();
                resultMap.put(STATUS, "");
                
                String str = null;
                try {
                        str = reader.readLine();
                        log.info("Capture response: " + str);
                } catch (IOException e) {
                        log.error("Error reading the capture response:", e);
                        return resultMap;
                }
                
                InputSource inputSource = new InputSource(new StringReader(str));
                XPath xpath = XPathFactory.newInstance().newXPath();
                String expression = "/output";
                NodeList nodes = null;
                try {
                        nodes = (NodeList) xpath.evaluate(expression, inputSource,      XPathConstants.NODESET);
                } catch(XPathExpressionException xpee) {
                        log.error("Input couldn't be parsed. See capture response for more info.");
                        return resultMap;
                }
                
                Element elem = (Element) nodes.item(0);
                String status = elem.getAttribute(STATUS);
                resultMap.put(STATUS, status);
                if("".equals(status) || !"Processing".equals(status)){
                        //We've received an error. Retrieve the error values
                        resultMap.put(ERR_CODE, elem.getAttribute(ERR_CODE));
                        resultMap.put(ERROR, elem.getAttribute(ERROR));
                }else{
                        resultMap.put(CAPTURE_TXN_ID, elem.getAttribute(TXN_ID));
                        resultMap.put(PAYMENT_ID, elem.getAttribute(PAYMENT_ID));
                        resultMap.put(AMOUNT, elem.getAttribute(AMOUNT));
                        resultMap.put(CAPTURE_TIME, elem.getAttribute(DATE_TIME));
                        resultMap.put(MODE, elem.getAttribute(MODE));
                        resultMap.put(REF_NO, elem.getAttribute(REF_NO));
                        resultMap.put(TXN_TYPE, elem.getAttribute(TXN_TYPE));
                }

                log.info("Parsed capture response:");
                for(Entry<String, String> entry : resultMap.entrySet()){
                        log.info("Key: " + entry.getKey() + ", Value: " + entry.getValue());
                }
                
                return resultMap;
        }
        
        public static void main(String[] args){
                //capturePayment(30450.00, "2412653");
                
//              <output  transactionId="4793507"  paymentId="2411078"  amount="25005"  dateTime="2011-05-16 09:03:15"  mode="TEST"  referenceNo="4"  transactionType="Captured"  status="Processing"  />";

//              <output  errorCode="2"  error="Invalid Account ID/Secret Key"  />
//              <output  errorCode="12"  error="This payment is failed"  />
//              <output  errorCode="13"  error="This payment is captured already"  />           
        }
}