Subversion Repositories SmartDukaan

Rev

Rev 3578 | Rev 3616 | 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
 
3578 mandeep.dh 165
	// Creates tickets for payment failures in CRM
166
	private void createTicketForFailedPayment(in.shop2020.payment.domain.Payment payment) {
167
        try {
168
            Client crmClient = new CRMClient().getClient();
169
            crmClient.processPaymentFailure(payment.getUserId());
170
        } catch (TTransportException e) {
171
            logger.error("Could not create CRM client", e);
172
        } catch (TException e) {
173
            logger.error("Could not process paymentId: " + payment.getId(), e);
174
        }
175
    }
176
 
177
    @Override
1946 chandransh 178
	public List<Double> getSuccessfulPaymentsAmountRange() throws TException {
3010 chandransh 179
	    logger.info("Getting the range of successful payments.");
1946 chandransh 180
		List<Double> minMaxAmounts = new ArrayList<Double>();
181
		Map<String, Float> minMax = paymentHandler.getMinMaxPaymentAmount();
182
		minMaxAmounts.add(Double.parseDouble(Float.toString(minMax.get("MIN"))));
183
		minMaxAmounts.add(Double.parseDouble(Float.toString(minMax.get("MAX"))));
184
		return minMaxAmounts;
185
	}
186
 
2391 chandransh 187
	@Override
188
	public String initializeHdfcPayment(long merchantPaymentId) throws PaymentException, TException {
3010 chandransh 189
	    logger.info("Initializing HDFC payment with id: " + merchantPaymentId);
2391 chandransh 190
		in.shop2020.payment.domain.Payment payment = paymentHandler.getPayment(merchantPaymentId);
191
		String redirectURL;
192
		try {
193
			redirectURL = HdfcPaymentHandler.initializeHdfcPayment(payment, this);
194
		} catch (Exception e) {
195
			throw new PaymentException(102, "Error while initiliazing payment. Check service log for more details.");
196
		}
197
		return redirectURL;
198
	}
199
 
200
	@Override
2689 chandransh 201
    public long createRefund(long orderId, long merchantTxnId, double amount) throws PaymentException, TException{
3010 chandransh 202
	    logger.info("Attempting to create a refund for order: " + orderId);
2689 chandransh 203
		List<in.shop2020.payment.domain.Payment> payments = paymentHandler.getPaymentForTxn(merchantTxnId);
204
		if(payments ==null || payments.isEmpty())
205
			throw new PaymentException(104, "No payments found corresponding to the merchant txn " + merchantTxnId);
206
 
3010 chandransh 207
		in.shop2020.payment.domain.Payment payment = payments.get(0);
2689 chandransh 208
		if(payment.getStatus() != PaymentStatus.SUCCESS.getValue())
209
			throw new PaymentException(104, "No successful payments found corresponding to the merchant txn " + merchantTxnId);
210
 
2747 chandransh 211
		Refund refund = new Refund();
212
		refund.setOrderId(orderId);
213
		refund.setPaymentId(payment.getId());
214
		refund.setGatewayId(payment.getGatewayId());
215
		refund.setAmount(amount);
216
		refund.setAttempts(0);
217
		return refundHandler.createRefund(refund);
2689 chandransh 218
    }
219
 
3010 chandransh 220
    @Override
221
    public boolean capturePayment(long merchantTxnId) throws PaymentException, TException {
222
        logger.info("Attempting to capture payment corresponding to our transaction " + merchantTxnId);
223
        List<in.shop2020.payment.domain.Payment> payments = paymentHandler.getPaymentForTxn(merchantTxnId);
224
        if(payments ==null || payments.isEmpty())
225
            throw new PaymentException(104, "No payments found corresponding to the merchant txn " + merchantTxnId);
226
 
227
        in.shop2020.payment.domain.Payment payment = payments.get(0);
228
        switch(PaymentStatus.findByValue(payment.getStatus())){
229
        case PENDING:
230
            logger.error("Attempt to capture a non-authorized payment");
231
            return false;
232
        case INIT:
233
            logger.warn("Attempt to capture a non-authorized payment");
234
            return false;
235
        case AUTHORIZED:
236
            //Actual work to be done in this case. Let the call proceed.
237
            break;
238
        case SUCCESS:
239
            logger.warn("Attempting to capture an already captured payment but we can let the client proceed.");
240
            return true;
241
        case FAILED:
242
            logger.error("Attempting to capture a failed payment");
243
            return false;
244
        }
245
 
246
        long gatewayId = payment.getGatewayId();
247
 
248
        if(gatewayId == HDFC_GATEWAY_ID){
249
            //Capture and update the HDFC payment
250
            return captureAndUpdateHdfcPayment(payment);
251
        } else if (gatewayId == EBS_GATEWAY_ID){
252
            //Capture and update the EBS payment
253
            return captureAndUpdateEbsPayment(payment);
3583 chandransh 254
        } else if (gatewayId == HDFC_EMI_GATEWAY_ID){
255
            //Capture and update the HDFC EMI payment
256
            return captureAndUpdateHdfcEmiPayment(payment);
3010 chandransh 257
        }
258
 
259
        logger.error("We have an authorized payment from unknown gateway: " + gatewayId);
260
        return false;
261
    }
