Subversion Repositories SmartDukaan

Rev

Rev 3616 | Rev 3956 | 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;
3583 chandransh 61
	private static final long HDFC_EMI_GATEWAY_ID = 5;
3010 chandransh 62
 
1946 chandransh 63
	ApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
64
	PaymentHandler paymentHandler = (PaymentHandler) context.getBean("paymentHandler");
65
	PaymentGatewayHandler paymentGatewayHandler = (PaymentGatewayHandler) context.getBean("paymentGatewayHandler");
2747 chandransh 66
	RefundHandler refundHandler = (RefundHandler) context.getBean("refundHandler");
1946 chandransh 67
 
68
	@Override
69
	public void closeSession() throws TException {
70
		// TODO Auto-generated method stub		
71
	}
72
 
73
	@Override
74
	public long createPayment(long userId, double amount, long gatewayId, long txnId) throws PaymentException, TException {
3010 chandransh 75
	    logger.info("Creating payment corresponding to our txn id:" + txnId);
1946 chandransh 76
		in.shop2020.payment.domain.Payment payment = new in.shop2020.payment.domain.Payment();
77
		payment.setUserId(userId);
78
		payment.setAmount(amount);
79
		payment.setGatewayId(gatewayId);
80
		payment.setMerchantTxnId(txnId);
81
		payment.setStatus(PaymentStatus.INIT.getValue());
82
 
83
		return paymentHandler.insertPayment(payment);
84
	}
85
 
86
	@Override
87
	public List<Payment> getPaymentsForUser(long userId, long fromTime, long toTime, PaymentStatus status, long gatewayId) throws PaymentException, TException {
3010 chandransh 88
	    logger.info("Getting payments from " + fromTime + " to " + toTime + " for user: " + userId);
2291 chandransh 89
		int statusValue = -1;
90
		if(status != null)
91
			statusValue = status.getValue();
92
		else
93
			statusValue = -1;
94
		return getThriftPayments(paymentHandler.getPaymentsForUser(userId, fromTime, toTime, statusValue, gatewayId));
1946 chandransh 95
	}
96
 
97
	@Override
98
	public List<Payment> getPayments(long fromTime, long toTime, PaymentStatus status, long gatewayId) throws PaymentException,	TException {
3010 chandransh 99
	    logger.info("Getting payments from " + fromTime + " to " + toTime);
2291 chandransh 100
		int statusValue = -1;
101
		if(status != null)
102
			statusValue = status.getValue();
103
		else
104
			statusValue = -1;
105
		return getThriftPayments(paymentHandler.getPayments(fromTime, toTime, statusValue, gatewayId));
1946 chandransh 106
	}
107
 
108
	@Override
109
	public PaymentGateway getPaymentGateway(long id) throws PaymentException, TException {
3010 chandransh 110
	    logger.info("Getting payment gateway with id:" + id);
2291 chandransh 111
		return paymentGatewayHandler.getPaymentGateway(id).getThriftPaymentGateway();
1946 chandransh 112
	}
113
 
114
	@Override
115
	public Payment getPayment(long id) throws PaymentException, TException {
3010 chandransh 116
	    logger.info("Getting payment with id: " + id);
1946 chandransh 117
		return paymentHandler.getPayment(id).getThriftPayment();
118
	}
119
 
120
	@Override
121
	public List<Payment> getPaymentForTxnId(long txnId) throws PaymentException, TException {
3010 chandransh 122
	    logger.info("Getting payment for the txn id: " + txnId);
1946 chandransh 123
		return getThriftPayments(paymentHandler.getPaymentForTxn(txnId));
124
	}
125
 
126
	@Override
