Subversion Repositories SmartDukaan

Rev

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