262
 
263
    /**
264
     * Capture the HDFC payment represented by the given payment object. If the
265
     * capture attempt is not successful, we mark this payment as failed. We
266
     * don't retry or anything. We'll add the support of multiple attempts later
267
     * on.
268
     * 
269
     * @param payment The payment which has to be captured.
270
     * @return True if the payment attempt is successful, false if not.
271
     */
272
    private boolean captureAndUpdateHdfcPayment(in.shop2020.payment.domain.Payment payment){
273
        long merchantPaymentId = payment.getId();
274
        logger.info("Capturing HDFC payment with id: " + merchantPaymentId);
275
        Map<String, String> captureResult = HdfcPaymentHandler.capturePayment(payment);
276
        String captureStatus = captureResult.get(IPaymentHandler.STATUS);
277
        String gatewayStatus = captureResult.get(IPaymentHandler.GATEWAY_STATUS);
278
 
279
        Map<String, String> attrMap = new HashMap<String, String>();
280
        if (!captureStatus.trim().equals("0") 
281
                || !HdfcPaymentReturnStatus.CAPTURED.value().equals(gatewayStatus)) {
282
            // Failure
283
            logger.info("Capture attempt failed for HDFC payment with id: " + merchantPaymentId);
284
            String description = captureResult.get(IPaymentHandler.ERROR);
285
            String errorCode = captureResult.get(IPaymentHandler.ERR_CODE);
286
 
287
            payment.setDescription(description);
288
            payment.setErrorCode(errorCode);
289
            payment.setStatus(PaymentStatus.FAILED.getValue());
290
            payment.setErrorTimestamp(new Date());
291
            paymentHandler.updatePayment(payment, attrMap);
3578 mandeep.dh 292
            createTicketForFailedPayment(payment);
3010 chandransh 293
            return false;
294
        } else {
295
            // Success
296
            logger.error("Capture attempt successful for HDFC payment with id: " + merchantPaymentId);
297
            payment.setDescription("Payment Captured");
298
            payment.setGatewayTxnStatus(gatewayStatus);
299
            payment.setStatus(PaymentStatus.SUCCESS.getValue());
300
            payment.setSuccessTimestamp(new Date());           
301
 
302
            attrMap.put(IPaymentHandler.CAPTURE_TXN_ID, captureResult.get(IPaymentHandler.CAPTURE_TXN_ID));
303
            attrMap.put(IPaymentHandler.CAPTURE_REF_ID, captureResult.get(IPaymentHandler.CAPTURE_REF_ID));
304
            attrMap.put(IPaymentHandler.CAPTURE_AUTH_ID, captureResult.get(IPaymentHandler.CAPTURE_AUTH_ID));
305
 
306
            SimpleDateFormat captureTimeDateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
307
            attrMap.put(HdfcPaymentHandler.CAPTURE_TIME, captureTimeDateFormatter.format(new Date()));
308
 
309
            paymentHandler.updatePayment(payment, attrMap);
310
            return true;
311
          }
312
    }
313
 
314
    /**
3583 chandransh 315
     * Capture the HDFC EMI payment represented by the given payment object. If
316
     * the capture attempt is not successful, we mark this payment as failed. We
317
     * don't retry or anything. We'll add the support of multiple attempts later
318
     * on.
319
     * 
320
     * @param payment
321
     *            The payment which has to be captured.
322
     * @return True if the payment attempt is successful, false if not.
323
     */
