Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

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