Subversion Repositories SmartDukaan

Rev

Rev 31420 | Rev 31921 | Go to most recent revision | View as "text/plain" | Blame | Compare with Previous | Last modification | View Log | RSS feed

package com.spice.profitmandi.service.wallet;

import com.spice.profitmandi.common.enumuration.MessageType;
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
import com.spice.profitmandi.common.model.ProfitMandiConstants;
import com.spice.profitmandi.common.util.FormattingUtils;
import com.spice.profitmandi.dao.entity.dtr.UserAccount;
import com.spice.profitmandi.dao.entity.fofo.FofoStore;
import com.spice.profitmandi.dao.entity.transaction.UserWallet;
import com.spice.profitmandi.dao.entity.transaction.UserWalletHistory;
import com.spice.profitmandi.dao.enumuration.dtr.AccountType;
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
import com.spice.profitmandi.dao.repository.dtr.UserAccountRepository;
import com.spice.profitmandi.dao.repository.transaction.UserWalletHistoryRepository;
import com.spice.profitmandi.dao.repository.transaction.UserWalletRepository;
import com.spice.profitmandi.service.NotificationService;
import com.spice.profitmandi.service.PartnerInvestmentService;
import in.shop2020.model.v1.order.WalletReferenceType;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Component
public class WalletServiceImpl implements WalletService {

        private static final Logger LOGGER = LogManager.getLogger(WalletServiceImpl.class);

        private boolean underMaintainance = false;
        ProfitMandiBusinessException pbse = new ProfitMandiBusinessException("Wallet", "Wallet",
                        "Wallet is under maintainance, please try after some time");
        ProfitMandiBusinessException inactivepbse = new ProfitMandiBusinessException("Wallet", "Wallet",
                        "Investment is incomplete, please add amount to wallet to complete the investment");

        @Autowired
        private UserAccountRepository userAccountRepository;

        @Autowired
        private WalletService walletService;

        @Autowired
        private UserWalletRepository userWalletRepository;

        @Autowired
        private FofoStoreRepository fofoStoreRepository;

        @Autowired
        private UserWalletHistoryRepository userWalletHistoryRepository;

        @Autowired
        private NotificationService notificationService;

        @Override
        public void addAmountToWallet(int retailerId, int referenceId, WalletReferenceType referenceType,
                                                                  String description, float amount, LocalDateTime businessTime) throws ProfitMandiBusinessException {
                if (amount == 0)
                        return;
                UserWallet userWallet = userWalletRepository.selectByRetailerId(retailerId);
                int walletAmount = walletService.getWalletAmount(retailerId);
                // userWallet = userWalletRepository.selectByIdForUpdate(userWallet.getId());
                userWallet.setAmount(walletAmount + Math.round(amount));
                if (amount > 0) {
                        notificationService.sendNotification(retailerId, "walletcredit", MessageType.wallet, "Rs." + FormattingUtils.formatDecimal(amount) + " credited in SD Wallet", description);
                }
                this.createUserWalletHistory(Math.round(amount), userWallet.getId(), referenceId, referenceType, description, businessTime);
        }

        @Override
        public void consumeAmountFromWallet(int retailerId, int referenceId, WalletReferenceType referenceType,
                                                                                String description, float amount, LocalDateTime businessTime) throws ProfitMandiBusinessException {
                if (underMaintainance) {
                        throw pbse;
                } else if (WalletReferenceType.RECHARGE.equals(referenceType) && !isActive(retailerId)) {
                        throw inactivepbse;
                }
                if (amount == 0)
                        return;
                UserWallet userWallet = userWalletRepository.selectByRetailerId(retailerId);
                int walletAmount = walletService.getWalletAmount(retailerId);
                // userWallet = userWalletRepository.selectByIdForUpdate(userWallet.getId());
                if (!WalletReferenceType.DAMAGE_PROTECTION.equals(referenceType) && amount > 2 && Math.floor(amount) > walletAmount) {
                        LOGGER.error("Wallet Balance is insufficient!");
                        throw new ProfitMandiBusinessException("balance", walletAmount, "WLT_1000");
                }
                userWallet.setAmount(walletAmount - Math.round(amount));
                userWalletRepository.persist(userWallet);
                this.createUserWalletHistory(-Math.round(amount), userWallet.getId(), referenceId, referenceType, description, businessTime);
        }

