Subversion Repositories SmartDukaan

Rev

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