Subversion Repositories SmartDukaan

Rev

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

Rev Author Line No. Line
1905 chandransh 1
package in.shop2020.serving.services;
2
 
8942 rajveer 3
import in.shop2020.model.v1.order.EmiScheme;
1905 chandransh 4
import in.shop2020.model.v1.order.LineItem;
5
import in.shop2020.model.v1.order.Order;
7293 anupam.sin 6
import in.shop2020.model.v1.order.OrderSource;
6050 anupam.sin 7
import in.shop2020.model.v1.order.RechargeOrder;
1905 chandransh 8
import in.shop2020.model.v1.order.Transaction;
9
import in.shop2020.model.v1.order.TransactionServiceException;
10
import in.shop2020.model.v1.order.TransactionStatus;
5527 anupam.sin 11
import in.shop2020.model.v1.order.OrderType;
1981 varun.gupt 12
import in.shop2020.model.v1.user.PromotionException;
1905 chandransh 13
import in.shop2020.model.v1.user.ShoppingCartException;
5527 anupam.sin 14
import in.shop2020.logistics.PickUpType;
2137 chandransh 15
import in.shop2020.payments.Payment;
1905 chandransh 16
import in.shop2020.payments.PaymentException;
6318 rajveer 17
import in.shop2020.payments.PaymentStatus;
8942 rajveer 18
import in.shop2020.serving.controllers.ProceedToPayController;
3126 rajveer 19
import in.shop2020.thrift.clients.PaymentClient;
20
import in.shop2020.thrift.clients.PromotionClient;
21
import in.shop2020.thrift.clients.TransactionClient;
22
import in.shop2020.thrift.clients.UserClient;
1905 chandransh 23
 
24
import java.util.HashMap;
8942 rajveer 25
import java.util.List;
1905 chandransh 26
import java.util.Map;
27
 
28
import org.apache.log4j.Logger;
29
import org.apache.thrift.TException;
30
 
31
/**
32
 * This class has methods to be used to process non-gateway-specific aspects of
33
 * payments and transactions.
34
 * 
35
 * @author Chandranshu
36
 * 
37
 */