127
	public boolean updatePaymentDetails(long id, String gatewayPaymentId,
128
			String sessionId, String gatewayTxnStatus, String description,
129
			String gatewayTxnId, String authCode, String referenceCode,
130
			String errorCode, PaymentStatus status, String gatewayTxnDate,
131
			List<Attribute> attributes) throws PaymentException, TException {
3010 chandransh 132
	    logger.info("Updating details of payment id: " + id);
1946 chandransh 133
		in.shop2020.payment.domain.Payment payment = paymentHandler.getPayment(id);
134
		payment.setGatewayPaymentId(gatewayPaymentId);
135
		payment.setSessionId(sessionId);
136
		payment.setGatewayTxnStatus(gatewayTxnStatus);
137
		payment.setDescription(description);
138
		payment.setGatewayTxnId(gatewayTxnId);
139
		payment.setAuthCode(authCode);
140
		payment.setReferenceCode(referenceCode);
141
		payment.setErrorCode(errorCode);
142
		if(status!=null){
143
			payment.setStatus(status.getValue());
144
			if(status.equals(PaymentStatus.SUCCESS))
145
				payment.setSuccessTimestamp(new Date());
3578 mandeep.dh 146
			else if(status.equals(PaymentStatus.FAILED)) {
147
			    payment.setErrorTimestamp(new Date());
148
			    createTicketForFailedPayment(payment);
149
			}
1946 chandransh 150
		}
151
 
152
		payment.setGatewayTxnDate(gatewayTxnDate);
153
 
154
		Map<String, String> attrMap = new HashMap<String, String>();
2272 rajveer 155
		if(attributes != null){
156
			for(Attribute attribute : attributes){
157
				attrMap.put(attribute.getName(), attribute.getValue());
158
			}
1946 chandransh 159
		}
160
 
161
		paymentHandler.updatePayment(payment, attrMap);
162
		return true;
163
	}
164
 
3649 mandeep.dh 165
	/**
166
	 * Creates a ticket in CRM tool for each customer whose payment got failed.
167
	 * Later, CRM agents follow-up with the users and try making a sale.
168
	 *
169
	 * We swallow the exceptions raised and just log them at error level. This is
170
	 * done to not make Website unaffected by any CRM related issues.
171
	 *
172
	 * @param payment  the payment object that failed.
173
	 */
3578 mandeep.dh 174
	private void createTicketForFailedPayment(in.shop2020.payment.domain.Payment payment) {
175
        try {
176
            Client crmClient = new CRMClient().getClient();
3649 mandeep.dh 177
 
178
            // This call is aync (oneway). This ensures that website response
179
            // is sent in time.
3578 mandeep.dh 180
            crmClient.processPaymentFailure(payment.getUserId());
181
        } catch (TTransportException e) {
182
            logger.error("Could not create CRM client", e);
183
        } catch (TException e) {
184
            logger.error("Could not process paymentId: " + payment.getId(), e);
185
        }
186
    }
187
 
188
    @Override
1946 chandransh 189
	public List<Double> getSuccessfulPaymentsAmountRange() throws TException {
3010 chandransh 190
	    logger.info("Getting the range of successful payments.");
1946 chandransh 191
		List<Double> minMaxAmounts = new ArrayList<Double>();
192
		Map<String, Float> minMax = paymentHandler.getMinMaxPaymentAmount();
193
		minMaxAmounts.add(Double.parseDouble(Float.toString(minMax.get("MIN"))));
194
		minMaxAmounts.add(Double.parseDouble(Float.toString(minMax.get("MAX"))));
195
		return minMaxAmounts;
196
	}
197
 
2391 chandransh 198
	@Override
199
	public String initializeHdfcPayment(long merchantPaymentId) throws PaymentException, TException {
3010 chandransh 200
	    logger.info("Initializing HDFC payment with id: " + merchantPaymentId);
2391 chandransh 201
		in.shop2020.payment.domain.Payment payment = paymentHandler.getPayment(merchantPaymentId);
202
		String redirectURL;
203
		try {
204
			redirectURL = HdfcPaymentHandler.initializeHdfcPayment(payment, this);
205
		} catch (Exception e) {
206
			throw new PaymentException(102, "Error while initiliazing payment. Check service log for more details.");
207
		}
208
		return redirectURL;
209
	}
210
 
211
	@Override
3616 chandransh 212
    public String initializeHdfcEmiPayment(long merchantPaymentId) throws PaymentException, TException {
213
        logger.info("Initializing HDFC payment with id: " + merchantPaymentId);
214
        in.shop2020.payment.domain.Payment payment = paymentHandler.getPayment(merchantPaymentId);
215
        String redirectURL;
216
        try {
217
            redirectURL = HdfcEmiPaymentHandler.initializeHdfcPayment(payment, this);
218
        } catch (Exception e) {
219
            throw new PaymentException(102, "Error while initiliazing payment. Check service log for more details.");
220
        }
221
        return redirectURL;
222
    }
