Subversion Repositories SmartDukaan

Rev

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