        @Override
        public void consumeAmountFromWallet(int retailerId, int referenceId, WalletReferenceType referenceType,
                                                                                String description, float amount, LocalDateTime businessTime, boolean forced) throws ProfitMandiBusinessException {
                if (underMaintainance) {
                        throw pbse;
                } else if (WalletReferenceType.RECHARGE.equals(referenceType) && !isActive(retailerId)) {
                        throw inactivepbse;
                }
                if (amount == 0)
                        return;
                UserWallet userWallet = userWalletRepository.selectByRetailerId(retailerId);
                int walletAmount = walletService.getWalletAmount(retailerId);
                // userWallet = userWalletRepository.selectByIdForUpdate(userWallet.getId());
                if (!forced && amount > 2 && amount > walletAmount) {
                        LOGGER.error("Wallet Balance is insufficient!");
                        throw new ProfitMandiBusinessException("balance", walletAmount, "WLT_1000");
                }
                userWallet.setAmount(walletAmount - Math.round(amount));
                this.createUserWalletHistory(-Math.round(amount), userWallet.getId(), referenceId, referenceType, description, businessTime);
        }

        @Override
        public void rollbackAmountFromWallet(int retailerId, float amountToRollback, int rollbackReference,
                                                                                 WalletReferenceType walletReferenceType, String rollbackReason, LocalDateTime businessTime) throws ProfitMandiBusinessException {

                if (amountToRollback == 0)
                        return;
                int walletAmount = walletService.getWalletAmount(retailerId);
                UserWallet userWallet = userWalletRepository.selectByRetailerId(retailerId);
                List<UserWalletHistory> uwh = userWalletHistoryRepository.selectAllByreferenceIdandreferenceType(rollbackReference, walletReferenceType)
                                .stream().filter(x -> x.getWalletId() == userWallet.getId()).collect(Collectors.toList());
                if (uwh.size() == 0) {
                        LOGGER.info("Retailer with id {} dont have valid reference {} and reference type {}",
                                        retailerId, rollbackReference, walletReferenceType);
                        throw new ProfitMandiBusinessException("Retailer specific wallet entries doesn't exist", retailerId, "Nothing to rollback");
                }
                // userWallet = userWalletRepository.selectByIdForUpdate(userWallet.getId());
                userWallet.setAmount(walletAmount - Math.round(amountToRollback));
                this.createUserWalletHistory(-Math.round(amountToRollback), userWallet.getId(), rollbackReference,
                                walletReferenceType, rollbackReason, businessTime);
                userWalletRepository.persist(userWallet);

        }

        private void createUserWalletHistory(float amount, int walletId, int referenceId, WalletReferenceType referenceType,
                                                                                 String description, LocalDateTime businessTimestamp) {
                if (amount == 0)
                        return;
                UserWalletHistory userWalletHistory = new UserWalletHistory();
                userWalletHistory.setWalletId(walletId);
                userWalletHistory.setAmount(Math.round(amount));
                userWalletHistory.setReference(referenceId);
                userWalletHistory.setReferenceType(referenceType);
                userWalletHistory.setTimestamp(LocalDateTime.now());
                userWalletHistory.setDescription(description);
                userWalletHistory.setBusinessTimestamp(businessTimestamp);
                userWalletHistoryRepository.persist(userWalletHistory);
        }

        @Override
        public UserWallet getUserWalletByUserId(int userId) throws ProfitMandiBusinessException {
                UserAccount userAccount = userAccountRepository.selectByUserIdType(userId, AccountType.saholic);

                if (underMaintainance) {
                        throw pbse;
                }
                return userWalletRepository.selectByRetailerId(Integer.valueOf(userAccount.getAccountKey()));
        }

