Subversion Repositories SmartDukaan

Rev

Rev 2141 | Rev 2219 | 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
 
3
import in.shop2020.model.v1.order.LineItem;
4
import in.shop2020.model.v1.order.Order;
5
import in.shop2020.model.v1.order.Transaction;
6
import in.shop2020.model.v1.order.TransactionServiceException;
7
import in.shop2020.model.v1.order.TransactionStatus;
8
import in.shop2020.model.v1.user.Cart;
9
import in.shop2020.model.v1.user.Line;
1981 varun.gupt 10
import in.shop2020.model.v1.user.PromotionException;
1905 chandransh 11
import in.shop2020.model.v1.user.ShoppingCartException;
1981 varun.gupt 12
import in.shop2020.model.v1.user.UserContextService;
2137 chandransh 13
import in.shop2020.payments.Payment;
1905 chandransh 14
import in.shop2020.payments.PaymentException;
15
import in.shop2020.serving.utils.Utils;
16
import in.shop2020.thrift.clients.PaymentServiceClient;
1981 varun.gupt 17
import in.shop2020.thrift.clients.PromotionServiceClient;
1905 chandransh 18
import in.shop2020.thrift.clients.TransactionServiceClient;
19
import in.shop2020.thrift.clients.UserContextServiceClient;
20
 
21
import java.util.HashMap;
22
import java.util.List;
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
 
41
	private long paymentId;
42
	private double amount;
43
 
44
	public long getPaymentId() {
45
		return paymentId;
46
	}
47
 
48
	public double getAmount() {
49
		return amount;
50
	}
51
 
52
	/**
53
	 * Creates a payment for the given cart of the given user for the given
54
	 * transaction. Stores the id of the newly created payment and the amount
55
	 * for which this payment was created. They can be retrieved later on using
56
	 * {@link #getPaymentId()}getPaymentId() and {@link #getAmount()}getAmount()
57
	 * methods respectively later on.
58
	 * 
59
	 * @param currentCartId
60
	 *            The cart for which the payment object has to be created.
61
	 * @param userId
62
	 *            The user for whom the payment has to be created.
63
	 * @param txnId
64
	 *            The transaction against which the payment has to be created.
65
	 * @param gatewayId
66
	 * @return True if the payment object is successfully created, False
67
	 *         otherwise.
68
	 */
69
	public boolean createPayment(long currentCartId, long userId, long txnId, int gatewayId){
70
		PaymentServiceClient paymentServiceClient = null;
71
		try {
72
			paymentServiceClient = new PaymentServiceClient();
73
		} catch (Exception e) {
2199 chandransh 74
			log.error("Error while getting payment client", e);
1905 chandransh 75
			return PAYMENT_NOT_CREATED;
76
		}
77
 
78
		try {
79
			amount = calculatePaymentAmount(currentCartId);
80
		} catch (ShoppingCartException e1) {
2199 chandransh 81
			log.error("Unable to fetch payment amount from cart id.", e1);
1905 chandransh 82
			return PAYMENT_NOT_CREATED;
83
		} catch (TException e1) {
2199 chandransh 84
			log.error("Unable to fetch payment amount.", e1);
1905 chandransh 85
			return PAYMENT_NOT_CREATED;
86
		}
87
 
88
		try {
2137 chandransh 89
			paymentId = paymentServiceClient.getClient().createPayment(userId, amount, gatewayId, txnId);
90
			// This is being done to ensure that the amount which we pass on to
91
			// the PGs is same as what we have in the database.
92
			Payment payment = paymentServiceClient.getClient().getPayment(paymentId);
93
			amount = payment.getAmount();
1905 chandransh 94
		} catch (PaymentException e1) {
2199 chandransh 95
			log.error("Unable to create payment object.", e1);
1905 chandransh 96
			return PAYMENT_NOT_CREATED;
97
		} catch (TException e) {
2199 chandransh 98
			log.error("Not able to create payment object.", e);
1905 chandransh 99
			return PAYMENT_NOT_CREATED;
100
		}
101
 
102
		return true;
103
	}
