Subversion Repositories SmartDukaan

Rev

Rev 35435 | 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.eclipsesource.json.JsonObject;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.spice.profitmandi.common.enumuration.MessageType;
import com.spice.profitmandi.common.enumuration.SchemeType;
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
import com.spice.profitmandi.common.model.*;
import com.spice.profitmandi.dao.entity.affiliate.AffiliateEarnings;
import com.spice.profitmandi.dao.entity.affiliate.AffiliateProduct;
import com.spice.profitmandi.dao.entity.catalog.LiquidationDetail;
import com.spice.profitmandi.common.solr.SolrService;
import com.spice.profitmandi.common.util.FormattingUtils;
import com.spice.profitmandi.common.util.PdfUtils;
import com.spice.profitmandi.common.util.Utils;
import com.spice.profitmandi.common.web.client.RestClient;
import com.spice.profitmandi.common.web.util.ResponseSender;
import com.spice.profitmandi.dao.entity.WebEntity.NavBar;
import com.spice.profitmandi.dao.entity.catalog.Bid;
import com.spice.profitmandi.dao.entity.catalog.Item;
import com.spice.profitmandi.dao.entity.catalog.Liquidation;
import com.spice.profitmandi.dao.entity.catalog.TagListing;
import com.spice.profitmandi.dao.entity.dtr.*;
import com.spice.profitmandi.dao.entity.fofo.*;
import com.spice.profitmandi.dao.entity.inventory.State;
import com.spice.profitmandi.dao.enumuration.cs.EscalationType;
import com.spice.profitmandi.dao.enumuration.dtr.OtpType;
import com.spice.profitmandi.dao.enumuration.dtr.WebListingSource;
import com.spice.profitmandi.dao.enumuration.transaction.OrderStatus;
import com.spice.profitmandi.dao.model.*;
import com.spice.profitmandi.dao.model.pendingOrder.PendingOrderDetail;
import com.spice.profitmandi.dao.repository.affiliateLink.AffiliateLinkRepository;
import com.spice.profitmandi.dao.repository.catalog.BidRepository;
import com.spice.profitmandi.dao.repository.catalog.ItemRepository;
import com.spice.profitmandi.dao.repository.catalog.LiquidationRepository;
import com.spice.profitmandi.dao.repository.catalog.TagListingRepository;
import com.spice.profitmandi.dao.repository.cs.CsService;
import com.spice.profitmandi.dao.repository.dtr.*;
import com.spice.profitmandi.dao.repository.fofo.*;
import com.spice.profitmandi.dao.repository.inventory.ItemAvailabilityCacheRepository;
import com.spice.profitmandi.dao.repository.inventory.StateRepository;
import com.spice.profitmandi.dao.repository.user.UserRepository;
import com.spice.profitmandi.dao.repository.webRepository.NavBarRepository;
import com.spice.profitmandi.dao.service.AffiliateService;
import com.spice.profitmandi.dao.service.BidService;
import com.spice.profitmandi.dao.service.OTPResponse;
import com.spice.profitmandi.service.CustomerService;
import com.spice.profitmandi.service.EmailService;
import com.spice.profitmandi.service.FofoUser;
import com.spice.profitmandi.service.NotificationService;
import com.spice.profitmandi.service.authentication.RoleManager;
import com.spice.profitmandi.service.catalog.BiddingModel;
import com.spice.profitmandi.service.integrations.zest.InsuranceService;
import com.spice.profitmandi.service.integrations.zest.MobileInsurancePlan;
import com.spice.profitmandi.service.inventory.*;
import com.spice.profitmandi.service.order.OrderService;
import com.spice.profitmandi.service.scheme.SchemeService;
import com.spice.profitmandi.service.user.RetailerService;
import com.spice.profitmandi.dao.service.OtpProcessor;
import com.spice.profitmandi.service.wallet.WalletService;
import com.spice.profitmandi.web.res.DealBrands;
import com.spice.profitmandi.web.res.DealObjectResponse;
import com.spice.profitmandi.web.res.DealsResponse;
import com.spice.profitmandi.web.res.ValidateCartResponse;
import com.spice.profitmandi.web.services.PartnerIndexService;
import in.shop2020.model.v1.order.WalletReferenceType;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.conn.HttpHostConnectException;
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.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

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

    private static final Logger logger = LogManager.getLogger(StoreController.class);

    private static final LocalTime CUTOFF_TIME = LocalTime.of(15, 0);

    private static final List<Integer> TAG_IDS = Arrays.asList(4);

    @Autowired
    CustomerAddressRepository customerAddressRepository;

    @Autowired
    WebOfferRepository webOfferRepository;

    @Value("${new.solr.url}")
    private String solrUrl;

    @Autowired
    private PartnerIndexService partnerIndexService;

    @Autowired
    InventoryService inventoryService;

    @Autowired
    UserAccountRepository userAccountRepository;

    @Value("${python.api.host}")
    private String host;

    @Autowired
    CustomerService customerService;

    @Value("${python.api.port}")
    private int port;

    @Autowired
    private SaholicInventoryService saholicInventoryService;

    @Autowired
    private PincodePartnerRepository pincodePartnerRepository;

    @Autowired
    private FofoStoreRepository fofoStoreRepository;

    @Autowired
    private RetailerService retailerService;

    @Autowired
    private PendingOrderRepository pendingOrderRepository;

    @Autowired
    private PendingOrderItemRepository pendingOrderItemRepository;

    @Autowired
    private PendingOrderService pendingOrderService;

    @Autowired
    private CustomerRepository customerRepository;

    @Autowired
    private SolrService commonSolrService;

    @Autowired
    private OtpProcessor otpProcessor;

    @Autowired
    private CurrentInventorySnapshotRepository currentInventorySnapshotRepository;

    @Autowired
    private ResponseSender<?> responseSender;

    @Autowired
    private TagListingRepository tagListingRepository;

    @Autowired
    private ItemRepository itemRepository;

    @Autowired
    private SchemeService schemeService;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private ItemAvailabilityCacheRepository itemAvailabilityCacheRepository;

    @Autowired
    private WebListingRepository webListingRepository;

    @Autowired
    private WebProductListingRepository webProductListingRepository;

    @Autowired
    private RoleManager roleManagerService;

    @Autowired
    EmailService emailService;

    @Autowired
    CsService csService;

    @Autowired
    private NotificationService notificationService;

    @Autowired
    private com.spice.profitmandi.dao.repository.dtr.UserRepository dtrUserRepository;

    @Autowired
    private FofoOrderRepository fofoOrderRepository;

    @Autowired
    private FofoOrderItemRepository fofoOrderItemRepository;

    @Autowired
    private OrderService orderService;

    @Autowired
    InsurancePolicyRepository insurancePolicyRepository;

    @Autowired
    LiquidationRepository liquidationRepository;

    @Autowired
    PendingOrderPlanRepository pendingOrderPlanRepository;

    @Autowired
    private ScratchOfferRepository scratchOfferRepository;
    private static final List<String> offlineOrders = Arrays.asList("EMIOD", "POD");

    @Autowired
    NavBarRepository navBarRepository;

    @Autowired
    BidRepository bidRepository;

    @Autowired
    BidService bidService;

    @Autowired
    WalletService walletService;

    @Autowired
    AffiliateLinkRepository affiliateLinkRepository;

    @Autowired
    AffiliateService affiliateService;

    @Autowired
    FofoUser fofoUser;

    List<String> filterableParams = Arrays.asList("brand");

    @RequestMapping(value = "/store/entity/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({@ApiImplicitParam(name = "Auth-Token", value = "Auth-Token", required = true, dataType = "string", paramType = "header")})
    @ApiOperation(value = "Get unit deal object")
    @Transactional(readOnly = true)
    public ResponseEntity<?> getUnitFocoDeal(HttpServletRequest request, @PathVariable(value = "id") long id) throws ProfitMandiBusinessException {
        List<FofoCatalogResponse> dealResponses = new ArrayList<>();
        List<Integer> tagIds = Arrays.asList(4);
        FofoCatalogResponse fofoCatalogResponse = null;
        UserInfo userInfo = (UserInfo) request.getAttribute("userInfo");
        if (roleManagerService.isPartner(userInfo.getRoleIds())) {
            String categoryId = "(3 OR 6)";

            RestClient rc = new RestClient();
            Map<String, String> params = new HashMap<>();
            List<String> mandatoryQ = new ArrayList<>();
            String catalogString = "catalog" + id;

            mandatoryQ.add(String.format("+(categoryId_i:%s) +(id:%s) +{!parent which=\"id:%s\"} tagId_i:(%s)", categoryId, catalogString, catalogString, StringUtils.join(tagIds, " ")));

            params.put("q", StringUtils.join(mandatoryQ, " "));
            params.put("fl", "*, [child parentFilter=id:catalog*]");
            params.put("sort", "rank_i asc, create_s desc");
            params.put("wt", "json");
            String response = null;
            try {
                response = rc.get(SchemeType.HTTP, solrUrl, 8984, "solr/demo/select", params);
            } catch (HttpHostConnectException e) {
                throw new ProfitMandiBusinessException("", "", "Could not connect to host");
            }
            JSONObject solrResponseJSONObj = new JSONObject(response).getJSONObject("response");
            JSONArray docs = solrResponseJSONObj.getJSONArray("docs");
            dealResponses = getCatalogResponse(docs, false, userInfo.getRetailerId());
            fofoCatalogResponse = dealResponses.get(0);
            fofoCatalogResponse.setWebOffers(webOfferRepository.selectAllActiveOffers().get(fofoCatalogResponse.getCatalogId()));

        } else {
            return responseSender.badRequest(
                    new ProfitMandiBusinessException("Retailer id", userInfo.getUserId(), "NOT_FOFO_RETAILER"));
        }
        return responseSender.ok(dealResponses.get(0));
    }

    private Object toDealObject(JsonObject jsonObject) {
        if (jsonObject.get("dealObject") != null && jsonObject.get("dealObject").asInt() == 1) {
            return new Gson().fromJson(jsonObject.toString(), DealObjectResponse.class);
        }
        return new Gson().fromJson(jsonObject.toString(), DealsResponse.class);
    }

    @RequestMapping(value = "/store/brands", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({@ApiImplicitParam(name = "Auth-Token", value = "Auth-Token", required = true, dataType = "string", paramType = "header")})
    @ApiOperation(value = "Get brand list and count for category")
    @Transactional(readOnly = true)
    public ResponseEntity<?> getBrands(HttpServletRequest request, @RequestParam(value = "category_id") String category_id) throws ProfitMandiBusinessException {
        logger.info("Request " + request.getParameterMap());
        String response = null;
        // TODO: move to properties
        String uri = ProfitMandiConstants.URL_BRANDS;
        RestClient rc = new RestClient();
        Map<String, String> params = new HashMap<>();
        params.put("category_id", category_id);
        List<DealBrands> dealBrandsResponse = null;
        try {
            response = rc.get(SchemeType.HTTP, host, port, uri, params);
        } catch (HttpHostConnectException e) {
            throw new ProfitMandiBusinessException("", "", "Could not connect to host");
        }

        dealBrandsResponse = new Gson().fromJson(response, new TypeToken<List<DealBrands>>() {
        }.getType());

        return responseSender.ok(dealBrandsResponse);
    }

    @RequestMapping(value = "/store/listing/{listingUrl}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @Transactional(readOnly = true)
    public ResponseEntity<?> bestSellers(HttpServletRequest request, @PathVariable String listingUrl) throws Exception {
        UserInfo userInfo = (UserInfo) request.getAttribute("userInfo");
        WebListing webListing = webListingRepository.selectByUrl(listingUrl);
        webListing.setFofoCatalogResponses(getDealResponses(userInfo, webListing));
        return responseSender.ok(webListing);
    }

    @RequestMapping(value = "/store/otp/generateOTP", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> generateOtp(HttpServletRequest request, @RequestParam String mobile) throws Exception {

        return responseSender.ok(otpProcessor.generateOtp(mobile, OtpType.REGISTRATION));

    }

    @RequestMapping(value = "/store/checkmobile/{mobile}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> checkRegistrationUsingMobile(HttpServletRequest request, @PathVariable String mobile ,@RequestParam(required = false, defaultValue = "false") boolean isSmartSeller) throws Exception {
        try {
            Customer customer = customerRepository.selectByMobileNumber(mobile);
            customer.setPasswordExist(StringUtils.isNotEmpty(customer.getPassword()));
            if(isSmartSeller){
                //ToDo: Send welcome mail
                customer.setSmartSeller(isSmartSeller);
                List<String> bccTo = Arrays.asList("sdtech@smartdukaan.com", "sriwant.wariz@smartdukaan.com");
                String[] userEmail = new String[]{customer.getEmailId()};
                emailService.sendMailWithAttachments("Welcome to SmartDukaan's SmartSeller", "welcome-smartseller.vm", null, userEmail, null, bccTo.toArray(new String[0]));
            }
            return responseSender.ok(new CustomerModel(true, customer));
        } catch (Exception e) {
            return responseSender.ok(new CustomerModel(false, null));
        }
    }


    @RequestMapping(value = "/store/getCustomerById/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @Transactional(readOnly = true)
    public ResponseEntity<?> getCustomerById(HttpServletRequest request, @PathVariable int id) throws Exception {

        Customer customer = customerRepository.selectById(id);
        customer.setPasswordExist(StringUtils.isNotEmpty(customer.getPassword()));

        return responseSender.ok(customer);

    }

    @RequestMapping(value = "/store/signin", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> signIn(HttpServletRequest request, @RequestBody UserModel userModel) throws Exception {
        if (customerService.authenticate(userModel.getMobile(), userModel.getPassword())) {
            return responseSender.ok(true);
        } else {
            return responseSender.badRequest("Invalid Credentials");
        }
    }

    @RequestMapping(value = "/store/resetPassword", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> resetPassword(@RequestBody UserModel userModel) throws Exception {
        if ((userModel.getMobile() == null || userModel.getMobile().isEmpty()) && (userModel.getPassword() == null || userModel.getPassword().isEmpty())) {
            throw new ProfitMandiBusinessException("error", "", "all field are required");
        }
        try {
            customerService.resetPassword(userModel.getMobile(), userModel.getPassword());
        } catch (ProfitMandiBusinessException p) {
            throw new ProfitMandiBusinessException("error", "", "An error occurred while resetting password");
        }

        return responseSender.ok(true);
    }

    @RequestMapping(value = "/store/changePassword", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> changePassword(@RequestBody UserModel userModel) throws Exception {
        logger.info("UserModel - " + userModel);
        if ((userModel.getOldPassword() == null || userModel.getOldPassword().isEmpty()) && (userModel.getMobile() == null || userModel.getMobile().isEmpty()) && (userModel.getPassword() == null || userModel.getPassword().isEmpty())) {
            throw new ProfitMandiBusinessException("error", "", "all fields are required");
        }
        try {
            customerService.changePassword(userModel.getMobile(), userModel.getOldPassword(), userModel.getPassword());
        } catch (ProfitMandiBusinessException p) {
            throw new ProfitMandiBusinessException("error", "", "An error occurred while changing password");
        }
        return responseSender.ok(true);
    }

    @RequestMapping(value = "/store/register", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> register(HttpServletRequest request, @RequestBody UserModel userModel) throws Exception {
        Customer customer = new Customer();
        customer.setPassword(userModel.getPassword());
        customer.setEmailId(userModel.getEmail());
        customer.setFirstName(userModel.getFirstName());
        customer.setLastName(userModel.getLastName());
        customer.setMobileNumber(userModel.getMobile());
        customer.setSmartSeller(userModel.getIsSmartSeller());
        if (userModel.getIsSmartSeller()){
            if (userModel.getReferralCode() != null && !userModel.getReferralCode().isEmpty()) {
                int referrerId = Integer.parseInt(userModel.getReferralCode().substring(2));
                AffiliateEarnings earnings = new AffiliateEarnings();
                earnings.setType(ProfitMandiConstants.EARNING_TYPE.REFERRAL);
                earnings.setAffiliateCode(userModel.getReferralCode());
                earnings.setPoints(ProfitMandiConstants.SMARTSELLER_REFERRAL_POINTS);
                earnings.setAmount((float) ProfitMandiConstants.SMARTSELLER_REFERRAL_POINTS);
                earnings.setCustomerId(referrerId);
                earnings.setOrderId(referrerId);
                earnings.setItemId(referrerId);
                earnings.setExpireAt(LocalDateTime.now().plusYears(1));
                affiliateService.createEarnings(earnings);
                customer.setReferralCode(userModel.getReferralCode());
            }
            List<String> bccTo = Arrays.asList("sdtech@smartdukaan.com", "sriwant.wariz@smartdukaan.com");
            String[] userEmail = new String[]{userModel.getEmail()};
            emailService.sendMailWithAttachments("Welcome to SmartDukaan's SmartSeller", "welcome-smartseller.vm", null, userEmail, null, bccTo.toArray(new String[0]));
        }
        return responseSender.ok(customerService.addCustomer(customer));
    }
    @RequestMapping(value = "/store/signinWithOtp", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> signInWithOtp(HttpServletRequest request,
                                           @RequestBody OtpLoginRequest otpLoginRequest) throws Exception {
        OTPResponse otpResponse = otpProcessor.validateOtp(
                otpLoginRequest.getReferenceId(),
                otpLoginRequest.getMobile(),
                otpLoginRequest.getOtp()
        );
        if (otpResponse.isResult()) {
            return responseSender.ok(true);
        } else {
            return responseSender.badRequest("Invalid otp please check again");
        }
    }

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

        try {
            Map<String, List<MobileInsurancePlan>> response = this.getPlans(price, itemId);
            List<MobileInsurancePlan> combinedPlans = new ArrayList<>();
            for (List<MobileInsurancePlan> plans : response.values()) {
                combinedPlans.addAll(plans);
            }
            return responseSender.ok(combinedPlans);
        } catch (Exception e) {
            logger.info(e.getMessage(), e);
            throw new ProfitMandiBusinessException("Plans", "Plans API", "Error formatting insurance plans");
        }

    }

    @Autowired
    InsuranceService insuranceService;

    private Map<String, List<MobileInsurancePlan>> getPlans(float sellingPrice, int itemId)
            throws ProfitMandiBusinessException {
        try {
            Map<String, List<MobileInsurancePlan>> productDurationPlans = insuranceService.getAllPlans(itemId, sellingPrice, true);
            Map<String, List<MobileInsurancePlan>> filteredPlans = productDurationPlans.entrySet()
                    .stream()
                    .collect(Collectors.toMap(
                            Map.Entry::getKey,
                            e -> e.getValue().stream()
                                    .filter(plan -> "5".equals(plan.getProviderId()))
                                    .collect(Collectors.toList())
                    ));
            return filteredPlans;
        } catch (Exception e) {
            logger.info(e, e);
            throw new ProfitMandiBusinessException("Fetch Insurance Plans", "Insurance", "Could not fetch insurance Plans");
        }

    }

    @RequestMapping(value = "/store/confirmOrder", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> confirmOrder(HttpServletRequest request, @RequestBody CreatePendingOrderRequest createPendingOrderRequest) throws Exception {
        UserInfo userInfo = (UserInfo) request.getAttribute("userInfo");
        Integer storeId = userInfo.getRetailerId();
        createPendingOrderRequest.setFofoId(storeId);
        List<CreatePendingOrderItem> pendingOrderItems = createPendingOrderRequest.getCreatePendingOrderItem();
        List<CartItem> cartItems = new ArrayList<>();
        pendingOrderItems.stream().forEach(x -> {
            CartItem ci = new CartItem();
            ci.setItemId(x.getItemId());
            ci.setQuantity(x.getQuantity());
            ci.setSellingPrice(x.getSellingPrice());
            ci.setSmartSellerId(x.getSmartSellerId());
            ci.setPendingOrderItemPolicyPlan(x.getPendingOrderItemPolicyPlan());
            cartItems.add(ci);
        });
        logger.info("cartItems {}", cartItems);
        CartResponse cr = this.validateCart(storeId, cartItems);
        logger.info("CartResponse cr {}", cr);
        if (cr.getCartMessageChanged() > 0 || cr.getTotalAmount() != createPendingOrderRequest.getTotalAmount()) {
            return responseSender.badRequest(cr.getCartMessages());
        }

        Map<String, String> returnMap = this.pendingOrderService.createPendingOrder(createPendingOrderRequest, cr);

        PendingOrder pendingOrder = pendingOrderRepository.selectById(Integer.parseInt(returnMap.get("poId")));
        if (offlineOrders.contains(pendingOrder.getPayMethod())) {

            Map<String, Object> emailModel = pendingOrderService.sendCreateOrderMail(pendingOrder);

            CustomRetailer customRetailer = retailerService.getFofoRetailer(pendingOrder.getFofoId());
            Customer customer = customerRepository.selectById(pendingOrder.getCustomerId());
            String[] customerEmail = null;
            if (Utils.validateEmail(customer.getEmailId())) {
                customerEmail = new String[]{customer.getEmailId()};
            }

            List<String> bccTo = Arrays.asList("kamini.sharma@smartdukaan.com", "tarun.verma@smartdukaan.com", "niranjan.kala@smartdukaan.com", "sm@smartdukaan.com", "ranu.rajput@smartdukaan.com", "devkinandan.lal@smartdukaan.com", customRetailer.getEmail());

            List<String> authUserEmails = csService.getAuthUserByPartnerId(customRetailer.getPartnerId());
            if (authUserEmails != null) {
                authUserEmails = new ArrayList<>();
            }
            logger.info("authUserEmails {}", authUserEmails);
            authUserEmails.addAll(bccTo);
            StringBuffer itemBuffer = new StringBuffer();
            List<PendingOrderItem> orderItems = pendingOrderItemRepository.selectByOrderId(pendingOrder.getId());
            int totalItems = 0;
            String itemNoColor = null;
            float maxValue = 0;
            for (PendingOrderItem orderItem : orderItems) {
                if (maxValue < orderItem.getSellingPrice()) {
                    maxValue = orderItem.getSellingPrice();
                    itemNoColor = itemRepository.selectById(orderItem.getItemId()).getItemDescriptionNoColor();
                }
                totalItems += orderItem.getQuantity();
            }
            if (totalItems > 1) {
                itemBuffer.append(StringUtils.abbreviate(itemNoColor, 22));
                itemBuffer.append(" +").append(totalItems - 1).append(" items");
            } else {
                itemBuffer.append(StringUtils.abbreviate(itemNoColor, 30));
            }
            String message = String.format(OtpProcessor.TEMPLATE_ORDER_CREATED, pendingOrder.getId(), itemBuffer.toString(), pendingOrder.getTotalAmount());
            otpProcessor.sendSms(OtpProcessor.TEMPLATE_ORDER_CREATED_ID, message, customer.getMobileNumber());

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

            List<String> emailIds = csService.getAuthUserIdByPartnerId(customRetailer.getPartnerId()).stream().map(x -> x.getEmailId()).collect(Collectors.toList());

            emailIds.addAll(
                    csService.getAuthUserIds(ProfitMandiConstants.TICKET_CATEGORY_MARKETING, Arrays.asList(EscalationType.L1, EscalationType.L2, EscalationType.L3, EscalationType.L4)).stream().map(x -> x.getEmailId()).collect(Collectors.toList()));
            emailIds.add("tarun.verma@smartdukaan.com");
            emailIds.add("devkinandan.lal@smartdukaan.com");
            emailIds.add("sdtech@smartdukaan.com");
            emailIds.add("sourcing@smartdukaan.com");
            List<User> user = dtrUserRepository.selectAllByEmailIds(emailIds);
            List<Integer> userIds = user.stream().map(x -> x.getId()).collect(Collectors.toList());

            logger.info("userIds" + userIds);
            SendNotificationModel sendNotificationModel = new SendNotificationModel();
            sendNotificationModel.setCampaignName("Online Order Alert");
            sendNotificationModel.setTitle("Online Order Update");
            sendNotificationModel.setMessage(String.format(
                    "You have new Online Order. Please check your Dashboard. In case of an activation scheme pls ensure the handset is activated, payout will be processed as per brand's activation report."));
            sendNotificationModel.setType("url");
            sendNotificationModel.setUrl("https://smartdukaan.com/pages/home/notifications");
            sendNotificationModel.setExpiresat(LocalDateTime.now().plusDays(1));
            sendNotificationModel.setMessageType(MessageType.notification);
            int userId = userAccountRepository.selectUserIdByRetailerId(pendingOrder.getFofoId());
            sendNotificationModel.setUserIds(Arrays.asList(userId));
            notificationService.sendNotification(sendNotificationModel);

            SendNotificationModel snm = new SendNotificationModel();
            snm.setCampaignName("Online Order Alert");
            snm.setTitle("Online Order Update");
            snm.setMessage(String.format("Your Partner " + customRetailer.getBusinessName() + " have new Online Order. Please inform your partner. In case of an activation scheme pls ensure the handset is activated, payout will be processed as per brand's activation report."));
            snm.setType("url");
            snm.setUrl("https://smartdukaan.com/pages/home/notifications");
            snm.setExpiresat(LocalDateTime.now().plusDays(1));
            snm.setMessageType(MessageType.notification);
            snm.setUserIds(userIds);
            notificationService.sendNotification(snm);

        }
        return responseSender.ok(returnMap);

    }
    @RequestMapping(value = "/store/address", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({@ApiImplicitParam(name = "Auth-Token", value = "Auth-Token", required = true, dataType = "string", paramType = "header")})
    @ApiOperation(value = "Get brand list and count for category")
    @Transactional(readOnly = true)
    public ResponseEntity<?> getAddress(HttpServletRequest request) throws Exception {
        UserInfo userInfo = (UserInfo) request.getAttribute("userInfo");
        Integer storeId = userInfo.getRetailerId();
        CustomRetailer customRetailer = retailerService.getFofoRetailer(storeId);

        return responseSender.ok(customRetailer.getAddress());

    }
    @RequestMapping(value = "/store/address/defaultAddress/{addressId}/{customerId}", method = RequestMethod.POST)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "Auth-Token", value = "Auth-Token", required = true, dataType = "string", paramType = "header")
    })
    @ApiOperation(value = "Set default address for a store")
    public ResponseEntity<?> setDefaultAddress(HttpServletRequest request, @PathVariable int addressId, @PathVariable int customerId) throws Exception {
        UserInfo userInfo = (UserInfo) request.getAttribute("userInfo");
        CustomerAddress defaultAddress;
        try {
            defaultAddress = customerAddressRepository.selectById(addressId);
        } catch (ProfitMandiBusinessException e) {
            return responseSender.badRequest("Address not found.");
        }
        logger.info("CustomerID: {}", customerId);
        List<CustomerAddress> customerAddresses = customerAddressRepository.selectByActiveCustomerId(customerId);
        logger.info("customerAddresses: {}", customerAddresses);
        for (CustomerAddress addr : customerAddresses) {
            if (addr.getDefault() ) {
                addr.setDefault(false);
            }
        }
        defaultAddress.setDefault(true);
        return responseSender.ok("Default address updated successfully.");
    }

    @RequestMapping(value = "/store/address/{pincode}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({@ApiImplicitParam(name = "Auth-Token", value = "Auth-Token", required = true, dataType = "string", paramType = "header")})
    @ApiOperation(value = "Get brand list and count for category")
    @Transactional(readOnly = true)
    public ResponseEntity<?> getStoresByPincode(HttpServletRequest request, @PathVariable String pincode) throws Exception {
        List<PincodePartner> pincodePartners = pincodePartnerRepository.selectPartnersByPincode(pincode);
        int fofoId = ProfitMandiConstants.DEFAULT_STORE;
        if (pincodePartners.size() > 0) {
            List<Integer> fofoIds = pincodePartners.stream().map(x -> x.getFofoId()).collect(Collectors.toList());
            List<FofoStore> fofoStores = fofoStoreRepository.selectActivePartnersByRetailerIds(fofoIds);
            if (fofoStores.size() > 0) {
                fofoId = fofoStores.get(0).getId();
            }

        }
        return responseSender.ok(fofoStoreRepository.selectByRetailerId(fofoId).getCode());
    }

    @RequestMapping(value = "/store/addresses", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({@ApiImplicitParam(name = "Auth-Token", value = "Auth-Token", required = true, dataType = "string", paramType = "header")})
    @ApiOperation(value = "Get brand list and count for category")
    @Transactional(readOnly = true)
    public ResponseEntity<?> getStoresByPincod(HttpServletRequest request, @RequestParam String pincode, @RequestParam(name = "fofoCode", defaultValue = "", required = false) String fofoCode) throws Exception {

        List<CustomRetailer> customerRetailers = new ArrayList<>();

        logger.info("fofoCode" + fofoCode);

        if (fofoCode != null) {
            FofoStore fs = fofoStoreRepository.selectByStoreCode(fofoCode.toUpperCase());
            PincodePartner pp = pincodePartnerRepository.selectPartnerByPincode(pincode, fs.getId());
            if (pp != null) {
                return responseSender.ok(customerRetailers.add(retailerService.getFofoRetailer(pp.getFofoId())));
            } else {

                List<PincodePartner> pincodePartners = pincodePartnerRepository.selectPartnersByPincode(pincode);
                if (pincodePartners.size() > 0) {

                    List<Integer> fofoIds = pincodePartners.stream().map(x -> x.getFofoId()).collect(Collectors.toList());
                    List<Integer> activefofoIds = fofoStoreRepository.selectByRetailerIds(fofoIds).stream().filter(x -> x.isActive()).map(x -> x.getId()).collect(Collectors.toList());

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

                    Map<Integer, CustomRetailer> customerRetailerMap = activefofoIds.stream().map(x -> customRetailerMap.get(x)).filter(x -> x != null).collect(Collectors.toList()).stream().collect(Collectors.toMap(x -> x.getPartnerId(), x -> x));

                    customerRetailers.addAll(customerRetailerMap.values());

                }
                return responseSender.ok(customerRetailers);

            }
        } else {

            List<PincodePartner> pincodePartners = pincodePartnerRepository.selectPartnersByPincode(pincode);
            if (pincodePartners.size() > 0) {
                List<Integer> fofoIds = pincodePartners.stream().map(x -> x.getFofoId()).collect(Collectors.toList());
                List<Integer> activefofoIds = fofoStoreRepository.selectByRetailerIds(fofoIds).stream().filter(x -> x.isActive()).map(x -> x.getId()).collect(Collectors.toList());

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

                Map<Integer, CustomRetailer> customerRetailerMap = activefofoIds.stream().map(x -> customRetailerMap.get(x)).filter(x -> x != null).collect(Collectors.toList()).stream().collect(Collectors.toMap(x -> x.getPartnerId(), x -> x));

                customerRetailers.addAll(customerRetailerMap.values());
            }

            return responseSender.ok(customerRetailers);

        }

    }

    @RequestMapping(value = "/store/address/detail/{pincode}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({@ApiImplicitParam(name = "Auth-Token", value = "Auth-Token", required = true, dataType = "string", paramType = "header")})
    @ApiOperation(value = "Get brand list and count for category")
    @Transactional(readOnly = true)
    public ResponseEntity<?> getStoresDetailsByPincode(HttpServletRequest request, @PathVariable String pincode) throws Exception {
        List<CustomRetailer> customerRetailers = new ArrayList<>();
        List<PincodePartner> pincodePartners = pincodePartnerRepository.selectPartnersByPincode(pincode);

        if (!pincodePartners.isEmpty()) {
            List<Integer> fofoIds = pincodePartners.stream().map(x -> x.getFofoId()).collect(Collectors.toList());
            List<Integer> activefofoIds = fofoStoreRepository.selectByRetailerIds(fofoIds).stream().filter(x -> x.isActive()).map(x -> x.getId()).collect(Collectors.toList());

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

            Map<Integer, CustomRetailer> customerRetailerMap = activefofoIds.stream().map(x -> customRetailerMap.get(x)).filter(x -> x != null).collect(Collectors.toList()).stream().collect(Collectors.toMap(x -> x.getPartnerId(), x -> x));

            customerRetailers.addAll(customerRetailerMap.values());
        }

        logger.info("customerRetailers" + customerRetailers);
        return responseSender.ok(customerRetailers);
    }

    @RequestMapping(value = "/store/order", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @Transactional(readOnly = true)
    public ResponseEntity<?> getOrderDetail(HttpServletRequest request, @RequestParam(value = "id") int id, @RequestParam(name = "offset") int offset, @RequestParam(name = "limit") int limit) throws Exception {

        List<PendingOrderDetail> pendingOrderDetails = new ArrayList<>();
        List<Integer> catalogIds = new ArrayList<>();
        List<PendingOrder> pendingOrders = pendingOrderRepository.selectByCustomerId(id, offset, limit);

        if (!pendingOrders.isEmpty()) {
            for (PendingOrder po : pendingOrders) {
                List<PendingOrderItem> pois = pendingOrderItemRepository.selectByOrderId(po.getId());
                for (PendingOrderItem pendingOrderItem : pois) {
                    Item item = itemRepository.selectById(pendingOrderItem.getItemId());
                    pendingOrderItem.setItemName(item.getItemDescription());
                    FofoOrderItem fofoItem = fofoOrderItemRepository.selectByPendingOrderItemId(pendingOrderItem.getId());
                    if (fofoItem != null) pendingOrderItem.setFofoOrderItem(fofoItem);
                    catalogIds.add(item.getCatalogItemId());
                }

                Map<Integer, JSONObject> contentMap = commonSolrService.getContentByCatalogIds(catalogIds);

                for (PendingOrderItem poi : pois) {
                    PendingOrderDetail pendingOrderDetail = new PendingOrderDetail();
                    Item item = itemRepository.selectById(poi.getItemId());
                    if(contentMap.containsKey(item.getCatalogItemId())) {
                        JSONObject jsonObj = contentMap.get(item.getCatalogItemId());
                        pendingOrderDetail.setImageUrl(jsonObj.getString("imageUrl_s"));
                    } else {
                        pendingOrderDetail.setImageUrl(ProfitMandiConstants.NO_IMAGE);
                    }
                    pendingOrderDetail.setBrand(item.getBrand());
                    pendingOrderDetail.setColor(item.getColor());
                    pendingOrderDetail.setPendingOrderItemId(poi.getId());
                    pendingOrderDetail.setId(poi.getOrderId());
                    if(poi.getFofoOrderItem() != null && poi.getFofoOrderItem().getOrderId() > 0) pendingOrderDetail.setFofoOrderId(poi.getFofoOrderItem().getOrderId());
                    pendingOrderDetail.setItemId(poi.getItemId());
                    pendingOrderDetail.setModelName(item.getModelName());
                    pendingOrderDetail.setModelNumber(item.getModelNumber());
                    pendingOrderDetail.setQuantity(poi.getQuantity());
                    pendingOrderDetail.setBilledTimestamp(poi.getBilledTimestamp());
                    pendingOrderDetail.setStatus(poi.getStatus());
                    pendingOrderDetail.setTotalPrice(poi.getSellingPrice());
                    pendingOrderDetail.setPayMethod(po.getPayMethod());
                    pendingOrderDetail.setCreatedTimeStamp(po.getCreateTimestamp());
                    pendingOrderDetail.setPendingOrderPlan(pendingOrderPlanRepository.selectByPoid(poi.getId()));
                    pendingOrderDetails.add(pendingOrderDetail);
                }
            }
        }

        return responseSender.ok(pendingOrderDetails);
    }

    @RequestMapping(value = "/store/invoiceOrder", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @Transactional(readOnly = true)
    public ResponseEntity<?> getOrderInvoiceDetail(HttpServletRequest request, @RequestParam(value = "id") int id, @RequestParam(name = "offset") int offset, @RequestParam(name = "limit") int limit) throws Exception {
        List<CustomerOrderAndInsuranceDetails> customerOrderAndInsuranceDetails = new ArrayList<>();
        List<Integer> catalogIds = new ArrayList<>();
        List<FofoOrder> fofoOrders = fofoOrderRepository.selectOrderByCustomerId(id, offset, limit);

        if (!fofoOrders.isEmpty()) {
            for (FofoOrder fo : fofoOrders) {
                List<FofoOrderItem> fofoOrderItems = fofoOrderItemRepository.selectByOrderId(fo.getId());
                for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
                    Item item = itemRepository.selectById(fofoOrderItem.getItemId());
                    fofoOrderItem.setItemName(item.getItemDescription());
                    catalogIds.add(item.getCatalogItemId());
                }

                Map<Integer, JSONObject> contentMap = commonSolrService.getContentByCatalogIds(catalogIds);
                for (FofoOrderItem foi : fofoOrderItems) {
                    CustomerOrderAndInsuranceDetails customerOrderDetail = new CustomerOrderAndInsuranceDetails();
                    Item item = itemRepository.selectById(foi.getItemId());
                    JSONObject jsonObj = contentMap.get(item.getCatalogItemId());
                    customerOrderDetail.setImageUrl(jsonObj.getString("imageUrl_s"));
                    customerOrderDetail.setBrand(item.getBrand());
                    customerOrderDetail.setColor(item.getColor());
                    customerOrderDetail.setFofoOrderItemId(foi.getId());
                    customerOrderDetail.setFofoOrderId(foi.getOrderId());
                    customerOrderDetail.setItemId(foi.getItemId());
                    customerOrderDetail.setModelName(item.getModelName());
                    customerOrderDetail.setModelNumber(item.getModelNumber());
                    customerOrderDetail.setQuantity(foi.getQuantity());
                    customerOrderDetail.setTotalPrice(foi.getSellingPrice());
                    customerOrderDetail.setCreatedTimeStamp(foi.getCreateTimestamp());
                    customerOrderDetail.setInvoiceNumber(fo.getInvoiceNumber());
                    customerOrderDetail.setCancelledTimestamp(fo.getCancelledTimestamp());
                    customerOrderDetail.setInsurancePolicies(insurancePolicyRepository.selectByRetailerIdInvoiceNumber(fo.getInvoiceNumber()));
                    customerOrderAndInsuranceDetails.add(customerOrderDetail);
                }

            }

        }
        return responseSender.ok(customerOrderAndInsuranceDetails);
    }

    @RequestMapping(value = "/store/generateInvoice", method = RequestMethod.GET)
    @Transactional(readOnly = true)
    public ResponseEntity<?> generateInvoice(HttpServletRequest request, @RequestParam(name = ProfitMandiConstants.ORDER_ID) int orderId) throws ProfitMandiBusinessException {
        InvoicePdfModel pdfModel = null;
        FofoOrder fo = fofoOrderRepository.selectByOrderId(orderId);
        pdfModel = orderService.getInvoicePdfModel(fo.getFofoId(), orderId);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        PdfUtils.generateAndWrite(Arrays.asList(pdfModel), byteArrayOutputStream);
        try {
            byteArrayOutputStream.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        final HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_PDF);
        // headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");

        headers.setContentType(MediaType.parseMediaType("application/pdf"));
        headers.set("Content-disposition", "inline; filename=invoice-" + pdfModel.getInvoiceNumber() + ".pdf");
        headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
        headers.add("Pragma", "no-cache");
        headers.add("Expires", "0");

        headers.setContentLength(byteArrayOutputStream.toByteArray().length);
        final InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        final InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
        return new ResponseEntity<>(inputStreamResource, headers, HttpStatus.OK);
        // return responseSender.ok(new
        // ResponseEntity<byte[]>(byteArrayOutputStream.toByteArray(),
        // headers,HttpStatus.OK));
        /*
         * ResponseEntity<byte[]> response = new
         * ResponseEntity<byte[]>(byteArrayOutputStream.toByteArray(), headers,
         * HttpStatus.OK); return response;{
         */

    }

    @RequestMapping(value = "/store/listing", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @Cacheable(value = "storesListing", cacheManager = "thirtyMinsTimeOutCacheManager")
    @Transactional(readOnly = true)
    public ResponseEntity<?> getStoresListing(HttpServletRequest request) throws Exception {
        List<WebListing> webListings = webListingRepository.selectAllWebListingByType(Optional.of(true), WebListingSource.store);
        UserInfo userInfo = (UserInfo) request.getAttribute("userInfo");
        for (WebListing webListing : webListings) {
            webListing.setFofoCatalogResponses(getDealResponses(userInfo, webListing));
        }
        return responseSender.ok(webListings);
    }

    @Autowired
    StateRepository stateRepository;

    @RequestMapping(value = "/store/stateList", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @Transactional(readOnly = true)
    public ResponseEntity<?> getStateList(HttpServletRequest request) throws Exception {
        List<State> states = stateRepository.selectAll();
        return responseSender.ok(states);
    }
    /*@RequestMapping(value = "/store/listing", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> getStoresListing(HttpServletRequest request) throws Exception {
        List<WebListing> webListings = webListingRepository.selectAllWebListingByType(Optional.of(true), WebListingSource.store);
        UserInfo userInfo = (UserInfo) request.getAttribute("userInfo");
        Iterator<WebListing> webListingIterator = webListings.iterator();
        while (webListingIterator.hasNext()) {
            WebListing webListing = webListingIterator.next();
            List<FofoCatalogResponse> catalogResponses = getDealResponses(userInfo, webListing);
            boolean isAvailable = catalogResponses.stream().anyMatch(x->x.getItems().stream().anyMatch(y->y.getAvailability()>0));
            webListing.setFofoCatalogResponses(catalogResponses);
            if(!isAvailable) {
                webListings.remove(webListing);
            }
        }

        return responseSender.ok(webListings);
    }*/

    private List<FofoCatalogResponse> getDealResponses(UserInfo userInfo, WebListing webListing) throws ProfitMandiBusinessException {
        List<Integer> webProducts = webProductListingRepository.selectAllByWebListingId(webListing.getId()).stream().filter(x -> x.getRank() > 0).map(x -> x.getEntityId()).collect(Collectors.toList());
        if (webProducts.size() == 0) {
            return new ArrayList<>();
        }
        RestClient rc = new RestClient();
        Map<String, String> params = new HashMap<>();
        List<String> mandatoryQ = new ArrayList<>();
        mandatoryQ.add(String.format(
                "+{!parent which=\"catalogId_i:(" + StringUtils.join(webProducts, " ") + ")\"} tagId_i:(%s)", StringUtils.join(TAG_IDS, " ")));
        params.put("q", StringUtils.join(mandatoryQ, " "));
        params.put("fl", "*, [child parentFilter=id:catalog*]");
        // params.put("sort", "create_s desc");
        params.put("start", String.valueOf(0));
        params.put("rows", String.valueOf(100));
        params.put("wt", "json");
        String response = null;
        try {
            response = rc.get(SchemeType.HTTP, solrUrl, 8984, "solr/demo/select", params);
        } catch (HttpHostConnectException e) {
            throw new ProfitMandiBusinessException("", "", "Could not connect to host");
        }
        JSONObject solrResponseJSONObj = new JSONObject(response).getJSONObject("response");
        JSONArray docs = solrResponseJSONObj.getJSONArray("docs");
        List<FofoCatalogResponse> dealResponse = getCatalogResponse(docs, false, userInfo.getRetailerId());
        return dealResponse;
    }

    @RequestMapping(value = "/store/cart", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({@ApiImplicitParam(name = "Auth-Token", value = "Auth-Token", required = true, dataType = "string", paramType = "header")})
    @ApiOperation(value = "Get brand list and count for category")
    public ResponseEntity<?> cart(HttpServletRequest request, @RequestBody AddCartRequest cartRequest) throws Exception {
        UserInfo userInfo = (UserInfo) request.getAttribute("userInfo");
        logger.info("cartRequest: {}",cartRequest);
        Integer storeId = userInfo.getRetailerId();
        ValidateCartResponse vc = new ValidateCartResponse(this.validateCart(storeId, cartRequest.getCartItems()), "Success", "Items added to cart successfully");
        return responseSender.ok(vc);
    }

    // Validate Cart for B2C Customers
    private CartResponse validateCart(int storeId, List<CartItem> cartItems) throws Exception {

        logger.info("cartItems {}", cartItems);
        cartItems = cartItems.stream().filter(x -> x.getQuantity() > 0).collect(Collectors.toList());
        List<Integer> itemIds = cartItems.stream().map(x -> x.getItemId()).collect(Collectors.toList());
        Map<Integer, AvailabilityModel> inventoryItemAvailabilityMap = inventoryService.getStoreAndOurStock(storeId, itemIds);
        CartResponse cartResponse = new CartResponse();
        List<CartItemResponseModel> cartItemResponseModels = new ArrayList<>();
        cartResponse.setCartItems(cartItemResponseModels);
        Set<Integer> itemsIdsSet = new HashSet<>(itemIds);
        logger.info("Store Id {}, Item Ids {}", storeId, itemsIdsSet);

        Map<Integer, Item> itemsMap = itemRepository.selectByIds(itemsIdsSet).stream().collect(Collectors.toMap(x -> x.getId(), x -> x));

        Map<Integer, TagListing> tagListingMap = tagListingRepository.selectByItemIdsAndTagIds(new HashSet<>(itemIds), new HashSet<>(Arrays.asList(4))).stream().collect(Collectors.toMap(x -> x.getItemId(), x -> x));

        List<Integer> catalogIds = itemsMap.values().stream().map(x -> x.getCatalogItemId()).collect(Collectors.toList());

        Map<Integer, JSONObject> contentMap = commonSolrService.getContentByCatalogIds(catalogIds);

        // cartResponse.getCartItems()
        int cartMessageChanged = 0;
        int cartMessageOOS = 0;
        int totalAmount = 0;
        int totalQty = 0;
        List<CartMessage> itemMessages = new ArrayList<>();
        for (CartItem cartItem : cartItems) {
            Item item = itemsMap.get(cartItem.getItemId());
            CartMessage itemMsg = new CartMessage();
            TagListing tagListing = tagListingMap.get(cartItem.getItemId());
            int catalogId = itemsMap.get(cartItem.getItemId()).getCatalogItemId();
            Float cashback = schemeService.getCatalogSchemeCashBack(storeId, Arrays.asList(catalogId))
                    .get(itemsMap.get(cartItem.getItemId()).getCatalogItemId());
            cashback = cashback == null ? 0 : cashback;
            float itemSellingPrice = tagListing.getMop() - cashback;
            CartItemResponseModel cartItemResponseModel = new CartItemResponseModel();
            cartItemResponseModel.setSellingPrice(cartItem.getSellingPrice());
            cartItemResponseModel.setPendingOrderItemPolicyPlan(cartItem.getPendingOrderItemPolicyPlan());
            logger.info("itemSellingPrice: {}", itemSellingPrice);
            logger.info("cartItem: {}", cartItem.getSellingPrice());
            logger.info("cashback: {}", cashback);
            if (itemSellingPrice != cartItem.getSellingPrice()) {
                itemMsg.setType("price");
                itemMsg.setMessageText("Price has changed to " + itemSellingPrice);
                cartItemResponseModel.setSellingPrice(itemSellingPrice);
                cartMessageChanged++;
            }
            int estimate = -2;
            LocalDateTime promiseDeliveryTime = LocalDateTime.now();
            int qtyRequired = (int) cartItem.getQuantity();
            AvailabilityModel availabilityModel = inventoryItemAvailabilityMap.get(cartItem.getItemId());
            cartItemResponseModel.setMaxQuantity(availabilityModel.getMaxAvailability());
            if (availabilityModel.getStoreAvailability() >= qtyRequired) {
                itemMsg.setType("estimate0");
                itemMsg.setMessageText("Store availability is " + availabilityModel.getStoreAvailability());
                estimate = 0;
            } else if (availabilityModel.getWarehouseAvailability() >= qtyRequired) {
                itemMsg.setType("estimate2");
                itemMsg.setMessageText("Store availability is " + availabilityModel.getWarehouseAvailability());
                estimate = 2;
            } else if (availabilityModel.getStoreAvailability() > 0) {
                estimate = 0;
                qtyRequired = availabilityModel.getStoreAvailability();
                cartMessageChanged++;
                itemMsg.setType("quantity0");
                itemMsg.setMessageText("quantity is updated " + qtyRequired);
            } else if (availabilityModel.getWarehouseAvailability() > 0) {
                qtyRequired = availabilityModel.getWarehouseAvailability();
                estimate = 2;
                cartMessageChanged++;
                itemMsg.setType("quantity2");
                itemMsg.setMessageText("quantity is updated " + qtyRequired);
            } else {
                qtyRequired = 0;
                cartMessageChanged++;
                itemMsg.setType("item");
                itemMsg.setMessageText(item.getItemDescriptionNoColor() + " is out of stock");
            }
            cartItemResponseModel.setQuantity(qtyRequired);
            if (estimate >= 0 && LocalTime.now().isAfter(CUTOFF_TIME)) {
                estimate = estimate + 1;
                promiseDeliveryTime = promiseDeliveryTime.plusDays(3);
            }
            totalQty += qtyRequired;
            if (cartItem.getPendingOrderItemPolicyPlan() != null) {
                totalAmount += qtyRequired * itemSellingPrice + qtyRequired * cartItem.getPendingOrderItemPolicyPlan().getPrice();
            } else {
                totalAmount += qtyRequired * itemSellingPrice;
            }
            AffiliateProduct product = affiliateLinkRepository.findByCode(cartItem.getSmartSellerId());

            logger.info("product ===: {}", product);

            if (product != null && !product.getExpiryDate().isBefore(LocalDateTime.now())) {
                cartItemResponseModel.setSmartSellerId(cartItem.getSmartSellerId());
            }

            cartItemResponseModel.setEstimate(estimate);
            cartItemResponseModel.setTitle(item.getItemDescriptionNoColor());
            cartItemResponseModel.setItemId(cartItem.getItemId());
            cartItemResponseModel.setMinBuyQuantity(1);
            cartItemResponseModel.setQuantity(qtyRequired);
            cartItemResponseModel.setCategoryId(item.getCategoryId());
            cartItemResponseModel.setQuantityStep(1);
            cartItemResponseModel.setPromiseDelivery(promiseDeliveryTime);
            cartItemResponseModel.setMaxQuantity(availabilityModel.getMaxAvailability());
            cartItemResponseModel.setCatalogItemId(item.getCatalogItemId());
            cartItemResponseModel.setImageUrl(contentMap.get(item.getCatalogItemId()).getString("imageUrl_s"));
            cartItemResponseModel.setColor(item.getColor());
            cartItemResponseModels.add(cartItemResponseModel);
            itemMessages.add(itemMsg);
        }
        cartResponse.setCartItems(cartItemResponseModels);
        cartResponse.setCartMessages(itemMessages);
        cartResponse.setCartMessageChanged(cartMessageChanged);
        cartResponse.setCartMessageOOS(cartMessageOOS);
        int maxEstimate = cartItemResponseModels.stream().mapToInt(x -> x.getEstimate()).max().getAsInt();
        cartResponse.setMaxEstimate(maxEstimate);
        cartResponse.setTotalAmount(totalAmount);
        cartResponse.setTotalQty(totalQty);

        return cartResponse;

    }

    @RequestMapping(value = "/store/partnerStock", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @Transactional(readOnly = true)
    public ResponseEntity<?> partnerStock(HttpServletRequest request, @RequestParam(required = false, defaultValue = "3") String categoryId, @RequestParam int offset,
      @RequestParam int limit, @RequestParam(required = false) String sort, @RequestParam(required = false) String brand,
      @RequestParam(value = "subCategoryId", required = false) int subCategoryId, @RequestParam(required = false) String queryTerm,
      @RequestParam(required = false) String listing, @RequestParam(required = false, defaultValue = "true") boolean partnerStockOnly) throws Throwable {
        List<FofoCatalogResponse> dealResponse = new ArrayList<>();
        UserInfo userInfo = (UserInfo) request.getAttribute("userInfo");
        FofoStore fs = fofoStoreRepository.selectByRetailerId(userInfo.getRetailerId());
        sort = "w" + fs.getWarehouseId() + "_i desc";
        dealResponse = this.getCatalogResponse(
                commonSolrService.getSolrDocs(queryTerm, categoryId, offset, limit, sort, brand, subCategoryId, false, false,false), false, userInfo.getRetailerId());
        return responseSender.ok(dealResponse);
    }

    private List<FofoCatalogResponse> getCatalogResponse(JSONArray docs, boolean hotDeal, int fofoId) throws ProfitMandiBusinessException {
        Map<Integer, Integer> ourItemAvailabilityMap = null;
        Map<Integer, Integer> partnerStockAvailabilityMap = null;
        List<FofoCatalogResponse> dealResponse = new ArrayList<>();
        List<Integer> tagIds = Arrays.asList(4);
        if (docs.length() > 0) {
            HashSet<Integer> itemsSet = new HashSet<>();
            for (int i = 0; i < docs.length(); i++) {
                JSONObject doc = docs.getJSONObject(i);
                if (doc.has("_childDocuments_")) {
                    for (int j = 0; j < doc.getJSONArray("_childDocuments_").length(); j++) {
                        JSONObject childItem = doc.getJSONArray("_childDocuments_").getJSONObject(j);
                        int itemId = childItem.getInt("itemId_i");
                        itemsSet.add(itemId);
                    }
                }
            }
            if (itemsSet.size() == 0) {
                return dealResponse;
            }
            if (fofoId > 0) {
                partnerStockAvailabilityMap = currentInventorySnapshotRepository.selectItemsStock(fofoId).stream().collect(Collectors.toMap(x -> x.getItemId(), x -> x.getAvailability()));
            }
            ourItemAvailabilityMap = saholicInventoryService.getTotalAvailabilityByItemIds(new ArrayList<>(itemsSet));
        }

        for (int i = 0; i < docs.length(); i++) {
            Map<Integer, FofoAvailabilityInfo> fofoAvailabilityInfoMap = new HashMap<>();
            JSONObject doc = docs.getJSONObject(i);
            FofoCatalogResponse ffdr = new FofoCatalogResponse();
            ffdr.setCatalogId(doc.getInt("catalogId_i"));
            ffdr.setImageUrl(doc.getString("imageUrl_s"));
            ffdr.setTitle(doc.getString("title_s"));
            ffdr.setSuperCatalogTitle(doc.getString("superCatalog_s"));
            ffdr.setSuperCatalogId(doc.getInt("superCatalog_i"));
            ffdr.setSuperCatalogVariants(doc.getString("superCatalogVariants_s"));
            List<WebOffer> webOffers = webOfferRepository.selectAllActiveOffers().get(ffdr.getCatalogId());
            if (webOffers != null && webOffers.size() > 0) {
                ffdr.setOffers(webOffers.stream().map(x -> x.getTitle()).collect(Collectors.toList()));
            }
            try {
                ffdr.setFeature(doc.getString("feature_s"));
            } catch (Exception e) {
                ffdr.setFeature(null);
            }
            ffdr.setBrand(doc.getJSONArray("brand_ss").getString(0));

            if (doc.has("_childDocuments_")) {
                for (int j = 0; j < doc.getJSONArray("_childDocuments_").length(); j++) {
                    JSONObject childItem = doc.getJSONArray("_childDocuments_").getJSONObject(j);
                    int itemId = childItem.getInt("itemId_i");
                    ffdr.setIsSmartPhone(itemRepository.selectById(itemId).isSmartPhone());
                    float sellingPrice = (float) childItem.getDouble("sellingPrice_f");
                    if (fofoAvailabilityInfoMap.containsKey(itemId)) {
                        if (fofoAvailabilityInfoMap.get(itemId).getSellingPrice() > sellingPrice) {
                            fofoAvailabilityInfoMap.get(itemId).setSellingPrice(sellingPrice);
                            fofoAvailabilityInfoMap.get(itemId).setMop((float) childItem.getDouble("mop_f"));
                        }
                    } else {
                        FofoAvailabilityInfo fdi = new FofoAvailabilityInfo();
                        fdi.setSellingPrice(sellingPrice);
                        fdi.setMrp(childItem.getDouble("mrp_f"));
                        fdi.setMop((float) childItem.getDouble("mop_f"));
                        fdi.setColor(childItem.has("color_s") ? childItem.getString("color_s") : "");
                        fdi.setTagId(childItem.getInt("tagId_i"));
                        fdi.setItem_id(itemId);
                        fdi.setCatalog_id(doc.getInt("catalogId_i"));
                        Float cashBack = schemeService.getCatalogSchemeCashBack(fofoId, Arrays.asList(ffdr.getCatalogId())).get(ffdr.getCatalogId());
                        cashBack = cashBack == null ? 0 : cashBack;
                        // TODO:Dont commit
                        // fdi.setCashback(Math.min(100, fdi.getMop()));
                        fdi.setCashback(cashBack);
                        fdi.setMinBuyQuantity(1);
                        int partnerAvailability = partnerStockAvailabilityMap.get(itemId) == null ? 0 : partnerStockAvailabilityMap.get(itemId);
                        int ourStockAvailability = ourItemAvailabilityMap.get(itemId) == null ? 0 : Math.max(0, ourItemAvailabilityMap.get(itemId));
                        fdi.setActive(partnerAvailability > 0);
                        // fdi.setActive(true);
                        fdi.setPartnerAvailability(partnerAvailability);
                        fdi.setAvailability(Math.min(5, ourStockAvailability + partnerAvailability));
                        fdi.setQuantityStep(1);
                        fdi.setMaxQuantity(fdi.getAvailability());
                        fofoAvailabilityInfoMap.put(itemId, fdi);
                    }
                }
            }
            if (fofoAvailabilityInfoMap.values().size() > 0) {
                ffdr.setItems(fofoAvailabilityInfoMap.values().stream().sorted(Comparator.comparing(FofoAvailabilityInfo::isActive, Comparator.reverseOrder()).thenComparingInt(y -> -y.getAvailability())).collect(Collectors.toList()));
                dealResponse.add(ffdr);
            }
        }
        return dealResponse.stream().sorted(Comparator.comparing(FofoCatalogResponse::getItems, (s1, s2) -> (s2.get(0).isActive() ? 1 : 0) - (s1.get(0).isActive() ? 1 : 0)).thenComparing(FofoCatalogResponse::getItems, (x, y) -> y.get(0).getAvailability() - x.get(0).getAvailability())).collect(Collectors.toList());
    }

    @GetMapping(value = "store/order-status/{pendingOrderId}")
    @Transactional(readOnly = true)
    public ResponseEntity<?> orderStatus(HttpServletRequest request, @PathVariable int pendingOrderId) throws Exception {
        PendingOrder pendingOrder = pendingOrderRepository.selectById(pendingOrderId);
        List<PendingOrderItem> pendingOrderItems = pendingOrderItemRepository.selectByOrderId(pendingOrder.getId());
        List<Integer> catalogIds = new ArrayList<>();
        for (PendingOrderItem pendingOrderItem : pendingOrderItems) {
            //TODO : Amit feedback use poItemId instead of poId change Param name
            // when list is supposed then use method names as selectAllBy instead selectBy of
            //check for unique constraint
            List<PendingOrderPlan> policyPlans = pendingOrderPlanRepository.selectByPoId(pendingOrderItem.getId());
            pendingOrderItem.setPendingOrderItemPolicyPlan(policyPlans);
            Item item = itemRepository.selectById(pendingOrderItem.getItemId());
            pendingOrderItem.setItemName(item.getItemDescription());
            pendingOrderItem.setCatalogId(item.getCatalogItemId());
            catalogIds.add(item.getCatalogItemId());
        }
        Map<Integer, JSONObject> contentMap = commonSolrService.getContentByCatalogIds(catalogIds);
        for (PendingOrderItem pendingOrderItem : pendingOrderItems) {
            Item item = itemRepository.selectById(pendingOrderItem.getItemId());
            JSONObject jsonObj = contentMap.get(item.getCatalogItemId());
            pendingOrderItem.setImgUrl(jsonObj.getString("imageUrl_s"));
        }
        pendingOrder.setPendingOrderItems(pendingOrderItems);

        return responseSender.ok(pendingOrder);
    }

    @RequestMapping(value = "/store/addresses/{customerId}", method = RequestMethod.GET)
    @Transactional(readOnly = true)
    public ResponseEntity<?> getAll(HttpServletRequest request, @PathVariable int customerId) throws Throwable {
        return responseSender.ok(customerAddressRepository.selectByActiveCustomerId(customerId));
    }

    @RequestMapping(value = "/store/address", method = RequestMethod.POST)
    public ResponseEntity<?> addAddress(HttpServletRequest request, @RequestBody CustomerAddress customerAddress) throws Throwable {
        List<CustomerAddress> customerAddresses = customerAddressRepository.selectByActiveCustomerId(customerAddress.getCustomerId());
        if (customerAddresses.isEmpty()) {
            customerAddress.setDefault(true);
        } else {
            customerAddress.setDefault(false);
        }
        customerAddressRepository.persist(customerAddress);
        return responseSender.ok(customerAddress);
    }

    @RequestMapping(value = "/store/deactivateCustomerAddress", method = RequestMethod.POST)
    public ResponseEntity<?> deactivateAddresss(HttpServletRequest request, @RequestParam int id) throws Throwable {
        CustomerAddress cust = customerAddressRepository.selectById(id);
        List<CustomerAddress> customerAddresses = customerAddressRepository.selectByCustomerId(cust.getCustomerId());
        cust.setActive(false);
        if(cust.getDefault()){
            List<CustomerAddress> activeAddresses = customerAddresses.stream()
                    .filter(a -> a.getActive() && a.getId() != id)
                    .sorted(Comparator.comparing(CustomerAddress::getUpdateTimestamp).reversed())
                    .collect(Collectors.toList());

            if (!activeAddresses.isEmpty()) {
                CustomerAddress newDefault = activeAddresses.get(0);
                newDefault.setDefault(true);
            }
        }
        return responseSender.ok(cust);
    }

    @RequestMapping(value = "/store/updateCustomer", method = RequestMethod.POST)
    public ResponseEntity<?> updateCustomerProfile(HttpServletRequest request, @RequestBody Customer customer) throws Throwable {
        Customer cust = customerRepository.selectById(customer.getId());
        cust.setGender(customer.getGender());
        cust.setProfileImageId(customer.getProfileImageId());
        cust.setEmailId(customer.getEmailId());
        cust.setDob(customer.getDob());
        return responseSender.ok(cust);
    }

    @RequestMapping(value = "/stores/{state}/{city}/{storeCode}", method = RequestMethod.GET)
    public void getStoreIndex(HttpServletResponse response, HttpServletRequest request, @PathVariable String state, @PathVariable String city, @PathVariable String storeCode) throws Throwable {
        logger.info("Store code {}", storeCode);
        Map<String, Integer> map = retailerService.getStoreCodeRetailerMap();
        logger.info("retailer id {}", map.get(storeCode));
        String retailerName = retailerService.getAllFofoRetailers().get(map.get(storeCode)).getBusinessName();
        String html = partnerIndexService.getPartnerIndexHtml();
        logger.info("html {}", html);
        html = html.replace("Buy Mobiles and Accessories at exciting prices - SmartDukaan", String.format("%s is now ONLINE. Buy Mobiles, Accessories & more | SmartDukaan", retailerName));
        response.getWriter().write(html);
    }

    @RequestMapping(value = "/cancelPendingOrderItem", method = RequestMethod.POST)
    public ResponseEntity<?> cancelPendingOrderItem(HttpServletRequest request, @RequestParam int id, @RequestParam String statusDescription, @RequestParam String reason) throws Exception {

        PendingOrderItem pendingOrderItem = pendingOrderItemRepository.selectById(id);
        PendingOrder pendingOrder = pendingOrderRepository.selectById(pendingOrderItem.getOrderId());
        Customer customer = customerRepository.selectById(pendingOrder.getCustomerId());
        if (pendingOrderItem.getBilledTimestamp() == null) {
            pendingOrderItem.setStatus(OrderStatus.CANCELLED);
            pendingOrderItem.setRemark(reason);
            pendingOrderItem.setStatusDescription("cancel by self");
            pendingOrderItem.setCancelledTimestamp(LocalDateTime.now());
            List<OrderStatus> status = pendingOrderItemRepository.selectByOrderId(pendingOrderItem.getOrderId()).stream().map(x -> x.getStatus()).collect(Collectors.toList());

            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);
            String itemDescription = itemRepository.selectById(pendingOrderItem.getItemId()).getItemDescription();
            otpProcessor.sendSms(OtpProcessor.SELF_CANCELLED_TEMPLATE_ID, String.format(OtpProcessor.SELF_CANCELLED_TEMPLATE, pendingOrder.getId(), StringUtils.abbreviate(itemDescription, 30), FormattingUtils.format(pendingOrderItem.getCancelledTimestamp())), customer.getMobileNumber());

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

            String[] customerEmail = null;
            if (customer.getEmailId() != null) {
                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]));

            }
        }

        return responseSender.ok(true);

    }

    @RequestMapping(value = "/store/checkEligibilityStoreOffers", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @Transactional(readOnly = true)
    public ResponseEntity<?> checkEligibilityStoreOffers(HttpServletRequest request, @RequestParam(value = "id") int id) throws Exception {

        boolean eligibility = false;

        List<ScratchOffer> scratchOffers = scratchOfferRepository.selectBycCustomerIdAndDate(id, ProfitMandiConstants.SCRATCH_OFFER_START_DATE, ProfitMandiConstants.SCRATCH_OFFER_END_DATE);

        if (!scratchOffers.isEmpty()) {
            eligibility = true;

        }
        return responseSender.ok(eligibility);
    }

    @RequestMapping(value = "/store/ScratchOffers", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @Transactional(readOnly = true)
    public ResponseEntity<?> scratchOffers(HttpServletRequest request, @RequestParam(value = "id") int id) throws Exception {

        List<ScratchOffer> scratchOffers = scratchOfferRepository.selectBycCustomerIdAndDate(id, ProfitMandiConstants.SCRATCH_OFFER_START_DATE, ProfitMandiConstants.SCRATCH_OFFER_END_DATE);

        logger.info("scratchOffers {}", scratchOffers);
        // List<ScratchOffer> scratchOffers =
        // scratchOfferRepository.selectBycCustomerId(id);
        for (ScratchOffer so : scratchOffers) {
            if (LocalDateTime.now().isAfter(so.getUnlockedAt())) {
                so.setUnlocked(true);
            } else {
                so.setUnlocked(false);
            }
            LocalDateTime expiredTimestamp = ProfitMandiConstants.SCRATCH_OFFER_END_DATE.plusDays(0).atTime(LocalTime.MAX);
            so.setExpiredTimestamp(expiredTimestamp);
            if (LocalDateTime.now().isAfter(expiredTimestamp)) {
                so.setExpired(true);
            }
        }

        return responseSender.ok(scratchOffers);
    }

    @RequestMapping(value = "/store/ScratchedOffer", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> scratchedOffer(HttpServletRequest request, @RequestParam(value = "id") int id) throws Exception {

        ScratchOffer scratchOffer = scratchOfferRepository.selectById(id);
        scratchOffer.setScratched(true);
        scratchOffer.setScracthedAt(LocalDateTime.now());

        return responseSender.ok(true);
    }

    @RequestMapping(value = "/store/navbar", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @Transactional(readOnly = true)
    public ResponseEntity<?> navBars() throws Exception {
        List<NavBar> navBars = navBarRepository.selectAllActive();
        return responseSender.ok(navBars);
    }


    @RequestMapping(value = "/getMonthSale", method = RequestMethod.GET)
    @Transactional(readOnly = true)
    public ResponseEntity<?> getMonthsale(HttpServletRequest request) throws Exception {
        UserInfo userInfo = (UserInfo) request.getAttribute("userInfo");
        int fofoId = userInfo.getRetailerId();
        logger.info("getting the user resonse {} ",userInfo);
        Map<String, MonthSaleModel> monthSaleMap = new HashMap<>();
        LocalDateTime curDate = LocalDate.now().atStartOfDay();
        int dayOfMonth = curDate.getDayOfMonth();
        YearMonth yearMonth = YearMonth.now();
        for (int i = 0; i <= 6; i++) {
            LocalDateTime startOfMonth = curDate.withDayOfMonth(1).minusMonths(i);
            int lengthOfMonth = YearMonth.from(startOfMonth).lengthOfMonth();
            logger.info("Start of previous Month {}, start of next month Month {}", startOfMonth, startOfMonth.plusMonths(1));
            double monthSales = fofoOrderItemRepository.selectSumMopGroupByRetailer(startOfMonth, startOfMonth.plusMonths(1), fofoId, false).get(fofoId);
            double mtdSales = fofoOrderItemRepository.selectSumMopGroupByRetailer(startOfMonth, startOfMonth.plusDays(Math.min(dayOfMonth, lengthOfMonth)), fofoId, false).get(fofoId);

            MonthSaleModel ms = new MonthSaleModel();
            ms.setMtdSales(fofoUser.format((long) mtdSales));
            ms.setMonthlySales(fofoUser.format(((long) monthSales)));
            ms.setMonth(startOfMonth.format(DateTimeFormatter.ofPattern("MMM''uu")));
            monthSaleMap.put(String.valueOf(i), ms);
        }
        logger.info("getting the month sale map {}",monthSaleMap);
        return responseSender.ok(monthSaleMap);
    }
    @RequestMapping(value = "/getBrandwisePartnerSale", method = RequestMethod.GET)
    @ResponseBody
    @Transactional(readOnly = true)
    public ResponseEntity<?> getBrandwisePartnerSale(HttpServletRequest request, @RequestParam(name = "month", required = true, defaultValue = "0") int month, Model model) throws Exception {
        UserInfo userInfo = (UserInfo) request.getAttribute("userInfo");
        int fofoId = userInfo.getRetailerId();
        List<BrandWisePartnerSaleModel> brandWisePartnerSaleModels = fofoStoreRepository.selectBrandWiseMonthlyPartnerSale(Collections.singletonList(fofoId), month);
        List<Map<String, Object>> response = new ArrayList<>();
        for (BrandWisePartnerSaleModel m : brandWisePartnerSaleModels) {
            Map<String, Object> row = new HashMap<>();
            row.put("brand", m.getBrand());
            row.put("lms", fofoUser.format(m.getLms()));
            row.put("lmsQty", m.getLmsQty());
            row.put("mtd", fofoUser.format(m.getMtd()));
            row.put("mtdQty", m.getMtdQty());
            row.put("lmtd", fofoUser.format(m.getLmtd()));
            row.put("lmtdQty", m.getLmtdQty());
            row.put("amtd", fofoUser.format(m.getAmtd()));
            response.add(row);
        }
        logger.info("brandItemWisePartnerSaleModels {}", response);
        return responseSender.ok(response);
    }
    @RequestMapping(value = "/getBrandItemwisePartnerSale", method = RequestMethod.GET)
    @ResponseBody
    @Transactional(readOnly = true)
    public ResponseEntity<?> getBrandItemwisePartnerSale(HttpServletRequest request, @RequestParam(name = "month", required = true, defaultValue = "0") int month, @RequestParam(name = "brand") String brand) throws Exception {
        UserInfo userInfo = (UserInfo) request.getAttribute("userInfo");
        int fofoId = userInfo.getRetailerId();
        List<BrandItemWisePartnerSaleModel> brandItemWisePartnerSaleModels = fofoStoreRepository.selectPartnerBrandItemMonthlySale(Collections.singletonList(fofoId), month, brand);
        logger.info("getting brandwise item sale {}",brandItemWisePartnerSaleModels);
        return responseSender.ok(brandItemWisePartnerSaleModels);
    }


    @RequestMapping(value = "/store/clearance", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @Transactional(readOnly = true)
    public ResponseEntity<?> getLiquidations() throws Exception {
        List<Integer> catalogIds = new ArrayList<>();
        Map<Integer, JSONObject> contentMap = null;
        List<Liquidation> liquidations = liquidationRepository.selectAllByStatus(ProfitMandiConstants.LIQUIDATION_ENUM.PUBLISHED);

        if (!liquidations.isEmpty()) {
            for (Liquidation liquidation : liquidations) catalogIds.add(liquidation.getCatalogId());
            contentMap = commonSolrService.getContentByCatalogIds(catalogIds);
        }

        List<LiquidationDetail> resultList = new ArrayList<>();

        if (contentMap != null) {
            for (Liquidation liquidation : liquidations) {
                List<Bid> bidList = bidRepository.selectBidByLiquidationId(liquidation.getId());
                LiquidationDetail liquidationDetail = new LiquidationDetail();
                if(contentMap.containsKey(liquidation.getCatalogId())) {
                    JSONObject jsonObj = contentMap.get(liquidation.getCatalogId());
                    liquidationDetail.setLiquidationId(liquidation.getId());
                    liquidationDetail.setImageURL(jsonObj.getString("imageUrl_s"));
                    liquidationDetail.setItemName(jsonObj.getString("title_s"));
                    liquidationDetail.setBrand(jsonObj.getString("title_s"));
                    liquidationDetail.setCatalogId(jsonObj.getInt("catalogId_i"));
                    liquidationDetail.setMrp(jsonObj.getFloat("mop_f"));
                    liquidationDetail.setMop(jsonObj.getFloat("mop_f"));
                    liquidationDetail.setDp(jsonObj.getFloat("dp_f"));
                    liquidationDetail.setSuperCatalogs(jsonObj.getString("superCatalogVariants_s"));
                    liquidationDetail.setStartDate(liquidation.getStartDate());
                    liquidationDetail.setEndDate(liquidation.getEndDate());
                    liquidationDetail.setSellingPrice(liquidation.getPrice());
                    liquidationDetail.setAvailableQuantity(liquidation.getQuantity());
                    liquidationDetail.setIncrementStep(liquidation.getIncrementStep());
                    liquidationDetail.setBidList(bidList);
                    resultList.add(liquidationDetail);
                }
            }
        }

        return responseSender.ok(resultList);
    }

    @RequestMapping(value = "/store/clearance/bid", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({@ApiImplicitParam(name = "Auth-Token", value = "Auth-Token", required = true, dataType = "string", paramType = "header")})
    public ResponseEntity<?> saveBidding(HttpServletRequest request, @RequestBody BiddingModel biddingModel) throws Exception {
        LocalDateTime now = LocalDateTime.now();
        Liquidation liquidation = liquidationRepository.selectLiquidationById(biddingModel.getLiquidationId());
        LocalDateTime endDateTime = LocalDateTime.of(liquidation.getEndDate().toLocalDate(), LocalTime.of(ProfitMandiConstants.BID_END_HOUR, ProfitMandiConstants.BID_END_MIN));
        List<Bid> biddings = bidRepository.selectBidByLiquidationId(biddingModel.getLiquidationId());
        if (now.isAfter(endDateTime)) {
            return responseSender.badRequest("Bid on this product has been closed");
        }
        Bid bid = null;
        UserInfo userInfo = (UserInfo) request.getAttribute("userInfo");
        if (biddingModel.getId() != null && biddingModel.getId() > 0) {
            bid = bidRepository.selectById(biddingModel.getId());
            if (bid == null) {
                return responseSender.badRequest("Bidding record not found with ID: " + biddingModel.getId());
            }
        } else {
            bid = new Bid();
        }
        logger.info("biddingModel {}: ",biddingModel);
        bid.setLiquidationId(biddingModel.getLiquidationId());
        bid.setBiddingAmount(biddingModel.getBiddingAmount());
        bid.setFofoId(userInfo.getRetailerId());
        bid.setItemName(biddingModel.getItemName());
        bid.setQuantity(biddingModel.getBidQty());
        bid.setStatus(ProfitMandiConstants.BID_ENUM.PENDING);
        bid.setCreatedAt(LocalDateTime.now());
        if (biddingModel.getId() == null) {
            bidRepository.persist(bid);
            //debit 500 from wallet
            try {
                String reason = "Advance security for "+bid.getItemName()+" bid";
                String message = "Dear Partner, We have Debited Rs "+ProfitMandiConstants.BID_CHARGES+" as booking amount against your bidding of Model No. "+bid.getItemName()+". We will adjust this amount from your order amount if the bid gets approved.";
                walletService.consumeAmountFromWallet(bid.getFofoId(),
                        bid.getId(),
                        WalletReferenceType.ADVANCE_SECURITY,
                        reason, ProfitMandiConstants.BID_CHARGES,
                        bid.getCreatedAt(),false);
                bidService.sendPushNotification(message,"Bidding Update!",Arrays.asList(bid.getFofoId()));
            } catch (Exception e) {
                logger.info("WalletDebit: {}",e.getMessage());
            }
        }
        if (biddings.size() > 1) {
            for (Bid bidding : biddings) {
                if (!(bid.getFofoId().equals(bidding.getFofoId()))) bidService.notifyPartner(bidding.getFofoId(), bid, ProfitMandiConstants.BID_ENUM.UPDATE);
            }
        }
        return responseSender.ok("Bid placed successfully!");
    }


}