        @Override
        public List<UserWalletHistory> getUserWalletHistoryByUserId(int userId) throws ProfitMandiBusinessException {
                if (underMaintainance || !isActive(userId)) {
                        throw pbse;
                }
                UserWallet userWallet = this.getUserWalletByUserId(userId);
                List<UserWalletHistory> userWalletHistories = userWalletHistoryRepository.selectByWalletId(userWallet.getId());
                return userWalletHistories;
        }

        @Autowired
        PartnerInvestmentService partnerInvestmentService;

        //Definition is now changed, active also means valid investment should be ok
        private boolean isActive(int userId) {
                boolean active = true;
                try {
                        FofoStore fs = fofoStoreRepository.selectByRetailerId(userId);
                        active = fs.isActive() && partnerInvestmentService.isInvestmentOk(userId, ProfitMandiConstants.MIN_INVESTMENT_PERCENTAGE, ProfitMandiConstants.CUTOFF_INVESTMENT);
                } catch (Exception e) {

                }
                return active;
        }

        @Override
        public List<UserWalletHistory> getUserWalletHistoryByRetailerId(int retailerId)
                        throws ProfitMandiBusinessException {
                if (underMaintainance) {
                        throw pbse;
                }
                UserWallet userWallet = userWalletRepository.selectByRetailerId(retailerId);
                return userWalletHistoryRepository.selectByWalletId(userWallet.getId());
        }

        @Override
        public long getSizeByRetailerId(int retailerId, LocalDateTime startDateTime, LocalDateTime endDateTime)
                        throws ProfitMandiBusinessException {
                if (underMaintainance) {
                        throw pbse;
                }
                UserWallet userWallet = userWalletRepository.selectByRetailerId(retailerId);
                return userWalletHistoryRepository.selectCountByWalletId(userWallet.getId(), startDateTime, endDateTime);
        }

        @Override
        public List<UserWalletHistory> getPaginatedUserWalletHistoryByRetailerId(int retailerId,
                                                                                                                                                         LocalDateTime startDateTime, LocalDateTime endDateTime, int offset, int limit)
                        throws ProfitMandiBusinessException {
                if (underMaintainance) {
                        throw pbse;
                }
                UserWallet userWallet = userWalletRepository.selectByRetailerId(retailerId);
                return userWalletHistoryRepository.selectPaginatedByWalletId(userWallet.getId(), startDateTime, endDateTime,
                                offset, limit);
        }

        @Override
        public Map<Integer, UserWallet> getRetailerIdUserWalletMap(Set<Integer> retailerIds) {
                List<UserWallet> userWallets = userWalletRepository.selectByRetailerIds(retailerIds);
                Map<Integer, UserWallet> retailerIdUserWalletMap = new HashMap<>();
                for (UserWallet userWallet : userWallets) {
                        retailerIdUserWalletMap.put(userWallet.getUserId(), userWallet);
                }
                return retailerIdUserWalletMap;
        }

        @Override
        public Map<Integer, Integer> getWaleltRetailerMap(Set<Integer> walletIds) {
                List<UserWallet> userWallets = userWalletRepository.selectAllById(walletIds);
                Map<Integer, Integer> walletRetailerMap = new HashMap<>();
                for (UserWallet userWallet : userWallets) {
                        walletRetailerMap.put(userWallet.getId(), userWallet.getUserId());
                }
                return walletRetailerMap;
        }

        @Override
        public boolean isExistWalletHistory(int retailerId, int referenceId, WalletReferenceType referenceType)
                        throws ProfitMandiBusinessException {
                if (underMaintainance) {
                        throw pbse;
                }
                UserWallet userWallet = userWalletRepository.selectByRetailerId(retailerId);
                return userWalletHistoryRepository.isExist(userWallet.getId(), referenceType, referenceId);
        }