104
 
2199 chandransh 105
	// TODO: The service client parameters in the processSuccessfulTxn et al are
106
	// unnecessary but initializing them again when the caller has the necessary
107
	// references has a performance overhead. Need to think more about this.
108
 
1905 chandransh 109
	/**
2199 chandransh 110
	 * Processes a successful transaction by:
111
	 * <ol>
112
	 * <li>Marking the given transaction as 'in process'.</li>
113
	 * <li>Removing the items in the cart for which the given transaction was
114
	 * processed.</li>
115
	 * <li>Marking the coupon associated with this transaction, if any, as used
116
	 * for this user.</li>
117
	 * <li>Queuing the transaction successful email, containing transaction
118
	 * info, to be sent later by a batch job.</li>
119
	 * </ol>
120
	 * <br>
1905 chandransh 121
	 * Please note that it's possible that a user has added items to the cart
2199 chandransh 122
	 * and so it's not possible to simply wipe out their cart. Therefore, it's
123
	 * important to ensure that we remove only as much quantity of items as for
124
	 * which the order was processed.
1905 chandransh 125
	 * 
2199 chandransh 126
	 * @param txnId
127
	 *            The transaction which should be marked as successful.
128
	 * @param userServiceClient
129
	 *            A user context service client to use.
130
	 * @param transactionServiceClient
131
	 *            A transaction service client to use.
1905 chandransh 132
	 */
133
	public static void processSuccessfulTxn(long txnId, UserContextServiceClient userServiceClient, TransactionServiceClient transactionServiceClient) {
134
		Transaction transaction = null;
135
		try {
136
			in.shop2020.model.v1.order.TransactionService.Client transactionClient = transactionServiceClient.getClient();
137
			transactionClient.changeTransactionStatus(txnId, TransactionStatus.IN_PROCESS, "Payment received for the order");
138
			transaction = transactionClient.getTransaction(txnId);
2199 chandransh 139
			transactionClient.enqueueTransactionInfoEmail(txnId);
1905 chandransh 140
		} catch (TException e1) {
2199 chandransh 141
			log.error("Unable to update status of transaction. Thrift Exception:", e1);
1905 chandransh 142
		} catch (TransactionServiceException e) {
2199 chandransh 143
			log.error("Unable to update status of transaction. Thrift Exception: ", e);
1905 chandransh 144
		}
2199 chandransh 145
		trackCouponUsage(transaction, userServiceClient);
146
        resetCart(transaction, userServiceClient);
1905 chandransh 147
	}
148
 
149
	/**
150
	 * Marks a transaction as well as all its orders as failed.
151
	 * 
152
	 * @param txnId
153
	 *            The id of the transaction which has to be marked as failed.
154
	 * @param transactionServiceClient
155
	 */
156
	public static void processFailedTxn(long txnId, TransactionServiceClient transactionServiceClient) {
157
		try {
158
			in.shop2020.model.v1.order.TransactionService.Client transactionClient = transactionServiceClient.getClient();
159
			transactionClient.changeTransactionStatus(txnId, TransactionStatus.FAILED, "Payment failed for the transaction.");
160
		} catch(TException e){
2199 chandransh 161
			log.error("Thrift exception while getting information from transaction service.", e);
1905 chandransh 162
		} catch (TransactionServiceException e) {
2199 chandransh 163
			log.error("Error while updating status information in transaction database.", e);
1905 chandransh 164
		}
165
	}
166
 
167
	/**
168
	 * Calculates the amount for the payment required for the given cart.
169
	 * 
170
	 * @param cartId
171
	 *            Id of the cart for which this payment amount has to be
172
	 *            calculated.
173
	 * @return The total amount for which a payment should be created.
174
	 * @throws ShoppingCartException
175
	 *             If no cart can be found for the given id.
176
	 * @throws TException
177
	 */