324
    private boolean captureAndUpdateHdfcEmiPayment(in.shop2020.payment.domain.Payment payment){
325
        long merchantPaymentId = payment.getId();
326
        logger.info("Capturing HDFC payment with id: " + merchantPaymentId);
327
        Map<String, String> captureResult = HdfcEmiPaymentHandler.capturePayment(payment);
328
        String captureStatus = captureResult.get(IPaymentHandler.STATUS);
329
        String gatewayStatus = captureResult.get(IPaymentHandler.GATEWAY_STATUS);
330
 
331
        Map<String, String> attrMap = new HashMap<String, String>();
332
        if (!captureStatus.trim().equals("0") 
333
                || !HdfcPaymentReturnStatus.CAPTURED.value().equals(gatewayStatus)) {
334
            // Failure
335
            logger.info("Capture attempt failed for HDFC payment with id: " + merchantPaymentId);
336
            String description = captureResult.get(IPaymentHandler.ERROR);
337
            String errorCode = captureResult.get(IPaymentHandler.ERR_CODE);
338
 
339
            payment.setDescription(description);
340
            payment.setErrorCode(errorCode);
341
            payment.setStatus(PaymentStatus.FAILED.getValue());
342
            payment.setErrorTimestamp(new Date());
343
            paymentHandler.updatePayment(payment, attrMap);
344
            createTicketForFailedPayment(payment);
345
            return false;
346
        } else {
347
            // Success
348
            logger.error("Capture attempt successful for HDFC payment with id: " + merchantPaymentId);
349
            payment.setDescription("Payment Captured");
350
            payment.setGatewayTxnStatus(gatewayStatus);
351
            payment.setStatus(PaymentStatus.SUCCESS.getValue());
352
            payment.setSuccessTimestamp(new Date());           
353
 
354
            attrMap.put(IPaymentHandler.CAPTURE_TXN_ID, captureResult.get(IPaymentHandler.CAPTURE_TXN_ID));
355
            attrMap.put(IPaymentHandler.CAPTURE_REF_ID, captureResult.get(IPaymentHandler.CAPTURE_REF_ID));
356
            attrMap.put(IPaymentHandler.CAPTURE_AUTH_ID, captureResult.get(IPaymentHandler.CAPTURE_AUTH_ID));
357
 
358
            SimpleDateFormat captureTimeDateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
359
            attrMap.put(HdfcPaymentHandler.CAPTURE_TIME, captureTimeDateFormatter.format(new Date()));
360
 
361
            paymentHandler.updatePayment(payment, attrMap);
362
            return true;
363
          }
364
    }
365
 
366
    /**
3010 chandransh 367
     * Capture the EBS payment represented by the given payment object. If the
368
     * capture attempt is not successful, we mark this payment as failed. We
369
     * don't retry or anything. We'll add the support of multiple attempts later
370
     * on.
371
     * 
372
     * @param payment The payment which has to be captured.
373
     * @return True if the payment attempt is successful, false if not.
374
     */
375
    private boolean captureAndUpdateEbsPayment(in.shop2020.payment.domain.Payment payment){
376
        Map<String, String> captureResult = EbsPaymentHandler.capturePayment(payment);
377
        String captureStatus = captureResult.get(EbsPaymentHandler.STATUS);
378
 
379
        Map<String, String> attrMap = new HashMap<String, String>();
380
        if("".equals(captureStatus)){
381
            //Failure
382
            String description = captureResult.get(EbsPaymentHandler.ERROR);
383
            String errorCode = captureResult.get(EbsPaymentHandler.ERR_CODE);
384
 
385
            payment.setDescription(description);
386
            payment.setErrorCode(errorCode);
387
            payment.setStatus(PaymentStatus.FAILED.getValue());
388
            payment.setErrorTimestamp(new Date());
389
            paymentHandler.updatePayment(payment, attrMap);
3578 mandeep.dh 390
            createTicketForFailedPayment(payment);
3010 chandransh 391
            return false;
392
        }else{
393
            //Success
394
            payment.setGatewayTxnStatus(captureStatus);
395
            payment.setStatus(PaymentStatus.SUCCESS.getValue());
396
            payment.setSuccessTimestamp(new Date());
397
 
398
            attrMap.put(IPaymentHandler.CAPTURE_TXN_ID, captureResult.get(IPaymentHandler.CAPTURE_TXN_ID));
399
            attrMap.put(IPaymentHandler.CAPTURE_TIME, captureResult.get(IPaymentHandler.CAPTURE_TIME));
400
            paymentHandler.updatePayment(payment, attrMap);
401
            return true;
402
        }
403
    }
404
 
405
 
406
    /**
407
     * Creates a list of thrift payment objects corresponding to a list of
408
     * payment data objects.
409
     * 
410
     * @param daoPayments
411
     *            A list of payment DAO.
412
     * @return A list of Thrift payment objects.
413
     */
414
    private List<Payment> getThriftPayments(List<in.shop2020.payment.domain.Payment> daoPayments){
415
 
416
        List<Payment> payments = new ArrayList<Payment>();
417
        for(in.shop2020.payment.domain.Payment payment : daoPayments){
418
            payments.add(payment.getThriftPayment());
419
        }
420
        return payments;
421
    }
3375 rajveer 422
 
423
	@Override
424
	public boolean isAlive() throws TException {
425
		// TODO Auto-generated method stub
426
		return true;
427
	}
1946 chandransh 428
}