Subversion Repositories SmartDukaan

Rev

Rev 3375 | Rev 3583 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1946 chandransh 1
package in.shop2020.payment.service.handler;
2
 
3578 mandeep.dh 3
import in.shop2020.crm.CRMService.Client;
4
import in.shop2020.payment.domain.Refund;
5
import in.shop2020.payment.handler.PaymentGatewayHandler;
6
import in.shop2020.payment.handler.PaymentHandler;
7
import in.shop2020.payment.handler.RefundHandler;
8
import in.shop2020.payments.Attribute;
9
import in.shop2020.payments.Payment;
10
import in.shop2020.payments.PaymentException;
11
import in.shop2020.payments.PaymentGateway;
12
import in.shop2020.payments.PaymentService.Iface;
13
import in.shop2020.payments.PaymentStatus;
14
import in.shop2020.thrift.clients.CRMClient;
15
 
3010 chandransh 16
import java.text.SimpleDateFormat;
1946 chandransh 17
import java.util.ArrayList;
18
import java.util.Date;
19
import java.util.HashMap;
20
import java.util.List;
21
import java.util.Map;
22
 
23
import org.apache.thrift.TException;
3578 mandeep.dh 24
import org.apache.thrift.transport.TTransportException;
3010 chandransh 25
import org.slf4j.Logger;
26
import org.slf4j.LoggerFactory;
1946 chandransh 27
import org.springframework.context.ApplicationContext;
28
import org.springframework.context.support.ClassPathXmlApplicationContext;
29
 
