Subversion Repositories SmartDukaan

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
21410 amit.gupta 1
package com.spice.profitmandi.web.controller.checkout;
2
 
3
import java.util.HashMap;
4
import java.util.Map;
5
 
6
import org.apache.thrift.TException;
7
import org.apache.thrift.transport.TTransportException;
8
import org.slf4j.Logger;
9
import org.slf4j.LoggerFactory;
10
 
11
import com.spice.profitmandi.thrift.clients.PaymentClient;
12
import com.spice.profitmandi.thrift.clients.PromotionClient;
13
import com.spice.profitmandi.thrift.clients.TransactionClient;
14
import com.spice.profitmandi.thrift.clients.UserClient;
15
 
16
import in.shop2020.logistics.PickUpType;
17
import in.shop2020.model.v1.order.LineItem;
18
import in.shop2020.model.v1.order.Order;
19
import in.shop2020.model.v1.order.OrderSource;
20
import in.shop2020.model.v1.order.OrderType;
21
import in.shop2020.model.v1.order.RechargeOrder;
22
import in.shop2020.model.v1.order.Transaction;
23
import in.shop2020.model.v1.order.TransactionService.Client;
24
import in.shop2020.model.v1.order.TransactionServiceException;
25
import in.shop2020.model.v1.order.TransactionStatus;
26
import in.shop2020.model.v1.user.PromotionException;
27
import in.shop2020.model.v1.user.ShoppingCartException;
28
import in.shop2020.payments.Payment;
29
import in.shop2020.payments.PaymentException;
21805 amit.gupta 30
import in.shop2020.payments.PaymentGateway;
21410 amit.gupta 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
 
21805 amit.gupta 43
	private static final Logger log = LoggerFactory.getLogger(CommonPaymentService.class);
21410 amit.gupta 44
 
21805 amit.gupta 45
	private static Map<Integer, PaymentGateway> PAYMENT_GATEWAYS;
46
 
21410 amit.gupta 47
	private long paymentId;
48
	private double amount;
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
	 */
21805 amit.gupta 73
	public boolean createPayment(long userId, long txnId, int gatewayId) {
21410 amit.gupta 74
		TransactionClient transactionClient = null;
75
		Client tc = null;
76
		try {
77
			transactionClient = new TransactionClient();
78
			tc = transactionClient.getClient();
79
		} catch (TTransportException e) {
21805 amit.gupta 80
			log.error("Unable to create transaction client", e);
21410 amit.gupta 81
			return PAYMENT_NOT_CREATED;
82
		}
83
 
84
		try {
85
			amount = calculatePaymentAmount(txnId);
86
		} catch (Exception e1) {
21805 amit.gupta 87
			log.error("Unable to calcuate payment amount", e1);
21410 amit.gupta 88
			return PAYMENT_NOT_CREATED;
89
		}
90
 
91
		try {
92
			paymentId = tc.createPayment(userId, txnId, gatewayId);
93
		} catch (TException e) {
21805 amit.gupta 94
			log.error("Unable to create payment", e);
21410 amit.gupta 95
			return PAYMENT_NOT_CREATED;
96
		}
21805 amit.gupta 97
 
21410 amit.gupta 98
		return true;
99
	}
100
 
101
	// TODO: The service client parameters in the processSuccessfulTxn et al are
102
	// unnecessary but initializing them again when the caller has the necessary
103
	// references has a performance overhead. Need to think more about this.
104
 
105
	/**
106
	 * Processes a successful transaction by:
107
	 * <ol>
108
	 * <li>Marking the given transaction as 'authorized'.</li>
109
	 * <li>Removing the items in the cart for which the given transaction was
110
	 * processed.</li>
111
	 * <li>Marking the coupon associated with this transaction, if any, as used
112
	 * for this user.</li>
113
	 * <li>Queuing the transaction successful email, containing transaction
114
	 * info, to be sent later by a batch job.</li>
115
	 * </ol>
116
	 * <br>
117
	 * Please note that it's possible that a user has added items to the cart
118
	 * and so it's not possible to simply wipe out their cart. Therefore, it's
119
	 * important to ensure that we remove only as much quantity of items as for
120
	 * which the order was processed.
121
	 * 
122
	 * @param txnId
123
	 *            The transaction which should be marked as successful.
124
	 * @param userServiceClient
125
	 *            A user context service client to use.
126
	 * @param transactionServiceClient
127
	 *            A transaction service client to use.
128
	 * @param isFlagged
21805 amit.gupta 129
	 *            If payment is flagged it will be true else false
21410 amit.gupta 130
	 */
