Subversion Repositories SmartDukaan

Rev

Rev 27069 | Rev 28206 | 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 java.io.StringWriter;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;

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.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
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.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.eclipsesource.json.JsonObject;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.Ordering;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.spice.profitmandi.common.enumuration.SchemeType;
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
import com.spice.profitmandi.common.model.CreatePendingOrderItem;
import com.spice.profitmandi.common.model.CreatePendingOrderRequest;
import com.spice.profitmandi.common.model.CustomRetailer;
import com.spice.profitmandi.common.model.ProfitMandiConstants;
import com.spice.profitmandi.common.model.UserInfo;
import com.spice.profitmandi.common.solr.SolrService;
import com.spice.profitmandi.common.web.client.RestClient;
import com.spice.profitmandi.common.web.util.ResponseSender;
import com.spice.profitmandi.dao.entity.catalog.Item;
import com.spice.profitmandi.dao.entity.catalog.TagListing;
import com.spice.profitmandi.dao.entity.dtr.WebListing;
import com.spice.profitmandi.dao.entity.fofo.Customer;
import com.spice.profitmandi.dao.entity.fofo.CustomerAddress;
import com.spice.profitmandi.dao.entity.fofo.PendingOrder;
import com.spice.profitmandi.dao.entity.fofo.PendingOrderItem;
import com.spice.profitmandi.dao.entity.fofo.PincodePartner;
import com.spice.profitmandi.dao.enumuration.dtr.OtpType;
import com.spice.profitmandi.dao.enumuration.transaction.OrderStatus;
import com.spice.profitmandi.dao.model.AddCartRequest;
import com.spice.profitmandi.dao.model.CartItem;
import com.spice.profitmandi.dao.model.CartItemResponseModel;
import com.spice.profitmandi.dao.model.CartResponse;
import com.spice.profitmandi.dao.model.CustomerOrderDetail;
import com.spice.profitmandi.dao.model.UserCart;
import com.spice.profitmandi.dao.repository.catalog.ItemRepository;
import com.spice.profitmandi.dao.repository.catalog.TagListingRepository;
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
import com.spice.profitmandi.dao.repository.dtr.UserAccountRepository;
import com.spice.profitmandi.dao.repository.dtr.WebListingRepository;
import com.spice.profitmandi.dao.repository.dtr.WebProductListingRepository;
import com.spice.profitmandi.dao.repository.fofo.CurrentInventorySnapshotRepository;
import com.spice.profitmandi.dao.repository.fofo.CustomerAddressRepository;
import com.spice.profitmandi.dao.repository.fofo.CustomerRepository;
import com.spice.profitmandi.dao.repository.fofo.PendingOrderItemRepository;
import com.spice.profitmandi.dao.repository.fofo.PendingOrderRepository;
import com.spice.profitmandi.dao.repository.fofo.PendingOrderService;
import com.spice.profitmandi.dao.repository.fofo.PincodePartnerRepository;
import com.spice.profitmandi.dao.repository.inventory.ItemAvailabilityCacheRepository;
import com.spice.profitmandi.service.CustomerService;
import com.spice.profitmandi.service.authentication.RoleManager;
import com.spice.profitmandi.service.inventory.AvailabilityModel;
import com.spice.profitmandi.service.inventory.FofoAvailabilityInfo;
import com.spice.profitmandi.service.inventory.FofoCatalogResponse;
import com.spice.profitmandi.service.inventory.InventoryService;
import com.spice.profitmandi.service.inventory.SaholicInventoryService;
import com.spice.profitmandi.service.scheme.SchemeService;
import com.spice.profitmandi.service.user.RetailerService;
import com.spice.profitmandi.web.processor.OtpProcessor;
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 io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;

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

        private static final int DEFAULT_STORE = 171912487;

        @Autowired
        CustomerAddressRepository customerAddressRepository;

        @Autowired
        SolrService solrService;

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

        // This is now unused as we are not supporting multiple companies.
        @Value("${gadgetCops.invoice.cc}")
        private String[] ccGadgetCopInvoiceTo;

        @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 ItemAvailabilityCacheRepository itemAvailabilityCacheRepository;

        @Autowired
        private WebListingRepository webListingRepository;

        @Autowired
        private WebProductListingRepository webProductListingRepository;

        @Autowired
        private RoleManager roleManagerService;

        @Autowired
        private VelocityEngine velocityEngine;

        @Autowired
        JavaMailSender mailSender;

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

        /*
         * @ApiImplicitParams({
         * 
         * @ApiImplicitParam(name = "Auth-Token", value = "Auth-Token", required = true,
         * dataType = "string", paramType = "header") })
         * 
         * @RequestMapping(value = "/store/fofo", method = RequestMethod.GET, produces =
         * MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<?>
         * getFofo(HttpServletRequest request,
         * 
         * @RequestParam(value = "categoryId", required = false, defaultValue =
         * "(3 OR 6)") String categoryId,
         * 
         * @RequestParam(value = "offset") String offset, @RequestParam(value = "limit")
         * String limit,
         * 
         * @RequestParam(value = "sort", required = false) String sort,
         * 
         * @RequestParam(value = "brand", required = false) String brand,
         * 
         * @RequestParam(value = "subCategoryId", required = false) int subCategoryId,
         * 
         * @RequestParam(value = "q", required = false) String queryTerm,
         * 
         * @RequestParam(value = "hotDeal", required = false) boolean hotDeal) throws
         * Throwable { List<FofoCatalogResponse> dealResponse = new ArrayList<>();
         * UserInfo userInfo = (UserInfo) request.getAttribute("userInfo"); if
         * (roleManagerService.isPartner(userInfo.getRoleIds())) { // UserCart uc =
         * userAccountRepository.getUserCart(userInfo.getUserId()); RestClient rc = new
         * RestClient(); Map<String, String> params = new HashMap<>(); List<String>
         * mandatoryQ = new ArrayList<>(); if (queryTerm != null &&
         * !queryTerm.equals("null")) { mandatoryQ.add(String.format("+(%s)",
         * queryTerm)); } else { queryTerm = null; } if (subCategoryId != 0) {
         * mandatoryQ .add(String.
         * format("+(subCategoryId_i:%s) +{!parent which=\"subCategoryId_i:%s\"} tagId_i:(%s)"
         * , subCategoryId, subCategoryId, StringUtils.join(TAG_IDS, " "))); } else if
         * (hotDeal) { mandatoryQ.add(String.
         * format("+{!parent which=\"hot_deals_b=true\"} tagId_i:(%s)",
         * StringUtils.join(TAG_IDS, " ")));
         * 
         * } else if (StringUtils.isNotBlank(brand)) { mandatoryQ.add( String.
         * format("+(categoryId_i:%s) +(brand_ss:%s) +{!parent which=\"brand_ss:%s\"} tagId_i:(%s)"
         * , categoryId, brand, brand, StringUtils.join(TAG_IDS, " ")));
         * 
         * } else { mandatoryQ.add(
         * String.format("+{!parent which=\"id:catalog*\"} tagId_i:(%s)",
         * StringUtils.join(TAG_IDS, " "))); } params.put("q",
         * StringUtils.join(mandatoryQ, " ")); params.put("fl",
         * "*, [child parentFilter=id:catalog*]"); if (queryTerm == null) {
         * params.put("sort", "create_s desc"); } params.put("start",
         * String.valueOf(offset)); params.put("rows", String.valueOf(limit));
         * params.put("wt", "json"); String response = null; try { response =
         * rc.get(SchemeType.HTTP, "50.116.10.120", 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"); dealResponse =
         * getCatalogResponse(docs, false, userInfo.getRetailerId());
         * 
         * if (Mongo.PARTNER_BLoCKED_BRANDS.containsKey(userInfo.getEmail())) {
         * dealResponse.stream() .filter(x ->
         * Mongo.PARTNER_BLoCKED_BRANDS.get(userInfo.getEmail()).contains(x.getBrand()))
         * ; }
         * 
         * } else { return responseSender.badRequest( new
         * ProfitMandiBusinessException("Retailer id", userInfo.getUserId(),
         * "NOT_FOFO_RETAILER")); } return responseSender.ok(dealResponse); }
         */

        @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")
        public ResponseEntity<?> getUnitFocoDeal(HttpServletRequest request, @PathVariable(value = "id") long id)
                        throws ProfitMandiBusinessException {
                List<FofoCatalogResponse> dealResponse = new ArrayList<>();
                List<Integer> tagIds = Arrays.asList(4);
                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, "50.116.10.120", 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");
                        dealResponse = getCatalogResponse(docs, false, userInfo.getRetailerId());
                } else {
                        return responseSender.badRequest(
                                        new ProfitMandiBusinessException("Retailer id", userInfo.getUserId(), "NOT_FOFO_RETAILER"));
                }
                return responseSender.ok(dealResponse.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")
        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)
        public ResponseEntity<?> bestSellers(HttpServletRequest request, @PathVariable String listingUrl) throws Exception {
                List<FofoCatalogResponse> dealResponse = new ArrayList<>();
                UserInfo userInfo = (UserInfo) request.getAttribute("userInfo");
                List<Integer> tagIds = Arrays.asList(4);

                WebListing webListing = webListingRepository.selectByUrl("url");
                if (webListing == null) {
                        throw new ProfitMandiBusinessException("Url", listingUrl, "Could not find the Url");
                }
                List<Integer> webProducts = webProductListingRepository.selectAllByWebListingId(webListing.getId()).stream()
                                .filter(x -> x.getRank() > 0).map(x -> x.getEntityId()).collect(Collectors.toList());

                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(tagIds, " ")));
                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(30));
                params.put("wt", "json");
                String response = null;
                try {
                        response = rc.get(SchemeType.HTTP, "50.116.10.120", 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");
                final Ordering<Integer> rankOrdering = Ordering.explicit(webProducts);
                dealResponse = getCatalogResponse(docs, false, userInfo.getRetailerId()).stream()
                                .sorted(new Comparator<FofoCatalogResponse>() {
                                        @Override
                                        public int compare(FofoCatalogResponse o1, FofoCatalogResponse o2) {
                                                return rankOrdering.compare(o1.getCatalogId(), o2.getCatalogId());
                                        }
                                }).collect(Collectors.toList());
                webListing.setFofoCatalogResponses(dealResponse);
                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)
                        throws Exception {
                try {
                        Customer customer = customerRepository.selectByMobileNumber(mobile);
                        customer.setPasswordExist(StringUtils.isNotEmpty(customer.getPassword()));
                        return responseSender.ok(new CustomerModel(true, customer));
                } catch (Exception e) {
                        return responseSender.ok(new CustomerModel(false, null));
                }
        }

        @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.ok(false);
                }
        }

        @RequestMapping(value = "/store/resetPassword", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
        public ResponseEntity<?> resetPassword(HttpServletRequest request, @RequestBody UserModel userModel)
                        throws Exception {
                customerService.changePassword(userModel.getMobile(), userModel.getPassword());
                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());
                return responseSender.ok(customerService.addCustomer(customer));
        }

        @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());
                        cartItems.add(ci);
                });
                CartResponse cr = this.validateCart(storeId, cartItems);
                if (cr.getCartMessageChanged() > 0 || cr.getTotalAmount() != createPendingOrderRequest.getTotalAmount()) {
                        return responseSender.badRequest("Invalid request");
                }

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

                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")
        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/{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")
        public ResponseEntity<?> getStoresByPincode(HttpServletRequest request, @PathVariable String pincode)
                        throws Exception {
                List<PincodePartner> pincodePartners = pincodePartnerRepository.selectPartnersByPincode(pincode);
                int fofoId = DEFAULT_STORE;
                if (pincodePartners.size() > 0) {
                        fofoId = pincodePartners.get(0).getFofoId();
                }
                return responseSender.ok(fofoStoreRepository.selectByRetailerId(fofoId).getCode());
        }

        @RequestMapping(value = "/store/order", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
        public ResponseEntity<?> getOrderDetail(HttpServletRequest request, @RequestParam(value = "id") int id,
                        @RequestParam(name = "offset") int offset, @RequestParam(name = "limit") int limit) throws Exception {
                List<CustomerOrderDetail> customerOrderDetails = 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());
                                        catalogIds.add(item.getCatalogItemId());
                                }

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

                                for (PendingOrderItem poi : pois) {

                                        CustomerOrderDetail customerOrderDetail = new CustomerOrderDetail();

                                        Item item = itemRepository.selectById(poi.getItemId());
                                        JSONObject jsonObj = contentMap.get(item.getCatalogItemId());
                                        customerOrderDetail.setImageUrl(jsonObj.getString("imageUrl_s"));
                                        customerOrderDetail.setBrand(item.getBrand());
                                        customerOrderDetail.setColor(item.getColor());
                                        customerOrderDetail.setPendingOrderItemId(poi.getId());
                                        customerOrderDetail.setId(poi.getOrderId());
                                        customerOrderDetail.setItemId(poi.getItemId());
                                        customerOrderDetail.setModelName(item.getModelName());
                                        customerOrderDetail.setModelNumber(item.getModelNumber());
                                        customerOrderDetail.setQuantity(poi.getQuantity());
                                        customerOrderDetail.setBilledTimestamp(poi.getBilledTimestamp());
                                        customerOrderDetail.setStatus(poi.getStatus());
                                        customerOrderDetail.setTotalPrice(poi.getSellingPrice());
                                        customerOrderDetail.setPayMethod(po.getPayMethod());
                                        customerOrderDetail.setCreatedTimeStamp(po.getCreateTimestamp());
                                        customerOrderDetails.add(customerOrderDetail);
                                }
                        }
                }

                return responseSender.ok(customerOrderDetails);
        }

        @RequestMapping(value = "/store/listing", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
        @Cacheable(value = "storelisting.all", cacheManager = "thirtyMinsTimeOutCacheManager")
        public ResponseEntity<?> getStoresListing(HttpServletRequest request) throws Exception {
                List<WebListing> webListings = webListingRepository.selectAllWebListing(Optional.of(true));
                for (WebListing webListing : webListings) {
                        UserInfo userInfo = (UserInfo) request.getAttribute("userInfo");
                        Integer storeId = userInfo.getRetailerId();

                        List<Integer> webProducts = webProductListingRepository.selectAllByWebListingId(webListing.getId()).stream()
                                        .filter(x -> x.getRank() > 0).map(x -> x.getEntityId()).collect(Collectors.toList());

                        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(30));
                        params.put("wt", "json");
                        String response = null;
                        try {
                                response = rc.get(SchemeType.HTTP, "50.116.10.120", 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");
                        final Ordering<Integer> colorOrdering = Ordering.explicit(webProducts);
                        List<FofoCatalogResponse> dealResponse = getCatalogResponse(docs, false, userInfo.getRetailerId()).stream()
                                        .sorted(new Comparator<FofoCatalogResponse>() {
                                                @Override
                                                public int compare(FofoCatalogResponse o1, FofoCatalogResponse o2) {
                                                        return colorOrdering.compare(o1.getCatalogId(), o2.getCatalogId());
                                                }
                                        }).collect(Collectors.toList());
                        webListing.setFofoCatalogResponses(dealResponse);
                }
                return responseSender.ok(webListings);
        }

        @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");
                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 {
                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;
                for (CartItem cartItem : cartItems) {
                        Item item = itemsMap.get(cartItem.getItemId());
                        TagListing tagListing = tagListingMap.get(cartItem.getItemId());
                        Float cashback = schemeService.getItemSchemeCashBack().get(cartItem.getItemId());
                        cashback = cashback == null ? 0 : cashback;
                        float itemSellingPrice = tagListing.getMop() - cashback;
                        CartItemResponseModel cartItemResponseModel = new CartItemResponseModel();
                        cartItemResponseModel.setSellingPrice(cartItem.getSellingPrice());
                        if (itemSellingPrice != cartItem.getSellingPrice()) {
                                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) {
                                estimate = 0;
                        } else if (availabilityModel.getWarehouseAvailability() >= qtyRequired) {
                                estimate = 2;
                        } else if (availabilityModel.getStoreAvailability() > 0) {
                                estimate = 0;
                                qtyRequired = availabilityModel.getStoreAvailability();
                                cartMessageChanged++;
                        } else if (availabilityModel.getWarehouseAvailability() > 0) {
                                qtyRequired = availabilityModel.getWarehouseAvailability();
                                estimate = 2;
                                cartMessageChanged++;
                        } else {
                                qtyRequired = 0;
                                cartMessageChanged++;
                        }
                        cartItemResponseModel.setQuantity(qtyRequired);
                        if (estimate >= 0 && LocalTime.now().isAfter(CUTOFF_TIME)) {
                                estimate = estimate + 1;
                                promiseDeliveryTime = promiseDeliveryTime.plusDays(3);
                        }
                        totalQty += qtyRequired;
                        totalAmount += qtyRequired * itemSellingPrice;
                        cartItemResponseModel.setEstimate(estimate);
                        cartItemResponseModel.setTitle(item.getItemDescriptionNoColor());
                        cartItemResponseModel.setItemId(cartItem.getItemId());
                        cartItemResponseModel.setMinBuyQuantity(1);
                        cartItemResponseModel.setQuantity(qtyRequired);
                        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);
                }
                cartResponse.setCartItems(cartItemResponseModels);
                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)
        public ResponseEntity<?> partnerStock(HttpServletRequest request,
                        @RequestParam(value = "categoryId", required = false, defaultValue = "3") String categoryId,
                        @RequestParam(value = "offset") String offset, @RequestParam(value = "limit") String limit,
                        @RequestParam(value = "sort", required = false) String sort,
                        @RequestParam(value = "brand", required = false) String brand,
                        @RequestParam(value = "subCategoryId", required = false) int subCategoryId,
                        @RequestParam(value = "q", required = false) String queryTerm,
                        @RequestParam(value = " ", required = false, defaultValue = "true") boolean partnerStockOnly)
                        throws Throwable {
                List<FofoCatalogResponse> dealResponse = new ArrayList<>();
                UserInfo userInfo = (UserInfo) request.getAttribute("userInfo");
                dealResponse = this.getCatalogResponse(
                                solrService.getSolrDocs(queryTerm, categoryId, offset, limit, sort, brand, subCategoryId, 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 (hotDeal) {
                                ourItemAvailabilityMap = saholicInventoryService
                                                .getTotalAvailabilityByItemIds(new ArrayList<>(itemsSet));
                        } else 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"));
                        try {
                                ffdr.setFeature(doc.getString("feature_s"));
                        } catch (Exception e) {
                                ffdr.setFeature(null);
                                logger.info("Could not find Feature_s for {}", ffdr.getCatalogId());
                        }
                        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");
                                        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.setActive(childItem.getBoolean("active_b"));
                                                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);
                                                Float cashBack = schemeService.getItemSchemeCashBack().get(itemId);
                                                cashBack = cashBack == null ? 0 : cashBack;
                                                fdi.setCashback(cashBack);
                                                fdi.setMinBuyQuantity(1);
                                                if (hotDeal) {
                                                        try {
                                                                int totalAvailability = ourItemAvailabilityMap.get(itemId);
                                                                if (totalAvailability <= 0) {
                                                                        continue;
                                                                }
                                                                fdi.setAvailability(ourItemAvailabilityMap.get(itemId));
                                                        } catch (Exception e) {
                                                                continue;
                                                        }
                                                } else if (fofoId == 0) {
                                                        // For accessories item availability should at be ordered for Rs.1000
                                                        fdi.setAvailability(100);
                                                        Item item = itemRepository.selectById(itemId);
                                                        // In case its tampered glass moq should be 5
                                                        if (item.getCategoryId() == 10020) {
                                                                fdi.setMinBuyQuantity(5);
                                                        }
                                                } else {
                                                        int ourStockAvailability = ourItemAvailabilityMap.get(itemId) == null ? 0
                                                                        : ourItemAvailabilityMap.get(itemId);
                                                        int partnerAvailability = partnerStockAvailabilityMap.get(itemId) == null ? 0
                                                                        : partnerStockAvailabilityMap.get(itemId);
                                                        fdi.setAvailability(ourStockAvailability + partnerAvailability);
                                                }
                                                fdi.setQuantityStep(1);
                                                fdi.setMaxQuantity(Math.min(fdi.getAvailability(), 100));
                                                fofoAvailabilityInfoMap.put(itemId, fdi);
                                        }
                                }
                        }
                        if (fofoAvailabilityInfoMap.values().size() > 0) {
                                ffdr.setItems(fofoAvailabilityInfoMap.values().stream()
                                                .sorted((x, y) -> y.getAvailability() - x.getAvailability()).collect(Collectors.toList()));
                                dealResponse.add(ffdr);
                        }
                }
                return dealResponse;

        }

        @GetMapping(value = "store/order-status/{pendingOrderId}")
        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) {
                        Item item = itemRepository.selectById(pendingOrderItem.getItemId());
                        pendingOrderItem.setItemName(item.getItemDescription());
                        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);

                CustomerAddress customerAddress = customerAddressRepository.selectById(pendingOrder.getCustomerAddressId());

                DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy H:m");
                Template t = velocityEngine.getTemplate("sms.vm");
                VelocityContext context = new VelocityContext();

                context.put("customer", customerAddress);
                context.put("pendingOrder", pendingOrder);
                context.put("date", dateTimeFormatter);
                StringWriter writer = new StringWriter();
                t.merge(context, writer);

                this.sendMailWithAttachments("Order Confirmation", writer.toString(), pendingOrder);
                return responseSender.ok(pendingOrder);
        }

        private void sendMailWithAttachments(String subject, String messageText, PendingOrder pendingOrder)
                        throws Exception {
                CustomRetailer customRetailer = retailerService.getFofoRetailer(pendingOrder.getFofoId());
                Customer customer = customerRepository.selectById(pendingOrder.getCustomerId());
                MimeMessage message = mailSender.createMimeMessage();
                MimeMessageHelper helper = new MimeMessageHelper(message, true);
                if (!customer.getEmailId().equals(null)) {
                        String[] email = {customer.getEmailId() };
                        helper.setTo(email);
                }
                String[] bccemail = { customRetailer.getEmail(), "tejbeer.kaur@shop2020.in", "tarun.verma@smartdukaan.com" };
                helper.setSubject(subject);
                helper.setBcc(bccemail);
                helper.setText(messageText, true);

                InternetAddress senderAddress = new InternetAddress("noreply@smartdukaan.com", "Smartdukaan Alerts");
                helper.setFrom(senderAddress);
                mailSender.send(message);

        }

        @RequestMapping(value = "/store/addresses/{customerId}", method = RequestMethod.GET)
        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 {
                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);
                cust.setActive(false);
                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.setDob(customer.getDob());
                return responseSender.ok(cust);
        }

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

                        @RequestParam String statusDescription) throws Exception {

                PendingOrderItem pendingOrderItem = pendingOrderItemRepository.selectById(id);

                PendingOrder pendingOrder = pendingOrderRepository.selectById(pendingOrderItem.getOrderId());
                if (pendingOrderItem.getBilledTimestamp() == null) {
                        pendingOrderItem.setStatus(OrderStatus.CANCELLED);
                        pendingOrderItem.setStatusDescription(statusDescription);
                        List<OrderStatus> status = pendingOrderItemRepository.selectByOrderId(pendingOrderItem.getOrderId())
                                        .stream().map(x -> x.getStatus()).collect(Collectors.toList());

                        if (!status.contains(OrderStatus.PENDING)) {
                                pendingOrder.setStatus(OrderStatus.CLOSED);
                        }

                        pendingOrderItemRepository.persist(pendingOrderItem);
                }

                return responseSender.ok(true);

        }

}

