Rev 13521 | Blame | Compare with Previous | Last modification | View Log | RSS feed
package in.shop2020.serving.services;import in.shop2020.logistics.PickUpType;import in.shop2020.model.v1.order.EmiScheme;import in.shop2020.model.v1.order.LineItem;import in.shop2020.model.v1.order.Order;import in.shop2020.model.v1.order.OrderSource;import in.shop2020.model.v1.order.OrderType;import in.shop2020.model.v1.order.RechargeOrder;import in.shop2020.model.v1.order.Transaction;import in.shop2020.model.v1.order.TransactionServiceException;import in.shop2020.model.v1.order.TransactionStatus;import in.shop2020.model.v1.user.PrivateDealUser;import in.shop2020.model.v1.user.PromotionException;import in.shop2020.model.v1.user.ShoppingCartException;import in.shop2020.payments.Payment;import in.shop2020.payments.PaymentException;import in.shop2020.payments.PaymentStatus;import in.shop2020.serving.controllers.ProceedToPayController;import in.shop2020.thrift.clients.PaymentClient;import in.shop2020.thrift.clients.PromotionClient;import in.shop2020.thrift.clients.TransactionClient;import in.shop2020.thrift.clients.UserClient;import java.util.HashMap;import java.util.List;import java.util.Map;import org.apache.log4j.Logger;import org.apache.thrift.TException;import org.apache.thrift.transport.TTransportException;/*** This class has methods to be used to process non-gateway-specific aspects of* payments and transactions.** @author Chandranshu**/public class CommonPaymentService {private static final boolean PAYMENT_NOT_CREATED = false;private static Logger log = Logger.getLogger(Class.class);private static long gvGatewayId = 9;private long paymentId;private double amount;private boolean isGv = false;private double gvAmount = 0;public long getPaymentId() {return paymentId;}public double getAmount() {return amount;}/*** Creates a payment for the given cart of the given user for the given* transaction. Stores the id of the newly created payment and the amount* for which this payment was created. They can be retrieved later on using* {@link #getPaymentId()}getPaymentId() and {@link #getAmount()}getAmount()* methods respectively later on.** @param userId* The user for whom the payment has to be created.* @param txnId* The transaction against which the payment has to be created.* @param gatewayId* @return True if the payment object is successfully created, False* otherwise.*/public boolean createPayment(long userId, long txnId, int gatewayId){PaymentClient paymentServiceClient = null;in.shop2020.payments.PaymentService.Client pclient;try {paymentServiceClient = new PaymentClient();pclient = paymentServiceClient.getClient();} catch (Exception e) {log.error("Error while getting payment client", e);return PAYMENT_NOT_CREATED;}try {amount = calculatePaymentAmount(txnId);} catch (TransactionServiceException e1) {log.error("Unable to fetch payment amount from txn id.", e1);return PAYMENT_NOT_CREATED;} catch (TException e1) {log.error("Unable to fetch payment amount.", e1);return PAYMENT_NOT_CREATED;}try {if(isGv){paymentId = pclient.createPayment(userId, gvAmount, gvGatewayId, txnId, false);pclient.updatePaymentDetails(paymentId, "", "", "SUCCESS", "Payment Received", "", "", "", "", PaymentStatus.SUCCESS, "", null);}if(amount > 0) {paymentId = paymentServiceClient.getClient().createPayment(userId, amount, gatewayId, txnId, false);// This is being done to ensure that the amount which we pass on to// the PGs is same as what we have in the database.Payment payment = paymentServiceClient.getClient().getPayment(paymentId);amount = payment.getAmount();}} catch (PaymentException e1) {log.error("Unable to create payment object.", e1);return PAYMENT_NOT_CREATED;} catch (TException e) {log.error("Not able to create payment object.", e);return PAYMENT_NOT_CREATED;}return true;}// TODO: The service client parameters in the processSuccessfulTxn et al are// unnecessary but initializing them again when the caller has the necessary// references has a performance overhead. Need to think more about this./*** Processes a successful transaction by:* <ol>* <li>Marking the given transaction as 'authorized'.</li>* <li>Removing the items in the cart for which the given transaction was* processed.</li>* <li>Marking the coupon associated with this transaction, if any, as used* for this user.</li>* <li>Queuing the transaction successful email, containing transaction* info, to be sent later by a batch job.</li>* </ol>* <br>* Please note that it's possible that a user has added items to the cart* and so it's not possible to simply wipe out their cart. Therefore, it's* important to ensure that we remove only as much quantity of items as for* which the order was processed.** @param txnId* The transaction which should be marked as successful.* @param userServiceClient* A user context service client to use.* @param transactionServiceClient* A transaction service client to use.* @param isFlagged* If payment is flagged it will be true else false*/public static void processSuccessfulTxn(long txnId, UserClient userServiceClient, TransactionClient transactionServiceClient, boolean isFlagged) {Transaction transaction = null;TransactionStatus tStatus = TransactionStatus.AUTHORIZED;String description = "Payment authorized for the order";// if flag is set, status to be changed to flaggedif(isFlagged){tStatus = TransactionStatus.FLAGGED;description = "Payment flagged for the order";}try {in.shop2020.model.v1.order.TransactionService.Client transactionClient = transactionServiceClient.getClient();transaction = transactionClient.getTransaction(txnId);transactionClient.changeTransactionStatus(txnId, tStatus, description, PickUpType.COURIER.getValue(), getOrderType(transaction.getCustomer_id()), OrderSource.WEBSITE);transactionClient.enqueueTransactionInfoEmail(txnId);} catch (TException e1) {log.error("Unable to update status of transaction. Thrift Exception:", e1);} catch (TransactionServiceException e) {log.error("Unable to update status of transaction. Thrift Exception: ", e);}long sum = resetCart(transaction, userServiceClient);trackCouponUsage(transaction, sum);}/*** Marks a transaction as well as all its orders as failed.** @param txnId* The id of the transaction which has to be marked as failed.* @param transactionServiceClient*/public static void processFailedTxn(long txnId, TransactionClient transactionServiceClient) {try {in.shop2020.model.v1.order.TransactionService.Client transactionClient = transactionServiceClient.getClient();transactionClient.changeTransactionStatus(txnId, TransactionStatus.FAILED, "Payment failed for the transaction.", PickUpType.COURIER.getValue(), OrderType.B2C, OrderSource.WEBSITE);} catch(TException e){log.error("Thrift exception while getting information from transaction service.", e);} catch (TransactionServiceException e) {log.error("Error while updating status information in transaction database.", e);}}/*** Processes a COD transaction by:* <ol>* <li>Setting the COD flag of all the orders and moving them to the INIT* state.* <li>Marking the given transaction to be in COD_IN_PROCESS state* <li>Marking the coupon associated with this transaction, if any, as used* for this user.</li>* <li>Queuing the transaction successful email, containing transaction* info, to be sent later by a batch job.</li>* </ol>* <br>* Please note that it's possible that a user has added items to the cart* and so it's not possible to simply wipe out their cart. Therefore, it's* important to ensure that we remove only as much quantity of items as for* which the order was processed.** @param txnId* The COD transaction which should be marked as verification* pending.*/public static void processCodTxn(long txnId, OrderType orderType){try {TransactionClient transactionServiceClient = new TransactionClient();in.shop2020.model.v1.order.TransactionService.Client transactionClient = transactionServiceClient.getClient();transactionClient.changeTransactionStatus(txnId, TransactionStatus.COD_IN_PROCESS, "COD payment awaited", PickUpType.COURIER.getValue(), orderType, OrderSource.WEBSITE);Transaction transaction = transactionClient.getTransaction(txnId);transactionClient.enqueueTransactionInfoEmail(txnId);UserClient userServiceClient = new UserClient();long sum = resetCart(transaction, userServiceClient);trackCouponUsage(transaction, sum);} catch (TException e1) {log.error("Unable to update status of transaction. Thrift Exception:", e1);} catch (TransactionServiceException e) {log.error("Unable to update status of transaction. Thrift Exception: ", e);} catch (Exception e) {log.error("Unable to update status of transaction. Thrift Exception: ", e);}}public static void processCouponTxn(long txnId, OrderType orderType){try {TransactionClient transactionServiceClient = new TransactionClient();in.shop2020.model.v1.order.TransactionService.Client transactionClient = transactionServiceClient.getClient();transactionClient.changeTransactionStatus(txnId, TransactionStatus.AUTHORIZED, "Payment by coupon successful", PickUpType.COURIER.getValue(), orderType, OrderSource.WEBSITE);Transaction transaction = transactionClient.getTransaction(txnId);UserClient userServiceClient = new UserClient();long sum = resetCart(transaction, userServiceClient);trackCouponUsage(transaction, sum);} catch (TException e1) {log.error("Unable to update status of transaction. Thrift Exception:", e1);} catch (TransactionServiceException e) {log.error("Unable to update status of transaction. Thrift Exception: ", e);} catch (Exception e) {log.error("Unable to update status of transaction. Thrift Exception: ", e);}}/*** Calculates the amount for the payment required for the given transaction.** @param txnId* Id of the transaction for which this payment amount has to be* calculated.* @return The total amount for which a payment should be created.* @throws TransactionServiceException* @throws TException*/private double calculatePaymentAmount(long txnId) throws TransactionServiceException, TException{double totalAmount = 0;TransactionClient transactionServiceClient = null;try {transactionServiceClient = new TransactionClient();} catch (Exception e) {log.error("Unable to initialize user context service client", e);throw new TransactionServiceException(100, "Unable to initialize the user service client");}in.shop2020.model.v1.order.TransactionService.Client tClient = transactionServiceClient.getClient();Transaction transaction = tClient.getTransaction(txnId);// Map<Long, Double> miscCharges = tClient.getMiscCharges(txnId);// System.out.println(miscCharges);// if(miscCharges != null & !miscCharges.isEmpty()){// totalAmount = totalAmount + miscCharges.get(1L);// }for(Order order: transaction.getOrders()){totalAmount = totalAmount + order.getTotal_amount();gvAmount = gvAmount + order.getGvAmount();}if(gvAmount>0){isGv = true;}return (totalAmount-gvAmount);}/*** Removes the items processed through the given transaction from the* shopping cart.** @param transaction* The transaction whose items have to be removed from the* shopping cart.* @param userServiceClient*/private static long resetCart(Transaction transaction, UserClient userServiceClient) {long sum = 0;Map<Long, Double> items = new HashMap<Long, Double>();for(Order order: transaction.getOrders()){sum += order.getGvAmount();for(LineItem lineitem: order.getLineitems()){Long itemId = lineitem.getItem_id();Double quantity = items.get(itemId);if(quantity==null){quantity = lineitem.getQuantity();} else {quantity= quantity + lineitem.getQuantity();}items.put(itemId, quantity);}}log.debug("Items to reset in cart are: " + items);try {//TODO Optimize the function to send less data over the wireuserServiceClient.getClient().resetCart(transaction.getShoppingCartid(), items);}catch (TException e) {log.error("Error while updating information in payment database.", e);} catch (ShoppingCartException e) {log.error("Error while reseting the cart in cart database.", e);}catch (Exception e) {log.error("Unexpected exception", e);}return sum;}/*** Mark the coupon associated with the given transaction as used.** @param transaction* The transaction to track coupon for.** @param userServiceClient* The user service client instance to use.*/private static void trackCouponUsage(Transaction transaction, long sum) {try {String couponCode = transaction.getCoupon_code();if (couponCode != null && !couponCode.isEmpty()) {PromotionClient promotionServiceClient = new PromotionClient();promotionServiceClient.getClient().trackCouponUsage(couponCode, transaction.getId(), transaction.getCustomer_id(), sum, false);}} catch (PromotionException e) {log.error("Promotion Exception: " + e);} catch (TException e) {log.error("Transport from Promotion Service failed:", e);} catch (Exception e) {log.error("Unexpected exception:", e);}}public boolean createPayment(RechargeOrder rechargeOrder, int gatewayId) {PaymentClient paymentServiceClient = null;try {paymentServiceClient = new PaymentClient();} catch (Exception e) {log.error("Error while getting payment client", e);return PAYMENT_NOT_CREATED;}amount = rechargeOrder.getTotalAmount() - rechargeOrder.getWalletAmount() - rechargeOrder.getCouponAmount();try {paymentId = paymentServiceClient.getClient().createPayment(rechargeOrder.getUserId(), amount, gatewayId, rechargeOrder.getTransactionId(), true);// This is being done to ensure that the amount which we pass on to// the PGs is same as what we have in the database.Payment payment = paymentServiceClient.getClient().getPayment(paymentId);amount = payment.getAmount();} catch (PaymentException e1) {log.error("Unable to create payment object.", e1);return PAYMENT_NOT_CREATED;} catch (TException e) {log.error("Not able to create payment object.", e);return PAYMENT_NOT_CREATED;}return true;}public static double calculateEmiAmount(String payOption, double totalAmount){double emiAmount = 0.0;List<EmiScheme> schemes = ProceedToPayController.getEmiSchemes();for(EmiScheme scheme: schemes){if(scheme.getId() == Long.parseLong(payOption)){double interestRate = scheme.getInterestRate()/12/100;emiAmount = totalAmount*interestRate*Math.pow((1+interestRate), scheme.getTenure())/(Math.pow((1+interestRate), scheme.getTenure())-1);}}return emiAmount;}public static void main(String[] args) {Map<Long, Double> miscCharges = new HashMap<Long, Double>();miscCharges.put(1L, 3.988);System.out.println(miscCharges);if(miscCharges != null & !miscCharges.isEmpty()){System.out.println( miscCharges.get(1L));;}}private static OrderType getOrderType(Long userId) throws TTransportException, TException{OrderType ot = OrderType.B2C;try {in.shop2020.model.v1.user.UserContextService.Client uc = new UserClient().getClient();PrivateDealUser pdu = uc.getPrivateDealUser(userId);if(pdu.getTin() != null && !pdu.getTin().trim().equals("")){ot = OrderType.B2B;}} catch (TTransportException e) {log.error("Unable to get user service client.", e);}return ot;}}