Subversion Repositories SmartDukaan

Rev

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

package com.spice.profitmandi.web.controller;

import com.google.gson.Gson;
import com.spice.profitmandi.common.enumuration.SearchType;
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
import com.spice.profitmandi.common.model.*;
import com.spice.profitmandi.common.solr.SolrService;
import com.spice.profitmandi.common.util.FileUtil;
import com.spice.profitmandi.common.util.PdfUtils;
import com.spice.profitmandi.common.util.StringUtils;
import com.spice.profitmandi.common.web.util.ResponseSender;
import com.spice.profitmandi.dao.entity.auth.AuthUser;
import com.spice.profitmandi.dao.entity.catalog.CustomerOffer;
import com.spice.profitmandi.dao.entity.catalog.CustomerOfferItem;
import com.spice.profitmandi.dao.entity.catalog.Item;
import com.spice.profitmandi.dao.entity.catalog.TagListing;
import com.spice.profitmandi.dao.entity.cs.Position;
import com.spice.profitmandi.dao.entity.dtr.*;
import com.spice.profitmandi.dao.entity.fofo.*;
import com.spice.profitmandi.dao.entity.transaction.EInvoiceDetails;
import com.spice.profitmandi.dao.entity.transaction.Order;
import com.spice.profitmandi.dao.entity.transaction.TransactionApproval;
import com.spice.profitmandi.dao.entity.transaction.UserWalletHistory;
import com.spice.profitmandi.dao.entity.user.Address;
import com.spice.profitmandi.dao.enumuration.cs.EscalationType;
import com.spice.profitmandi.dao.enumuration.dtr.PaymentOptionReferenceType;
import com.spice.profitmandi.dao.enumuration.transaction.OrderStatus;
import com.spice.profitmandi.dao.enumuration.transaction.TransactionApprovalStatus;
import com.spice.profitmandi.dao.model.ItemWiseCustomerOfferSummaryModel;
import com.spice.profitmandi.dao.model.hdfc.IrnResetOrderModel;
import com.spice.profitmandi.dao.repository.auth.AuthRepository;
import com.spice.profitmandi.dao.repository.catalog.*;
import com.spice.profitmandi.dao.repository.cs.PositionRepository;
import com.spice.profitmandi.dao.repository.dtr.*;
import com.spice.profitmandi.dao.repository.fofo.*;
import com.spice.profitmandi.dao.repository.inventory.StateRepository;
import com.spice.profitmandi.dao.repository.transaction.*;
import com.spice.profitmandi.dao.repository.user.AddressRepository;
import com.spice.profitmandi.dao.repository.user.CartRepository;
import com.spice.profitmandi.dao.service.ScratchService;
import com.spice.profitmandi.service.EmailService;
import com.spice.profitmandi.service.NotificationService;
import com.spice.profitmandi.service.authentication.RoleManager;
import com.spice.profitmandi.service.integrations.bharti.model.PlanVariant;
import com.spice.profitmandi.service.integrations.icicilombard.IciciLombardService;
import com.spice.profitmandi.service.integrations.pinelabs.PinelabsOfferCacheService;
import com.spice.profitmandi.service.integrations.pinelabs.dto.Tenure;
import com.spice.profitmandi.service.integrations.icicilombard.model.AfinityQuoteModel;
import com.spice.profitmandi.service.integrations.icicilombard.model.AfinityQuoteResponseModel;
import com.spice.profitmandi.service.integrations.oneassist.OneAssistService;
import com.spice.profitmandi.service.integrations.oneassist.model.CancelPlanRequestModel;
import com.spice.profitmandi.service.integrations.zest.InsuranceService;
import com.spice.profitmandi.service.integrations.zest.MobileInsurancePlan;
import com.spice.profitmandi.service.order.BulkOrderService;
import com.spice.profitmandi.service.order.OrderService;
import com.spice.profitmandi.service.pricing.PricingService;
import com.spice.profitmandi.service.transaction.SDCreditService;
import com.spice.profitmandi.service.transaction.TransactionService;
import com.spice.profitmandi.service.user.RetailerService;
import com.spice.profitmandi.service.wallet.WalletService;
import com.spice.profitmandi.service.whatsapp.WhatsappMessageService;
import com.spice.profitmandi.service.whatsapp.WhatsappMessageType;
import com.spice.profitmandi.web.model.LoginDetails;
import com.spice.profitmandi.web.util.CookiesProcessor;
import com.spice.profitmandi.web.util.MVCResponseSender;
import in.shop2020.model.v1.order.WalletReferenceType;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.mail.MessagingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

@Controller
@Transactional(rollbackFor = Throwable.class)
public class OrderController {

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

    private static final List<String> offlineOrders = Arrays.asList("EMIOD", "POD");
    private static final List<String> allowedDoaImeis = Arrays.asList("863903054378477");
    @Autowired
    NotificationService notificationService;
    @Autowired
    TransactionApprovalRepository transactionApprovalRepository;
    @Autowired
    LineItemRepository lineItemRepository;
    @Autowired
    AuthRepository authRepository;
    @Autowired
    TransactionService transactionService;
    @Autowired
    BulkOrderService bulkOrderService;
    @Autowired
    private CustomerRepository customerRepository;
    private boolean accessoriesDeals = true;
    @Autowired
    private RoleManager roleManager;
    @Autowired
    private Gson gson;
    @Autowired
    private CustomerReturnItemRepository customerReturnItemRepository;
    @Autowired
    private FofoOrderItemRepository fofoOrderItemRepository;
    @Autowired
    private PaymentOptionRepository paymentOptionRepository;
    @Autowired
    private StateRepository stateRepository;
    @Autowired
    private ItemRepository itemRepository;
    @Autowired
    private MVCResponseSender mvcResponseSender;
    @Autowired
    private InsuranceService insuranceService;
    @Autowired
    private FofoOrderRepository fofoOrderRepository;
    @Autowired
    private CustomerAddressRepository customerAddressRepository;
    @Autowired
    private InsurancePolicyRepository insurancePolicyRepository;
    @Autowired
    private InsuranceProviderRepository insuranceProviderRepository;
    @Autowired
    private CookiesProcessor cookiesProcessor;
    @Autowired
    private PricingService pricingService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private RetailerRegisteredAddressRepository retailerRegisteredAddressRepository;
    @Autowired
    private AddressRepository addressRepository;
    @Autowired
    private PaymentOptionTransactionRepository paymentOptionTransactionRepository;
    @Autowired
    private FofoPartnerPaymentOptionRepository fofoPartnerPaymentOptionRepository;
    @Autowired
    private ResponseSender<?> responseSender;
    @Autowired
    private PendingOrderRepository pendingOrderRepository;
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private PendingOrderItemRepository pendingOrderItemRepository;
    @Autowired
    private FofoStoreRepository fofoStoreRepository;
    @Autowired
    private RetailerService retailerService;
    @Autowired
    private CurrentInventorySnapshotRepository currentInventorySnapshotRepository;
    @Autowired
    private TagListingRepository tagListingRepository;
    @Autowired
    private PendingOrderService pendingOrderService;
    @Autowired
    private EmailService emailService;
    @Autowired
    private SolrService commonSolrService;
    @Autowired
    private MouRepository mouRepository;
    @Autowired
    private WhatsappMessageService whatsappMessageService;
    @Autowired
    private TransactionRepository transactionRepository;
    @Autowired
    WalletService walletService;
    @Autowired
    CartRepository cartRepository;
    @Autowired
    UserWalletRepository userWalletRepository;

    @Autowired
    private CatalogRepository catalogRepository;

    @Autowired
    private CustomerOfferRepository customerOfferRepository;

    @Autowired
    private CustomerOfferItemRepository customerOfferItemRepository;

    @Autowired
    private WebOfferRepository webOfferRepository;

    @Autowired
    PositionRepository positionRepository;

    @Autowired
    PendingOrderPlanRepository pendingOrderPlanRepository;

    @Autowired
    PartnerOnBoardingPanelRepository partnerOnBoardingPanelRepository;

    @Autowired
    SDCreditService sdCreditService;

    @Autowired
    IciciPolicyTrackerRepository iciciPolicyTrackerRepository;

    @Autowired
    ScratchService scratchService;

    @Autowired
    IciciLombardService iciciLombardService;

    @Autowired
    PinelabsOfferCacheService pinelabsOfferCacheService;

    @RequestMapping(value = "/wa-send-invoice", method = RequestMethod.GET)
    public String sendWhatsappMessage(HttpServletRequest request, @RequestParam(name = ProfitMandiConstants.ORDER_ID) int orderId, Model model) {
        try {
            this.sendWhatsappInvoice(fofoOrderRepository.selectByOrderId(orderId));
        } catch (Exception e) {
            LOGGER.info("Could not send whatsapp message");
            e.printStackTrace();
        }
        model.addAttribute("response1", true);
        return "response";
    }

    @RequestMapping(value = "/get-order", method = RequestMethod.GET)
    public String getOrder(HttpServletRequest request, @RequestParam(name = ProfitMandiConstants.ORDER_ID) int orderId,
                           Model model) throws ProfitMandiBusinessException {
        LoginDetails fofoDetails = cookiesProcessor.getCookiesObject(request);
        FofoOrder fofoOrder = fofoOrderRepository.selectByFofoIdAndOrderId(fofoDetails.getFofoId(), orderId);
        List<FofoOrderItem> fofoLineItems = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId());
        CustomerAddress customerAddress = null;
        if (fofoOrder.getCustomerAddressId() != 0) {
            customerAddress = customerAddressRepository.selectById(fofoOrder.getCustomerAddressId());
        }

        Customer customer = customerRepository.selectById(fofoOrder.getCustomerId());
        if (customerAddress != null) {
            customerAddress.setPhoneNumber(customer.getMobileNumber());
        }
        LOGGER.info("Added to get invoice - {}, {}", customer, 123);
        List<PaymentOptionTransaction> paymentOptionTransactions = paymentOptionTransactionRepository
                .selectByReferenceIdAndType(fofoOrder.getId(), PaymentOptionReferenceType.ORDER);
        Map<Integer, PaymentOption> paymentOptionIdPaymentOptionMap = this
                .paymentOptionIdPaymentOptionMap(paymentOptionTransactions);
        List<InsurancePolicy> insurancePolicies = insurancePolicyRepository
                .selectByRetailerIdInvoiceNumber(fofoOrder.getInvoiceNumber());
        this.addInsuranceProvider(insurancePolicies);