21805 amit.gupta 131
	public static void processSuccessfulTxn(long txnId, UserClient userServiceClient,
132
			TransactionClient transactionServiceClient, boolean isFlagged) {
21410 amit.gupta 133
		Transaction transaction = null;
134
		TransactionStatus tStatus = TransactionStatus.AUTHORIZED;
135
		String description = "Payment authorized for the order";
136
		// if flag is set, status to be changed to flagged
21805 amit.gupta 137
		if (isFlagged) {
21410 amit.gupta 138
			tStatus = TransactionStatus.FLAGGED;
139
			description = "Payment flagged for the order";
140
		}
141
		try {
22586 amit.gupta 142
			PickUpType pickupType = PickUpType.COURIER;
21805 amit.gupta 143
			in.shop2020.model.v1.order.TransactionService.Client transactionClient = transactionServiceClient
144
					.getClient();
21410 amit.gupta 145
			transaction = transactionClient.getTransaction(txnId);
22586 amit.gupta 146
			if (transaction.getOrders().get(0).getLogistics_provider_id() == 4 ){
147
				pickupType = PickUpType.SELF;
148
			} else if (transaction.getOrders().get(0).getLogistics_provider_id()==5) {
149
				pickupType = PickUpType.RUNNER;
150
			}
151
			transactionClient.changeTransactionStatus(txnId, tStatus, description, pickupType.getValue(), null,
21805 amit.gupta 152
					null);
21410 amit.gupta 153
			transactionClient.enqueueTransactionInfoEmail(txnId);
154
		} catch (TException e1) {
155
			log.error("Unable to update status of transaction. Thrift Exception:", e1);
156
		} catch (TransactionServiceException e) {
157
			log.error("Unable to update status of transaction. Thrift Exception: ", e);
158
		}
159
		long sum = resetCart(transaction, userServiceClient);
160
		trackCouponUsage(transaction, sum);
161
	}
162
 
163
	/**
164
	 * Marks a transaction as well as all its orders as failed.
165
	 * 
166
	 * @param txnId
167
	 *            The id of the transaction which has to be marked as failed.
168
	 * @param transactionServiceClient
169
	 */
170
	public static void processFailedTxn(long txnId, TransactionClient transactionServiceClient) {
171
		try {
21805 amit.gupta 172
			in.shop2020.model.v1.order.TransactionService.Client transactionClient = transactionServiceClient
173
					.getClient();
174
			transactionClient.changeTransactionStatus(txnId, TransactionStatus.FAILED,
175
					"Payment failed for the transaction.", PickUpType.COURIER.getValue(), OrderType.B2C,
176
					OrderSource.WEBSITE);
177
		} catch (TException e) {
21410 amit.gupta 178
			log.error("Thrift exception while getting information from transaction service.", e);
179
		} catch (TransactionServiceException e) {
180
			log.error("Error while updating status information in transaction database.", e);
181
		}
182
	}
183
 
184
	/**
185
	 * Processes a COD transaction by:
186
	 * <ol>
187
	 * <li>Setting the COD flag of all the orders and moving them to the INIT
188
	 * state.
189
	 * <li>Marking the given transaction to be in COD_IN_PROCESS state
190
	 * <li>Marking the coupon associated with this transaction, if any, as used
191
	 * for this user.</li>
192
	 * <li>Queuing the transaction successful email, containing transaction
193
	 * info, to be sent later by a batch job.</li>
194
	 * </ol>
195
	 * <br>
196
	 * Please note that it's possible that a user has added items to the cart
197
	 * and so it's not possible to simply wipe out their cart. Therefore, it's
198
	 * important to ensure that we remove only as much quantity of items as for
199
	 * which the order was processed.
200
	 * 
201
	 * @param txnId
202
	 *            The COD transaction which should be marked as verification
203
	 *            pending.
204
	 */