223
 
224
	@Override
2689 chandransh 225
    public long createRefund(long orderId, long merchantTxnId, double amount) throws PaymentException, TException{
3010 chandransh 226
	    logger.info("Attempting to create a refund for order: " + orderId);
2689 chandransh 227
		List<in.shop2020.payment.domain.Payment> payments = paymentHandler.getPaymentForTxn(merchantTxnId);
228
		if(payments ==null || payments.isEmpty())
229
			throw new PaymentException(104, "No payments found corresponding to the merchant txn " + merchantTxnId);
230
 
3010 chandransh 231
		in.shop2020.payment.domain.Payment payment = payments.get(0);
2689 chandransh 232
		if(payment.getStatus() != PaymentStatus.SUCCESS.getValue())
233
			throw new PaymentException(104, "No successful payments found corresponding to the merchant txn " + merchantTxnId);
234
 
2747 chandransh 235
		Refund refund = new Refund();
236
		refund.setOrderId(orderId);
237
		refund.setPaymentId(payment.getId());
238
		refund.setGatewayId(payment.getGatewayId());
239
		refund.setAmount(amount);
240
		refund.setAttempts(0);
241
		return refundHandler.createRefund(refund);
2689 chandransh 242
    }
243
 
3010 chandransh 244
    @Override
245
    public boolean capturePayment(long merchantTxnId) throws PaymentException, TException {
246
        logger.info("Attempting to capture payment corresponding to our transaction " + merchantTxnId);
247
        List<in.shop2020.payment.domain.Payment> payments = paymentHandler.getPaymentForTxn(merchantTxnId);
248
        if(payments ==null || payments.isEmpty())
249
            throw new PaymentException(104, "No payments found corresponding to the merchant txn " + merchantTxnId);
250
 
251
        in.shop2020.payment.domain.Payment payment = payments.get(0);
252
        switch(PaymentStatus.findByValue(payment.getStatus())){
253
        case PENDING:
254
            logger.error("Attempt to capture a non-authorized payment");
255
            return false;
256
        case INIT:
257
            logger.warn("Attempt to capture a non-authorized payment");
258
            return false;
259
        case AUTHORIZED:
260
            //Actual work to be done in this case. Let the call proceed.
261
            break;
262
        case SUCCESS:
263
            logger.warn("Attempting to capture an already captured payment but we can let the client proceed.");
264
            return true;
265
        case FAILED:
266
            logger.error("Attempting to capture a failed payment");
267
            return false;
268
        }
269
 
270
        long gatewayId = payment.getGatewayId();
271
 
272
        if(gatewayId == HDFC_GATEWAY_ID){
273
            //Capture and update the HDFC payment
274
            return captureAndUpdateHdfcPayment(payment);
275
        } else if (gatewayId == EBS_GATEWAY_ID){
276
            //Capture and update the EBS payment
277
            return captureAndUpdateEbsPayment(payment);
3583 chandransh 278
        } else if (gatewayId == HDFC_EMI_GATEWAY_ID){
279
            //Capture and update the HDFC EMI payment
280
            return captureAndUpdateHdfcEmiPayment(payment);
3010 chandransh 281
        }
282
 
283
        logger.error("We have an authorized payment from unknown gateway: " + gatewayId);
284
        return false;
285
    }
286
 
287
    /**
288
     * Capture the HDFC payment represented by the given payment object. If the
289
     * capture attempt is not successful, we mark this payment as failed. We
290
     * don't retry or anything. We'll add the support of multiple attempts later
291
     * on.
292
     * 
293
     * @param payment The payment which has to be captured.
294
     * @return True if the payment attempt is successful, false if not.
295
     */