        model.addAttribute("fofoOrder", fofoOrder);
        model.addAttribute("fofoLineItems", fofoLineItems);
        if (customerAddress != null) {
            model.addAttribute("customerBillingAddress", orderService.getBillingAddress(customerAddress));
        } else {
            model.addAttribute("customerBillingAddress", "");

        }
        model.addAttribute("customerBillingAddressObj", customerAddress);
        model.addAttribute("customerDetailsObj", customer);
        model.addAttribute("paymentOptionTransactions", paymentOptionTransactions);
        model.addAttribute("paymentOptionIdPaymentOptionMap", paymentOptionIdPaymentOptionMap);
        model.addAttribute("insurancePolicies", insurancePolicies);
        return "order-details";
    }

    private Map<Integer, InsuranceProvider> toInsuranceProviderIdInsuranceProvider(
            List<InsuranceProvider> insuranceProviders) {
        Map<Integer, InsuranceProvider> insuranceProviderIdInsuranceProviderMap = new HashMap<>();
        for (InsuranceProvider insuranceProvider : insuranceProviders) {
            insuranceProviderIdInsuranceProviderMap.put(insuranceProvider.getId(), insuranceProvider);
        }
        return insuranceProviderIdInsuranceProviderMap;
    }

    private void addInsuranceProvider(List<InsurancePolicy> insurancePolicies) throws ProfitMandiBusinessException {
        if (insurancePolicies.isEmpty()) {
            return;
        }
        Set<Integer> insuranceProviderIds = new HashSet<>();
        for (InsurancePolicy insurancePolicy : insurancePolicies) {
            insuranceProviderIds.add(insurancePolicy.getProviderId());
        }
        LOGGER.info("insuranceProviderIds {}", insuranceProviderIds);
        List<InsuranceProvider> insuranceProviders = insuranceProviderRepository.selectByIds(insuranceProviderIds);
        Map<Integer, InsuranceProvider> insuranceProviderIdInsuranceProviderMap = this
                .toInsuranceProviderIdInsuranceProvider(insuranceProviders);
        for (InsurancePolicy insurancePolicy : insurancePolicies) {
            insurancePolicy
                    .setInsuranceProvider(insuranceProviderIdInsuranceProviderMap.get(insurancePolicy.getProviderId()));
        }
    }

    @RequestMapping(value = "/saleDetails", method = RequestMethod.GET)
    public String getSaleDetails(HttpServletRequest request,
                                 @RequestParam(name = ProfitMandiConstants.ORDER_ID) int orderId, Model model) throws Exception {
        LoginDetails fofoDetails = cookiesProcessor.getCookiesObject(request);
        boolean isAdmin = roleManager.isAdmin(fofoDetails.getRoleIds());
        FofoOrder fofoOrder = fofoOrderRepository.selectByFofoIdAndOrderId(fofoDetails.getFofoId(), orderId);
        List<FofoOrderItem> fofoOrderItems = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId());
        CustomerAddress customerAddress = customerAddressRepository.selectById(fofoOrder.getCustomerAddressId());
        List<PaymentOptionTransaction> paymentOptionTransactions = paymentOptionTransactionRepository
                .selectByReferenceIdAndType(fofoOrder.getId(), PaymentOptionReferenceType.ORDER);

        // Added Migration info as we lost it.
        if (paymentOptionTransactions == null || paymentOptionTransactions.size() == 0) {
            PaymentOptionTransaction pot = new PaymentOptionTransaction();
            pot.setAmount(fofoOrder.getTotalAmount());
            pot.setCreateTimestamp(fofoOrder.getCreateTimestamp());
            // Mark it paid through cash
            pot.setPaymentOptionId(1);
            pot.setReferenceType(PaymentOptionReferenceType.ORDER);
            paymentOptionTransactionRepository.persist(pot);
            paymentOptionTransactions.add(pot);
            LOGGER.info("Added to get invoice");
        }
        Map<Integer, PaymentOption> paymentOptionIdPaymentOptionMap = this
                .paymentOptionIdPaymentOptionMap(paymentOptionTransactions);
        List<InsurancePolicy> insurancePolicies = insurancePolicyRepository
                .selectByRetailerIdInvoiceNumber(fofoOrder.getInvoiceNumber());
        this.addInsuranceProvider(insurancePolicies);
        Map<Integer, Item> itemsMap = fofoOrderItems.stream().collect(Collectors.toMap(x -> x.getItemId(), x -> {
            try {
                return itemRepository.selectById(x.getItemId());
            } catch (ProfitMandiBusinessException e) {
                // TODO Auto-generated catch block
                return null;
            }
        }));
        Map<Integer, Set<FofoLineItem>> fofoOrderItemIdLineItemMap = fofoOrderItems.stream()
                .collect(Collectors.toMap(FofoOrderItem::getId, FofoOrderItem::getFofoLineItems));

        Map<Integer, List<CustomerReturnItem>> foiIdCustomerReturnInventoryItemsMap = fofoOrderItems.stream()
                .collect(Collectors.toMap(foi -> foi.getId(),
                        foi -> customerReturnItemRepository.selectAllByOrderItemId(foi.getId())));

        Map<Integer, Integer> inventoryItemBilledQtyMap = new HashMap<>();

        for (FofoOrderItem foi : fofoOrderItems) {
            for (FofoLineItem fli : foi.getFofoLineItems()) {
                inventoryItemBilledQtyMap.put(fli.getInventoryItemId(), fli.getQuantity());
            }
            List<CustomerReturnItem> customerReturnItems = customerReturnItemRepository
                    .selectAllByOrderItemId(foi.getId());
            this.markDoa(fofoOrder, foi, isAdmin);
            for (CustomerReturnItem customerReturnItem : customerReturnItems) {
                inventoryItemBilledQtyMap.put(customerReturnItem.getInventoryItemId(),
                        inventoryItemBilledQtyMap.get(customerReturnItem.getInventoryItemId()) - 1);
            }
        }

        LOGGER.info("fofoOrderItemIdLineItemMap {}", fofoOrderItemIdLineItemMap);
        model.addAttribute("fofoOrder", fofoOrder);
        model.addAttribute("itemsMap", itemsMap);
        model.addAttribute("fofoOrderItemIdLineItemsMap", StringUtils.toString(fofoOrderItemIdLineItemMap));
        model.addAttribute("foiIdCustomerReturnInventoryItemsMap",
                StringUtils.toString(foiIdCustomerReturnInventoryItemsMap));
        model.addAttribute("fofoOrderItemIdLineItemMap", fofoOrderItemIdLineItemMap);

        model.addAttribute("fofoOrderItems", fofoOrderItems);
        model.addAttribute("inventoryItemBilledQtyMap", StringUtils.toString(inventoryItemBilledQtyMap));
        if (customerAddress != null) {

            model.addAttribute("customerBillingAddress", orderService.getBillingAddress(customerAddress));
        } else {
            model.addAttribute("customerBillingAddress", "");

        }
        model.addAttribute("customerBillingAddressObj", customerAddress);
        model.addAttribute("paymentOptionTransactions", paymentOptionTransactions);
        model.addAttribute("paymentOptionIdPaymentOptionMap", paymentOptionIdPaymentOptionMap);
        model.addAttribute("insurancePolicies", insurancePolicies);
        model.addAttribute("markDefective", this.markDefective(fofoOrder));
        return "sale-details";
    }

    private void markDoa(FofoOrder fofoOrder, FofoOrderItem foi, boolean isAdmin) {
        if (isAdmin) {
            foi.setDoa(true);
            return;
        }
        boolean isImei = foi.getFofoLineItems().stream()
                .anyMatch(x -> org.apache.commons.lang3.StringUtils.isNotEmpty(x.getSerialNumber())
                        && allowedDoaImeis.contains(x.getSerialNumber()));
        LocalDateTime buyDate = fofoOrder.getCreateTimestamp().truncatedTo(ChronoUnit.DAYS);
        LocalDateTime curDate = LocalDateTime.now().truncatedTo(ChronoUnit.DAYS);
        if (buyDate.isAfter(curDate.minusDays(45)) || isImei) {
            foi.setDoa(true);
        } else
            foi.setDoa(
                    foi.getBrand().equals("Nokia") && foi.getCost() < 4990 && buyDate.isAfter(curDate.minusYears(1)));
    }

    private boolean markDefective(FofoOrder fofoOrder) {
        return fofoOrder.getCreateTimestamp().truncatedTo(ChronoUnit.DAYS).plusDays(180)
                .isAfter(LocalDateTime.now().truncatedTo(ChronoUnit.DAYS));

    }

    @RequestMapping(value = "/getSearchOrder")
    public String getSearchOrder(HttpServletRequest request, Model model) throws ProfitMandiBusinessException {
        return "search-order";
    }

    @RequestMapping(value = "/getInvoiceSearchOrder")
    public String getInvoiceSearchOrder(HttpServletRequest request, Model model) throws ProfitMandiBusinessException {
        return "invoices-cancel";
    }

    @RequestMapping(value = "/customerDetails", method = RequestMethod.PUT)
    public String updateCustomerDetails(HttpServletRequest request, @RequestBody CustomCustomer customCustomer,
                                        @RequestParam(name = ProfitMandiConstants.INVOICE_NUMBER) String invoiceNumber, Model model)
            throws Exception {
        LOGGER.info("CustomCustomer {}", customCustomer);

        orderService.updateCustomerDetails(customCustomer, invoiceNumber);
        return this.getSearchOrderDetails(request, invoiceNumber, model);
    }

    @RequestMapping(value = "/searchOrderDetails", method = RequestMethod.GET)
    public String getSearchOrderDetails(HttpServletRequest request,
                                        @RequestParam(name = ProfitMandiConstants.INVOICE_NUMBER) String invoiceNumber, Model model)
            throws Exception {

        FofoOrder fofoOrder = fofoOrderRepository.selectByInvoiceNumber(invoiceNumber);
        if (fofoOrder == null) {
            throw new ProfitMandiBusinessException("invalid invoice number", "invoice - " + invoiceNumber, "Please enter valid invoice number");
        }

        List<FofoOrderItem> fofoOrderItems = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId());
        Customer customer = customerRepository.selectById(fofoOrder.getCustomerId());
        CustomerAddress customerAddress = customerAddressRepository.selectById(fofoOrder.getCustomerAddressId());
        Map<Integer, PaymentOption> paymentOptionIdPaymentOptionMap = paymentOptionRepository.selectActiveOption().stream().collect(Collectors.toMap(x -> x.getId(), x -> x));
        List<Integer> fofoPartnerPaymentOptions = new ArrayList<>(paymentOptionIdPaymentOptionMap.keySet());
        Map<Integer, Item> itemsMap = fofoOrderItems.stream().collect(Collectors.toMap(x -> x.getItemId(), x -> {
            try {
                return itemRepository.selectById(x.getItemId());
            } catch (ProfitMandiBusinessException e) {
                // TODO Auto-generated catch block
                return null;
            }
        }));
        LOGGER.info("fofoPartnerPaymentOptions" + fofoPartnerPaymentOptions);
        List<PaymentOptionTransaction> paymentOptionTransactions = paymentOptionTransactionRepository
                .selectByReferenceIdAndType(fofoOrder.getId(), PaymentOptionReferenceType.ORDER);
        LOGGER.info("paymentOptionTransactions" + paymentOptionTransactions);

        Map<Integer, PaymentOptionTransaction> paymentOptionIdPaymentOptionTransactionMap = this
                .paymentOptionIdPaymentOptionTransactionMap(paymentOptionTransactions);
        LOGGER.info("paymentOptionIdPaymentOptionTransactionMap" + paymentOptionIdPaymentOptionTransactionMap.keySet());
        List<InsurancePolicy> insurancePolicies = insurancePolicyRepository
                .selectByRetailerIdInvoiceNumber(fofoOrder.getInvoiceNumber());
        this.addInsuranceProvider(insurancePolicies);
        model.addAttribute("fofoOrder", fofoOrder);
        for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
            fofoOrderItem.setDoa(true);
        }

        Map<Integer, Set<FofoLineItem>> fofoOrderItemIdLineItemMap = fofoOrderItems.stream()
                .collect(Collectors.toMap(FofoOrderItem::getId, FofoOrderItem::getFofoLineItems));

        Map<Integer, List<CustomerReturnItem>> foiIdCustomerReturnInventoryItemsMap = fofoOrderItems.stream()
                .collect(Collectors.toMap(foi -> foi.getId(),
                        foi -> customerReturnItemRepository.selectAllByOrderItemId(foi.getId())));

        Map<Integer, Integer> inventoryItemBilledQtyMap = new HashMap<>();

        for (FofoOrderItem foi : fofoOrderItems) {
            for (FofoLineItem fli : foi.getFofoLineItems()) {
                inventoryItemBilledQtyMap.put(fli.getInventoryItemId(), fli.getQuantity());
            }
            List<CustomerReturnItem> customerReturnItems = customerReturnItemRepository
                    .selectAllByOrderItemId(foi.getId());
            for (CustomerReturnItem customerReturnItem : customerReturnItems) {
                inventoryItemBilledQtyMap.put(customerReturnItem.getInventoryItemId(),
                        inventoryItemBilledQtyMap.get(customerReturnItem.getInventoryItemId()) - 1);
            }
        }
        model.addAttribute("foiIdCustomerReturnInventoryItemsMap",
                StringUtils.toString(foiIdCustomerReturnInventoryItemsMap));
        model.addAttribute("fofoOrderItems", fofoOrderItems);
        model.addAttribute("inventoryItemBilledQtyMap", StringUtils.toString(inventoryItemBilledQtyMap));
        model.addAttribute("fofoOrderItemIdLineItemsMap", StringUtils.toString(fofoOrderItemIdLineItemMap));
        model.addAttribute("itemsMap", itemsMap);
        model.addAttribute("markDefective", true);
        model.addAttribute("customer", customer);
        model.addAttribute("customerAddress", customerAddress);
        model.addAttribute("paymentOptionTransactions", paymentOptionTransactions);
        model.addAttribute("paymentOptionIdPaymentOptionMap", paymentOptionIdPaymentOptionMap);
        model.addAttribute("paymentOptionIdPaymentOptionTransactionMap", paymentOptionIdPaymentOptionTransactionMap);
        model.addAttribute("insurancePolicies", insurancePolicies);
        model.addAttribute("fofoPartnerPaymentOptions", fofoPartnerPaymentOptions);
        model.addAttribute("totalNumberOfPaymentOptionId", fofoPartnerPaymentOptions.size());
        model.addAttribute("stateNames",
                stateRepository.selectAll().stream().map(x -> x.getName()).collect(Collectors.toList()));
        return "search-order-details";
    }

    private Map<Integer, PaymentOption> paymentOptionIdPaymentOptionMap(
            List<PaymentOptionTransaction> paymentOptionTransactions) throws ProfitMandiBusinessException {
        Set<Integer> paymentOptionIds = new HashSet<>();
        for (PaymentOptionTransaction paymentOptionTransaction : paymentOptionTransactions) {
            paymentOptionIds.add(paymentOptionTransaction.getPaymentOptionId());
        }
        List<PaymentOption> paymentOptions = paymentOptionRepository.selectByIds(paymentOptionIds);
        Map<Integer, PaymentOption> paymentOptionIdPaymentOptionMap = new HashMap<>();
        for (PaymentOption paymentOption : paymentOptions) {
            paymentOptionIdPaymentOptionMap.put(paymentOption.getId(), paymentOption);
        }
        return paymentOptionIdPaymentOptionMap;
    }

    private Map<Integer, PaymentOption> paymentOptionIdPaymentOptionMapUsingPaymentOptions(
            List<Integer> fofoPartnerPaymentOptions) throws ProfitMandiBusinessException {
        List<PaymentOption> paymentOptions = paymentOptionRepository
                .selectByIds(new HashSet<>(fofoPartnerPaymentOptions));
        Map<Integer, PaymentOption> paymentOptionIdPaymentOptionMap = new HashMap<>();
        for (PaymentOption paymentOption : paymentOptions) {
            paymentOptionIdPaymentOptionMap.put(paymentOption.getId(), paymentOption);
        }
        return paymentOptionIdPaymentOptionMap;
    }

    private Map<Integer, PaymentOptionTransaction> paymentOptionIdPaymentOptionTransactionMap(
            List<PaymentOptionTransaction> paymentOptionTransactions) {
        Map<Integer, PaymentOptionTransaction> paymentOptionIdPaymentOptionTransactionMap = new HashMap<>();
        for (PaymentOptionTransaction paymentOptionTransaction : paymentOptionTransactions) {
            paymentOptionIdPaymentOptionTransactionMap.put(paymentOptionTransaction.getPaymentOptionId(),
                    paymentOptionTransaction);
        }
        return paymentOptionIdPaymentOptionTransactionMap;
    }

    @RequestMapping(value = "/checkplans", method = RequestMethod.GET)
    public String getInsurancePrices(HttpServletRequest request, @RequestParam float price, Model model,
                                     @RequestParam int itemId, @RequestParam int poiId) throws ProfitMandiBusinessException {
        LOGGER.info("Request received at url : {}", request.getRequestURI());

        try {
            String response = mvcResponseSender.createResponseString(this.getPlans(price, itemId, poiId));
            model.addAttribute("response1", response);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            LOGGER.info(e.getMessage(), e);
            throw new ProfitMandiBusinessException("Plans", "Plans API", "Error formatting insurance plans");
        }

        return "response";
    }

    @RequestMapping(value = "/getPlanQuote", method = RequestMethod.GET)
    public String getPlanQuote(HttpServletRequest request, Model model,
                               @RequestParam String planCode, @RequestParam int sumInsured, @RequestParam String manufacturedDate, @RequestParam int itemId, @RequestParam String planName) throws ProfitMandiBusinessException {

        try {

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy");
            LocalDate manufactured = LocalDate.parse(manufacturedDate, formatter);

            PlanVariant planVariant = insuranceService.getICICIPremiumByVariantId(planCode);

            LOGGER.info("planVariant111 {}", planVariant);

            String correlationId = UUID.randomUUID().toString();
            IciciPolicyTracker policyTracker = new IciciPolicyTracker();
            policyTracker.setCorrelationId(correlationId);
            iciciPolicyTrackerRepository.persist(policyTracker);

            // Policy validity (1 year from today)
            LocalDate today = LocalDate.now();
            LocalDate oneYearLater = today.plusYears(1);

            String itemBrand = itemRepository.selectById(itemId).getBrand();

            AfinityQuoteModel quoteModel = new AfinityQuoteModel();
            quoteModel.setProductCode(iciciLombardService.PRODUCT_CODE_STAGGING);
            quoteModel.setPlanCode(String.valueOf(planVariant.getOurPlanId()));
            quoteModel.setPlanName(planName);
            quoteModel.setSumInsured((int) sumInsured);
            quoteModel.setPolicyStartDate(today.toString());          // format: yyyy-MM-dd
            quoteModel.setPolicyEndDate(oneYearLater.toString());
            quoteModel.setTaxEffectiveDate(today.toString());
            quoteModel.setPolicyType("New");
            quoteModel.setIlgicStateName(iciciLombardService.PARTY_STATE_NAME);
            quoteModel.setPartyStateName(iciciLombardService.PARTY_STATE_NAME);
            quoteModel.setUserLevel("UW3");
            quoteModel.setNoOfClaimsAllowed(999);
            quoteModel.setMakeAndModelOfGadget("High");
            quoteModel.setPremiumBeforeEndorsementCancellation(0);
            quoteModel.setGeographicalLimit("WithinIndia");
            quoteModel.setTransactionDate(today.toString());
            quoteModel.setEndorsementEffectiveDate(today.toString());
            quoteModel.setRegisteredCustomer(true);
            quoteModel.setCorrelationId(correlationId);

            // Set cover details
            AfinityQuoteModel.CoverDetail coverDetail = new AfinityQuoteModel.CoverDetail();
            coverDetail.setName("Accidental Damage");
            coverDetail.setPremium(0);

            // Set risk details
            AfinityQuoteModel.RiskDetail riskDetail = new AfinityQuoteModel.RiskDetail();
            riskDetail.setRiskSIComponent("MOBILE");
            riskDetail.setCoverDetails(Arrays.asList(coverDetail));

            quoteModel.setRisksDetails(Arrays.asList(riskDetail));

            AfinityQuoteResponseModel afinityQuoteResponseModel = iciciLombardService.hitAfinityQuote(quoteModel);
            float planDp = insuranceService.getPlanDp(afinityQuoteResponseModel.getTotalPremium(), planVariant.getCoverage());

            Map<String, Object> responseMap = new HashMap<>();
            responseMap.put("afinityQuoteModel", afinityQuoteResponseModel);
            responseMap.put("planDp", planDp);
            model.addAttribute("response1", mvcResponseSender.createResponseString(responseMap));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            LOGGER.info(e.getMessage(), e);
            throw new ProfitMandiBusinessException("Plans", "Plans Quote", "Error qutotation insurance plans");
        }

        return "response";
    }

    private boolean sendWhatsappInvoice(FofoOrder fofoOrder) throws Exception {
        return this.sendWhatsappInvoice(fofoOrder, "");
    }

    private boolean sendWhatsappInvoice(FofoOrder fofoOrder, String whatsAppNo) throws Exception {
        boolean shouldSendWhatsappMessage = notificationService.shouldSendWhatsappMessage(whatsAppNo);
        boolean isSend = false;
        if (shouldSendWhatsappMessage) {
            Customer customer = customerRepository.selectById(fofoOrder.getCustomerId());
            String mobileNumber;
            if (!whatsAppNo.isEmpty()) {
                mobileNumber = whatsAppNo;
            } else {
                mobileNumber = customer.getMobileNumber();
            }
            CustomRetailer retailer = retailerService.getFofoRetailer(fofoOrder.getFofoId());
            String message = String.format("Dear %s,\n" +
                    "Thank you for your purchase from SmartDukaan store - %s, %s.\n" +
                    "Your purchase invoice is attached for your reference.\n" +
                    "\n" +
                    "Download our app for offers and updates on new products.\n" +
                    "https://www.smartdukaan.com/b2c\n" +
                    "\n" +
                    "Best Regards\n" +
                    "SmartDukaan", customer.getFirstName(), retailer.getBusinessName(), retailer.getAddress().getCity());

            isSend = notificationService.sendWhatsappMediaMessage(message, mobileNumber, this.getPublicInvoiceUrl(fofoOrder.getInvoiceNumber()),
                    this.getFileName(fofoOrder.getInvoiceNumber()), WhatsappMessageType.DOCUMENT);
        }
        return isSend;
    }

    private String getFileName(String invoiceNumber) {
        return "INV-" + invoiceNumber.replace("/", "-") + ".pdf";
    }

    private String getPublicInvoiceUrl(String invoiceNumber) {
        String base64Encoded = Base64.getMimeEncoder().encodeToString(invoiceNumber.getBytes(StandardCharsets.UTF_8));
        String publicUrl = "https://partners.smartdukaan.com/wa-invoice-send/" + base64Encoded + ".pdf";
        LOGGER.info("Public Whatsapp Url for Invoice Message - {}", publicUrl);
        return publicUrl;
    }

    @RequestMapping(value = "/order/bad_return", method = RequestMethod.POST)
    public ResponseEntity<?> badReturn(HttpServletRequest request, @RequestBody FoiBadReturnRequest foiBadReturnRequest,
                                       Model model) throws ProfitMandiBusinessException {
        LOGGER.info("request at uri {} body {}", request.getRequestURI(), foiBadReturnRequest);
        LoginDetails fofoDetails = cookiesProcessor.getCookiesObject(request);
        CustomerCreditNote custmoerCreditNote;
        if (roleManager.isAdmin(fofoDetails.getRoleIds())) {
            FofoOrderItem foi = fofoOrderItemRepository.selectById(foiBadReturnRequest.getFofoOrderItemId());
            FofoOrder fo = fofoOrderRepository.selectByOrderId(foi.getOrderId());
            custmoerCreditNote = orderService.badReturn(fofoDetails.getEmailId(), fo.getFofoId(), foiBadReturnRequest);
        } else {
            custmoerCreditNote = orderService.badReturn(fofoDetails.getFofoId(), foiBadReturnRequest);
        }
        return responseSender.ok(custmoerCreditNote.getId());
    }

    @GetMapping(value = "/wa-invoice-send/{invoiceHash}")
    public ResponseEntity<?> generateInvoice(@PathVariable String invoiceHash) throws ProfitMandiBusinessException {
        String decodedInvoiceNumber = new String(Base64.getMimeDecoder().decode(invoiceHash));
        LOGGER.info("Invoice Hash {}", invoiceHash);


        FofoOrder fofoOrder = fofoOrderRepository.selectByInvoiceNumber(decodedInvoiceNumber);

        InvoicePdfModel pdfModel = orderService.getInvoicePdfModel(fofoOrder.getId());

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        PdfUtils.generateAndWrite(Arrays.asList(pdfModel), byteArrayOutputStream);
        final HttpHeaders headers = new HttpHeaders();
        //headers.setContentDispositionFormData("inline", number + ".pdf");
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "inline;filename=" + pdfModel.getInvoiceNumber() + ".pdf");
        int contentLength = byteArrayOutputStream.toByteArray().length;
        final InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        final InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
        return ResponseEntity.ok()
                .headers(headers)
                .contentLength(contentLength)
                .contentType(MediaType.parseMediaType("application/pdf"))
                .body(inputStreamResource);
    }

    @RequestMapping(value = "/wa-listen", method = RequestMethod.POST)
    public ResponseEntity<?> listenWhatsappStatus(@RequestBody String whatsappJsonResponse) {
        LOGGER.info("whatsappJsonResponse {}", whatsappJsonResponse);
        //jaihind
        //  String jsonString = "[{\"srcAddr\":\"TESTSM\",\"channel\":\"WHATSAPP\",\"externalId\":\"4977024756456780043-180044363908187691\",\"cause\":\"SUCCESS\",\"errorCode\":\"000\",\"destAddr\":\"919813272029\",\"eventType\":\"DELIVERED\",\"eventTs\":1692848106000}]";
        JSONArray jsonArray = new JSONArray(whatsappJsonResponse);
        for (int i = 0; i < jsonArray.length(); i++) {

            JSONObject jsonObject = jsonArray.getJSONObject(i);
            String externalId = jsonObject.getString("externalId");
            String destAddr = jsonObject.getString("destAddr");
            String eventType = jsonObject.getString("eventType");
            whatsappMessageService.setWhatsappResponse(externalId, destAddr, eventType);
        }
        //jaihind
        return responseSender.ok("Success");

    }

    @RequestMapping(value = "/generateInvoice")
    public ResponseEntity<?> generateInvoice(HttpServletRequest request, HttpServletResponse response,
                                             @RequestParam(name = ProfitMandiConstants.ORDER_ID) int orderId) throws ProfitMandiBusinessException {
        LOGGER.info("Request received at url {} with params [{}={}] ", request.getRequestURI(),
                ProfitMandiConstants.ORDER_ID, orderId);
        LoginDetails fofoDetails = cookiesProcessor.getCookiesObject(request);
        InvoicePdfModel pdfModel = null;
        if (roleManager.isAdmin(fofoDetails.getRoleIds())) {
            pdfModel = orderService.getInvoicePdfModel(orderId);
        } else {
            pdfModel = orderService.getInvoicePdfModel(fofoDetails.getFofoId(), orderId);
        }
        FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(orderId);
        List<InsurancePolicy> insurancePolicies = insurancePolicyRepository.selectByRetailerIdInvoiceNumber(fofoOrder.getInvoiceNumber());

        // Step 1: Generate invoice PDF
        ByteArrayOutputStream invoiceOutput = new ByteArrayOutputStream();
        PdfUtils.generateAndWrite(Arrays.asList(pdfModel), invoiceOutput);
        byte[] invoicePdf = invoiceOutput.toByteArray();

        // Step 2: Load all policy certificate PDFs
        List<byte[]> pdfFiles = new ArrayList<>();
        pdfFiles.add(invoicePdf); // first add invoice

        for (InsurancePolicy insurancePolicy : insurancePolicies) {
            if (insurancePolicy.getProviderId() == 6) {
                String policyNumber = insurancePolicy.getPolicyNumber();
                String safePolicyNo = policyNumber.replace("/", "-");
                String filePath = "/uploads/policy-certificate-" + safePolicyNo + ".pdf";
                File file = new File(filePath);

                if (file.exists()) {
                    try {
                        byte[] policyPdf = Files.readAllBytes(file.toPath());
                        pdfFiles.add(policyPdf);
                    } catch (IOException e) {
                        LOGGER.error("Failed to read policy PDF: {}", filePath, e);
                    }
                } else {
                    LOGGER.warn("Policy PDF not found: {}", filePath);
                }
            }
        }

        // Step 3: Merge all PDFs
        byte[] mergedPdf;
        try {
            mergedPdf = PdfUtils.mergePdfFiles(pdfFiles);
        } catch (Exception e) {
            LOGGER.error("Error merging PDFs", e);
            throw new ProfitMandiBusinessException("Failed to generate merged PDF", "", "");
        }

        // Step 4: Return merged PDF as response
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_PDF);
        headers.setContentDispositionFormData("inline", "invoice-with-policies-" + pdfModel.getInvoiceNumber() + ".pdf");
        headers.setContentLength(mergedPdf.length);

        InputStreamResource resource = new InputStreamResource(new ByteArrayInputStream(mergedPdf));
        return new ResponseEntity<>(resource, headers, HttpStatus.OK);
    }

   /* @RequestMapping(value = "/generateInvoice")
    public ResponseEntity<?> generateInvoice(HttpServletRequest request, HttpServletResponse response,
                                             @RequestParam(name = ProfitMandiConstants.ORDER_ID) int orderId, @RequestParam(required = false) PrinterType printerType) throws ProfitMandiBusinessException {
        LOGGER.info("Request received at url {} with params [{}={}] ", request.getRequestURI(),
                ProfitMandiConstants.ORDER_ID, orderId);
        LoginDetails fofoDetails = cookiesProcessor.getCookiesObject(request);
        InvoicePdfModel pdfModel = null;
        int fofoId;
        if (roleManager.isAdmin(fofoDetails.getRoleIds())) {
            pdfModel = orderService.getInvoicePdfModel(orderId);
            fofoId = pdfModel.getCustomer().getCustomerId();
        } else {
            pdfModel = orderService.getInvoicePdfModel(fofoDetails.getFofoId(), orderId);
            fofoId = fofoDetails.getFofoId();
        }

        if (printerType == null) {
            FofoStore fs = fofoStoreRepository.selectByRetailerId(fofoId);
            //printerType = fs.getPrinterType();
        }


        FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(orderId);
        List<InsurancePolicy> insurancePolicies = insurancePolicyRepository.selectByRetailerIdInvoiceNumber(fofoOrder.getInvoiceNumber());

        // Step 1: Generate invoice PDF
        ByteArrayOutputStream invoiceOutput = new ByteArrayOutputStream();

        PdfUtils.generateAndWrite(Arrays.asList(pdfModel), printerType, invoiceOutput);
        byte[] invoicePdf = invoiceOutput.toByteArray();

        // Step 2: Load all policy certificate PDFs
        List<byte[]> pdfFiles = new ArrayList<>();
        pdfFiles.add(invoicePdf); // first add invoice

        for (InsurancePolicy insurancePolicy : insurancePolicies) {
            if (insurancePolicy.getProviderId() == 6) {
                String policyNumber = insurancePolicy.getPolicyNumber();
                String safePolicyNo = policyNumber.replace("/", "-");
                String filePath = "/uploads/policy-certificate-" + safePolicyNo + ".pdf";
                File file = new File(filePath);

                if (file.exists()) {
                    try {
                        byte[] policyPdf = Files.readAllBytes(file.toPath());
                        pdfFiles.add(policyPdf);
                    } catch (IOException e) {
                        LOGGER.error("Failed to read policy PDF: {}", filePath, e);
                    }
                } else {
                    LOGGER.warn("Policy PDF not found: {}", filePath);
                }
            }

        }

        // Step 3: Merge all PDFs
        byte[] mergedPdf;
        try {
            mergedPdf = PdfUtils.mergePdfFiles(pdfFiles);
        } catch (Exception e) {
            LOGGER.error("Error merging PDFs", e);
            throw new ProfitMandiBusinessException("Failed to generate merged PDF", "", "");
        }

        // Step 4: Return merged PDF as response
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_PDF);
        headers.setContentDispositionFormData("inline", "invoice-with-policies-" + pdfModel.getInvoiceNumber() + ".pdf");
        headers.setContentLength(mergedPdf.length);

        InputStreamResource resource = new InputStreamResource(new ByteArrayInputStream(mergedPdf));
        return new ResponseEntity<>(resource, headers, HttpStatus.OK);
    }*/

    @RequestMapping(value = "/generateInvoices")
    public ResponseEntity<?> generateInvoice(HttpServletRequest request, HttpServletResponse response,
                                             @RequestParam LocalDateTime startDate, @RequestParam LocalDateTime endDate, @RequestParam int partnerId)
            throws ProfitMandiBusinessException {
        LoginDetails fofoDetails = cookiesProcessor.getCookiesObject(request);
        List<InvoicePdfModel> pdfModels = new ArrayList<>();
        if (roleManager.isAdmin(fofoDetails.getRoleIds())) {
            List<Integer> orderIds = fofoOrderRepository.selectByFofoId(partnerId, startDate, endDate, 0, 0).stream()
                    .map(x -> x.getId()).collect(Collectors.toList());
            for (int orderId : orderIds) {
                pdfModels.add(orderService.getInvoicePdfModel(orderId));
            }
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            PdfUtils.generateAndWrite(pdfModels, byteArrayOutputStream);
            LOGGER.info("Pdf Stream length {}", byteArrayOutputStream.toByteArray().length);
            final HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_PDF);
            headers.set("Content-disposition", "inline; filename=invoice-" + partnerId + ".pdf");
            headers.setContentLength(byteArrayOutputStream.toByteArray().length);
            final InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            final InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
            return new ResponseEntity<InputStreamResource>(inputStreamResource, headers, HttpStatus.OK);
        } else {
            throw new ProfitMandiBusinessException("Auth", fofoDetails.getEmailId(), "Unauthorised access");
        }
    }

    @RequestMapping(value = "/saleHistory")
    public String saleHistory(HttpServletRequest request,
                              @RequestParam(name = "searchValue", defaultValue = "") String searchValue,
                              @RequestParam(name = "searchType", defaultValue = "") SearchType searchType,
                              @RequestParam(required = false) LocalDateTime startTime,
                              @RequestParam(required = false) LocalDateTime endTime,
                              @RequestParam(name = "offset", defaultValue = "0") int offset,
                              @RequestParam(name = "limit", defaultValue = "10") int limit, Model model)
            throws ProfitMandiBusinessException {
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);

        Map<String, Object> map = orderService.getSaleHistory(loginDetails.getFofoId(), searchType, searchValue,
                startTime, endTime, offset, limit);
        model.addAllAttributes(map);
        return "sale-history";
    }

    @RequestMapping(value = "/downloadInvoices")
    public ResponseEntity<?> downloadInvoices(HttpServletRequest request,
                                              @RequestParam(name = "searchValue", defaultValue = "") String searchValue,
                                              @RequestParam(name = "searchType", defaultValue = "") SearchType searchType,
                                              @RequestParam(required = false) LocalDateTime startTime,
                                              @RequestParam(required = false) LocalDateTime endTime,
                                              @RequestParam(name = "offset", defaultValue = "0") int offset,
                                              @RequestParam(name = "limit", defaultValue = "10") int limit, Model model)
            throws ProfitMandiBusinessException {
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);

        Map<String, Object> map = orderService.getSaleHistory(loginDetails.getFofoId(), searchType, searchValue,
                startTime, endTime, offset, 100);
        List<FofoOrder> fofoOrders = (List<FofoOrder>) map.get("saleHistories");

        if (fofoOrders.size() == 0) {
            throw new ProfitMandiBusinessException("Search criteria", "", "No orders found for criteria");
        }

        final HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_PDF);
        headers.set("Content-disposition", "inline; filename=invoices.pdf");
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        List<InvoicePdfModel> pdfModels = new ArrayList<>();
        for (FofoOrder fofoOrder : fofoOrders) {
            try {
                pdfModels.add(orderService.getInvoicePdfModel(fofoOrder.getId()));
            } catch (Exception e) {
                LOGGER.info("could not create invoice for {}, invoice number {}", fofoOrder.getId(),
                        fofoOrder.getInvoiceNumber());
            }
        }
        PdfUtils.generateAndWrite(pdfModels, byteArrayOutputStream);
        headers.setContentLength(byteArrayOutputStream.toByteArray().length);
        final InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        final InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
        return new ResponseEntity<InputStreamResource>(inputStreamResource, headers, HttpStatus.OK);
    }

    @RequestMapping(value = "/credit-note/{creditNoteId}")
    public ResponseEntity<?> downloadCreditNote(HttpServletRequest request, @PathVariable int creditNoteId)
            throws ProfitMandiBusinessException {
        CreditNotePdfModel creditNotePdfModel = orderService.getCreditNotePdfModel(creditNoteId);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        PdfUtils.generateAndWriteCustomerCreditNotes(Arrays.asList(creditNotePdfModel), byteArrayOutputStream);
        LOGGER.info("Pdf Stream length {}", byteArrayOutputStream.toByteArray().length);
        final HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_PDF);
        headers.set("Content-disposition",
                "inline; filename=invoice-" + creditNotePdfModel.getCreditNoteNumber() + ".pdf");
        headers.setContentLength(byteArrayOutputStream.toByteArray().length);
        final InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        final InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
        return new ResponseEntity<InputStreamResource>(inputStreamResource, headers, HttpStatus.OK);
    }

    @RequestMapping(value = "/getPaginatedSaleHistory")
    public String getSaleHistoryPaginated(HttpServletRequest request,
                                          @RequestParam(name = "searchValue", defaultValue = "") String searchValue,
                                          @RequestParam(name = "searchType", defaultValue = "") SearchType searchType,
                                          @RequestParam(required = false) LocalDateTime startTime,
                                          @RequestParam(required = false) LocalDateTime endTime,
                                          @RequestParam(name = "offset", defaultValue = "0") int offset,
                                          @RequestParam(name = "limit", defaultValue = "10") int limit, Model model)
            throws ProfitMandiBusinessException {
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
        Map<String, Object> map = orderService.getSaleHistoryPaginated(loginDetails.getFofoId(), searchType,
                searchValue, startTime, endTime, offset, limit);
        model.addAllAttributes(map);
        return "sale-history-paginated";
    }

    @PutMapping(value = "/updatePaymentTransaction")
    public String updateTransactionDetails(HttpServletRequest request, @RequestParam String referenceType,
                                           @RequestParam int fofoId, @RequestParam int referenceId,
                                           @RequestBody PartnerOptionsAndItemAmountModel partnerOptionsAndItemAmountModel,
                                           @RequestParam float totalAmount, Model model) throws Exception {

        List<PaymentOptionTransactionModel> paymentOptionTransactionModels = partnerOptionsAndItemAmountModel
                .getPaymentOptionTransactionModel();
        LOGGER.info(paymentOptionTransactionModels);
        FofoOrder fofoOrder = fofoOrderRepository.selectByFofoIdAndOrderId(fofoId, referenceId);
        LOGGER.info("sdssd" + fofoOrder);
        fofoOrder.setTotalAmount(totalAmount);
        List<FofoItemIdAmountModel> fofoItemIdAmountModel = partnerOptionsAndItemAmountModel.getItemAmountModel();
        for (FofoItemIdAmountModel fim : fofoItemIdAmountModel) {
            LOGGER.info("fim" + fim.getFofoItemId());

            LOGGER.info("fimAmount" + fim.getAmount());
            Item item = itemRepository.selectById(fim.getItemId());
            TagListing tagListing = tagListingRepository.selectByItemId(item.getId());
            FofoOrderItem fofoOrderItem = fofoOrderItemRepository.selectById(fim.getFofoItemId());
            LOGGER.info("category" + item.getCategoryId());
            if (item.getCategoryId() == ProfitMandiConstants.MOBILE_CATEGORY_ID) {
                if (fofoOrderItem.getMop() <= fim.getAmount()) {

                    if (fim.getAmount() <= tagListing.getMrp()) {
                        fofoOrderItem.setSellingPrice(fim.getAmount());
                    } else {
                        throw new ProfitMandiBusinessException("Amount", fim.getAmount(),
                                "Sum of amount is not less than  to MRP");
                    }

                    LOGGER.info("fofoOrderItem2" + fofoOrderItem);

                } else {
                    // TODO below mop condition need to added added
                    fofoOrderItem.setSellingPrice(fim.getAmount());
                }

            } else {
                fofoOrderItem.setSellingPrice(fim.getAmount());
                LOGGER.info("fofoOrderItem1" + fofoOrderItem);

            }
            LOGGER.info("fofoOrderItem" + fofoOrderItem);

        }

        /*
         * for (PaymentOptionTransactionModel paymentOptionTransactionModel :
         * paymentOptionTransactionModels) { amount = amount +
         * paymentOptionTransactionModel.getAmount(); } LOGGER.info("FofoOrder amount" +
         * fofoOrder.getUnitPrice() + "amount" + amount); if (amount ==
         * fofoOrder.getUnitPrice()) {
         */
        if (paymentOptionTransactionModels.size() > 0) {
            List<PaymentOptionTransaction> paymentOptionTransactions = paymentOptionTransactionRepository
                    .selectByReferenceIdAndType(referenceId, PaymentOptionReferenceType.ORDER);
            Map<Integer, PaymentOptionTransaction> paymentOptionIdPaymentOptionTransactionMap = this
                    .paymentOptionIdPaymentOptionTransactionMap(paymentOptionTransactions);
            LOGGER.info(
                    "paymentOptionIdPaymentOptionTransactionMap" + paymentOptionIdPaymentOptionTransactionMap.keySet());
            for (PaymentOptionTransactionModel paymentOptionTransactionModel : paymentOptionTransactionModels) {
                if (paymentOptionIdPaymentOptionTransactionMap
                        .containsKey(paymentOptionTransactionModel.getPaymentOptionId())) {

                    PaymentOptionTransaction paymentOptionTransaction = paymentOptionIdPaymentOptionTransactionMap
                            .get(paymentOptionTransactionModel.getPaymentOptionId());

                    if (paymentOptionTransactionModel.getAmount() == 0) {
                        paymentOptionTransactionRepository.delete(paymentOptionTransaction);
                        LOGGER.info("deleted successfully");
                    } else {

                        paymentOptionTransaction.setAmount(paymentOptionTransactionModel.getAmount());
                        paymentOptionTransactionRepository.persist(paymentOptionTransaction);
                        LOGGER.info("updated successfully");

                    }
                } else {
                    if (paymentOptionTransactionModel.getAmount() > 0) {
                        PaymentOptionTransaction paymentOptionTransaction = new PaymentOptionTransaction();
                        paymentOptionTransaction.setReferenceId(referenceId);
                        paymentOptionTransaction.setReferenceType(PaymentOptionReferenceType.ORDER);
                        paymentOptionTransaction.setPaymentOptionId(paymentOptionTransactionModel.getPaymentOptionId());
                        paymentOptionTransaction.setAmount(paymentOptionTransactionModel.getAmount());
                        paymentOptionTransaction.setFofoId(fofoId);
                        paymentOptionTransaction.setCreateTimestamp(fofoOrder.getCreateTimestamp());
                        paymentOptionTransactionRepository.persist(paymentOptionTransaction);
                        LOGGER.info("inserted successfully");
                    }
                }

            }

            model.addAttribute("response1", mvcResponseSender.createResponseString(true));
        }
        /*
         * else
         *
         * { throw new ProfitMandiBusinessException("Amount", amount,
         * "Sum of amount is not equal to total amount"); }
         */

        return "response";

    }

    @RequestMapping(value = "/order")
    public String orderIndex(HttpServletRequest request, @RequestParam(name = "cartData") String cartData, Model model)
            throws ProfitMandiBusinessException {
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);

        int addressId = retailerRegisteredAddressRepository.selectAddressIdByRetailerId(loginDetails.getFofoId());
        Address address = addressRepository.selectById(addressId);

        List<CartFofo> cartItems = orderService.cartCheckout(cartData);
        Set<Integer> itemIds = new HashSet<>();
        List<Integer> poIds = new ArrayList<>();
        List<Integer> poItemIds = new ArrayList<>();
        for (CartFofo cartFofo : cartItems) {
            itemIds.add(cartFofo.getItemId());
            if (cartFofo.getPoId() != 0) {
                poIds.add(cartFofo.getPoId());
                poItemIds.add(cartFofo.getPoItemId());
            }
        }

        PendingOrder po = null;
        Customer customer = null;
        PendingOrderItem poi = null;
        Map<Integer, PriceModel> mopPriceMap = pricingService.getPurchasePriceMopPriceNotFound(itemIds,
                loginDetails.getFofoId());
        List<Integer> paymentOptionIds = fofoPartnerPaymentOptionRepository
                .selectPaymentOptionIdsByFofoId(loginDetails.getFofoId());

        if (!poIds.isEmpty()) {
            po = pendingOrderRepository.selectById(poIds.get(0));
            customer = customerRepository.selectById(po.getCustomerId());
            if (!offlineOrders.contains(po.getPayMethod())) {
                paymentOptionIds.add(23);
            }
        }

        if (!poItemIds.isEmpty()) {
            poi = pendingOrderItemRepository.selectById(poItemIds.get(0));
        }

        // List<PaymentOption> paymentOptions = paymentOptionRepository.selectByIds(new
        // HashSet<>(paymentOptionIds));

        List<PaymentOption> paymentOptions = paymentOptionRepository.selectActiveOption();

        LOGGER.info("pendingOrder" + po);
        LOGGER.info("pendingOrderItem" + poi);

        int onlineSellingPrice = 0;
        Map<Integer, PendingOrderItem> itemIdAndPoiMap = new HashMap<>();

        if (po != null) {
            List<PendingOrderItem> pendingOrderItems = pendingOrderItemRepository.selectByOrderId(po.getId());
            if (!(po.getPayMethod().equals("EMIOD") || po.getPayMethod().equals("POD"))) {
                for (CartFofo cartItem : cartItems) {
                    PendingOrderItem pendingOItem = pendingOrderItemRepository.selectById(cartItem.getPoItemId());
                    PendingOrderPlan pendingOrderPlan = pendingOrderPlanRepository.selectByPoid(cartItem.getPoItemId());
                    if (pendingOrderPlan != null) {
                        onlineSellingPrice += pendingOItem.getSellingPrice() * pendingOItem.getQuantity() + pendingOrderPlan.getPremiumPrice() * pendingOItem.getQuantity();
                    } else {
                        onlineSellingPrice += pendingOItem.getSellingPrice() * pendingOItem.getQuantity();
                    }
                }
            }

            itemIdAndPoiMap = pendingOrderItems.stream().collect(Collectors.toMap(x -> x.getItemId(), x -> pendingOrderItemRepository.selectById(x.getId())));
        }