21805 amit.gupta 205
	public static void processCodTxn(long txnId, OrderType orderType) {
206
		try {
21410 amit.gupta 207
			TransactionClient transactionServiceClient = new TransactionClient();
21805 amit.gupta 208
			in.shop2020.model.v1.order.TransactionService.Client transactionClient = transactionServiceClient
209
					.getClient();
210
			transactionClient.changeTransactionStatus(txnId, TransactionStatus.COD_IN_PROCESS, "COD payment awaited",
211
					PickUpType.COURIER.getValue(), orderType, OrderSource.WEBSITE);
21410 amit.gupta 212
			Transaction transaction = transactionClient.getTransaction(txnId);
213
			transactionClient.enqueueTransactionInfoEmail(txnId);
214
 
215
			UserClient userServiceClient = new UserClient();
216
			long sum = resetCart(transaction, userServiceClient);
217
			trackCouponUsage(transaction, sum);
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
		}
21469 amit.gupta 225
		log.info("successfully processed cod transaction");
21410 amit.gupta 226
	}
227
 
21805 amit.gupta 228
	public static void processCouponTxn(long txnId, OrderType orderType) {
229
		try {
21410 amit.gupta 230
			TransactionClient transactionServiceClient = new TransactionClient();
21805 amit.gupta 231
			in.shop2020.model.v1.order.TransactionService.Client transactionClient = transactionServiceClient
232
					.getClient();
233
			transactionClient.changeTransactionStatus(txnId, TransactionStatus.AUTHORIZED,
234
					"Payment by coupon successful", PickUpType.COURIER.getValue(), orderType, OrderSource.WEBSITE);
21410 amit.gupta 235
			Transaction transaction = transactionClient.getTransaction(txnId);
236
			UserClient userServiceClient = new UserClient();
237
			long sum = resetCart(transaction, userServiceClient);
238
			trackCouponUsage(transaction, sum);
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
 
248
	/**
249
	 * Calculates the amount for the payment required for the given transaction.
250
	 * 
251
	 * @param txnId
252
	 *            Id of the transaction for which this payment amount has to be
253
	 *            calculated.
254
	 * @return The total amount for which a payment should be created.
21805 amit.gupta 255
	 * @throws TransactionServiceException
21410 amit.gupta 256
	 * @throws TException
257
	 */
21805 amit.gupta 258
	private double calculatePaymentAmount(long txnId) throws TransactionServiceException, TException {
259
		Client tc = new TransactionClient().getClient();
21410 amit.gupta 260
		double payment_amount = tc.calculatePaymentAmount(txnId);
261
		return payment_amount;
262
	}
263
 
21805 amit.gupta 264
	public double getOrderAmount(long txnId) throws TransactionServiceException, TException {
21410 amit.gupta 265
		return calculatePaymentAmount(txnId);
266
	}
267
 
268
	/**
269
	 * Removes the items processed through the given transaction from the
270
	 * shopping cart.
271
	 * 
272
	 * @param transaction
273
	 *            The transaction whose items have to be removed from the
274
	 *            shopping cart.
275
	 * @param userServiceClient
276
	 */
277
	private static long resetCart(Transaction transaction, UserClient userServiceClient) {
278
		long sum = 0;
279
		Map<Long, Double> items = new HashMap<Long, Double>();
21805 amit.gupta 280
		for (Order order : transaction.getOrders()) {
21410 amit.gupta 281
			sum += order.getGvAmount();
21805 amit.gupta 282
			for (LineItem lineitem : order.getLineitems()) {
21410 amit.gupta 283
				Long itemId = lineitem.getItem_id();
284
				Double quantity = items.get(itemId);
21805 amit.gupta 285
				if (quantity == null) {
21410 amit.gupta 286
					quantity = lineitem.getQuantity();
287
				} else {
21805 amit.gupta 288
					quantity = quantity + lineitem.getQuantity();
21410 amit.gupta 289
				}
290
				items.put(itemId, quantity);
291
			}
292
		}
293
 
294
		log.debug("Items to reset in cart are: " + items);
295
 
296
		try {
21805 amit.gupta 297
			// TODO Optimize the function to send less data over the wire
21410 amit.gupta 298
			userServiceClient.getClient().resetCart(transaction.getShoppingCartid(), items);
21805 amit.gupta 299
		} catch (TException e) {
21410 amit.gupta 300
			log.error("Error while updating information in payment database.", e);
301
		} catch (ShoppingCartException e) {
302
			log.error("Error while reseting the cart in cart database.", e);
21805 amit.gupta 303
		} catch (Exception e) {
21410 amit.gupta 304
			log.error("Unexpected exception", e);
305
		}
306
		return sum;
307
	}
308
 
309
	/**
310
	 * Mark the coupon associated with the given transaction as used.
311
	 * 
312
	 * @param transaction
313
	 *            The transaction to track coupon for.
314
	 * 
315
	 * @param userServiceClient
316
	 *            The user service client instance to use.
317
	 */
318
	private static void trackCouponUsage(Transaction transaction, long sum) {
319
		try {
320
			String couponCode = transaction.getCoupon_code();
321
 
322
			if (couponCode != null && !couponCode.isEmpty()) {
323
				PromotionClient promotionServiceClient = new PromotionClient();
21805 amit.gupta 324
				promotionServiceClient.getClient().trackCouponUsage(couponCode, transaction.getId(),
325
						transaction.getCustomer_id(), sum, false);
21410 amit.gupta 326
			}
327
		} catch (PromotionException e) {
328
			log.error("Promotion Exception: " + e);
21805 amit.gupta 329
		} catch (TException e) {
21410 amit.gupta 330
			log.error("Transport from Promotion Service failed:", e);
331
		} catch (Exception e) {
332
			log.error("Unexpected exception:", e);
333
		}
334
	}
335
 
336
	public boolean createPayment(RechargeOrder rechargeOrder, int gatewayId) {
337
		PaymentClient paymentServiceClient = null;
338
		try {
339
			paymentServiceClient = new PaymentClient();
340
		} catch (Exception e) {
341
			log.error("Error while getting payment client", e);
342
			return PAYMENT_NOT_CREATED;
343
		}
344
 
345
		amount = rechargeOrder.getTotalAmount() - rechargeOrder.getWalletAmount() - rechargeOrder.getCouponAmount();
346
 
347
		try {
21805 amit.gupta 348
			paymentId = paymentServiceClient.getClient().createPayment(rechargeOrder.getUserId(), amount, gatewayId,
349
					rechargeOrder.getTransactionId(), true);
21410 amit.gupta 350
			// This is being done to ensure that the amount which we pass on to
351
			// the PGs is same as what we have in the database.
352
			Payment payment = paymentServiceClient.getClient().getPayment(paymentId);
353
			amount = payment.getAmount();
354
		} catch (PaymentException e1) {
355
			log.error("Unable to create payment object.", e1);
356
			return PAYMENT_NOT_CREATED;
357
		} catch (TException e) {
358
			log.error("Not able to create payment object.", e);
359
			return PAYMENT_NOT_CREATED;
360
		}
361
 
362
		return true;
363
 
364
	}
365
 
21805 amit.gupta 366
	public static PaymentGateway getPaymentGatewayById(int gatewayId) {
367
 
368
		if (PAYMENT_GATEWAYS == null || PAYMENT_GATEWAYS.isEmpty()) {
369
			PaymentClient paymentServiceClient = null;
370
			PAYMENT_GATEWAYS = new HashMap<>();
371
			try {
372
				paymentServiceClient = new PaymentClient();
373
				for (PaymentGateway pg : paymentServiceClient.getClient().getActivePaymentGateways()){
374
					PAYMENT_GATEWAYS.put((int)pg.getId(), pg);
375
				}
376
			} catch (Exception e) {
377
				log.error("Error while getting payment client", e);
378
			}
379
		}
380
		return PAYMENT_GATEWAYS.get(gatewayId);
381
	}
382
 
21410 amit.gupta 383
	public static void main(String[] args) {
384
		Map<Long, Double> miscCharges = new HashMap<Long, Double>();
385
		miscCharges.put(1L, 3.988);
386
		System.out.println(miscCharges);
21805 amit.gupta 387
		if (miscCharges != null & !miscCharges.isEmpty()) {
388
			System.out.println(miscCharges.get(1L));
389
			;
21410 amit.gupta 390
		}
391
	}
392
 
21805 amit.gupta 393
	/*
394
	 * private static OrderType getOrderType(Long userId) throws
395
	 * TTransportException, TException{ OrderType ot = OrderType.B2C; try {
396
	 * 
397
	 * in.shop2020.model.v1.user.UserContextService.Client uc = new
398
	 * UserClient().getClient(); uc.tax PrivateDealUser pdu =
399
	 * uc.getPrivateDealUser(userId); if(pdu.getTin() != null &&
400
	 * !pdu.getTin().trim().equals("")){ ot = OrderType.B2B; } } catch
401
	 * (TTransportException e) { log.error("Unable to get user service client.",
402
	 * e); } return ot; }
403
	 */
21410 amit.gupta 404
}