30
public class PaymentServiceHandler implements Iface {
3010 chandransh 31
 
32
    private static Logger logger = LoggerFactory.getLogger(PaymentServiceHandler.class);
33
 
34
    /**
35
     * Enum of all statuses that can be returned by the HDFC gateway
36
     * 
37
     * @author Chandranshu
38
     * 
39
     */
40
    private enum HdfcPaymentReturnStatus{
41
        APPROVED("APPROVED"),
42
        NOT_APPROVED("NOT APPROVED"),
43
        CAPTURED("CAPTURED"),
44
        NOT_CAPTURED ("NOT CAPTURED"),
45
        CANCELLED ("CANCELLED"),
46
        DENIED_BY_RISK("DENIED BY RISK"),
47
        HOST_TIMEOUT("HOST TIMEOUT");
48
        private String value;
49
        HdfcPaymentReturnStatus(String value) {
50
            this.value = value;
51
        }
52
        public String value(){
53
            return this.value;
54
        }
55
    }
56
 
2391 chandransh 57
	public static final long PAYMENT_NOT_CREATED = -1;
58
 
3010 chandransh 59
	private static final long HDFC_GATEWAY_ID = 1;
60
	private static final long EBS_GATEWAY_ID = 2;
61
 
1946 chandransh 62
	ApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
63
	PaymentHandler paymentHandler = (PaymentHandler) context.getBean("paymentHandler");
64
	PaymentGatewayHandler paymentGatewayHandler = (PaymentGatewayHandler) context.getBean("paymentGatewayHandler");
2747 chandransh 65
	RefundHandler refundHandler = (RefundHandler) context.getBean("refundHandler");
1946 chandransh 66
 
67
	@Override
68
	public void closeSession() throws TException {
69
		// TODO Auto-generated method stub		
70
	}
71
 
72
	@Override
73
	public long createPayment(long userId, double amount, long gatewayId, long txnId) throws PaymentException, TException {
3010 chandransh 74
	    logger.info("Creating payment corresponding to our txn id:" + txnId);
1946 chandransh 75
		in.shop2020.payment.domain.Payment payment = new in.shop2020.payment.domain.Payment();
76
		payment.setUserId(userId);
77
		payment.setAmount(amount);
78
		payment.setGatewayId(gatewayId);
79
		payment.setMerchantTxnId(txnId);
80
		payment.setStatus(PaymentStatus.INIT.getValue());
81
 
82
		return paymentHandler.insertPayment(payment);
83
	}
84
 
85
	@Override
86
	public List<Payment> getPaymentsForUser(long userId, long fromTime, long toTime, PaymentStatus status, long gatewayId) throws PaymentException, TException {
3010 chandransh 87
	    logger.info("Getting payments from " + fromTime + " to " + toTime + " for user: " + userId);
2291 chandransh 88
		int statusValue = -1;
89
		if(status != null)
90
			statusValue = status.getValue();
91
		else
92
			statusValue = -1;
93
		return getThriftPayments(paymentHandler.getPaymentsForUser(userId, fromTime, toTime, statusValue, gatewayId));
1946 chandransh 94
	}
95
 
96
	@Override
97
	public List<Payment> getPayments(long fromTime, long toTime, PaymentStatus status, long gatewayId) throws PaymentException,	TException {
3010 chandransh 98
	    logger.info("Getting payments from " + fromTime + " to " + toTime);
2291 chandransh 99
		int statusValue = -1;
100
		if(status != null)
101
			statusValue = status.getValue();
102
		else
103
			statusValue = -1;
104
		return getThriftPayments(paymentHandler.getPayments(fromTime, toTime, statusValue, gatewayId));
1946 chandransh 105
	}
106
 
107
	@Override
108
	public PaymentGateway getPaymentGateway(long id) throws PaymentException, TException {
3010 chandransh 109
	    logger.info("Getting payment gateway with id:" + id);
2291 chandransh 110
		return paymentGatewayHandler.getPaymentGateway(id).getThriftPaymentGateway();
1946 chandransh 111
	}
112
 
113
	@Override
114
	public Payment getPayment(long id) throws PaymentException, TException {
3010 chandransh 115
	    logger.info("Getting payment with id: " + id);
1946 chandransh 116
		return paymentHandler.getPayment(id).getThriftPayment();
117
	}
118
 
119
	@Override
120
	public List<Payment> getPaymentForTxnId(long txnId) throws PaymentException, TException {
3010 chandransh 121
	    logger.info("Getting payment for the txn id: " + txnId);
1946 chandransh 122
		return getThriftPayments(paymentHandler.getPaymentForTxn(txnId));
123
	}
124
 
125
	@Override
126
	public boolean updatePaymentDetails(long id, String gatewayPaymentId,
127
			String sessionId, String gatewayTxnStatus, String description,
128
			String gatewayTxnId, String authCode, String referenceCode,
129
			String errorCode, PaymentStatus status, String gatewayTxnDate,
130
			List<Attribute> attributes) throws PaymentException, TException {
3010 chandransh 131
	    logger.info("Updating details of payment id: " + id);
1946 chandransh 132
		in.shop2020.payment.domain.Payment payment = paymentHandler.getPayment(id);
133
		payment.setGatewayPaymentId(gatewayPaymentId);
134
		payment.setSessionId(sessionId);
135
		payment.setGatewayTxnStatus(gatewayTxnStatus);
136
		payment.setDescription(description);
137
		payment.setGatewayTxnId(gatewayTxnId);
138
		payment.setAuthCode(authCode);
139
		payment.setReferenceCode(referenceCode);
140
		payment.setErrorCode(errorCode);
141
		if(status!=null){
142
			payment.setStatus(status.getValue());
143
			if(status.equals(PaymentStatus.SUCCESS))
144
				payment.setSuccessTimestamp(new Date());
3578 mandeep.dh 145
			else if(status.equals(PaymentStatus.FAILED)) {
146
			    payment.setErrorTimestamp(new Date());
147
			    createTicketForFailedPayment(payment);
148
			}
1946 chandransh 149
		}
150
 
151
		payment.setGatewayTxnDate(gatewayTxnDate);
152
 
153
		Map<String, String> attrMap = new HashMap<String, String>();
2272 rajveer 154
		if(attributes != null){
155
			for(Attribute attribute : attributes){
156
				attrMap.put(attribute.getName(), attribute.getValue());
157
			}
1946 chandransh 158
		}
159
 
160
		paymentHandler.updatePayment(payment, attrMap);
161
		return true;
162
	}
163
 
3578 mandeep.dh 164
	// Creates tickets for payment failures in CRM
165
	private void createTicketForFailedPayment(in.shop2020.payment.domain.Payment payment) {
166
        try {
167
            Client crmClient = new CRMClient().getClient();
168
            crmClient.processPaymentFailure(payment.getUserId());
169
        } catch (TTransportException e) {
170
            logger.error("Could not create CRM client", e);
171
        } catch (TException e) {
172
            logger.error("Could not process paymentId: " + payment.getId(), e);
173
        }
174
    }
175
 
176
    @Override
1946 chandransh 177
	public List<Double> getSuccessfulPaymentsAmountRange() throws TException {
3010 chandransh 178
	    logger.info("Getting the range of successful payments.");
1946 chandransh 179
		List<Double> minMaxAmounts = new ArrayList<Double>();
180
		Map<String, Float> minMax = paymentHandler.getMinMaxPaymentAmount();
181
		minMaxAmounts.add(Double.parseDouble(Float.toString(minMax.get("MIN"))));
182
		minMaxAmounts.add(Double.parseDouble(Float.toString(minMax.get("MAX"))));
183
		return minMaxAmounts;
184
	}
185
 
2391 chandransh 186
	@Override
187
	public String initializeHdfcPayment(long merchantPaymentId) throws PaymentException, TException {
3010 chandransh 188
	    logger.info("Initializing HDFC payment with id: " + merchantPaymentId);
2391 chandransh 189
		in.shop2020.payment.domain.Payment payment = paymentHandler.getPayment(merchantPaymentId);
190
		String redirectURL;
191
		try {
192
			redirectURL = HdfcPaymentHandler.initializeHdfcPayment(payment, this);
193
		} catch (Exception e) {
194
			throw new PaymentException(102, "Error while initiliazing payment. Check service log for more details.");
195
		}
196
		return redirectURL;
197
	}
198
 
199
	@Override
2708 chandransh 200
	public Map<String, String> captureHdfcPayment(long merchantPaymentId) throws PaymentException, TException {
3010 chandransh 201
	    logger.info("Capturing HDFC payment with id: " + merchantPaymentId);
2391 chandransh 202
		in.shop2020.payment.domain.Payment payment = paymentHandler.getPayment(merchantPaymentId);
203
		return HdfcPaymentHandler.capturePayment(payment);
204
	}
205
 
2689 chandransh 206
	@Override
2708 chandransh 207
	public Map<String, String> captureEbsPayment(long merchantPaymentId) throws PaymentException, TException {
3010 chandransh 208
	    logger.info("Capturing EBS payment with id: " + merchantPaymentId);
2708 chandransh 209
		in.shop2020.payment.domain.Payment payment = paymentHandler.getPayment(merchantPaymentId);
3010 chandransh 210
		return EbsPaymentHandler.capturePayment(payment);
2708 chandransh 211
	}
212
 
213
	@Override
2689 chandransh 214
    public long createRefund(long orderId, long merchantTxnId, double amount) throws PaymentException, TException{
3010 chandransh 215
	    logger.info("Attempting to create a refund for order: " + orderId);
2689 chandransh 216
		List<in.shop2020.payment.domain.Payment> payments = paymentHandler.getPaymentForTxn(merchantTxnId);
217
		if(payments ==null || payments.isEmpty())
218
			throw new PaymentException(104, "No payments found corresponding to the merchant txn " + merchantTxnId);
219
 
3010 chandransh 220
		in.shop2020.payment.domain.Payment payment = payments.get(0);
2689 chandransh 221
		if(payment.getStatus() != PaymentStatus.SUCCESS.getValue())
222
			throw new PaymentException(104, "No successful payments found corresponding to the merchant txn " + merchantTxnId);
223
 
2747 chandransh 224
		Refund refund = new Refund();
225
		refund.setOrderId(orderId);
226
		refund.setPaymentId(payment.getId());
227
		refund.setGatewayId(payment.getGatewayId());
228
		refund.setAmount(amount);
229
		refund.setAttempts(0);
230
		return refundHandler.createRefund(refund);
2689 chandransh 231
    }
232
 
3010 chandransh 233
    @Override
234
    public boolean capturePayment(long merchantTxnId) throws PaymentException, TException {
235
        logger.info("Attempting to capture payment corresponding to our transaction " + merchantTxnId);
236
        List<in.shop2020.payment.domain.Payment> payments = paymentHandler.getPaymentForTxn(merchantTxnId);
237
        if(payments ==null || payments.isEmpty())
238
            throw new PaymentException(104, "No payments found corresponding to the merchant txn " + merchantTxnId);
239
 
240
        in.shop2020.payment.domain.Payment payment = payments.get(0);
241
        switch(PaymentStatus.findByValue(payment.getStatus())){
242
        case PENDING:
243
            logger.error("Attempt to capture a non-authorized payment");
244
            return false;
245
        case INIT:
246
            logger.warn("Attempt to capture a non-authorized payment");
247
            return false;
248
        case AUTHORIZED:
249
            //Actual work to be done in this case. Let the call proceed.
250
            break;
251
        case SUCCESS:
252
            logger.warn("Attempting to capture an already captured payment but we can let the client proceed.");
253
            return true;
254
        case FAILED:
255
            logger.error("Attempting to capture a failed payment");
256
            return false;
257
        }
258
 
259
        long gatewayId = payment.getGatewayId();
260
 
261
        if(gatewayId == HDFC_GATEWAY_ID){
262
            //Capture and update the HDFC payment
263
            return captureAndUpdateHdfcPayment(payment);
264
        } else if (gatewayId == EBS_GATEWAY_ID){
265
            //Capture and update the EBS payment
266
            return captureAndUpdateEbsPayment(payment);
267
        }
268
 
269
        logger.error("We have an authorized payment from unknown gateway: " + gatewayId);
270
        return false;
271
    }
272
 
273
    /**
274
     * Capture the HDFC payment represented by the given payment object. If the
275
     * capture attempt is not successful, we mark this payment as failed. We
276
     * don't retry or anything. We'll add the support of multiple attempts later
277
     * on.
278
     * 
279
     * @param payment The payment which has to be captured.
280
     * @return True if the payment attempt is successful, false if not.
281
     */
282
    private boolean captureAndUpdateHdfcPayment(in.shop2020.payment.domain.Payment payment){
283
        long merchantPaymentId = payment.getId();
284
        logger.info("Capturing HDFC payment with id: " + merchantPaymentId);
285
        Map<String, String> captureResult = HdfcPaymentHandler.capturePayment(payment);
286
        String captureStatus = captureResult.get(IPaymentHandler.STATUS);
287
        String gatewayStatus = captureResult.get(IPaymentHandler.GATEWAY_STATUS);
288
 
289
        Map<String, String> attrMap = new HashMap<String, String>();
290
        if (!captureStatus.trim().equals("0") 
291
                || !HdfcPaymentReturnStatus.CAPTURED.value().equals(gatewayStatus)) {
292
            // Failure
293
            logger.info("Capture attempt failed for HDFC payment with id: " + merchantPaymentId);
294
            String description = captureResult.get(IPaymentHandler.ERROR);
295
            String errorCode = captureResult.get(IPaymentHandler.ERR_CODE);
296
 
297
            payment.setDescription(description);
298
            payment.setErrorCode(errorCode);
299
            payment.setStatus(PaymentStatus.FAILED.getValue());
300
            payment.setErrorTimestamp(new Date());
301
            paymentHandler.updatePayment(payment, attrMap);
3578 mandeep.dh 302
            createTicketForFailedPayment(payment);
3010 chandransh 303
            return false;
304
        } else {
305
            // Success
306
            logger.error("Capture attempt successful for HDFC payment with id: " + merchantPaymentId);
307
            payment.setDescription("Payment Captured");
308
            payment.setGatewayTxnStatus(gatewayStatus);
309
            payment.setStatus(PaymentStatus.SUCCESS.getValue());
310
            payment.setSuccessTimestamp(new Date());           
311
 
312
            attrMap.put(IPaymentHandler.CAPTURE_TXN_ID, captureResult.get(IPaymentHandler.CAPTURE_TXN_ID));
313
            attrMap.put(IPaymentHandler.CAPTURE_REF_ID, captureResult.get(IPaymentHandler.CAPTURE_REF_ID));
314
            attrMap.put(IPaymentHandler.CAPTURE_AUTH_ID, captureResult.get(IPaymentHandler.CAPTURE_AUTH_ID));
315
 
316
            SimpleDateFormat captureTimeDateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
317
            attrMap.put(HdfcPaymentHandler.CAPTURE_TIME, captureTimeDateFormatter.format(new Date()));
318
 
319
            paymentHandler.updatePayment(payment, attrMap);
320
            return true;
321
          }
322
    }
323
 
324
    /**
325
     * Capture the EBS payment represented by the given payment object. If the
326
     * capture attempt is not successful, we mark this payment as failed. We
327
     * don't retry or anything. We'll add the support of multiple attempts later
328
     * on.
329
     * 
330
     * @param payment The payment which has to be captured.
331
     * @return True if the payment attempt is successful, false if not.
332
     */
333
    private boolean captureAndUpdateEbsPayment(in.shop2020.payment.domain.Payment payment){
334
        Map<String, String> captureResult = EbsPaymentHandler.capturePayment(payment);
335
        String captureStatus = captureResult.get(EbsPaymentHandler.STATUS);
336
 
337
        Map<String, String> attrMap = new HashMap<String, String>();
338
        if("".equals(captureStatus)){
339
            //Failure
340
            String description = captureResult.get(EbsPaymentHandler.ERROR);
341
            String errorCode = captureResult.get(EbsPaymentHandler.ERR_CODE);
342
 
343
            payment.setDescription(description);
344
            payment.setErrorCode(errorCode);
345
            payment.setStatus(PaymentStatus.FAILED.getValue());
346
            payment.setErrorTimestamp(new Date());
347
            paymentHandler.updatePayment(payment, attrMap);
3578 mandeep.dh 348
            createTicketForFailedPayment(payment);
3010 chandransh 349
            return false;
350
        }else{
351
            //Success
352
            payment.setGatewayTxnStatus(captureStatus);
353
            payment.setStatus(PaymentStatus.SUCCESS.getValue());
354
            payment.setSuccessTimestamp(new Date());
355
 
356
            attrMap.put(IPaymentHandler.CAPTURE_TXN_ID, captureResult.get(IPaymentHandler.CAPTURE_TXN_ID));
357
            attrMap.put(IPaymentHandler.CAPTURE_TIME, captureResult.get(IPaymentHandler.CAPTURE_TIME));
358
            paymentHandler.updatePayment(payment, attrMap);
359
            return true;
360
        }
361
    }
362
 
363
 
364
    /**
365
     * Creates a list of thrift payment objects corresponding to a list of
366
     * payment data objects.
367
     * 
368
     * @param daoPayments
369
     *            A list of payment DAO.
370
     * @return A list of Thrift payment objects.
371
     */
372
    private List<Payment> getThriftPayments(List<in.shop2020.payment.domain.Payment> daoPayments){
373
 
374
        List<Payment> payments = new ArrayList<Payment>();
375
        for(in.shop2020.payment.domain.Payment payment : daoPayments){
376
            payments.add(payment.getThriftPayment());
377
        }
378
        return payments;
379
    }
3375 rajveer 380
 
381
	@Override
382
	public boolean isAlive() throws TException {
383
		// TODO Auto-generated method stub
384
		return true;
385
	}
1946 chandransh 386
}