//        get the list of customer item for every item code start here
//        ...............................................................

        LocalDateTime todayDate = LocalDateTime.now();
        LocalDate todayDate2 = LocalDate.now();

        Map<Integer, List<CustomerOfferItem>> offerItemMap = new HashMap<>();
        Map<Integer, List<WebOffer>> webOfferMap = new HashMap<>();

        List<CustomerOffer> customerOffers = customerOfferRepository.selectOffersByDate(todayDate);
        List<Integer> customerOfferIds = customerOffers.stream().map(x -> x.getId()).distinct().collect(Collectors.toList());
        /*for (CartFofo cartItem : cartItems) {
            Item item = itemRepository.selectById(cartItem.getItemId());
            if (customerOfferIds.size() > 0) {

                List<CustomerOfferItem> customerOfferItems = customerOfferItemRepository.selectByOfferIds(customerOfferIds, item.getCatalogItemId(), todayDate2);

                List<CustomerOfferItem> filteredCustomerOfferItems = customerOfferItems.stream()
                        .filter(x -> x.getEndDate() != null && !x.getEndDate().isBefore(todayDate2))
                        .collect(Collectors.toList());

                offerItemMap.put(item.getId(), filteredCustomerOfferItems);
            }


            List<WebOffer> webOffers = webOfferRepository.selectAllActiveOffers().get(item.getCatalogItemId());
            webOfferMap.put(item.getId(), webOffers);
        }*/


        Map<Integer, ItemWiseCustomerOfferSummaryModel> offerItemSummaryMap = new HashMap<>();

        for (CartFofo cartItem : cartItems) {
            Item item = itemRepository.selectById(cartItem.getItemId());
            List<CustomerOfferItem> customerOfferItems = null;
            if (customerOfferIds.size() > 0) {
                customerOfferItems = customerOfferItemRepository
                        .selectByOfferIds(customerOfferIds, item.getCatalogItemId(), todayDate2)
                        .stream()
                        .filter(x -> x.getEndDate() != null && !x.getEndDate().isBefore(todayDate2))
                        .collect(Collectors.toList());
            }


            ItemWiseCustomerOfferSummaryModel summary = new ItemWiseCustomerOfferSummaryModel();
            summary.setItemId(item.getId());
            summary.setCatalogId(item.getCatalogItemId());

            if (customerOfferItems != null) {
                for (CustomerOfferItem coi : customerOfferItems) {
                    String key = coi.getOfferType().name() + "-" + coi.getCustomerOfferId();

                    ItemWiseCustomerOfferSummaryModel.OfferTypeSummary typeSummary =
                            summary.getOfferTypeMap().computeIfAbsent(key, k -> {
                                ItemWiseCustomerOfferSummaryModel.OfferTypeSummary ts = new ItemWiseCustomerOfferSummaryModel.OfferTypeSummary();
                                ts.setOfferType(coi.getOfferType());
                                ts.setCustomerOfferId(coi.getCustomerOfferId());
                                return ts;
                            });

                    typeSummary.setTotalSchemePayout(typeSummary.getTotalSchemePayout() + coi.getSchemePayout());
                    typeSummary.setTotalDealerPayout(typeSummary.getTotalDealerPayout() + coi.getDealerPayout());
                    typeSummary.getDescriptions().add(coi.getAdditionalInfo());
                    typeSummary.getOfferItemIds().add(coi.getId());
                }
            }

            offerItemSummaryMap.put(item.getId(), summary);
        }


