Subversion Repositories SmartDukaan

Rev

Rev 36305 | 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.exception.ProfitMandiBusinessException;
import com.spice.profitmandi.common.model.CustomRetailer;
import com.spice.profitmandi.common.model.ProfitMandiConstants;
import com.spice.profitmandi.common.util.FileUtil;
import com.spice.profitmandi.dao.entity.dtr.UserAccount;
import com.spice.profitmandi.dao.entity.fofo.FofoStore;
import com.spice.profitmandi.dao.entity.transaction.AddWalletRequest;
import com.spice.profitmandi.dao.entity.transaction.ManualPaymentType;
import com.spice.profitmandi.dao.entity.transaction.UserWallet;
import com.spice.profitmandi.dao.entity.transaction.UserWalletHistory;
import com.spice.profitmandi.dao.entity.user.User;
import com.spice.profitmandi.dao.enumuration.dtr.AccountType;
import com.spice.profitmandi.dao.enumuration.transaction.AddWalletRequestStatus;
import com.spice.profitmandi.dao.repository.catalog.AddWalletRequestRepository;
import com.spice.profitmandi.dao.repository.catalog.ManualPaymentRequestRepository;
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
import com.spice.profitmandi.dao.repository.dtr.PartnerOnBoardingPanelRepository;
import com.spice.profitmandi.dao.repository.dtr.RetailerRepository;
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.dao.repository.user.StoreTimelinetbRepository;
import com.spice.profitmandi.dao.repository.user.UserRepository;
import com.spice.profitmandi.service.NotificationService;
import com.spice.profitmandi.service.PartnerInvestmentService;
import com.spice.profitmandi.service.order.OrderService;
import com.spice.profitmandi.service.user.RetailerService;
import com.spice.profitmandi.service.user.StoreTimelineTatService;
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.http.ResponseEntity;
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);

    @Autowired
    ManualPaymentRequestRepository manualPaymentRequestRepository;
    @Autowired
    AddWalletRequestRepository addWalletRequestRepository;
    @Autowired
    OrderService orderService;
    @Autowired
    RetailerService retailerService;
    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
    PartnerInvestmentService partnerInvestmentService;
    private boolean underMaintainance = false;
    @Autowired
    private UserAccountRepository userAccountRepository;

    @Autowired
    private UserWalletRepository userWalletRepository;
    @Autowired
    private FofoStoreRepository fofoStoreRepository;
    @Autowired
    private UserWalletHistoryRepository userWalletHistoryRepository;
    @Autowired
    private NotificationService notificationService;

    @Autowired
    RetailerRepository retailerRepository;
    @Autowired
    PartnerOnBoardingPanelRepository partnerOnBoardingPanelRepository;
    @Autowired
    StoreTimelineTatService storeTimelineTatService;
    @Autowired
    StoreTimelinetbRepository storeTimelinetbRepository;

    @Autowired
    UserRepository userRepository;

    @Override
    public void addAmountToWallet(int retailerId, int referenceId, WalletReferenceType referenceType,
                                  String description, float amount, LocalDateTime businessTime) throws ProfitMandiBusinessException {
        if (Math.round(amount) == 0)
            return;
        UserWallet userWallet = userWalletRepository.selectByRetailerIdForUpdate(retailerId);
        userWallet.setAmount(userWallet.getAmount() + Math.round(amount));
        this.createUserWalletHistory(Math.round(amount), userWallet.getId(), referenceId, referenceType, description, businessTime);
        if (WalletReferenceType.AUTOMATED_ADVANCE.equals(referenceType)
                || WalletReferenceType.ADVANCE_AMOUNT.equals(referenceType)
                || WalletReferenceType.PAYMENT_GATEWAY.equals(referenceType)
                || WalletReferenceType.ONLINE_ORDER_PAYMENT.equals(referenceType)
                || WalletReferenceType.PURCHASE.equals(referenceType)) {
            partnerInvestmentService.evictInvestmentCache(retailerId);
        }
    }

    @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.selectByRetailerIdForUpdate(retailerId);
        int walletAmount = userWallet.getAmount();
        if (!WalletReferenceType.DAMAGE_PROTECTION.equals(referenceType) && amount > ProfitMandiConstants.MAX_NEGATIVE_WALLET_VALUE && Math.floor(amount) > walletAmount) {
            LOGGER.error("Wallet Balance is insufficient!, needed - {}, wallet has - {}, for retailer - {}", Math.floor(amount), walletAmount, retailerId);
            User user = userRepository.selectById(retailerId);
            throw new ProfitMandiBusinessException(user.getName(), walletAmount, "WLT_1000");
        }
        userWallet.setAmount(walletAmount - Math.round(amount));
        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.selectByRetailerIdForUpdate(retailerId);
        int walletAmount = userWallet.getAmount();
        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;
        UserWallet userWallet = userWalletRepository.selectByRetailerIdForUpdate(retailerId);
        int walletAmount = userWallet.getAmount();
        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.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;
    }

    //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) throws ProfitMandiBusinessException {
        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) throws ProfitMandiBusinessException {
        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 = userWallet.getAmount();
        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) {
            userWallet = new UserWallet();
            userWallet.setUserId(retailerId);
            userWalletRepository.persist(userWallet);
        }
        int sum = (int) userWalletHistoryRepository.selectSumByWallet(userWallet.getId());
        userWallet.setAmount(sum);
        return sum;
    }

    @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()));

        }
    }

    @Override
    public int getManualReference(WalletReferenceType referenceType) {
        ManualPaymentType paymentType = manualPaymentRequestRepository.selectByReferenceType(referenceType);

        if (paymentType == null) {
            paymentType = new ManualPaymentType();
            paymentType.setReferenceType(referenceType);
            manualPaymentRequestRepository.persist(paymentType);
        }
        paymentType.setCounter(paymentType.getCounter() + 1);
        return paymentType.getCounter();

    }

    @Override
    public ResponseEntity<?> createAddWalletRequestReport(LocalDateTime startDate, LocalDateTime endDate, AddWalletRequestStatus status) throws Exception {
        List<List<?>> rows = new ArrayList<>();
        List<String> header = Arrays.asList(
                "Retailer Id",
                "Retailer Name",
                "Email",
                "City",
                "State",
                "Transaction Reference",
                "Bank Name",
                "Reference Date",
                "Amount",
                "status",
                "Created On",
                "Updated On"
        );

        List<AddWalletRequest> addWalletRequests = addWalletRequestRepository.selectAllRetailerIdByDateAndStatus(startDate, endDate, status);
        Map<Integer, CustomRetailer> customRetailerMap = retailerService.getAllFofoRetailers();
        for (AddWalletRequest addWalletRequest : addWalletRequests) {
            CustomRetailer customRetailer = customRetailerMap.get(addWalletRequest.getRetailerId());
            rows.add(Arrays
                    .asList(
                            addWalletRequest.getRetailerId(),
                            customRetailer.getBusinessName(),
                            customRetailer.getEmail(),
                            customRetailer.getAddress().getCity(),
                            customRetailer.getAddress().getState(),
                            addWalletRequest.getTransaction_reference(),
                            addWalletRequest.getBank_name(),
                            addWalletRequest.getReference_date(),
                            addWalletRequest.getAmount(),
                            addWalletRequest.getStatus(),
                            addWalletRequest.getCreateTimestamp(),
                            addWalletRequest.getUpdateTimestamp()
                    )
            );
        }
        org.apache.commons.io.output.ByteArrayOutputStream baos = FileUtil.getCSVByteStream(header, rows);
        ResponseEntity<?> responseEntity = orderService.downloadReportInCsv(baos, rows, "Add-wallet-request-"+status+"-Reort-" + startDate.toLocalDate() + "-To-" + endDate.toLocalDate());
        return responseEntity;
    }
}