296
    private boolean captureAndUpdateHdfcPayment(in.shop2020.payment.domain.Payment payment){
297
        long merchantPaymentId = payment.getId();
298
        logger.info("Capturing HDFC payment with id: " + merchantPaymentId);
299
        Map<String, String> captureResult = HdfcPaymentHandler.capturePayment(payment);
300
        String captureStatus = captureResult.get(IPaymentHandler.STATUS);
301
        String gatewayStatus = captureResult.get(IPaymentHandler.GATEWAY_STATUS);
302
 
303
        Map<String, String> attrMap = new HashMap<String, String>();
304
        if (!captureStatus.trim().equals("0") 
305
                || !HdfcPaymentReturnStatus.CAPTURED.value().equals(gatewayStatus)) {
306
            // Failure
3616 chandransh 307
            logger.error("Capture attempt failed for HDFC payment with id: " + merchantPaymentId);
3010 chandransh 308
            String description = captureResult.get(IPaymentHandler.ERROR);
309
            String errorCode = captureResult.get(IPaymentHandler.ERR_CODE);
310
 
311
            payment.setDescription(description);
312
            payment.setErrorCode(errorCode);
313
            payment.setStatus(PaymentStatus.FAILED.getValue());
314
            payment.setErrorTimestamp(new Date());
315
            paymentHandler.updatePayment(payment, attrMap);
3578 mandeep.dh 316
            createTicketForFailedPayment(payment);
3010 chandransh 317
            return false;
318
        } else {
319
            // Success
3616 chandransh 320
            logger.info("Capture attempt successful for HDFC payment with id: " + merchantPaymentId);
3010 chandransh 321
            payment.setDescription("Payment Captured");
322
            payment.setGatewayTxnStatus(gatewayStatus);
323
            payment.setStatus(PaymentStatus.SUCCESS.getValue());
324
            payment.setSuccessTimestamp(new Date());           
325
 
326
            attrMap.put(IPaymentHandler.CAPTURE_TXN_ID, captureResult.get(IPaymentHandler.CAPTURE_TXN_ID));
327
            attrMap.put(IPaymentHandler.CAPTURE_REF_ID, captureResult.get(IPaymentHandler.CAPTURE_REF_ID));
328
            attrMap.put(IPaymentHandler.CAPTURE_AUTH_ID, captureResult.get(IPaymentHandler.CAPTURE_AUTH_ID));
329
 
330
            SimpleDateFormat captureTimeDateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
331
            attrMap.put(HdfcPaymentHandler.CAPTURE_TIME, captureTimeDateFormatter.format(new Date()));
332
 
333
            paymentHandler.updatePayment(payment, attrMap);
334
            return true;
335
          }
336
    }
337
 
338
    /**
3583 chandransh 339
     * Capture the HDFC EMI payment represented by the given payment object. If
340
     * the capture attempt is not successful, we mark this payment as failed. We
341
     * don't retry or anything. We'll add the support of multiple attempts later
342
     * on.
343
     * 
344
     * @param payment
345
     *            The payment which has to be captured.
346
     * @return True if the payment attempt is successful, false if not.
347
     */
348
    private boolean captureAndUpdateHdfcEmiPayment(in.shop2020.payment.domain.Payment payment){
349
        long merchantPaymentId = payment.getId();
350
        logger.info("Capturing HDFC payment with id: " + merchantPaymentId);
351
        Map<String, String> captureResult = HdfcEmiPaymentHandler.capturePayment(payment);
352
        String captureStatus = captureResult.get(IPaymentHandler.STATUS);
353
        String gatewayStatus = captureResult.get(IPaymentHandler.GATEWAY_STATUS);
354
 
355
        Map<String, String> attrMap = new HashMap<String, String>();
356
        if (!captureStatus.trim().equals("0") 
357
                || !HdfcPaymentReturnStatus.CAPTURED.value().equals(gatewayStatus)) {
358
            // Failure
3616 chandransh 359
            logger.error("Capture attempt failed for HDFC payment with id: " + merchantPaymentId);
3583 chandransh 360
            String description = captureResult.get(IPaymentHandler.ERROR);
361
            String errorCode = captureResult.get(IPaymentHandler.ERR_CODE);
362
 
363
            payment.setDescription(description);
364
            payment.setErrorCode(errorCode);
365
            payment.setStatus(PaymentStatus.FAILED.getValue());
366
            payment.setErrorTimestamp(new Date());
367
            paymentHandler.updatePayment(payment, attrMap);
368
            createTicketForFailedPayment(payment);
369
            return false;
370
        } else {
371
            // Success
3616 chandransh 372
            logger.info("Capture attempt successful for HDFC payment with id: " + merchantPaymentId);
3583 chandransh 373
            payment.setDescription("Payment Captured");
374
            payment.setGatewayTxnStatus(gatewayStatus);
375
            payment.setStatus(PaymentStatus.SUCCESS.getValue());
376
            payment.setSuccessTimestamp(new Date());           
377
 
378
            attrMap.put(IPaymentHandler.CAPTURE_TXN_ID, captureResult.get(IPaymentHandler.CAPTURE_TXN_ID));
379
            attrMap.put(IPaymentHandler.CAPTURE_REF_ID, captureResult.get(IPaymentHandler.CAPTURE_REF_ID));
380
            attrMap.put(IPaymentHandler.CAPTURE_AUTH_ID, captureResult.get(IPaymentHandler.CAPTURE_AUTH_ID));
381
 
382
            SimpleDateFormat captureTimeDateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
383
            attrMap.put(HdfcPaymentHandler.CAPTURE_TIME, captureTimeDateFormatter.format(new Date()));
384
 
385
            paymentHandler.updatePayment(payment, attrMap);
386
            return true;
387
          }
388
    }