//        get the list of customer item for every item code end here
//        ...............................................................

        LOGGER.info("itemIdAndPoiMap {}", itemIdAndPoiMap);
        LOGGER.info("mopPriceMap {}", mopPriceMap);
        model.addAttribute("stateNames",
                stateRepository.selectAll().stream().map(x -> x.getName()).collect(Collectors.toList()));
        model.addAttribute("retailerStateName", address.getState());
        model.addAttribute("pendingPOCustomer", gson.toJson(customer));
        model.addAttribute("pendingPO", gson.toJson(po));

        model.addAttribute("cartItems", cartItems);
        model.addAttribute("pendingOrder", po);
        model.addAttribute("pendingOrderItem", poi);
        model.addAttribute("itemIdAndPoiMap", itemIdAndPoiMap);
        model.addAttribute("onlineSellingPrice", onlineSellingPrice);

        model.addAttribute("mopPriceMap", mopPriceMap);
        model.addAttribute("paymentOptions", paymentOptions);
        model.addAttribute("accessoriesDeals", accessoriesDeals);
        model.addAttribute("webOfferMap", webOfferMap);
        model.addAttribute("offerItemSummaryMap", offerItemSummaryMap);

        // Fetch pinelabs offers from cache and group by issuer display name
        Map<Integer, Map<String, List<Tenure>>> pinelabsOfferMap =
                pinelabsOfferCacheService.getGroupedCachedOffersForItems(new ArrayList<>(itemIds));
        model.addAttribute("pinelabsOfferMap", pinelabsOfferMap);

        return "order-index";
    }

    private Map<String, List<MobileInsurancePlan>> getPlans(float sellingPrice, int itemId, int poiId)
            throws ProfitMandiBusinessException {
        try {
            Map<String, List<MobileInsurancePlan>> productDurationPlans = new HashMap<>();
            PendingOrderPlan pendingOrderPlan = null;
            if (poiId > 0) {
                pendingOrderPlan = pendingOrderPlanRepository.selectByPoid(poiId);
            }
            if (pendingOrderPlan != null) {
                MobileInsurancePlan productDurationPlan = insuranceService.getPlanById(String.valueOf(pendingOrderPlan.getPlanId()), sellingPrice);
                productDurationPlans.put(pendingOrderPlan.getPlanName(), Collections.singletonList(productDurationPlan));

            } else {
                productDurationPlans = insuranceService.getAllPlans(itemId,
                        sellingPrice, false);
            }

            return productDurationPlans;
        } catch (Exception e) {
            LOGGER.info(e, e);
            throw new ProfitMandiBusinessException("Fetch Insurance Plans", "Insurance",
                    "Could not fetch insurance Plans");
        }

    }


    @GetMapping("/getItemWiseUpgradeOffer")
    public String getItemWiseUpgradeOffer(HttpServletRequest request, @RequestParam int itemId, Model model)
            throws ProfitMandiBusinessException {
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);

        Item item = itemRepository.selectById(itemId);

        LocalDateTime todayDate = LocalDateTime.now();
        LocalDate todayDate2 = LocalDate.now();

        List<CustomerOffer> customerOffers = customerOfferRepository.selectOffersByDate(todayDate);
        Map<Integer, CustomerOffer> customerOfferMap = customerOffers.stream().collect(Collectors.toMap(x -> x.getId(), x -> x));
        List<Integer> customerOfferIds = customerOffers.stream().map(x -> x.getId()).distinct().collect(Collectors.toList());
        List<CustomerOfferItem> customerOfferItems = customerOfferItemRepository.selectByOfferIds(customerOfferIds, item.getCatalogItemId(), todayDate2);

        List<CustomerOfferItem> filteredCustomerOfferItems = customerOfferItems.stream()
                .filter(x -> x.getEndDate() != null && !x.getEndDate().isBefore(todayDate2))
                .collect(Collectors.toList());

        List<WebOffer> webOffers = webOfferRepository.selectAllActiveOffers().get(item.getCatalogItemId());

        model.addAttribute("webOffers", webOffers);
        model.addAttribute("customerOfferMap", customerOfferMap);
        model.addAttribute("customerOfferItems", filteredCustomerOfferItems);

        return "upgrade-customer-offer-model";
    }

    @GetMapping("/insuranceDetails")
    public String getInsuranceDetails(HttpServletRequest request,
                                      @RequestParam(name = "offset", defaultValue = "0") int offset,
                                      @RequestParam(name = "limit", defaultValue = "10") int limit, Model model)
            throws ProfitMandiBusinessException {
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
        long size = 0;
        List<InsurancePolicy> insurancePolicies = insurancePolicyRepository.selectByRetailerId(loginDetails.getFofoId(),
                offset, limit);
        size = insurancePolicyRepository.selectCountByRetailerId(loginDetails.getFofoId());
        Map<Integer, String> providerPolicyNameAndIdMap = insuranceProviderRepository
                .selectByIds(insurancePolicies.stream().map(x -> x.getProviderId()).collect(Collectors.toSet()))
                .stream().collect(Collectors.toMap(InsuranceProvider::getId, InsuranceProvider::getName));
        if (size < limit) {
            model.addAttribute("end", offset + size);
        } else {
            model.addAttribute("end", offset + limit);
        }
        model.addAttribute("start", offset + 1);
        model.addAttribute("size", size);
        model.addAttribute("insurancePolicies", insurancePolicies);
        model.addAttribute("providerPolicyNameAndIdMap", providerPolicyNameAndIdMap);
        return "insurance-details";
    }

    @GetMapping("/insuranceDetailsPaginated")
    public String getInsuranceDetailsPaginated(HttpServletRequest request,
                                               @RequestParam(name = "offset", defaultValue = "0") int offset,
                                               @RequestParam(name = "limit", defaultValue = "10") int limit, Model model)
            throws ProfitMandiBusinessException {
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
        List<InsurancePolicy> insurancePolicies = insurancePolicyRepository.selectByRetailerId(loginDetails.getFofoId(),
                offset, limit);
        Map<Integer, String> providerPolicyNameAndIdMap = insuranceProviderRepository
                .selectByIds(insurancePolicies.stream().map(x -> x.getProviderId()).collect(Collectors.toSet()))
                .stream().collect(Collectors.toMap(InsuranceProvider::getId, InsuranceProvider::getName));
        model.addAttribute("insurancePolicies", insurancePolicies);
        model.addAttribute("providerPolicyNameAndIdMap", providerPolicyNameAndIdMap);
        return "insurance-details-paginated";
    }

    @GetMapping("/getMouForm")
    public String getMouForm(HttpServletRequest request, Model model) throws Exception {
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);

        Mou mou = mouRepository.selectByFofoId(loginDetails.getFofoId());
        if (mou != null) {
            if (mou.getUpdateTimestamp().getMonth().equals(LocalDateTime.now().getMonth())) {
                model.addAttribute("response1", mvcResponseSender.createResponseString(true));
            } else {
                model.addAttribute("response1", mvcResponseSender.createResponseString(false));
            }

        } else {
            model.addAttribute("response1", mvcResponseSender.createResponseString(false));

        }
        return "response";

    }

    @GetMapping("/pendingOrders")
    public String getPendingOrders(HttpServletRequest request, Model model) throws ProfitMandiBusinessException {
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
        boolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());
        Mou mou = mouRepository.selectByFofoId(loginDetails.getFofoId());
        if (mou == null) {
            mou = new Mou();
            mou.setFofoId(loginDetails.getFofoId());
            mou.setCreateTimestamp(LocalDateTime.now());
            mou.setUpdateTimestamp(LocalDateTime.now());
            mouRepository.persist(mou);
        } else if (!mou.getUpdateTimestamp().getMonth().equals(LocalDateTime.now().getMonth())) {
            mou.setUpdateTimestamp(LocalDateTime.now());
        }

        List<PendingOrderItem> pendingOrderItems = pendingOrderItemRepository.selectOrderItemByStatusAndFofoId(OrderStatus.PROCESSING,
                loginDetails.getFofoId());

        Map<String, List<PendingOrderPlan>> pendingOrderPlansMap = pendingOrderPlanRepository.selectAll().stream()
                .collect(Collectors.groupingBy(PendingOrderPlan::getPlanId));
        Map<String, Object> map = pendingOrderService.getItemOrders(pendingOrderItems, loginDetails.getFofoId());
        model.addAttribute("inventoryMap", map.get("inventoryMap"));
        model.addAttribute("pendingOrderPlansMap", pendingOrderPlansMap);
        model.addAttribute("pendingOrderItems", (List<PendingOrderItem>) map.get("pendingOrderItems"));

        model.addAttribute("isAdmin", isAdmin);
        return "pending_fofo_order";

    }

    @RequestMapping(value = "/create-order", method = RequestMethod.POST)
    public String createOrder(HttpServletRequest request, @RequestBody CreateOrderRequest createOrderRequest,
                              Model model) throws Exception {
        // throw new ProfitMandiBusinessException("Billing is on hold temporarily",
        // "Billing is on hold temporarily", "Billing is on hold temporarily");
        LOGGER.info("request at uri {}", request.getRequestURI());
        LOGGER.info("request body {}", createOrderRequest);
        LoginDetails fofoDetails = cookiesProcessor.getCookiesObject(request);
        int fofoOrderId = orderService.createOrder(createOrderRequest, fofoDetails.getFofoId(), accessoriesDeals);
        try {
            Set<Integer> fofoOrderItemIds = createOrderRequest.getFofoOrderItems()
                    .stream().map(CustomFofoOrderItem::getItemId).collect(Collectors.toSet());
            scratchService.processScratchOffer(fofoOrderId, createOrderRequest.getPaymentOptions(), fofoOrderItemIds);
        } catch (Exception e) {
            LOGGER.error("Exception during processScratchOffer for order {}: {}", fofoOrderId, e.getMessage(), e);
        }

        LOGGER.info("Order has been created successfully...");
        return "redirect:/get-order/?orderId=" + fofoOrderId;
    }

    @GetMapping("/billedOrders")
    public String getBilledOrders(HttpServletRequest request, Model model) throws ProfitMandiBusinessException {
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
        boolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());

        List<PendingOrderItem> pendingOrderItems;

        if (isAdmin) {

            pendingOrderItems = pendingOrderItemRepository.selectOrderItemByStatus(OrderStatus.BILLED);

        } else {
            pendingOrderItems = pendingOrderItemRepository.selectOrderItemByStatusAndFofoId(OrderStatus.BILLED,
                    loginDetails.getFofoId());


        }

        Map<String, Object> map = pendingOrderService.getItemOrders(pendingOrderItems, loginDetails.getFofoId());
        model.addAttribute("pendingOrderItems", (List<PendingOrderItem>) map.get("pendingOrderItems"));

        model.addAttribute("isAdmin", isAdmin);
        return "billed_order_item";
    }

    @GetMapping("/settledOrders")
    public String getSettledOrders(HttpServletRequest request, Model model) throws ProfitMandiBusinessException {
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
        boolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());

        List<PendingOrderItem> pendingOrderItem = null;

        if (isAdmin) {

            pendingOrderItem = pendingOrderItemRepository.selectOrderItemByStatus(OrderStatus.SETTLED);

        } else {
            pendingOrderItem = pendingOrderItemRepository.selectOrderItemByStatusAndFofoId(OrderStatus.SETTLED,
                    loginDetails.getFofoId());
        }

        Map<String, Object> map = pendingOrderService.getItemOrders(pendingOrderItem, loginDetails.getFofoId());

        model.addAttribute("pendingOrderItems", (List<PendingOrderItem>) map.get("pendingOrderItems"));
        model.addAttribute("isAdmin", isAdmin);
        return "settled_order_item";
    }

    @GetMapping("/unsettledOrders")
    public String getunsettledOrders(HttpServletRequest request, Model model) throws ProfitMandiBusinessException {
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
        boolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());

        List<PendingOrderItem> pendingOrderItem = null;

        if (isAdmin) {

            pendingOrderItem = pendingOrderItemRepository.selectOrderItemByStatus(OrderStatus.UNSETTLED);

        } else {
            pendingOrderItem = pendingOrderItemRepository.selectOrderItemByStatusAndFofoId(OrderStatus.UNSETTLED,
                    loginDetails.getFofoId());
        }

        Map<String, Object> map = pendingOrderService.getItemOrders(pendingOrderItem, loginDetails.getFofoId());

        model.addAttribute("pendingOrderItems", (List<PendingOrderItem>) map.get("pendingOrderItems"));
        model.addAttribute("isAdmin", isAdmin);
        return "unsettled_order_item";
    }

    @GetMapping("/getPendingOrderItem")
    public String getPendingOrderItem(HttpServletRequest request, @RequestParam int orderId, Model model)
            throws ProfitMandiBusinessException {
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
        Map<Integer, Item> itemMap = new HashMap<>();
        Map<Integer, CurrentInventorySnapshot> inventoryMap = new HashMap<>();
        PendingOrder pendingPO = pendingOrderRepository.selectById(orderId);
        Customer customer = customerRepository.selectById(pendingPO.getCustomerId());
        List<PendingOrderItem> pendingOrderItems = pendingOrderItemRepository.selectByOrderId(orderId);
        for (PendingOrderItem pendingOrderItem : pendingOrderItems) {
            Item item = itemRepository.selectById(pendingOrderItem.getItemId());
            CurrentInventorySnapshot cis = currentInventorySnapshotRepository
                    .selectByItemAndFofoId(pendingOrderItem.getItemId(), pendingPO.getFofoId());
            itemMap.put(pendingOrderItem.getItemId(), item);
            LOGGER.info("cis" + cis);
            inventoryMap.put(pendingOrderItem.getItemId(), cis);
        }

        LOGGER.info("inventoryMap" + inventoryMap);
        model.addAttribute("pendingOrderItems", pendingOrderItems);
        model.addAttribute("itemMap", itemMap);
        model.addAttribute("inventoryMap", inventoryMap);
        model.addAttribute("pendingPO", gson.toJson(pendingPO));
        model.addAttribute("pendingPOCustomer", gson.toJson(customer));
        model.addAttribute("isAdmin", roleManager.isAdmin(loginDetails.getRoleIds()));
        return "pending-order-item";
    }

    @RequestMapping(value = "/getPendingOrderItemById", method = RequestMethod.GET)
    public String getPendingOrderItemById(HttpServletRequest request, @RequestParam int id, Model model)
            throws Exception {

        PendingOrderItem pendingOrderItem = pendingOrderItemRepository.selectById(id);
        model.addAttribute("pendingOrderItem", pendingOrderItem);
        return "cancel-pending-order";
    }

    @RequestMapping(value = "/getPendingOrderChangePartnerById", method = RequestMethod.GET)
    public String getPendingOrderChangePartnerById(HttpServletRequest request, @RequestParam int id, @RequestParam String pinCode, Model model)
            throws Exception {

        PendingOrder pendingOrder = pendingOrderRepository.selectById(id);
        Map<Integer, CustomRetailer> customRetailersMap = retailerService.getFofoRetailers(true);
        model.addAttribute("customRetailersMap", customRetailersMap);
        model.addAttribute("pendingOrder", pendingOrder);
        return "change-partner-po";
    }

    @RequestMapping(value = "/changePendingOrderPartner", method = RequestMethod.POST)
    public String changePendingOrderPartner(HttpServletRequest request, @RequestParam int id, @RequestParam int fofoId,
                                            Model model) throws Exception {

        PendingOrder pendingOrder = pendingOrderRepository.selectById(id);
        pendingOrder.setFofoId(fofoId);
        model.addAttribute("response1", mvcResponseSender.createResponseString(true));

        return "response";
    }

    @RequestMapping(value = "/cancelPendingOrderItem", method = RequestMethod.POST)
    public String cancelPendingOrderItem(HttpServletRequest request, @RequestParam int id, @RequestParam String reason,
                                         Model model) throws Exception {

        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
        PendingOrderItem pendingOrderItem = pendingOrderItemRepository.selectById(id);

        pendingOrderItem.setStatus(OrderStatus.CANCELLED);
        pendingOrderItem.setStatusDescription(loginDetails.getEmailId());
        pendingOrderItem.setRemark(reason);
        pendingOrderItem.setCancelledTimestamp(LocalDateTime.now());
        PendingOrder pendingOrder = pendingOrderRepository.selectById(pendingOrderItem.getOrderId());

        List<OrderStatus> status = pendingOrderItemRepository.selectByOrderId(pendingOrderItem.getOrderId()).stream()
                .map(x -> x.getStatus()).collect(Collectors.toList());

        Customer customer = customerRepository.selectById(pendingOrder.getCustomerId());

        List<Integer> catalogIds = new ArrayList<>();

        Item item = itemRepository.selectById(pendingOrderItem.getItemId());
        pendingOrderItem.setItemName(item.getItemDescription());
        catalogIds.add(item.getCatalogItemId());

        Map<Integer, JSONObject> contentMap = commonSolrService.getContentByCatalogIds(catalogIds);
        JSONObject jsonObj = contentMap.get(item.getCatalogItemId());
        pendingOrderItem.setImgUrl(jsonObj.getString("imageUrl_s"));
        pendingOrder.setPendingOrderItems(Arrays.asList(pendingOrderItem));
        CustomerAddress customerAddress = customerAddressRepository.selectById(pendingOrder.getCustomerAddressId());

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy h:mm a");

        Map<String, Object> emailModel = new HashMap<>();
        emailModel.put("customer", customerAddress);
        emailModel.put("pendingOrder", pendingOrder);
        emailModel.put("date", dateTimeFormatter);
        LOGGER.info("emal" + customer.getEmailId());
        String[] customerEmail = null;
        if (customer.getEmailId() != null && !customer.getEmailId().isEmpty()) {
            customerEmail = new String[]{customer.getEmailId()};

            List<String> bccTo = Arrays.asList("vikas.jangra@smartdukaan.com");

            emailService.sendMailWithAttachments("Order Cancellation", "order-cancellation.vm", emailModel,
                    customerEmail, null, bccTo.toArray(new String[0]));

        }

        if (!status.contains(OrderStatus.PENDING) && !status.contains(OrderStatus.PROCESSING)
                && !status.contains(OrderStatus.BILLED) && !status.contains(OrderStatus.UNSETTLED)
                && !status.contains(OrderStatus.CLAIMED)) {
            pendingOrder.setStatus(OrderStatus.CLOSED);
        }
        pendingOrderItemRepository.persist(pendingOrderItem);

        model.addAttribute("response1", mvcResponseSender.createResponseString(true));

        return "response";
    }

    @GetMapping("/claimedOrders")
    public String getclaimedOrders(HttpServletRequest request, Model model) throws ProfitMandiBusinessException {
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
        boolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());
        List<Integer> fofoIds = fofoStoreRepository.selectActiveStores().stream().map(x -> x.getId())
                .collect(Collectors.toList());

        List<PendingOrderItem> pendingOrderItem = null;

        if (isAdmin) {

            pendingOrderItem = pendingOrderItemRepository.selectOrderItemByStatus(OrderStatus.CLAIMED);
            Map<Integer, CustomRetailer> customRetailerMap = retailerService.getAllFofoRetailers();

            Map<Integer, CustomRetailer> customRetailersMap = fofoIds.stream().map(x -> customRetailerMap.get(x))
                    .filter(x -> x != null).collect(Collectors.toList()).stream()
                    .collect(Collectors.toMap(x -> x.getPartnerId(), x -> x));
            model.addAttribute("customRetailersMap", customRetailersMap);

        } else {
            pendingOrderItem = pendingOrderItemRepository.selectOrderItemByStatusAndFofoId(OrderStatus.CLAIMED,
                    loginDetails.getFofoId());
        }

        Map<String, Object> map = pendingOrderService.getItemOrders(pendingOrderItem, loginDetails.getFofoId());

        model.addAttribute("pendingOrderItems", map.get("pendingOrderItems"));
        model.addAttribute("isAdmin", isAdmin);
        return "claim_raised_order_item";
    }

    @RequestMapping(value = "/raiseClaimOrderItem", method = RequestMethod.POST)
    public String raiseClaimOrderItem(HttpServletRequest request, @RequestParam int id, Model model) throws Exception {

        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
        PendingOrderItem pendingOrderItem = pendingOrderItemRepository.selectById(id);
        PendingOrder pendingOrder = pendingOrderRepository.selectById(pendingOrderItem.getOrderId());

        if (pendingOrder.getTotalAmount() == pendingOrder.getPaidAmount()) {
            pendingOrderItem.setStatus(OrderStatus.CLAIMED);
            pendingOrderItem.setClaimedTimestamp(LocalDateTime.now());

        }
        pendingOrderItemRepository.persist(pendingOrderItem);
        model.addAttribute("response1", mvcResponseSender.createResponseString(true));

        return "response";
    }

    @RequestMapping(value = "/verifyOrderItem", method = RequestMethod.POST)
    public String verifyOrderItem(HttpServletRequest request, @RequestParam int id, Model model) throws Exception {

        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
        PendingOrderItem pendingOrderItem = pendingOrderItemRepository.selectById(id);
        pendingOrderItem.setVerifiedTimestamp(LocalDateTime.now());

        model.addAttribute("response1", mvcResponseSender.createResponseString(true));

        return "response";
    }

    @RequestMapping(value = "/cancelOrderByInvoice", method = RequestMethod.POST)
    public String cancelOrder(HttpServletRequest request, @RequestParam List<String> invoiceNumbers, Model model)
            throws Exception {
        orderService.cancelOrder(invoiceNumbers);
        model.addAttribute("response1", mvcResponseSender.createResponseString(true));

        return "response";
    }

    @RequestMapping(value = "/getOnlineOrder", method = RequestMethod.GET)
    public String cancelOrder(HttpServletRequest request, Model model) throws Exception {
        return "online-order";
    }

    @RequestMapping(value = "/deliveredPendingOrderItem", method = RequestMethod.POST)
    public String deliveredPendingOrderItem(HttpServletRequest request, @RequestParam(name = "id") int pendingOrderItemId, Model model)
            throws Exception {

        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
        PendingOrderItem pendingOrderItem = pendingOrderItemRepository.selectById(pendingOrderItemId);
        PendingOrder pendingOrder = pendingOrderRepository.selectById(pendingOrderItem.getOrderId());

        //Prepaid payment successful
        if (pendingOrder.getTotalAmount() == pendingOrder.getPaidAmount()) {
            //pendingOrderItem.setStatus(OrderStatus.UNSETTLED);
//            pendingOrderItem.setSettled(false);
            pendingOrderItem.setStatus(OrderStatus.CLAIMED);
            pendingOrderItem.setClaimedTimestamp(LocalDateTime.now());
        } else {
            pendingOrderItem.setStatus(OrderStatus.SETTLED);
        }
        pendingOrderItem.setDeliveredTimestamp(LocalDateTime.now());

        List<OrderStatus> pendingOrderItemStatusList = pendingOrderItemRepository.selectByOrderId(pendingOrderItem.getOrderId()).stream()
                .map(x -> x.getStatus()).collect(Collectors.toList());

        List<Integer> catalogIds = new ArrayList<>();

        Item item = itemRepository.selectById(pendingOrderItem.getItemId());
        pendingOrderItem.setItemName(item.getItemDescription());
        catalogIds.add(item.getCatalogItemId());

        Map<Integer, JSONObject> contentMap = commonSolrService.getContentByCatalogIds(catalogIds);
        JSONObject jsonObj = contentMap.get(item.getCatalogItemId());
        pendingOrderItem.setImgUrl(jsonObj.getString("imageUrl_s"));
        pendingOrder.setPendingOrderItems(Arrays.asList(pendingOrderItem));
        CustomerAddress customerAddress = customerAddressRepository.selectById(pendingOrder.getCustomerAddressId());
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy h:mm a");
        Map<String, Object> emailModel = new HashMap<>();
        emailModel.put("customer", customerAddress);
        emailModel.put("pendingOrder", pendingOrder);
        emailModel.put("date", dateTimeFormatter);
        Customer customer = customerRepository.selectById(pendingOrder.getCustomerId());
        String[] customerEmail = null;
        if (customer.getEmailId() != null && !customer.getEmailId().isEmpty()) {
            customerEmail = new String[]{customer.getEmailId()};
            List<String> bccTo = Arrays.asList("vikas.jangra@smartdukaan.com");

            emailService.sendMailWithAttachments("Order Delivered with SmartDukaan", "order-delivered.vm", emailModel,
                    customerEmail, null, bccTo.toArray(new String[0]));

        }
        if (!pendingOrderItemStatusList.contains(OrderStatus.PENDING) && !pendingOrderItemStatusList.contains(OrderStatus.PROCESSING)
                && !pendingOrderItemStatusList.contains(OrderStatus.BILLED) && !pendingOrderItemStatusList.contains(OrderStatus.UNSETTLED)
                && !pendingOrderItemStatusList.contains(OrderStatus.CLAIMED)) {
            pendingOrder.setStatus(OrderStatus.CLOSED);
        }
        pendingOrderItemRepository.persist(pendingOrderItem);
        model.addAttribute("response1", mvcResponseSender.createResponseString(true));

        return "response";
    }

    @GetMapping("/getAllOrdersByStatus")
    public String getAllOrdersByStatus(HttpServletRequest request, @RequestParam OrderStatus status,
                                       @RequestParam(required = false) LocalDateTime startTime,
                                       @RequestParam(required = false) LocalDateTime endTime, Model model) throws ProfitMandiBusinessException {
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
        boolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());
        boolean isAccountsL2AndL3 = false;
        if (isAdmin) {
            AuthUser authUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());
            List<Position> positions = positionRepository.selectPositionByAuthId(authUser.getId());
            for (Position position : positions) {
                if (((position.getEscalationType().equals(EscalationType.L2) || position.getEscalationType().equals(EscalationType.L3))
                        && position.getCategoryId() == ProfitMandiConstants.TICKET_CATEGORY_ACCOUNTS)) {
                    isAccountsL2AndL3 = true;
                    break;
                }
            }
        }

        LOGGER.info("startTime {}", startTime);
        LOGGER.info("endTime {}", endTime);

        List<PendingOrderItem> pendingOrderItems;
        if (startTime == null) {
            LocalDate date = LocalDate.now().minusDays(15);
            if (status.equals(OrderStatus.PENDING)) {
                pendingOrderItems = pendingOrderItemRepository.selectByStatusAndCreateTimestamp(Collections.singletonList(status), date.atStartOfDay(), LocalDateTime.now());
            } else {
                pendingOrderItems = pendingOrderItemRepository.selectOrderItemByStatus(status);
            }

        } else {
            List<OrderStatus> statusList = new ArrayList<>();
            if (status.equals(OrderStatus.DELIVERED)) {
                statusList.add(OrderStatus.SETTLED);
                statusList.add(OrderStatus.UNSETTLED);
            } else {
                statusList.add(status);
            }
            pendingOrderItems = pendingOrderItemRepository.selectByStatusAndCreateTimestamp(statusList,
                    startTime.toLocalDate().atStartOfDay(), endTime);
        }

        List<Integer> pendingOrderIds = pendingOrderItems.stream().map(x -> x.getOrderId()).collect(Collectors.toList());

        List<Integer> fofoIds = pendingOrderRepository.selectByIds(pendingOrderIds)
                .stream().map(x -> x.getFofoId()).distinct().collect(Collectors.toList());

        Map<Integer, CustomRetailer> customRetailerMap = retailerService.getAllFofoRetailers();

        Map<Integer, CustomRetailer> customRetailersMap = fofoIds.stream().map(x -> customRetailerMap.get(x))
                .filter(x -> x != null).collect(Collectors.toList()).stream()
                .collect(Collectors.toMap(x -> x.getPartnerId(), x -> x));
        model.addAttribute("customRetailersMap", customRetailersMap);

        LOGGER.info("customRetailersMap {}", customRetailersMap);

        Map<String, Object> map = pendingOrderService.getItemOrders(pendingOrderItems, 0);

        model.addAttribute("pendingOrderItems", (List<PendingOrderItem>) map.get("pendingOrderItems"));
        model.addAttribute("partnerInventoryMap", map.get("partnerInventoryMap"));

        model.addAttribute("isAdmin", isAdmin);
        model.addAttribute("isAccountsL2AndL3", isAccountsL2AndL3);
        return "online-order-item";
    }

    @RequestMapping(value = "/onlinePaymentAddToPartnerWallet", method = RequestMethod.POST)
    public String onlinePaymentAddToPartnerWallet(HttpServletRequest request, @RequestParam int id,
                                                  Model model) throws Exception {
        PendingOrderItem pendingOrderItem = pendingOrderItemRepository.selectById(id);
        PendingOrder pendingOrder = pendingOrderRepository.selectById(pendingOrderItem.getOrderId());
        int fofoId = pendingOrder.getFofoId();
        double deductionPayment = (pendingOrderItem.getSellingPrice() * 2.36) / 100;
        walletService.addAmountToWallet(fofoId, id, WalletReferenceType.ONLINE_ORDER_PAYMENT, "Online Order Payment", pendingOrderItem.getSellingPrice(), LocalDateTime.now());
        walletService.consumeAmountFromWallet(fofoId, id,
                WalletReferenceType.ONLINE_GATEWAY_FEE, "Payment Gatewayfee", (float) deductionPayment, LocalDateTime.now());

        pendingOrderItem.setStatus(OrderStatus.CLOSED);
        pendingOrder.setStatus(OrderStatus.CLOSED);

        model.addAttribute("response1", mvcResponseSender.createResponseString(true));

        return "response";
    }

    //TODO Tejus
    @RequestMapping(value = "/getBulkOrder")
    public String getBulkOrder(HttpServletRequest request, Model model) throws ProfitMandiBusinessException, MessagingException, IOException {
        return "bulk-order";
    }

    @PostMapping(value = "/bulkOrder/upload")
    public String uploadCatalog(HttpServletRequest request, @RequestPart("file") MultipartFile file, Model model)
            throws Exception {
        LoginDetails fofoDetails = cookiesProcessor.getCookiesObject(request);
        int authId = authRepository.selectByEmailOrMobile(fofoDetails.getEmailId()).getId();
        LOGGER.info("authId - {}", authId);
        bulkOrderService.parseBulkOrders(file, authId);
        model.addAttribute("response1", mvcResponseSender.createResponseString(true));
        return "response";
    }

    // This method is use for sending all pending transaction to Transation Approval menu
    @RequestMapping(value = "/transaction/pendingApprovals", method = RequestMethod.GET)
    public String getTransactionApproval(HttpServletRequest request, Model model) throws Exception {
        List<TransactionApproval> transactionApprovals = transactionApprovalRepository.selectAllPending();
        LOGGER.info("list of Approval transaction Id " + transactionApprovals);
        List<TransactionApprovalModel> approvalModelList = bulkOrderService.getAllPendingTransactionApproval();
        model.addAttribute("approvalModelList", approvalModelList);
        return "transaction/transaction-approvals";
    }

    @RequestMapping(value = "transaction/approval", method = RequestMethod.PUT)
    public String transactionApproval(HttpServletRequest request, Model model,
                                      @RequestParam int transactionId,
                                      @RequestParam String remark,
                                      @RequestParam TransactionApprovalStatus transactionApprovalStatus
    ) throws Exception {
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
        AuthUser authUser = authRepository.selectByEmailOrMobile(loginDetails.getEmailId());
        int approvalId = authUser.getId();
        String approvedBy = authUser.getFullName();
        LocalDateTime approvedOn = LocalDateTime.now();
        this.updateApprovalStatus(transactionId, approvalId, approvedBy, approvedOn, remark, transactionApprovalStatus);
        model.addAttribute("response1", mvcResponseSender.createResponseString(true));
        return "response";

    }


    private void updateApprovalStatus(int transactionId, int approvalId, String approvedBy, LocalDateTime approvedOn, String remark, TransactionApprovalStatus transactionApprovalStatus) throws Exception {
        TransactionApproval transactionApproval = transactionApprovalRepository.selectById(transactionId);
        int retailerId = transactionRepository.selectById(transactionId).getRetailerId();
        if (!transactionApproval.getStatus().equals(TransactionApprovalStatus.PENDING)) {
            throw new ProfitMandiBusinessException("Transaction already Processed", "Transaction already Processed", "Transaction already Processed");
        }
        transactionApproval.setStatus(transactionApprovalStatus);
        transactionApproval.setRemark(remark);
        transactionApproval.setApprovalId(approvalId);
        transactionApproval.setApprovedBy(approvedBy);
        transactionApproval.setApprovedOn(approvedOn);
        if (transactionApprovalStatus.equals(TransactionApprovalStatus.APPROVED)) {
            transactionService.processTransaction(transactionId, 0);
        } else {
            float totalAmount = 0;
            // referense id = transaction id
            // here refund the amount of an order
            List<UserWalletHistory> uwhList = walletService.getAllByReference(retailerId, transactionId, WalletReferenceType.PURCHASE);
            //Refund only if any amount is deducted from wallet for that particular Transaction
            if (uwhList.size() > 0) {
                totalAmount = -uwhList.get(0).getAmount();
                walletService.refundToWallet(retailerId, totalAmount, transactionId, WalletReferenceType.PURCHASE, "Order canceled");
                sdCreditService.settleBlockedLoan(transactionId, totalAmount);
            }
        }
    }

    @RequestMapping(value = "/bulkOrderTemplate", method = RequestMethod.GET)
    public ResponseEntity<?> bulkOrderTemplate() throws Exception {
        List<List<?>> rows = new ArrayList<>();
        rows.add(Arrays.asList("Mahaveer", "Change description for your reference", "175139287", "28264", "0", "4"));
        rows.add(Arrays.asList("Mahaveer", "Price =0 means system price", "175139287", "28268", "0", "7"));
        rows.add(Arrays.asList("Jas", "You give custom price also ", "171273247", "28264", "300", "3"));
        org.apache.commons.io.output.ByteArrayOutputStream baos = FileUtil
                .getCSVByteStream(Arrays.asList("Partner name", "Description", "Partner Id", "Item Id", "Price", "Quantity"), rows);
        ResponseEntity<?> responseEntity = orderService.downloadReportInCsv(baos, rows, "Bulk order template");

        return responseEntity;

    }

    @Autowired
    EInvoiceDetailsRepository eInvoiceDetailsRepository;

    @GetMapping("/resetIrnGeneratedPanel")
    public String resetIrnGeneratedPanel() {
        return "reset-irn-panel";
    }

    @GetMapping("/getTransactionForIrnReset")
    public String getTransactionForIrnReset(@RequestParam String invoiceNumber, Model model) throws Exception {
        List<String> invoiceNumbers = Arrays.asList(invoiceNumber.split(","));
        List<EInvoiceDetails> eInvoiceDetailsList = eInvoiceDetailsRepository.selectByInvoiceNumbers(invoiceNumbers);
        if (invoiceNumbers.size() == eInvoiceDetailsList.size()) {
            model.addAttribute("irnResetOrderModelList", new ArrayList<>());
            model.addAttribute("notEligibleInvoiceNumbers", invoiceNumber);
            return "eligible-irn-reset-orders";
        }
        Set<String> existingInvoiceInEInvoiceDtl = eInvoiceDetailsList.stream().map(x -> x.getInvoiceNumber()).collect(Collectors.toSet());
        List<String> missingInvoiceInEInvoiceDtl = invoiceNumbers.stream().filter(x -> !existingInvoiceInEInvoiceDtl.contains(x)).collect(Collectors.toList());

        List<Order> orderList = orderRepository.selectByInvoiceNumbers(missingInvoiceInEInvoiceDtl).stream().filter(x -> x.getIrnGenerated() != null).collect(Collectors.toList());
        Map<String, List<Order>> invoiceMap = orderList.stream().collect(Collectors.groupingBy(x -> x.getInvoiceNumber()));
        Set<String> notEligibleInvoiceNumbers = new HashSet<>();
        notEligibleInvoiceNumbers.addAll(existingInvoiceInEInvoiceDtl);
        List<IrnResetOrderModel> irnResetOrderModelList = new ArrayList<>();
        for (Map.Entry<String, List<Order>> invoiceMapEntry : invoiceMap.entrySet()) {
            String invoice = invoiceMapEntry.getKey();
            List<Order> orders = invoiceMapEntry.getValue();
            LocalDate earlierDate = LocalDate.now().minusDays(5);
            boolean isEligible = !orders.isEmpty() && orders.stream().allMatch(x -> x.getBillingTimestamp().toLocalDate().isAfter(earlierDate) && x.getIrnGenerated() != null);
            if (isEligible) {
                Order order = orders.get(0);
                FofoStore fofoStore = fofoStoreRepository.selectByRetailerId(order.getRetailerId());

                IrnResetOrderModel irnResetOrderModel = new IrnResetOrderModel();
                irnResetOrderModel.setName(partnerOnBoardingPanelRepository.selectByCode(fofoStore.getCode()).getOutLetName());
                irnResetOrderModel.setInvoiceNumber(order.getInvoiceNumber());
                irnResetOrderModel.setInvoiceDate(order.getBillingTimestamp());
                irnResetOrderModel.setWarehouseId(ProfitMandiConstants.WAREHOUSE_MAP.get(order.getWarehouseId()));
                irnResetOrderModel.setTotalOrderValue(orders.stream().mapToDouble(Order::getTotalAmount).sum());
                irnResetOrderModelList.add(irnResetOrderModel);
            } else {
                notEligibleInvoiceNumbers.add(invoice);
            }
        }
        model.addAttribute("irnResetOrderModelList", irnResetOrderModelList);
        model.addAttribute("notEligibleInvoiceNumbers", notEligibleInvoiceNumbers.stream().collect(Collectors.joining(", ")));
        return "eligible-irn-reset-orders";
    }

    @PutMapping("/resetOrdersIrn")
    public String resetIrn(@RequestParam String invoiceNumbers, Model model) throws Exception {
        List<String> invoices = new ArrayList<>();
        if (!invoiceNumbers.isEmpty()) {
            invoices = Arrays.asList(invoiceNumbers.split(","));
        }
        List<Order> orderList = orderRepository.selectByInvoiceNumbers(invoices);
        orderList.forEach(order -> {
            order.setIrnGenerated(null);
        });
        model.addAttribute("response1", mvcResponseSender.createResponseString(true));
        return "response";
    }

    @PutMapping(value = "/sendInvoiceOnWhatsApp")
    public String sendInvoiceOnWhatsApp(HttpServletRequest request, @RequestParam int orderId, @RequestParam String whatsAppMobile, Model model) throws Exception {
        boolean isSend = this.sendWhatsappInvoice(fofoOrderRepository.selectByOrderId(orderId), whatsAppMobile);
        model.addAttribute("response1", isSend);
        return "response";
    }

    @Autowired
    OneAssistService oneAssistService;

    @RequestMapping(value = "/cancelInsuranceWithoutInvoice/{applicationNumber}/{memberShipNumber}", method = RequestMethod.GET)
    public String cancelInsuranceWithoutInvoice(HttpServletRequest request, @PathVariable int applicationNumber, @PathVariable int memberShipNumber, Model model) throws Exception {
        CancelPlanRequestModel cancelPlanRequestModel = new CancelPlanRequestModel();
        cancelPlanRequestModel.setMembershipId(Long.parseLong(String.valueOf(memberShipNumber)));
        cancelPlanRequestModel.setApplicationNo(applicationNumber + "");
        oneAssistService.cancelCertificate(cancelPlanRequestModel);

        model.addAttribute("response1", mvcResponseSender.createResponseString(true));

        return "response";

    }

}