class UserModel {
        @JsonProperty(required = true)
        private String mobile;
        @JsonProperty(required = true)
        private String password;
        @JsonProperty(required = false)
        private String firstName;
        @JsonProperty(required = false)
        private String lastName;
        @JsonProperty(required = false)
        private String email;

        @Override
        public String toString() {
                return "UserModel [mobile=" + mobile + ", password=" + password + "]";
        }

        public String getMobile() {
                return mobile;
        }

        public void setMobile(String mobile) {
                this.mobile = mobile;
        }

        public String getPassword() {
                return password;
        }

        public void setPassword(String password) {
                this.password = password;
        }

        public String getFirstName() {
                return firstName;
        }

        public void setFirstName(String firstName) {
                this.firstName = firstName;
        }

        public String getLastName() {
                return lastName;
        }

        public void setLastName(String lastName) {
                this.lastName = lastName;
        }

        public String getEmail() {
                return email;
        }

        public void setEmail(String email) {
                this.email = email;
        }

}

class CustomerModel {

        @JsonProperty(required = false)
        private Customer customer;
        @JsonProperty(required = true)
        private boolean exists;

        public CustomerModel(boolean exists, Customer customer) {
                super();
                this.customer = customer;
                this.exists = exists;
        }

        @Override
        public String toString() {
                return "CustomerModel [customer=" + customer + ", exists=" + exists + "]";
        }

        public Customer getCustomer() {
                return customer;
        }

        public void setCustomer(Customer customer) {
                this.customer = customer;
        }

        public boolean isExists() {
                return exists;
        }

        public void setExists(boolean exists) {
                this.exists = exists;
        }
}