389
 
390
    /**
3010 chandransh 391
     * Capture the EBS payment represented by the given payment object. If the
392
     * capture attempt is not successful, we mark this payment as failed. We
393
     * don't retry or anything. We'll add the support of multiple attempts later
394
     * on.
395
     * 
396
     * @param payment The payment which has to be captured.
397
     * @return True if the payment attempt is successful, false if not.
398
     */
399
    private boolean captureAndUpdateEbsPayment(in.shop2020.payment.domain.Payment payment){
400
        Map<String, String> captureResult = EbsPaymentHandler.capturePayment(payment);
401
        String captureStatus = captureResult.get(EbsPaymentHandler.STATUS);
402
 
403
        Map<String, String> attrMap = new HashMap<String, String>();
404
        if("".equals(captureStatus)){
405
            //Failure
3616 chandransh 406
            logger.error("Capture attempt failed for EBS payment with id: " + payment.getId());
3010 chandransh 407
            String description = captureResult.get(EbsPaymentHandler.ERROR);
408
            String errorCode = captureResult.get(EbsPaymentHandler.ERR_CODE);
409
 
410
            payment.setDescription(description);
411
            payment.setErrorCode(errorCode);
412
            payment.setStatus(PaymentStatus.FAILED.getValue());
413
            payment.setErrorTimestamp(new Date());
414
            paymentHandler.updatePayment(payment, attrMap);
3578 mandeep.dh 415
            createTicketForFailedPayment(payment);
3010 chandransh 416
            return false;
417
        }else{
418
            //Success
3616 chandransh 419
            logger.info("Capture attempt successful for EBS payment with id: " + payment.getId());
3010 chandransh 420
            payment.setGatewayTxnStatus(captureStatus);
421
            payment.setStatus(PaymentStatus.SUCCESS.getValue());
422
            payment.setSuccessTimestamp(new Date());
423
 
424
            attrMap.put(IPaymentHandler.CAPTURE_TXN_ID, captureResult.get(IPaymentHandler.CAPTURE_TXN_ID));
425
            attrMap.put(IPaymentHandler.CAPTURE_TIME, captureResult.get(IPaymentHandler.CAPTURE_TIME));
426
            paymentHandler.updatePayment(payment, attrMap);
427
            return true;
428
        }
429
    }
430
 
431
 
432
    /**
433
     * Creates a list of thrift payment objects corresponding to a list of
434
     * payment data objects.
435
     * 
436
     * @param daoPayments
437
     *            A list of payment DAO.
438
     * @return A list of Thrift payment objects.
439
     */
440
    private List<Payment> getThriftPayments(List<in.shop2020.payment.domain.Payment> daoPayments){
441
 
442
        List<Payment> payments = new ArrayList<Payment>();
443
        for(in.shop2020.payment.domain.Payment payment : daoPayments){
444
            payments.add(payment.getThriftPayment());
445
        }
446
        return payments;
447
    }
3375 rajveer 448
 
449
	@Override
450
	public boolean isAlive() throws TException {
451
		// TODO Auto-generated method stub
452
		return true;
453
	}
1946 chandransh 454
}