178
	private double calculatePaymentAmount(long cartId) throws ShoppingCartException, TException{
179
		double totalAmount = 0;
180
		Cart cart;
181
		UserContextServiceClient userContextServiceClient = null;
182
		try {
183
			userContextServiceClient = new UserContextServiceClient();
184
		} catch (Exception e) {
185
			e.printStackTrace();
186
		}
187
		in.shop2020.model.v1.user.UserContextService.Client userClient = userContextServiceClient.getClient();
188
		cart = userClient.getCart(cartId);
1981 varun.gupt 189
 
2199 chandransh 190
		if(cart.getCouponCode() == null)  {
1981 varun.gupt 191
		    List<Line> lineItems = cart.getLines(); 
192
 
193
	        for (Line line : lineItems) {
194
	            long productId = line.getItemId();
195
	            // FIXME: It's expensive to get the price of each item from the
196
	            // catalog service. We maintain the pricing info in the line items
197
	            // themselves now.
198
	            totalAmount =  totalAmount + line.getQuantity() * Utils.getItemPrice(productId);
199
	        }
2199 chandransh 200
		} else {
1981 varun.gupt 201
		    totalAmount = cart.getDiscountedPrice();
1905 chandransh 202
		}
1981 varun.gupt 203
 
1905 chandransh 204
		return totalAmount;
205
	}
206
 
2199 chandransh 207
	/**
208
	 * Removes the items processed through the given transaction from the
209
	 * shopping cart.
210
	 * 
211
	 * @param transaction
212
	 *            The transaction whose items have to be removed from the
213
	 *            shopping cart.
214
	 * @param userServiceClient
215
	 */
216
	private static void resetCart(Transaction transaction, UserContextServiceClient userServiceClient) {
217
		Map<Long, Double> items = new HashMap<Long, Double>();
218
		for(Order order: transaction.getOrders()){
219
			for(LineItem lineitem: order.getLineitems()){
220
				Long itemId = lineitem.getItem_id();
221
				Double quantity = items.get(itemId);
222
				if(quantity==null){
223
					quantity = lineitem.getQuantity();
224
				} else {
225
					quantity= quantity + lineitem.getQuantity();
226
				}
227
				items.put(itemId, quantity);
228
			}
229
		}
230
 
231
		log.debug("Items to restr in cart are: " + items);
232
 
233
		try {
234
			//TODO Optimize the function to send less data over the wire
235
            userServiceClient.getClient().resetCart(transaction.getShoppingCartid(), items);
236
		}catch (TException e) {
237
			log.error("Error while updating information in payment database.", e);
238
		} catch (ShoppingCartException e) {
239
			log.error("Error while reseting the cart in cart database.", e);
240
		}catch (Exception e) {
241
			log.error("Unexpected exception", e);
242
        }
243
	}
244
 
245
	/**
246
	 * Mark the coupon associated with the given transaction as used.
247
	 * 
248
	 * @param transaction
249
	 *            The transaction to track coupon for.
250
	 * 
251
	 * @param userServiceClient
252
	 *            The user service client instance to use.
253
	 */
254
	private static void trackCouponUsage(Transaction transaction, UserContextServiceClient userServiceClient) {
255
        try {
256
            // Tracking Coupon Usage 
257
            UserContextService.Client userClient = userServiceClient.getClient();
258
            Cart cart = userClient.getCart(transaction.getShoppingCartid());
259
            String couponCode = cart.getCouponCode();
260
 
261
            if (couponCode != null && !couponCode.isEmpty()) {
262
            	PromotionServiceClient promotionServiceClient = new PromotionServiceClient();
263
                promotionServiceClient.getClient().trackCouponUsage(couponCode, transaction.getId(), transaction.getCustomer_id());
264
            }
265
        } catch (ShoppingCartException e) {
266
            log.error("Error occurred in reading CardId for transaction", e);
267
        } catch (PromotionException e) {
268
            log.error("Promotion Exception: " + e);
269
        } catch (TException e)  {
270
            log.error("Transport from Promotion Service failed:", e);
271
        } catch (Exception e) {
272
            log.error("Unexpected exception:", e);
273
        }
274
	}
1905 chandransh 275
}