        @Override
        public UserWallet getUserWallet(int retailerId) throws ProfitMandiBusinessException {
                if (underMaintainance) {
                        throw pbse;
                }
                try {
                        return userWalletRepository.selectByRetailerId(retailerId);
                } catch (Exception e) {
                        UserWallet uw = new UserWallet();
                        uw.setAmount(0);
                        uw.setRefundableAmount(0);
                        uw.setUserId(retailerId);
                        userWalletRepository.persist(uw);
                        return uw;
                }
        }

        @Override
        public float getOpeningTill(int fofoId, LocalDateTime date) throws ProfitMandiBusinessException {
                UserWallet wallet = userWalletRepository.selectByRetailerId(fofoId);
                return userWalletHistoryRepository.getSumTillDate(wallet.getId(), date);
        }

        @Override
        public float getOpeningTillExcludingPurchase(int fofoId, LocalDateTime date) throws ProfitMandiBusinessException {
                UserWallet wallet = userWalletRepository.selectByRetailerId(fofoId);
                return userWalletHistoryRepository.getSumTillDate(wallet.getId(), date) - userWalletHistoryRepository.getSumTillDate(wallet.getId(), date, WalletReferenceType.PURCHASE);
        }

        @Override
        public boolean refundToWallet(int retailerId, float amountToRefund, int transactionId,
                                                                  WalletReferenceType walletReferenceType, String description) throws ProfitMandiBusinessException {

                List<UserWalletHistory> all_entries = userWalletHistoryRepository
                                .selectAllByreferenceIdandreferenceType(transactionId, walletReferenceType);

                UserWallet userWallet = userWalletRepository.selectByRetailerId(retailerId);
                int walletAmount = walletService.getWalletAmount(retailerId);
                LOGGER.info("userWallet" + userWallet);
                int max_eligible_credit_amount = 0;

                LOGGER.info("all_entries {}", all_entries);
                for (UserWalletHistory history : all_entries) {
                        max_eligible_credit_amount -= history.getAmount();
                }
                if (max_eligible_credit_amount < amountToRefund) {
                        LOGGER.info("Cant be credited back to wallet as most of it has been already credited");
                        return false;
                }

                userWallet.setAmount(walletAmount + Math.round(amountToRefund));

                LOGGER.info("userWallet" + userWallet);

                UserWalletHistory userWalletHistory = new UserWalletHistory();
                userWalletHistory.setAmount(Math.round(amountToRefund));
                userWalletHistory.setReference(transactionId);
                userWalletHistory.setReferenceType(walletReferenceType);
                userWalletHistory.setWalletId(userWallet.getId());
                userWalletHistory.setTimestamp(LocalDateTime.now());
                userWalletHistory.setDescription(description);
                userWalletHistory.setBusinessTimestamp(all_entries.get(0).getBusinessTimestamp());

                userWalletHistoryRepository.persist(userWalletHistory);
                return true;

        }

        @Override
        public int getWalletAmount(int retailerId) throws ProfitMandiBusinessException {
                UserWallet userWallet = userWalletRepository.selectByRetailerId(retailerId);
                if (userWallet == null) {
                        return 0;
                }
                return (int) userWalletHistoryRepository.selectSumByWallet(userWallet.getId());
        }

        @Override
        public List<UserWalletHistory> getAllByReference(int fofoId, int reference, WalletReferenceType walletReferenceType)
                        throws ProfitMandiBusinessException {
                UserWallet userWallet = userWalletRepository.selectByRetailerId(fofoId);
                if (userWallet == null) {
                        return new ArrayList<UserWalletHistory>();
                }
                return userWalletHistoryRepository.selectAllByreferenceIdandreferenceType(userWallet.getId(), reference,
                                walletReferenceType);
        }

        @Override
        public void resetWallet() throws ProfitMandiBusinessException {
                List<UserWallet> userWallets = userWalletRepository.selectAll();
                for (UserWallet userWallet : userWallets) {
                        userWallet.setAmount(this.getWalletAmount(userWallet.getUserId()));

                }
        }
}