38
public class CommonPaymentService {
39
 
40
	private static final boolean PAYMENT_NOT_CREATED = false;
41
 
42
	private static Logger log = Logger.getLogger(Class.class);
6318 rajveer 43
	private static long gvGatewayId = 9;
1905 chandransh 44
 
45
	private long paymentId;
46
	private double amount;
6318 rajveer 47
	private boolean isGv = false;
48
	private double gvAmount = 0;
1905 chandransh 49
 
50
	public long getPaymentId() {
51
		return paymentId;
52
	}
53
 
54
	public double getAmount() {
55
		return amount;
56
	}
57
 
58
	/**
59
	 * Creates a payment for the given cart of the given user for the given
60
	 * transaction. Stores the id of the newly created payment and the amount
61
	 * for which this payment was created. They can be retrieved later on using
62
	 * {@link #getPaymentId()}getPaymentId() and {@link #getAmount()}getAmount()
63
	 * methods respectively later on.
64
	 * 
65
	 * @param userId
66
	 *            The user for whom the payment has to be created.
67
	 * @param txnId
68
	 *            The transaction against which the payment has to be created.
69
	 * @param gatewayId
70
	 * @return True if the payment object is successfully created, False
71
	 *         otherwise.
72
	 */
6390 rajveer 73
	public boolean createPayment(long userId, long txnId, int gatewayId){
3126 rajveer 74
		PaymentClient paymentServiceClient = null;
6318 rajveer 75
		in.shop2020.payments.PaymentService.Client pclient;
1905 chandransh 76
		try {
3126 rajveer 77
			paymentServiceClient = new PaymentClient();
6318 rajveer 78
			pclient = paymentServiceClient.getClient();
1905 chandransh 79
		} catch (Exception e) {
2199 chandransh 80
			log.error("Error while getting payment client", e);
1905 chandransh 81
			return PAYMENT_NOT_CREATED;
82
		}
83
 
84
		try {
6390 rajveer 85
			amount = calculatePaymentAmount(txnId);
86
		} catch (TransactionServiceException e1) {
87
			log.error("Unable to fetch payment amount from txn id.", e1);
1905 chandransh 88
			return PAYMENT_NOT_CREATED;
89
		} catch (TException e1) {
2199 chandransh 90
			log.error("Unable to fetch payment amount.", e1);
1905 chandransh 91
			return PAYMENT_NOT_CREATED;
92
		}
93
 
94
		try {
6318 rajveer 95
			if(isGv){
96
				paymentId = pclient.createPayment(userId, gvAmount, gvGatewayId, txnId, false);
97
				pclient.updatePaymentDetails(paymentId, "", "", "SUCCESS", "Payment Received", "", "", "", "", PaymentStatus.SUCCESS, "", null);
98
			}
7953 anupam.sin 99
 
100
			if(amount > 0) {
101
    			paymentId = paymentServiceClient.getClient().createPayment(userId, amount, gatewayId, txnId, false);
102
    			// This is being done to ensure that the amount which we pass on to
103
    			// the PGs is same as what we have in the database.
104
    			Payment payment = paymentServiceClient.getClient().getPayment(paymentId);
105
    			amount = payment.getAmount();
106
			}
1905 chandransh 107
		} catch (PaymentException e1) {
2199 chandransh 108
			log.error("Unable to create payment object.", e1);
1905 chandransh 109
			return PAYMENT_NOT_CREATED;
110
		} catch (TException e) {
2199 chandransh 111
			log.error("Not able to create payment object.", e);
1905 chandransh 112
			return PAYMENT_NOT_CREATED;
113
		}
114
 
115
		return true;
116
	}
117
 
2199 chandransh 118
	// TODO: The service client parameters in the processSuccessfulTxn et al are
119
	// unnecessary but initializing them again when the caller has the necessary
120
	// references has a performance overhead. Need to think more about this.
121
 
1905 chandransh 122
	/**
2199 chandransh 123
	 * Processes a successful transaction by:
124
	 * <ol>
3063 chandransh 125
	 * <li>Marking the given transaction as 'authorized'.</li>
2199 chandransh 126
	 * <li>Removing the items in the cart for which the given transaction was
127
	 * processed.</li>
128
	 * <li>Marking the coupon associated with this transaction, if any, as used
129
	 * for this user.</li>
130
	 * <li>Queuing the transaction successful email, containing transaction
131
	 * info, to be sent later by a batch job.</li>
132
	 * </ol>
133
	 * <br>
1905 chandransh 134
	 * Please note that it's possible that a user has added items to the cart
2199 chandransh 135
	 * and so it's not possible to simply wipe out their cart. Therefore, it's
136
	 * important to ensure that we remove only as much quantity of items as for
137
	 * which the order was processed.
1905 chandransh 138
	 * 
2199 chandransh 139
	 * @param txnId
140
	 *            The transaction which should be marked as successful.
141
	 * @param userServiceClient
142
	 *            A user context service client to use.
143
	 * @param transactionServiceClient
144
	 *            A transaction service client to use.
4246 rajveer 145
	 * @param isFlagged
146
	 * 			  If payment is flagged it will be true else false 
1905 chandransh 147
	 */
4246 rajveer 148
	public static void processSuccessfulTxn(long txnId, UserClient userServiceClient, TransactionClient transactionServiceClient, boolean isFlagged) {
1905 chandransh 149
		Transaction transaction = null;
4246 rajveer 150
		TransactionStatus tStatus = TransactionStatus.AUTHORIZED;
151
        String description = "Payment authorized for the order";
152
		// if flag is set, status to be changed to flagged
153
		if(isFlagged){
154
			tStatus = TransactionStatus.FLAGGED;
155
			description = "Payment flagged for the order";
156
		}
1905 chandransh 157
		try {
158
			in.shop2020.model.v1.order.TransactionService.Client transactionClient = transactionServiceClient.getClient();
7293 anupam.sin 159
			transactionClient.changeTransactionStatus(txnId, tStatus, description, PickUpType.COURIER.getValue(), OrderType.B2C, OrderSource.WEBSITE);
1905 chandransh 160
			transaction = transactionClient.getTransaction(txnId);
2199 chandransh 161
			transactionClient.enqueueTransactionInfoEmail(txnId);
1905 chandransh 162
		} catch (TException e1) {
2199 chandransh 163
			log.error("Unable to update status of transaction. Thrift Exception:", e1);
1905 chandransh 164
		} catch (TransactionServiceException e) {
2199 chandransh 165
			log.error("Unable to update status of transaction. Thrift Exception: ", e);
1905 chandransh 166
		}
2219 varun.gupt 167
		trackCouponUsage(transaction);
2199 chandransh 168
        resetCart(transaction, userServiceClient);
1905 chandransh 169
	}
170
 
171
	/**
172
	 * Marks a transaction as well as all its orders as failed.
173
	 * 
174
	 * @param txnId
175
	 *            The id of the transaction which has to be marked as failed.
176
	 * @param transactionServiceClient
177
	 */
3126 rajveer 178
	public static void processFailedTxn(long txnId, TransactionClient transactionServiceClient) {
1905 chandransh 179
		try {
180
			in.shop2020.model.v1.order.TransactionService.Client transactionClient = transactionServiceClient.getClient();
7293 anupam.sin 181
			transactionClient.changeTransactionStatus(txnId, TransactionStatus.FAILED, "Payment failed for the transaction.", PickUpType.COURIER.getValue(), OrderType.B2C, OrderSource.WEBSITE);
1905 chandransh 182
		} catch(TException e){
2199 chandransh 183
			log.error("Thrift exception while getting information from transaction service.", e);
1905 chandransh 184
		} catch (TransactionServiceException e) {
2199 chandransh 185
			log.error("Error while updating status information in transaction database.", e);
1905 chandransh 186
		}
187
	}
188
 
3063 chandransh 189
    /**
190
     * Processes a COD transaction by:
191
     * <ol>
192
     * <li>Setting the COD flag of all the orders and moving them to the INIT
193
     * state.
194
     * <li>Marking the given transaction to be in COD_IN_PROCESS state
195
     * <li>Marking the coupon associated with this transaction, if any, as used
196
     * for this user.</li>
197
     * <li>Queuing the transaction successful email, containing transaction
198
     * info, to be sent later by a batch job.</li>
199
     * </ol>
200
     * <br>
201
     * Please note that it's possible that a user has added items to the cart
202
     * and so it's not possible to simply wipe out their cart. Therefore, it's
203
     * important to ensure that we remove only as much quantity of items as for
204
     * which the order was processed.
205
     * 
206
     * @param txnId
207
     *            The COD transaction which should be marked as verification
208
     *            pending.
209
     */
210
	public static void processCodTxn(long txnId){
211
        try {            
3126 rajveer 212
            TransactionClient transactionServiceClient = new TransactionClient();
3063 chandransh 213
            in.shop2020.model.v1.order.TransactionService.Client transactionClient = transactionServiceClient.getClient();
7293 anupam.sin 214
            transactionClient.changeTransactionStatus(txnId, TransactionStatus.COD_IN_PROCESS, "COD payment awaited", PickUpType.COURIER.getValue(), OrderType.B2C, OrderSource.WEBSITE);
3063 chandransh 215
            Transaction transaction = transactionClient.getTransaction(txnId);
216
            transactionClient.enqueueTransactionInfoEmail(txnId);
217
 
3126 rajveer 218
            UserClient userServiceClient = new UserClient();
3063 chandransh 219
            trackCouponUsage(transaction);
220
            resetCart(transaction, userServiceClient);
221
        } catch (TException e1) {
222
            log.error("Unable to update status of transaction. Thrift Exception:", e1);
223
        } catch (TransactionServiceException e) {
224
            log.error("Unable to update status of transaction. Thrift Exception: ", e);
225
        } catch (Exception e) {
226
            log.error("Unable to update status of transaction. Thrift Exception: ", e);
227
        }
228
	}
229
 
7862 anupam.sin 230
	public static void processCouponTxn(long txnId){
231
        try {            
232
            TransactionClient transactionServiceClient = new TransactionClient();
233
            in.shop2020.model.v1.order.TransactionService.Client transactionClient = transactionServiceClient.getClient();
234
            transactionClient.changeTransactionStatus(txnId, TransactionStatus.AUTHORIZED, "Payment by coupon successful", PickUpType.COURIER.getValue(), OrderType.B2C, OrderSource.WEBSITE);
235
            Transaction transaction = transactionClient.getTransaction(txnId);
236
            UserClient userServiceClient = new UserClient();
237
            trackCouponUsage(transaction);
238
            resetCart(transaction, userServiceClient);
239
        } catch (TException e1) {
240
            log.error("Unable to update status of transaction. Thrift Exception:", e1);
241
        } catch (TransactionServiceException e) {
242
            log.error("Unable to update status of transaction. Thrift Exception: ", e);
243
        } catch (Exception e) {
244
            log.error("Unable to update status of transaction. Thrift Exception: ", e);
245
        }
246
    }
247
 
1905 chandransh 248
	/**
6390 rajveer 249
	 * Calculates the amount for the payment required for the given transaction.
1905 chandransh 250
	 * 
6390 rajveer 251
	 * @param txnId
252
	 *            Id of the transaction for which this payment amount has to be
1905 chandransh 253
	 *            calculated.
254
	 * @return The total amount for which a payment should be created.
6390 rajveer 255
	 * @throws TransactionServiceException 
1905 chandransh 256
	 * @throws TException
257
	 */
6390 rajveer 258
	private double calculatePaymentAmount(long txnId) throws TransactionServiceException, TException{
1905 chandransh 259
		double totalAmount = 0;
6390 rajveer 260
		TransactionClient transactionServiceClient = null;
1905 chandransh 261
		try {
6390 rajveer 262
			transactionServiceClient = new TransactionClient();
1905 chandransh 263
		} catch (Exception e) {
2942 chandransh 264
			log.error("Unable to initialize user context service client", e);
6390 rajveer 265
			throw new TransactionServiceException(100, "Unable to initialize the user service client");
1905 chandransh 266
		}
6390 rajveer 267
		in.shop2020.model.v1.order.TransactionService.Client tClient = transactionServiceClient.getClient();
268
		Transaction transaction = tClient.getTransaction(txnId);
8942 rajveer 269
//		Map<Long, Double> miscCharges = tClient.getMiscCharges(txnId);
270
//		System.out.println(miscCharges);
271
//		if(miscCharges != null & !miscCharges.isEmpty()){
272
//			totalAmount = totalAmount + miscCharges.get(1L);
273
//		}
6390 rajveer 274
		for(Order order: transaction.getOrders()){
275
			totalAmount = totalAmount + order.getTotal_amount();
276
			gvAmount = gvAmount + order.getGvAmount();
277
		}
278
		if(gvAmount>0){
279
			isGv = true;	
280
		}
6431 rajveer 281
		return (totalAmount-gvAmount);
1905 chandransh 282
	}
283
 
2199 chandransh 284
	/**
285
	 * Removes the items processed through the given transaction from the
286
	 * shopping cart.
287
	 * 
288
	 * @param transaction
289
	 *            The transaction whose items have to be removed from the
290
	 *            shopping cart.
291
	 * @param userServiceClient
292
	 */
3126 rajveer 293
	private static void resetCart(Transaction transaction, UserClient userServiceClient) {
2199 chandransh 294
		Map<Long, Double> items = new HashMap<Long, Double>();
295
		for(Order order: transaction.getOrders()){
296
			for(LineItem lineitem: order.getLineitems()){
297
				Long itemId = lineitem.getItem_id();
298
				Double quantity = items.get(itemId);
299
				if(quantity==null){
300
					quantity = lineitem.getQuantity();
301
				} else {
302
					quantity= quantity + lineitem.getQuantity();
303
				}
304
				items.put(itemId, quantity);
305
			}
306
		}
307
 
3063 chandransh 308
		log.debug("Items to reset in cart are: " + items);
2199 chandransh 309
 
310
		try {
311
			//TODO Optimize the function to send less data over the wire
312
            userServiceClient.getClient().resetCart(transaction.getShoppingCartid(), items);
313
		}catch (TException e) {
314
			log.error("Error while updating information in payment database.", e);
315
		} catch (ShoppingCartException e) {
316
			log.error("Error while reseting the cart in cart database.", e);
317
		}catch (Exception e) {
318
			log.error("Unexpected exception", e);
319
        }
320
	}
321
 
322
	/**
323
	 * Mark the coupon associated with the given transaction as used.
324
	 * 
325
	 * @param transaction
326
	 *            The transaction to track coupon for.
327
	 * 
328
	 * @param userServiceClient
329
	 *            The user service client instance to use.
330
	 */
2219 varun.gupt 331
	private static void trackCouponUsage(Transaction transaction) {
2199 chandransh 332
        try {
2219 varun.gupt 333
            String couponCode = transaction.getCoupon_code();
334
 
2199 chandransh 335
            if (couponCode != null && !couponCode.isEmpty()) {
3126 rajveer 336
            	PromotionClient promotionServiceClient = new PromotionClient();
2199 chandransh 337
                promotionServiceClient.getClient().trackCouponUsage(couponCode, transaction.getId(), transaction.getCustomer_id());
338
            }
339
        } catch (PromotionException e) {
340
            log.error("Promotion Exception: " + e);
341
        } catch (TException e)  {
342
            log.error("Transport from Promotion Service failed:", e);
343
        } catch (Exception e) {
344
            log.error("Unexpected exception:", e);
345
        }
346
	}
6050 anupam.sin 347
 
348
    public boolean createPayment(RechargeOrder rechargeOrder, int gatewayId) {
349
        PaymentClient paymentServiceClient = null;
350
        try {
351
            paymentServiceClient = new PaymentClient();
352
        } catch (Exception e) {
353
            log.error("Error while getting payment client", e);
354
            return PAYMENT_NOT_CREATED;
355
        }
356
 
6443 anupam.sin 357
        amount = rechargeOrder.getTotalAmount() - rechargeOrder.getWalletAmount() - rechargeOrder.getCouponAmount();
6050 anupam.sin 358
 
359
        try {
360
            paymentId = paymentServiceClient.getClient().createPayment(rechargeOrder.getUserId(), amount, gatewayId, rechargeOrder.getTransactionId(), true);
361
            // This is being done to ensure that the amount which we pass on to
362
            // the PGs is same as what we have in the database.
363
            Payment payment = paymentServiceClient.getClient().getPayment(paymentId);
364
            amount = payment.getAmount();
365
        } catch (PaymentException e1) {
366
            log.error("Unable to create payment object.", e1);
367
            return PAYMENT_NOT_CREATED;
368
        } catch (TException e) {
369
            log.error("Not able to create payment object.", e);
370
            return PAYMENT_NOT_CREATED;
371
        }
372
 
373
        return true;
374
 
375
    }
8942 rajveer 376
 
377
    public static double calculateEmiAmount(String payOption, double totalAmount){
378
    	double emiAmount = 0.0;
379
    	List<EmiScheme> schemes = ProceedToPayController.getEmiSchemes();
380
    	for(EmiScheme scheme: schemes){
381
    		if(scheme.getId() == Long.parseLong(payOption)){
382
    			double interestRate = scheme.getInterestRate()/12/100;
383
    			emiAmount = totalAmount*interestRate*Math.pow((1+interestRate), scheme.getTenure())/(Math.pow((1+interestRate), scheme.getTenure())-1);
384
    		}
385
    	}
386
    	return emiAmount;
387
    }
388
 
6415 rajveer 389
    public static void main(String[] args) {
390
    	Map<Long, Double> miscCharges = new HashMap<Long, Double>();
391
    	miscCharges.put(1L, 3.988);
392
    	System.out.println(miscCharges);
393
		if(miscCharges != null & !miscCharges.isEmpty()){
394
			System.out.println( miscCharges.get(1L));;
395
		}
396
	}
1905 chandransh 397
}