Subversion Repositories SmartDukaan

Rev

Rev 31218 | Rev 31328 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

package com.smartdukaan.cron.scheduled;

import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.razorpay.Payment;
import com.smartdukaan.cron.itelImeiActivation.ItelImeiActivationService;
import com.smartdukaan.cron.itelImeiActivation.TecnoImeiActivation;
import com.spice.profitmandi.common.enumuration.MessageType;
import com.spice.profitmandi.common.enumuration.RechargeStatus;
import com.spice.profitmandi.common.enumuration.ReporticoProject;
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
import com.spice.profitmandi.common.model.*;
import com.spice.profitmandi.common.services.ReporticoService;
import com.spice.profitmandi.common.services.mandii.AccountStatusResponseOut;
import com.spice.profitmandi.common.services.mandii.EligibilityStatusEnum;
import com.spice.profitmandi.common.services.mandii.MandiiService;
import com.spice.profitmandi.common.util.FileUtil;
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.util.Utils.Attachment;
import com.spice.profitmandi.common.web.client.RestClient;
import com.spice.profitmandi.dao.Interface.Campaign;
import com.spice.profitmandi.dao.entity.auth.AuthUser;
import com.spice.profitmandi.dao.entity.auth.PartnerCollectionRemark;
import com.spice.profitmandi.dao.entity.catalog.FocusedModel;
import com.spice.profitmandi.dao.entity.catalog.Item;
import com.spice.profitmandi.dao.entity.catalog.Scheme;
import com.spice.profitmandi.dao.entity.cs.Position;
import com.spice.profitmandi.dao.entity.cs.Ticket;
import com.spice.profitmandi.dao.entity.dtr.User;
import com.spice.profitmandi.dao.entity.dtr.*;
import com.spice.profitmandi.dao.entity.fofo.*;
import com.spice.profitmandi.dao.entity.inventory.ReporticoCacheTable;
import com.spice.profitmandi.dao.entity.inventory.SaholicCIS;
import com.spice.profitmandi.dao.entity.inventory.SaholicPOItem;
import com.spice.profitmandi.dao.entity.transaction.*;
import com.spice.profitmandi.dao.entity.user.*;
import com.spice.profitmandi.dao.enumuration.auth.CollectionRemark;
import com.spice.profitmandi.dao.enumuration.catalog.SchemeType;
import com.spice.profitmandi.dao.enumuration.cs.EscalationType;
import com.spice.profitmandi.dao.enumuration.dtr.RefferalStatus;
import com.spice.profitmandi.dao.enumuration.fofo.Gateway;
import com.spice.profitmandi.dao.enumuration.fofo.ScanType;
import com.spice.profitmandi.dao.enumuration.transaction.CreditRisk;
import com.spice.profitmandi.dao.enumuration.transaction.LoanReferenceType;
import com.spice.profitmandi.dao.enumuration.transaction.PriceDropImeiStatus;
import com.spice.profitmandi.dao.model.PartnerDetailModel;
import com.spice.profitmandi.dao.model.SimpleCampaign;
import com.spice.profitmandi.dao.model.SimpleCampaignParams;
import com.spice.profitmandi.dao.repository.auth.AuthRepository;
import com.spice.profitmandi.dao.repository.auth.PartnerCollectionRemarkRepository;
import com.spice.profitmandi.dao.repository.catalog.*;
import com.spice.profitmandi.dao.repository.cs.*;
import com.spice.profitmandi.dao.repository.dtr.*;
import com.spice.profitmandi.dao.repository.fofo.*;
import com.spice.profitmandi.dao.repository.inventory.ReporticoCacheTableRepository;
import com.spice.profitmandi.dao.repository.inventory.StateRepository;
import com.spice.profitmandi.dao.repository.inventory.WarehouseRepository;
import com.spice.profitmandi.dao.repository.transaction.*;
import com.spice.profitmandi.dao.repository.user.AddressRepository;
import com.spice.profitmandi.dao.repository.user.UserRepository;
import com.spice.profitmandi.service.NotificationService;
import com.spice.profitmandi.service.PartnerInvestmentService;
import com.spice.profitmandi.service.PartnerStatsService;
import com.spice.profitmandi.service.integrations.RazorpayPaymentService;
import com.spice.profitmandi.service.integrations.bharti.model.BAGInsuranceModel;
import com.spice.profitmandi.service.integrations.toffee.ToffeeService;
import com.spice.profitmandi.service.inventory.InventoryService;
import com.spice.profitmandi.service.inventory.SaholicInventoryService;
import com.spice.profitmandi.service.order.OrderService;
import com.spice.profitmandi.service.pricing.PriceDropService;
import com.spice.profitmandi.service.recharge.provider.OxigenRechargeProviderService;
import com.spice.profitmandi.service.recharge.provider.ThinkWalnutDigitalRechargeProviderService;
import com.spice.profitmandi.service.scheme.SchemeService;
import com.spice.profitmandi.service.serviceConfig.ServiceConfigService;
import com.spice.profitmandi.service.transaction.CreditNoteService;
import com.spice.profitmandi.service.transaction.SDCreditService;
import com.spice.profitmandi.service.transaction.TransactionService;
import com.spice.profitmandi.service.user.RetailerService;
import com.spice.profitmandi.service.wallet.WalletService;
import in.shop2020.model.v1.order.OrderStatus;
import in.shop2020.model.v1.order.WalletReferenceType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.XML;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.InputStreamSource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Component
@Transactional(rollbackFor = Throwable.class)
public class ScheduledTasks {

        @Value("${oxigen.recharge.transaction.url}")
        private String oxigenRechargeTransactionUrl;

        @Value("${oxigen.recharge.enquiry.url}")
        private String oxigenRechargeEnquiryUrl;

        @Autowired
        private RegionRepository regionRepository;

        @Autowired
        private ServiceConfigService serviceConfigService;

        @Autowired
        private TecnoImeiActivation tecnoImeiActivation;

        private static final DateTimeFormatter leadTimeFormatter = DateTimeFormatter.ofPattern("d LLL, hh:mm a");

        @Autowired
        private PartnerRegionRepository partnerRegionRepository;

        @Autowired
        private EmployeeAttendanceRepository employeeAttendanceRepository;

        @Autowired
        VivoImeiActivationService vivoImeiActivationService;

        @Autowired
        ItelImeiActivationService itelImeiActivationService;

        @Autowired
        private PartnerTypeChangeService partnerTypeChangeService;

        @Autowired
        private ActivatedImeiRepository activatedImeiRepository;

        @Autowired
        private LineItemRepository lineItemRepository;

        @Autowired
        private LeadRepository leadRepository;

        @Autowired
        private AuthRepository authRepository;

        @Autowired
        private PriceDropService priceDropService;

        @Autowired
        private FranchiseeVisitRepository franchiseeVisitRepository;

        @Autowired
        private FranchiseeActivityRepository franchiseeActivityRepository;

        @Autowired
        private HdfcPaymentRepository hdfcPaymentRepository;

        @Autowired
        private CsService csService;

        @Autowired
        private SaholicInventoryService saholicInventoryService;

        @Autowired
        private InsurancePolicyRepository insurancePolicyRepository;

        @Autowired
        private ToffeeService toffeeService;

        @Value("${oxigen.recharge.auth.key}")
        private String oxigenRechargeAuthKey;

        @Value("${oxigen.recharge.validation.url}")
        private String oxigenRechargeValidationUrl;

        @Value("${oxigen.recharge.validation.auth.key}")
        private String oxigenRechargeValidationAuthKey;

        @Value("${think.walnut.digital.recharge.transaction.mobile.url}")
        private String thinkWalnutDigitalRechargeTransactionMobileUrl;

        @Value("${think.walnut.digital.recharge.transaction.dth.url}")
        private String thinkWalnutDigitalRechargeTransactionDthUrl;

        @Value("${think.walnut.digital.recharge.enquiry.url}")
        private String thinkWalnutDigitalRechargeEnquiryUrl;

        @Value("${think.walnut.digital.recharge.balance.url}")
        private String thinkWalnutDigitalRechargeBalanceUrl;

        @Value("${think.walnut.digital.recharge.username}")
        private String thinkWalnutDigitalRechargeUserName;

        @Value("${think.walnut.digital.recharge.password}")
        private String thinkWalnutDigitalRechargePassword;

        @Value("${think.walnut.digital.recharge.auth.key}")
        private String thinkWalnutDigitalRechargeAuthKey;

        @Autowired
        private PurchaseRepository purchaseRepository;

        @Autowired
        private PriceDropIMEIRepository priceDropIMEIRepository;

        @Autowired
        PriceDropRepository priceDropRepository;

        @Autowired
        private PartnerTypeChangeRepository partnerTypeChangeRepository;

        @Autowired
        private SchemeService schemeService;

        @Autowired
        private ServiceConfigRepository serviceConfigRepository;

        @Value("${delhivery.tracking.token}")
        private String token;

        private static final String[] STOCK_AGEING_MAIL_LIST = new String[] { "uday.singh@smartudkaan.com",
                        "mohinder.mutreja@smartdukaan.com", "ankit.bhatia@smartdukaan.com", "tarun.verma@smartdukaan.com",
                        "kuldeep.kumar@smartdukaan.com", "manish.gupta@smartdukaan.com" };

        private static final String[] ITEMWISE_PENDING_INDENT_MAIL_LIST = new String[] { "kamini.sharma@smartdukaan.com",
                        "tarun.verma@smartdukaan.com", "uday.singh@smartdukaan.com", "kuldeep.kumar@smartdukaan.com",
                        "niranjan.kala@smartdukaan.com" };

        private static final String[] INDENT_TERTIARY_MAIL_LIST = new String[] { "uday.singh@smartdukaan.com",
                        "kuldeep.kumar@smartdukaan.com" };

        private static final String[] EMPLOYEE_ATTENDANCE_MAIL_LIST = new String[] { "sm@smartdukaan.com",
                        "sm@smartdukaan.com" };

        private List<OrderStatus> orderStatusList = Arrays.asList(OrderStatus.SUBMITTED_FOR_PROCESSING);

        @Autowired
        private ReporticoService reporticoService;

        @Autowired
        private PartnerInvestmentService partnerInvestmentService;

        @Autowired
        private PositionRepository positionRepository;

        @Autowired
        private FofoOrderItemRepository fofoOrderItemRepository;

        @Autowired
        private NotificationService notificationService;

        @Autowired
        private PartnerDailyInvestmentRepository partnerDailyInvestmentRepository;

        @Autowired
        private SchemeInOutRepository schemeInOutRepository;

        @Autowired
        private RechargeTransactionRepository rechargeTransactionRepository;

        @Autowired
        private CustomerAddressRepository customerAddressRepository;

        @Autowired
        private RechargeProviderCreditWalletHistoryRepository rechargeProviderCreditWalletHistoryRepository;

        @Autowired
        private FofoLineItemRepository fofoLineItemRepository;

        @Autowired
        private FofoOrderRepository fofoOrderRepository;

        @Autowired
        private UserWalletHistoryRepository userWalletHistoryRepository;

        @Autowired
        private UserWalletRepository userWalletRepository;

        @Autowired
        private InventoryItemRepository inventoryItemRepository;

        @Autowired
        private WalletService walletService;

        @Autowired
        private ThinkWalnutDigitalRechargeProviderService thinkWalnutDigitalRechargeProviderService;

        @Autowired
        private OxigenRechargeProviderService oxigenRechargeProviderService;

        @Autowired
        private RechargeProviderRepository rechargeProviderRepository;

        @Autowired
        private ScanRecordRepository scanRecordRepository;

        @Autowired
        private DailyRechargeRepository dailyRechargeRepository;

        @Autowired
        private FofoStoreRepository fofoStoreRepository;

        @Value("${prod}")
        private boolean prod;

        @Autowired
        private StateGstRateRepository stateGstRateRepository;

        @Autowired
        private RetailerService retailerService;

        @Autowired
        private TransactionService transactionService;

        @Autowired
        private ItemRepository itemRepository;

        @Autowired
        private OrderRepository orderRepository;

        @Autowired
        private OrderService orderService;

        @Autowired
        private SchemeRepository schemeRepository;

        @Autowired
        private JavaMailSender mailSender;

        @Autowired
        private PartnerTargetRepository partnerTargetRepository;

        @Autowired
        @Qualifier(value = "googleMailSender")
        private JavaMailSender googleMailSender;

        @Autowired
        private InventoryService inventoryService;

        @Autowired
        private AddressRepository addressRepository;

        @Autowired
        private RetailerRegisteredAddressRepository retailerRegisteredAddressRepository;

        @Autowired
        private Mongo mongoClient;

        @Autowired
        private DeviceRepository deviceRepository;

        @Autowired
        private PushNotificationRepository pushNotificationRepository;

        @Autowired
        private NotificationCampaignRepository notificationCampaignRepository;

        @Autowired
        private CurrentInventorySnapshotRepository currentInventorySnapshotRepository;

        @Autowired
        private FocusedModelRepository focusedModelRepository;

        @Autowired
        private UserAccountRepository userAccountRepository;

        @Autowired
        private UserRepository userUserRepository;

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

        @Autowired
        private UserCampaignRepository userCampaignRepository;

        @Autowired
        private Gson gson;

        @Autowired
        private TicketRepository ticketRepository;

        @Autowired
        private RefferalRepository refferalRepository;

        @Autowired
        private PartnerProblemRepository partnerProblemRepository;

        @Autowired
        private PendingOrderRepository pendingOrderRepository;

        @Autowired
        private PendingOrderItemRepository pendingOrderItemRepository;

        @Value("${razorpay.account.keyId}")
        private String keyId;

        @Value("${razorpay.account.keySecret}")
        private String keySecret;

        @Autowired
        private RazorpayPaymentService razorPaymentService;

        @Autowired
        private RazorPayRepository razorPayRepository;

        @Autowired
        private PendingOrderService pendingOrderService;

        @Autowired
        private CustomerRepository customerRepository;

        @Autowired
        private RestClient restClient;

        @Autowired
        private MandiiService mandiiService;

        @Autowired
        CreditAccountRepository creditAccountRepository;
        private static final Logger LOGGER = LogManager.getLogger(ScheduledTasks.class);

        private String FCM_URL = "https://fcm.googleapis.com/fcm/send";
        private String FCM_API_KEY = "AAAASAjNcn4:APA91bG6fWRIgYJI0L9gCjP5ynaXz2hJHYKtD9dfH7Depdv31Nd9APJwhx-OPkAJ1WSz4BGNYG8lHThLFSjDGFxIwUZv241YcAJEGDLgt86mxq9FXJe-yBRu-S0_ZwHqmX-QaVKl5F_A";

        public void generateDailyRecharge() {
                List<RechargeProviderCreditWalletHistory> allCreditHistory = rechargeProviderCreditWalletHistoryRepository
                                .selectAll(0, 2000);
                List<RechargeProvider> rechargeProviders = rechargeProviderRepository.selectAll();
                rechargeProviders.stream().forEach(x -> x.setAmount(0));

                rechargeProviders.stream().forEach(x -> {
                        Map<LocalDate, List<RechargeProviderCreditWalletHistory>> dateWiseProviderCreditsMap = allCreditHistory
                                        .stream().filter(z -> z.getProviderId() == x.getId())
                                        .collect(Collectors.groupingBy(x1 -> x1.getReceiveTimestamp().toLocalDate()));

                        LOGGER.info("dateWiseProviderCreditsMap -{}", dateWiseProviderCreditsMap);
                        LocalDate endDate = LocalDate.now().plusDays(1);
                        float previousDayClosing = 0;
                        LocalDate date = LocalDate.of(2018, 4, 6);
                        while (date.isBefore(endDate)) {
                                List<RechargeTransaction> dateWiseRechargeTransactions = rechargeTransactionRepository
                                                .selectAllBetweenTimestamp(Arrays.asList(RechargeStatus.values()), date.atStartOfDay(),
                                                                date.plusDays(1).atStartOfDay());

                                List<RechargeTransaction> successfulTransactions = dateWiseRechargeTransactions.stream()
                                                .filter(y -> y.getStatus().equals(RechargeStatus.SUCCESS)).collect(Collectors.toList());

                                float dailyAmount = 0;
                                float totalCommission = 0;
                                for (RechargeTransaction rechargeTransaction : successfulTransactions) {
                                        if (rechargeTransaction.getProviderId() == x.getId()) {
                                                dailyAmount += rechargeTransaction.getAmount();
                                                totalCommission += rechargeTransaction.getCommission();
                                        }
                                }

                                List<RechargeProviderCreditWalletHistory> rechargeHistoryList = dateWiseProviderCreditsMap.get(date);
                                float dailyWalletRecharge = 0;
                                if (rechargeHistoryList != null) {
                                        for (RechargeProviderCreditWalletHistory rechargeProviderCreditWalletHistory : rechargeHistoryList) {
                                                if (rechargeProviderCreditWalletHistory.getProviderId() == x.getId()) {
                                                        dailyWalletRecharge += rechargeProviderCreditWalletHistory.getAmount();
                                                }
                                        }
                                }
                                if (dailyAmount > 0 || dailyWalletRecharge > 0) {
                                        DailyRecharge dailyRecharge = null;
                                        try {
                                                dailyRecharge = dailyRechargeRepository.selectByProviderIdAndCreateDate(x.getId(), date);
                                        } catch (Exception e) {
                                                LOGGER.info("Could not find Recharge entry");
                                        }
                                        if (dailyRecharge == null) {
                                                dailyRecharge = new DailyRecharge();
                                                dailyRecharge.setCreateDate(date);
                                        }
                                        dailyRecharge.setOpeningBalance(previousDayClosing);
                                        dailyRecharge.setProviderId(x.getId());
                                        dailyRecharge.setWalletRechargeAmount(dailyWalletRecharge);
                                        dailyRecharge.setTotalAmount(dailyAmount);
                                        dailyRecharge.setTotalCommission(totalCommission);
                                        float closingBalance = dailyRecharge.getOpeningBalance() + dailyWalletRecharge - dailyAmount;
                                        dailyRecharge.setClosingBalance(closingBalance);
                                        dailyRechargeRepository.persist(dailyRecharge);
                                        x.setAmount(x.getAmount() + dailyRecharge.getClosingBalance() - dailyRecharge.getOpeningBalance());
                                        previousDayClosing = dailyRecharge.getClosingBalance();
                                }
                                date = date.plusDays(1);
                        }
                        rechargeProviderRepository.persist(x);
                });
                LOGGER.info("finished generating daily recharge");
        }

        public void reconcileRecharge() throws Exception {
                LocalDateTime fromDate = LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).minusDays(30);
                LocalDateTime toDate = LocalDateTime.now().truncatedTo(ChronoUnit.DAYS);
                List<RechargeStatus> nonSuccessRechargeStatuses = new ArrayList<>(Arrays.asList(RechargeStatus.values()));
                LOGGER.info("nonSuccessRechargeStatuses {} ", nonSuccessRechargeStatuses);
                nonSuccessRechargeStatuses.remove(RechargeStatus.SUCCESS);
                nonSuccessRechargeStatuses.remove(RechargeStatus.FAILED);
                RechargeCredential thinkWalnutDigitalRechargeEnquiryCredential = new RechargeCredential();
                thinkWalnutDigitalRechargeEnquiryCredential.setRechargeUrl(thinkWalnutDigitalRechargeEnquiryUrl);
                thinkWalnutDigitalRechargeEnquiryCredential.setRechargeUserName(thinkWalnutDigitalRechargeUserName);
                thinkWalnutDigitalRechargeEnquiryCredential.setRechargePassword(thinkWalnutDigitalRechargePassword);
                thinkWalnutDigitalRechargeEnquiryCredential.setRechargeAuthKey(thinkWalnutDigitalRechargeAuthKey);
                Map<String, RechargeStatus> requestRechargeStatusChanged = new HashMap<>();
                List<RechargeTransaction> rechargeTransactions = rechargeTransactionRepository
                                .selectAllBetweenTimestamp(nonSuccessRechargeStatuses, fromDate, toDate);
                for (RechargeTransaction rechargeTransaction : rechargeTransactions) {
                        try {
                                int providerId = rechargeTransaction.getProviderId();
                                if (providerId == 1) {
                                        oxigenRechargeProviderService.doCheckStatusRequest(oxigenRechargeEnquiryUrl, oxigenRechargeAuthKey,
                                                        rechargeTransaction);
                                } else if (providerId == 2) {
                                        thinkWalnutDigitalRechargeProviderService
                                                        .doCheckStatusRequest(thinkWalnutDigitalRechargeEnquiryCredential, rechargeTransaction);
                                }
                                if (rechargeTransaction.getStatus().equals(RechargeStatus.SUCCESS)
                                                || rechargeTransaction.getStatus().equals(RechargeStatus.FAILED)) {
                                        requestRechargeStatusChanged.put(rechargeTransaction.getRequestId(),
                                                        rechargeTransaction.getStatus());
                                }
                        } catch (Exception e) {
                                LOGGER.info("Could not check status for Request {}", rechargeTransaction.getRequestId());
                        }
                }
                LOGGER.info("Reconcile recharge ran successfully");
        }

        public void processActivation() throws Exception {
                schemeService.processActivation();
        }

        // TemporaryMethod
        public void migrateInvoice() {
                List<FofoOrder> fofoOrders = fofoOrderRepository.selectFromSaleDate(LocalDateTime.now().minusDays(3));
                Map<Integer, List<FofoOrder>> partnerOrdersMap = new HashMap<>();
                partnerOrdersMap = fofoOrders.stream()
                                .collect(Collectors.groupingBy(FofoOrder::getFofoId, Collectors.toList()));
                for (List<FofoOrder> orderList : partnerOrdersMap.values()) {
                        int sequence = 0;
                        String prefix = "";
                        List<FofoOrder> sortedList = orderList.stream().sorted((x1, x2) -> x1.getId() - x2.getId())
                                        .collect(Collectors.toList());
                        for (FofoOrder order : sortedList) {

                                LOGGER.info("Order Id is {}, partner Id is {}", order.getId(), order.getFofoId());
                                if (!order.getInvoiceNumber().contains("SEC")) {
                                        sequence = Integer.parseInt(order.getInvoiceNumber().split("/")[1]);
                                        prefix = order.getInvoiceNumber().split("/")[0];
                                } else {
                                        sequence += 1;
                                        String invoiceNumber = prefix + "/" + sequence;
                                        order.setInvoiceNumber(invoiceNumber);
                                        fofoOrderRepository.persist(order);
                                }
                        }

                }
        }

        @Autowired
        private ReporticoCacheTableRepository reporticoCacheTableRepository;

        public void processScheme(int offset, boolean dryRun) throws Exception {
                LocalDateTime startDate = LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT).minusDays(offset);
                LocalDateTime endDate = startDate.plusDays(30);
                processScheme(startDate, endDate, dryRun);
        }

        public void processSchemeOut(List<String> invoiceNumbers) throws Exception {
                for (String invoiceNumber : invoiceNumbers) {
                        System.out.println("Invoice Number - " + invoiceNumber);
                        FofoOrder fofoOrder = fofoOrderRepository.selectByInvoiceNumber(invoiceNumber);
                        orderService.reverseScheme(fofoOrder);
                        schemeService.processSchemeOut(fofoOrder.getId(), fofoOrder.getFofoId());
                }
        }

        public void processSchemeIn(List<String> invoiceNumbers) throws Exception {
                for (String invoiceNumber : invoiceNumbers) {
                        System.out.println("Invoice Number - " + invoiceNumber);
                        Purchase purchase = purchaseRepository.selectByPurchaseReference(invoiceNumber);
                        schemeService.processSchemeIn(purchase.getId(), purchase.getFofoId());
                }
        }

        public void processScheme(int offset, int durationDays, boolean dryRun) throws Exception {
                LocalDateTime startDate = LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT).minusDays(offset);
                LocalDateTime endDate = startDate.plusDays(durationDays);
                processScheme(startDate, endDate, dryRun);
        }

        public void processScheme(boolean dryRun) throws Exception {
                LocalDateTime fromDate = LocalDateTime.now().minusDays(30);
                processScheme(fromDate, LocalDateTime.now(), dryRun);
        }

        public void processScheme(LocalDateTime startDate, LocalDateTime endDate, boolean dryRun) throws Exception {
                LOGGER.info("Started execution at {}", LocalDateTime.now());
                System.out.println(
                                "InventoryId\tSerialNumber\tItem Id\tScheme Id\tScheme Name\tScheme Type\tAmount Type\tDP\tTaxable\tScheme Amount\tAmount Paid");
                try {
                        List<Purchase> purchases = purchaseRepository.selectAllBetweenPurchaseDate(startDate, endDate);
                        for (Purchase purchase : purchases) {
                                schemeService.processSchemeIn(purchase.getId(), purchase.getFofoId());
                        }

                        List<FofoOrder> fofoOrders = fofoOrderRepository.selectBetweenSaleDate(startDate, endDate);
                        for (FofoOrder fofoOrder : fofoOrders) {
                                schemeService.processSchemeOut(fofoOrder.getId(), fofoOrder.getFofoId());
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                        throw e;
                }
                List<UserWalletHistory> uwhs = userWalletHistoryRepository.selectAllByDateType(LocalDate.now().atStartOfDay(),
                                endDate, Arrays.asList(WalletReferenceType.SCHEME_IN, WalletReferenceType.SCHEME_OUT));
                System.out.println("Amount\tReference\tReferenceType\tTimestamp\tDescription");
                for (UserWalletHistory uwh : uwhs) {
                        System.out.println(String.format("%d\t%d\t%s\t%s\t%s", uwh.getAmount(), uwh.getReference(),
                                        uwh.getReferenceType(), uwh.getTimestamp().toString(), uwh.getDescription()));
                }
                LOGGER.info("Schemes processed successfully.");
                if (dryRun) {
                        throw new Exception();
                }
        }

        public void processRechargeCashback() throws Throwable {
                LocalDateTime cashbackTime = LocalDateTime.now();
                int referenceId = (int) Timestamp.valueOf(cashbackTime).getTime() / 1000;
                List<RechargeTransaction> pendingTransactions = rechargeTransactionRepository
                                .getPendingCashBackRehargeTransactions();
                Map<Object, Double> totalRetailerCashbacks = pendingTransactions.stream().collect(
                                Collectors.groupingBy(x -> x.getRetailerId(), Collectors.summingDouble(x -> x.getCommission())));
                for (Map.Entry<Object, Double> totalRetailerCashback : totalRetailerCashbacks.entrySet()) {
                        int retailerId = (Integer) totalRetailerCashback.getKey();
                        float amount = totalRetailerCashback.getValue().floatValue();
                        if (Math.round(amount) > 0) {
                                walletService.addAmountToWallet(retailerId, referenceId, WalletReferenceType.CASHBACK,
                                                "Recharge Cashback", Math.round(amount), LocalDateTime.now());
                        }
                }
                for (RechargeTransaction rt : pendingTransactions) {
                        rt.setCashbackTimestamp(cashbackTime);
                        rt.setCashbackReference(referenceId);
                        rechargeTransactionRepository.persist(rt);
                }
                LOGGER.info("Cashbacks for Recharge processed Successfully");
        }

        public void rollOutUpgardedMarginsNextMonth() throws Exception {
                LocalDate startOfPreviousMonth = LocalDate.now().with(ChronoField.DAY_OF_MONTH, 1).minusMonths(1);

                List<FofoStore> stores = fofoStoreRepository.selectActiveStores();
                for (FofoStore store : stores) {
                        int fofoId = store.getId();

                        PartnerType startOfPreviousMonthPartnerType = partnerTypeChangeService.getTypeOnDate(fofoId,
                                        startOfPreviousMonth);
                        PartnerType todayPartnerType = partnerTypeChangeService.getTypeOnMonth(fofoId,
                                        YearMonth.from(startOfPreviousMonth.atStartOfDay()));
                        if (!startOfPreviousMonthPartnerType.nextPartnerTypes().contains(todayPartnerType)) {
                                continue;
                        }
                        if (!startOfPreviousMonthPartnerType.equals(todayPartnerType)) {
                                LOGGER.info("Partner Type has been changed for code {} from {} to {}", store.getCode(),
                                                startOfPreviousMonthPartnerType, todayPartnerType);
                                List<FofoOrder> fofoOrders = fofoOrderRepository.selectByFofoId(fofoId,
                                                startOfPreviousMonth.atStartOfDay(), startOfPreviousMonth.plusMonths(1).atStartOfDay(), 0, 0);
                                for (FofoOrder fofoOrder : fofoOrders) {
                                        schemeService.processSchemeOut(fofoOrder.getId(), fofoId);
                                }

                        }
                }
        }

        public void rollOutUpgardedMargins() throws Exception {
                LocalDate today = LocalDate.now();
                LocalDate yesterday = today.minusDays(1);
                int upgradedCount = 0;
                List<FofoStore> stores = fofoStoreRepository.selectActiveStores();
                StringBuilder sb = new StringBuilder();
                for (FofoStore store : stores) {
                        int fofoId = store.getId();

                        PartnerType yesterdayPartnerType = partnerTypeChangeService.getTypeOnDate(fofoId, yesterday);
                        PartnerType todayPartnerType = partnerTypeChangeService.getTypeOnDate(fofoId, today);
                        if (!yesterdayPartnerType.nextPartnerTypes().contains(todayPartnerType)) {
                                continue;
                        }
                        if (!yesterdayPartnerType.equals(todayPartnerType)) {
                                upgradedCount++;
                                sb.append(String.format("Partner Type has been changed for code %s from %s to %s", store.getCode(),
                                                yesterdayPartnerType.toString(), todayPartnerType.toString()));
                                sb.append("<br>");
                                LOGGER.info("Partner Type has been changed for code {} from {} to {}", store.getCode(),
                                                yesterdayPartnerType, todayPartnerType);
                                List<FofoOrder> fofoOrders = fofoOrderRepository.selectByFofoId(fofoId,
                                                yesterday.withDayOfMonth(1).atStartOfDay(), yesterday.atStartOfDay(), 0, 0);
                                for (FofoOrder fofoOrder : fofoOrders) {
                                        schemeService.processSchemeOut(fofoOrder.getId(), fofoId);
                                }

                        }
                }
                if (upgradedCount > 0) {
                        sendMailHtmlFormat(
                                        new String[] { "amit.gupta@smartdukaan.com", "tarun.verma@smartdukaan.com",
                                                        "neeraj.gupta@smartdukaan.com" },
                                        sb.toString(), null, "Few Partners Category have been Upgraded");
                } else {
                        sendMailHtmlFormat(
                                        new String[] { "amit.gupta@smartdukaan.com", "tarun.verma@smartdukaan.com",
                                                        "neeraj.gupta@smartdukaan.com" },
                                        sb.toString(), null, "No partners Category have been upgraded today");
                }
        }

        @Autowired
        private PartnerStatsService partnerStatsService;

        // Temporary Method
        public void evaluateExcessSchemeOut() throws Exception {
                Map<Integer, String> userNameMap = retailerService.getAllFofoRetailerIdNameMap();
                Map<Integer, Float> userAmountMap = new HashMap<>();

                List<List<?>> rows = new ArrayList<>();
                List<String> headers = Arrays.asList("Scheme", "Item", "Partner", "Amount", "Credited On", "Invoice Number",
                                "Sale On", "Scheme Start", "Scheme End", "Active On", "Expired On");
                schemeRepository.selectAll().stream().forEach(x -> {
                        if (x.getType().equals(SchemeType.OUT)) {
                                List<SchemeInOut> sioList = schemeInOutRepository
                                                .selectBySchemeIds(new HashSet<>(Arrays.asList(x.getId())));
                                if (x.getActiveTimestamp() != null) {
                                        LocalDateTime endDateTime = x.getEndDateTime();
                                        if (x.getExpireTimestamp() != null && x.getExpireTimestamp().isBefore(x.getEndDateTime())) {
                                                endDateTime = x.getExpireTimestamp();
                                        }
                                        for (SchemeInOut sio : sioList) {
                                                InventoryItem inventoryItem = null;
                                                inventoryItem = inventoryItemRepository.selectById(sio.getInventoryItemId());
                                                FofoOrder fofoOrder = fofoOrderRepository.selectByFofoIdAndSerialNumber(
                                                                inventoryItem.getFofoId(), inventoryItem.getSerialNumber(), null, null, 0, 1).get(0);
                                                Optional<ScanRecord> record = scanRecordRepository
                                                                .selectByInventoryItemId(sio.getInventoryItemId()).stream()
                                                                .filter(y -> y.getType().equals(ScanType.SALE)).findFirst();
                                                if (record.isPresent()) {
                                                        int fofoId = record.get().getFofoId();
                                                        if (record.get().getCreateTimestamp().isAfter(endDateTime)
                                                                        || record.get().getCreateTimestamp().isBefore(x.getStartDateTime())) {
                                                                if (!userAmountMap.containsKey(fofoId)) {
                                                                        userAmountMap.put(fofoId, 0f);
                                                                }
                                                                userAmountMap.put(fofoId, sio.getAmount() + userAmountMap.get(fofoId));
                                                                try {
                                                                        rows.add(Arrays.asList(x.getDescription(),
                                                                                        itemRepository.selectById(inventoryItem.getItemId()).getItemDescription(),
                                                                                        userNameMap.get(fofoId), sio.getAmount(),
                                                                                        FormattingUtils.formatDate(sio.getCreateTimestamp()),
                                                                                        fofoOrder.getInvoiceNumber(),
                                                                                        FormattingUtils.formatDate(record.get().getCreateTimestamp()),
                                                                                        FormattingUtils.formatDate(x.getStartDateTime()),
                                                                                        FormattingUtils.formatDate(x.getEndDateTime()),
                                                                                        FormattingUtils.formatDate(x.getActiveTimestamp()),
                                                                                        FormattingUtils.formatDate(x.getExpireTimestamp())));
                                                                } catch (Exception e) {
                                                                        e.printStackTrace();
                                                                }
                                                        }
                                                }
                                        }
                                }
                        }
                });
                userAmountMap.entrySet().stream()
                                .forEach(x -> LOGGER.info("{} to be deducted from {}({}) for wrongly disbursed due to technical error.",
                                                x.getValue(), userNameMap.get(x.getKey())));

                ByteArrayOutputStream baos = FileUtil.getCSVByteStream(headers, rows);
                Utils.sendMailWithAttachment(googleMailSender,
                                new String[] { "amit.gupta@shop2020.in", "adeel.yazdani@smartdukaan.com" }, null,
                                "Partner Excess Amount", "PFA", "ListofSchemes.csv", new ByteArrayResource(baos.toByteArray()));

        }

        public void fetchParnterStats() throws Exception {
                Map<Integer, PartnerDetailModel> partnerStats = partnerStatsService.getAllPartnerStats();
                ObjectOutputStream oos = null;
                FileOutputStream fout = null;
                try {
                        fout = new FileOutputStream("/tmp/partnerStat.tmp", false);
                        oos = new ObjectOutputStream(fout);
                        oos.writeObject(partnerStats);

                } catch (Exception ex) {
                        ex.printStackTrace();
                } finally {
                        if (oos != null) {
                                oos.close();
                        }
                }
                ReporticoCacheTable rct = reporticoCacheTableRepository.selectByTableName("partnerStat");
                if (rct == null) {
                        rct = new ReporticoCacheTable();
                        rct.setTableName("partnerStat");
                        rct.setLastCreatedTimestamp(LocalDateTime.now());
                        reporticoCacheTableRepository.persist(rct);
                } else {
                        rct.setLastCreatedTimestamp(LocalDateTime.now());
                }
        }

        public void processPriceDrop() throws Exception {
                List<PriceDrop> priceDrops = priceDropRepository.selectAllByDatesBetween(LocalDateTime.now(),
                                LocalDateTime.now().minusYears(1));
                for (PriceDrop priceDrop : priceDrops) {
                        if (priceDrop.getDropAmount() > 0) {
                                priceDropService.processPriceDrop(priceDrop.getId(), true);
                        }
                }
        }

        @Autowired
        CreditNoteService creditNoteService;

        public void sendCreditNote(YearMonth yearMonth) throws Exception {
                creditNoteService.issueMonthlyMarginsCN(yearMonth);
        }

        private class SaleRoles {

                private List<String> l1;
                private List<String> l2;

                public SaleRoles() {
                        l1 = new ArrayList<>();
                        l2 = new ArrayList<>();
                }

                public List<String> getL1() {
                        return l1;
                }

                public List<String> getL2() {
                        return l2;
                }

        }

        private class FofoReportingModel {
                private String code;
                private int fofoId;
                private String businessName;
                private String territoryManager;
                private String regionalManager;

                @Override
                public String toString() {
                        return "FofoReportingModel [code=" + code + ", fofoId=" + fofoId + ", businessName=" + businessName
                                        + ", territoryManager=" + territoryManager + ", regionalManager=" + regionalManager + "]";
                }

                public String getCode() {
                        return code;
                }

                public void setCode(String code) {
                        this.code = code;
                }

                public String getBusinessName() {
                        return businessName;
                }

                public void setBusinessName(String businessName) {
                        this.businessName = businessName;
                }

                public String getTerritoryManager() {
                        return territoryManager;
                }

                public void setTerritoryManager(String territoryManager) {
                        this.territoryManager = territoryManager;
                }

                public String getRegionalManager() {
                        return regionalManager;
                }

                public void setRegionalManager(String regionalManager) {
                        this.regionalManager = regionalManager;
                }

                private ScheduledTasks getOuterType() {
                        return ScheduledTasks.this;
                }

                @Override
                public int hashCode() {
                        final int prime = 31;
                        int result = 1;
                        result = prime * result + getOuterType().hashCode();
                        result = prime * result + ((businessName == null) ? 0 : businessName.hashCode());
                        result = prime * result + ((code == null) ? 0 : code.hashCode());
                        result = prime * result + fofoId;
                        result = prime * result + ((regionalManager == null) ? 0 : regionalManager.hashCode());
                        result = prime * result + ((territoryManager == null) ? 0 : territoryManager.hashCode());
                        return result;
                }

                @Override
                public boolean equals(Object obj) {
                        if (this == obj)
                                return true;
                        if (obj == null)
                                return false;
                        if (getClass() != obj.getClass())
                                return false;
                        FofoReportingModel other = (FofoReportingModel) obj;
                        if (!getOuterType().equals(other.getOuterType()))
                                return false;
                        if (businessName == null) {
                                if (other.businessName != null)
                                        return false;
                        } else if (!businessName.equals(other.businessName))
                                return false;
                        if (code == null) {
                                if (other.code != null)
                                        return false;
                        } else if (!code.equals(other.code))
                                return false;
                        if (fofoId != other.fofoId)
                                return false;
                        if (regionalManager == null) {
                                if (other.regionalManager != null)
                                        return false;
                        } else if (!regionalManager.equals(other.regionalManager))
                                return false;
                        if (territoryManager == null) {
                                if (other.territoryManager != null)
                                        return false;
                        } else if (!territoryManager.equals(other.territoryManager))
                                return false;
                        return true;
                }

                public int getFofoId() {
                        return fofoId;
                }

                public void setFofoId(int fofoId) {
                        this.fofoId = fofoId;
                }

        }

        public void sendPartnerInvestmentDetails(List<String> sendTo) throws Exception {
                LocalDate yesterDay = LocalDate.now().minusDays(1);
                List<FofoStore> fofoStores = fofoStoreRepository.selectActiveStores();
                Map<Integer, CustomRetailer> customRetailerMap = retailerService
                                .getFofoRetailers(fofoStores.stream().map(x -> x.getId()).collect(Collectors.toList()));

                List<String> headers = Arrays.asList("Code", "Outlet name", "State Manager", "Teritory/Team Lead",
                                "Wallet Amount", "In Stock Amount", "Activated Stock", "Return In Transit Stock", "Unbilled Amount",
                                "Grn Pending Amount", "Min Investment", "Investment Amount", "Investment Short", "Unbilled Qty",
                                "Short Days");
                List<List<?>> rows = new ArrayList<>();
                Map<Integer, List<?>> partnerRowsMap = new HashMap<>();

                Map<Integer, FofoReportingModel> partnerIdSalesHeaderMap = this.getPartnerIdSalesHeaders();

                Map<Integer, Integer> shortDaysMap = partnerDailyInvestmentRepository
                                .selectAll(LocalDate.now().withDayOfMonth(1), LocalDate.now()).stream().collect(Collectors.groupingBy(
                                                x -> x.getFofoId(), Collectors.summingInt(x -> x.getShortPercentage() > 10 ? 1 : 0)));

                for (FofoStore fofoStore : fofoStores) {
                        LOGGER.info("Fofo Store {},  {}", fofoStore.getId(), fofoStore.getCode());
                        int fofoId = fofoStore.getId();
                        PartnerDailyInvestment partnerDailyInvestment = partnerInvestmentService.getInvestment(fofoId, 1);
                        partnerDailyInvestment.setDate(yesterDay);

                        try {
                                partnerDailyInvestmentRepository.persist(partnerDailyInvestment);
                                shortDaysMap.put(fofoId,
                                                shortDaysMap.get(fofoId) + (partnerDailyInvestment.getShortPercentage() > 10 ? 1 : 0));
                        } catch (Exception e) {
                                // ignore the exceptions during persist
                        }

                        CustomRetailer retailer = customRetailerMap.get(fofoStore.getId());
                        if (retailer == null || partnerIdSalesHeaderMap.get(fofoStore.getId()) == null) {
                                LOGGER.info("Could not find retailer with retailer Id {}", fofoStore.getId());
                                continue;
                        }
                        FofoReportingModel reportingModel = partnerIdSalesHeaderMap.get(fofoStore.getId());
                        List<Serializable> row = new ArrayList<>();
                        row.addAll(Arrays.asList(reportingModel.getCode(), reportingModel.getBusinessName(),
                                        reportingModel.getRegionalManager(), reportingModel.getTerritoryManager()));
                        row.addAll(
                                        Arrays.asList(partnerDailyInvestment.getWalletAmount(), partnerDailyInvestment.getInStockAmount(),
                                                        partnerDailyInvestment.getActivatedStockAmount() == 0 ? "-"
                                                                        : "(" + partnerDailyInvestment.getActivatedStockAmount() + ")",
                                                        0, partnerDailyInvestment.getUnbilledAmount(), partnerDailyInvestment.getGrnPendingAmount(),
                                                        partnerDailyInvestment.getMinInvestment(), partnerDailyInvestment.getTotalInvestment(),
                                                        partnerDailyInvestment.getShortInvestment(), partnerDailyInvestment.getUnbilledQty(),
                                                        shortDaysMap.get(fofoId)));
                        partnerRowsMap.put(fofoStore.getId(), row);
                        rows.add(row);

                }

                String fileName = "InvestmentSummary-" + FormattingUtils.formatDate(LocalDateTime.now()) + ".csv";

                if (sendTo == null) {
                        for (Map.Entry<String, Set<Integer>> storeGuyEntry : csService.getAuthUserPartnerIdMapping().entrySet()) {
                                List<List<?>> filteredRows = storeGuyEntry.getValue().stream().map(x -> partnerRowsMap.get(x))
                                                .filter(x -> x != null).collect(Collectors.toList());
                                ByteArrayOutputStream baos = FileUtil.getCSVByteStream(headers, filteredRows);
                                String[] sendToArray = new String[] { storeGuyEntry.getKey() };
                                Utils.sendMailWithAttachment(googleMailSender, sendToArray, null, "Franchise Investment Summary", "PFA",
                                                fileName, new ByteArrayResource(baos.toByteArray()));
                        }
                        sendTo = Arrays.asList("tarun.verma@smartdukaan.com", "kamini.sharma@smartdukaan.com",
                                        "neeraj.gupta@smartdukaan.com", "amit.gupta@shop2020.in", "manish.gupta@smartdukaan.com",
                                        "niranjan.kala@smartdukaan.com");
                }

                ByteArrayOutputStream baos = FileUtil.getCSVByteStream(headers, rows);
                String[] sendToArray = sendTo.toArray(new String[sendTo.size()]);
                Utils.sendMailWithAttachment(googleMailSender, sendToArray, null, "Franchise Investment Summary", "PFA",
                                fileName, new ByteArrayResource(baos.toByteArray()));

        }

        private Map<Integer, FofoReportingModel> getPartnerIdSalesHeaders() {
                Map<String, SaleRoles> partnerEmailSalesMap = new HashMap<>();

                List<Position> positions = positionRepository
                                .selectPositionByCategoryId(ProfitMandiConstants.TICKET_CATEGORY_SALES);
                Map<Integer, AuthUser> authUsersMap = authRepository.selectAllActiveUser().stream()
                                .collect(Collectors.toMap(x -> x.getId(), x -> x));
                Map<Integer, List<CustomRetailer>> positionIdRetailerMap = csService.getPositionCustomRetailerMap(positions);
                for (Position position : positions) {
                        List<CustomRetailer> crList = positionIdRetailerMap.get(position.getId());
                        if (crList == null)
                                continue;
                        for (CustomRetailer cr : crList) {
                                if (!partnerEmailSalesMap.containsKey(cr.getEmail())) {
                                        partnerEmailSalesMap.put(cr.getEmail(), new SaleRoles());
                                }
                                SaleRoles saleRoles = partnerEmailSalesMap.get(cr.getEmail());
                                AuthUser authUser = authUsersMap.get(position.getAuthUserId());
                                if (authUser == null) {
                                        continue;
                                }
                                String name = authUser.getFirstName() + " " + authUser.getLastName();
                                if (position.getEscalationType().equals(EscalationType.L1)) {
                                        saleRoles.getL1().add(name);
                                } else if (position.getEscalationType().equals(EscalationType.L2)) {
                                        saleRoles.getL2().add(name);
                                }
                        }
                }

                Set<CustomRetailer> allCrList = new HashSet<>();
                for (List<CustomRetailer> cr : positionIdRetailerMap.values()) {
                        allCrList.addAll(cr);
                }

                Map<Integer, FofoStore> fofoStoresMap = fofoStoreRepository.selectActiveStores().stream()
                                .collect(Collectors.toMap(x -> x.getId(), x -> x));

                Map<Integer, FofoReportingModel> partnerIdSalesHeadersMap = new HashMap<>();

                for (CustomRetailer cr : allCrList) {
                        FofoStore fofoStore = fofoStoresMap.get(cr.getPartnerId());
                        if (fofoStore == null) {
                                LOGGER.info("Could not find Store {} in active Store", cr.getBusinessName());
                                continue;
                        }
                        String code = fofoStore.getCode();
                        // String storeName = "SmartDukaan-" +
                        // fofoStore.getCode().replaceAll("[a-zA-Z]", "");
                        String businessName = cr.getBusinessName();
                        try {
                                String stateManager = StringUtils.join(partnerEmailSalesMap.get(cr.getEmail()).getL2(), ", ");
                                String territoryManager = StringUtils.join(partnerEmailSalesMap.get(cr.getEmail()).getL1(), ", ");
                                FofoReportingModel reportingModel = new FofoReportingModel();
                                reportingModel.setBusinessName(businessName);
                                reportingModel.setCode(code);
                                reportingModel.setFofoId(fofoStore.getId());
                                reportingModel.setRegionalManager(stateManager);
                                reportingModel.setTerritoryManager(territoryManager);
                                partnerIdSalesHeadersMap.put(fofoStore.getId(), reportingModel);
                        } catch (Exception e) {
                                LOGGER.warn("Could not find partner with email - {}", cr.getEmail());
                        }
                }
                return partnerIdSalesHeadersMap;

        }

        public void sendPartnerInvestmentDetails() throws Exception {
                this.sendPartnerInvestmentDetails(null);
        }

        public void sendAgeingReport(String... sendTo) throws Exception {

                InputStreamSource isr = reporticoService.getReportInputStreamSource(ReporticoProject.WAREHOUSENEW,
                                "itemstockageing.xml");
                InputStreamSource isr1 = reporticoService.getReportInputStreamSource(ReporticoProject.FOCO,
                                "ItemwiseOverallPendingIndent.xml");
                Attachment attachment = new Attachment(
                                "ageing-report-" + FormattingUtils.formatDate(LocalDateTime.now().minusDays(1)) + ".csv", isr);
                Attachment attachment1 = new Attachment(
                                "pending-indent-" + FormattingUtils.formatDate(LocalDateTime.now().minusDays(1)) + ".csv", isr1);

                Utils.sendMailWithAttachments(googleMailSender, STOCK_AGEING_MAIL_LIST, null, "Stock Ageing Report", "PFA",
                                attachment);
                Utils.sendMailWithAttachments(googleMailSender, ITEMWISE_PENDING_INDENT_MAIL_LIST, null,
                                "Itemwise Pending indent", "PFA", attachment1);

                // Reports to be sent to mapped partners
                Map<String, Set<String>> storeGuysMap = csService.getAuthUserPartnerEmailMapping();

                for (Map.Entry<String, Set<String>> storeGuyEntry : storeGuysMap.entrySet()) {
                        Map<String, String> params = new HashMap<>();
                        if (storeGuyEntry.getValue().size() == 0)
                                continue;
                        params.put("MANUAL_email", String.join(",", storeGuyEntry.getValue()));
                        InputStreamSource isr3 = reporticoService.getReportInputStreamSource(ReporticoProject.FOCO,
                                        "focostockreport.xml", params);
                        Attachment attache = new Attachment(
                                        "Franchise-stock-report" + FormattingUtils.formatDate(LocalDateTime.now()) + ".csv", isr3);
                        System.out.println(storeGuyEntry.getValue());
                        Utils.sendMailWithAttachments(googleMailSender, new String[] { storeGuyEntry.getKey() }, null,
                                        "Franchise Stock Report", "PFA", attache);
                }

        }

        public void sendIndentTertiary() throws Exception {

                InputStreamSource isr = reporticoService.getReportInputStreamSource(ReporticoProject.FOCO,
                                "indentandtertiary.xml");
                Attachment attachment = new Attachment(
                                "indentandtertiary-report-" + FormattingUtils.formatDate(LocalDateTime.now()) + ".csv", isr);
                Utils.sendMailWithAttachments(googleMailSender, INDENT_TERTIARY_MAIL_LIST, null, "Indent Tertiary Report",
                                "PFA", attachment);

        }

        public void sendAttendanceMorningAlert() throws Exception {
                LocalDateTime moriningTime = LocalDate.now().atTime(10, 31);
                List<AuthUser> authUsers = authRepository.selectAllActiveUser();
                Map<String, AuthUser> authUserEmailMap = authUsers.stream().filter(x -> x.isActive())
                                .collect(Collectors.toMap(x -> x.getEmailId(), x -> x));

                List<User> users = dtrUserRepository.selectAllByEmailIds(new ArrayList<>(authUserEmailMap.keySet()));
                Map<String, User> userMap = users.stream().collect(Collectors.toMap(x -> x.getEmailId(), x -> x));

                List<EmployeeAttendance> employeeAttendances = employeeAttendanceRepository
                                .selectAllByDatesBetween(LocalDate.now().atStartOfDay(), LocalDateTime.now());

                Map<Integer, Optional<EmployeeAttendance>> employeeMorningAttendance = employeeAttendances.stream()
                                .collect(Collectors.groupingBy(EmployeeAttendance::getUserId,
                                                Collectors.minBy(Comparator.comparing(EmployeeAttendance::getCreateTimestamp))));
                for (AuthUser authUser : authUsers) {
                        User user = userMap.get(authUser.getEmailId());
                        Optional<EmployeeAttendance> employeeAttendanceOptional = employeeMorningAttendance.get(user.getId());
                        LOGGER.info("AuthUser - {}, employeeAttendanceOptional {}", authUser.getName(), employeeAttendanceOptional);
                        if (employeeAttendanceOptional != null) {
                                LOGGER.info("employeeAttendanceOptional.orElse {}", employeeAttendanceOptional.orElse(null));
                                if (employeeAttendanceOptional.orElse(null) != null) {
                                        LOGGER.info("employeeAttendanceOptional.get().getCreateTimestamp() {}",
                                                        employeeAttendanceOptional.get().getCreateTimestamp());
                                }
                        }
                        if (employeeAttendanceOptional == null || employeeAttendanceOptional.orElse(null) == null
                                        || employeeAttendanceOptional.get().getCreateTimestamp().isAfter(moriningTime)) {
                                LOGGER.info("Will Send Email to {}", authUser.getFullName());
                                String body = String.format(
                                                "Dear %s,\n Pls note that you haven't punched your attendance by 10:30am%s. You have been marked absent for half the day.\n\nRegards\nHR Team",
                                                authUser.getFullName(),
                                                (employeeAttendanceOptional == null || employeeAttendanceOptional.orElse(null) == null) ? ""
                                                                : "(Punched at "
                                                                                + FormattingUtils.format(employeeAttendanceOptional.get().getCreateTimestamp())
                                                                                + ")");

                                Utils.sendMailWithAttachments(googleMailSender, new String[] { authUser.getEmailId() },
                                                new String[] { "kangan.monga@smartdukaan.com" }, "Attendance Alert", body);

                        }
                }

        }

        public void sendAttendanceEveningAlert() throws Exception {
                List<AuthUser> authUsers = authRepository.selectAllActiveUser();
                Map<String, AuthUser> authUserEmailMap = authUsers.stream().filter(x -> x.isActive())
                                .collect(Collectors.toMap(x -> x.getEmailId(), x -> x));

                List<User> users = dtrUserRepository.selectAllByEmailIds(new ArrayList<>(authUserEmailMap.keySet()));
                Map<String, User> userMap = users.stream().collect(Collectors.toMap(x -> x.getEmailId(), x -> x));

                Map<Integer, List<EmployeeAttendance>> employeeAttendancesMap = employeeAttendanceRepository
                                .selectAllByDatesBetween(LocalDate.now().atStartOfDay(), LocalDateTime.now()).stream()
                                .collect(Collectors.groupingBy(x -> x.getUserId()));

                for (AuthUser authUser : authUsers) {
                        User user = userMap.get(authUser.getEmailId());
                        String body = null;
                        List<EmployeeAttendance> employeeAttendances = employeeAttendancesMap.get(user.getId());
                        if (employeeAttendances == null) {
                                body = String.format(
                                                "Dear %s,\n No attendance has been registered by you today. You have been marked absent for the day.\n\nRegards\nHR Team",
                                                authUser.getFullName());
                        } else {
                                List<LocalDateTime> punchTimes = employeeAttendances.stream()
                                                .sorted(Comparator.comparing(EmployeeAttendance::getCreateTimestamp))
                                                .map(x -> x.getCreateTimestamp()).collect(Collectors.toList());
                                if (punchTimes.size() == 1) {
                                        // body = String.format("Dear %s,\n Pls note that you haven't punched out yet.
                                        // You have been marked absent for half the day. You may contact your manager
                                        // and get it regularise.\n\nRegards\nHR Team", authUser.getFullName());
                                } else {
                                        LocalDateTime firstPunch = punchTimes.get(0);
                                        LocalDateTime lastPunch = punchTimes.get(punchTimes.size() - 1);
                                        Duration duration = Duration.between(firstPunch, lastPunch);
                                        boolean hoursCompleted = lastPunch.isAfter(firstPunch.plusHours(8).plusMinutes(30));
                                        if (!hoursCompleted) {
                                                body = String.format(
                                                                "Dear %s,\n Pls note that you haven't completed 8.30 Hrs (%d.%d Hrs). You have been marked absent for half the day.\n\nRegards\nHR Team",
                                                                authUser.getFullName(), duration.toHours(),
                                                                duration.toMinutes() - duration.toHours() * 60);
                                        }
                                }

                        }
                        if (body != null) {
                                Utils.sendMailWithAttachments(googleMailSender, new String[] { authUser.getEmailId() },
                                                new String[] { "kangan.monga@smartdukaan.com" }, "Attendance Alert", body);
                        }
                }

                this.sendMailToHR();

        }

        private void sendMailToHR() throws Exception {
                Map<String, String> map = new HashMap<>();
                String reporticoDate = FormattingUtils.formatReporitcoDate(LocalDateTime.now());
                map.put("MANUAL_datesBetween_FROMDATE", reporticoDate);
                map.put("MANUAL_datesBetween_FROMDATE", reporticoDate);
                InputStreamSource isr = reporticoService.getReportInputStreamSource(ReporticoProject.FOCO,
                                "employeeattendance.xml");
                Attachment attachment = new Attachment("attendance-" + FormattingUtils.formatDate(LocalDateTime.now()) + ".csv",
                                isr);
                Utils.sendMailWithAttachments(googleMailSender, EMPLOYEE_ATTENDANCE_MAIL_LIST, null,
                                "Attendance - " + FormattingUtils.formatDate(LocalDateTime.now()), "PFA Attendance", attachment);
        }

        public void checkPartnerActiveStore() throws Exception {

                List<FofoStore> fofoStores = fofoStoreRepository.selectByStatus(true);

                LocalDateTime currentDate = LocalDate.now().atStartOfDay();
                if (!fofoStores.isEmpty()) {
                        for (FofoStore fofoStore : fofoStores) {

                                if (currentDate.isBefore(fofoStore.getActiveTimeStamp())) {

                                        fofoStore.setActive(true);
                                        fofoStoreRepository.persist(fofoStore);
                                        LOGGER.info("inserted into InActiveFofoStore successfully");

                                } else {
                                        fofoStore.setActive(false);
                                        fofoStore.setActiveTimeStamp(null);
                                        fofoStoreRepository.persist(fofoStore);
                                        LOGGER.info("inserted into InActiveFofoStore successfully");
                                }

                        }
                }

        }

        public void sendAgeingReport() throws Exception {
                sendAgeingReport("kamini.sharma@smartdukaan.com", "tarun.verma@smartdukaan.com",
                                "niranjan.kala@smartdukaan.com", "manish.gupta@smartdukaan.com", "kuldeep.kumar@smartdukaan.com");
        }

        public void moveImeisToPriceDropImeis() throws Exception {
                List<PriceDrop> priceDrops = priceDropRepository.selectAll();
                for (PriceDrop priceDrop : priceDrops) {
                        priceDropService.priceDropStatus(priceDrop.getId());
                }
        }

        public void walletmismatch() throws Exception {
                LocalDate curDate = LocalDate.now();
                List<PartnerDailyInvestment> pdis = partnerDailyInvestmentRepository.selectAll(curDate.minusDays(2));
                System.out.println(pdis.size());
                for (PartnerDailyInvestment pdi : pdis) {
                        int fofoId = pdi.getFofoId();
                        for (PartnerDailyInvestment investment : Lists
                                        .reverse(partnerDailyInvestmentRepository.selectAll(fofoId, null, null))) {
                                float statementAmount = walletService.getOpeningTill(fofoId,
                                                investment.getDate().plusDays(1).atTime(LocalTime.of(4, 0)));
                                CustomRetailer retailer = retailerService.getFofoRetailer(fofoId);
                                LOGGER.info("{}\t{}\t{}\t{}\t{}", fofoId, retailer.getBusinessName(), retailer.getMobileNumber(),
                                                investment.getDate().toString(), investment.getWalletAmount(), statementAmount);

                        }
                }

        }

        @Autowired
        StateRepository stateRepository;

        public void gst() throws Exception {
                List<FofoOrder> fofoOrders = fofoOrderRepository.selectBetweenSaleDate(LocalDate.of(2021, 8, 16).atStartOfDay(),
                                LocalDateTime.now());
                for (FofoOrder fofoOrder : fofoOrders) {
                        int retailerAddressId = retailerRegisteredAddressRepository
                                        .selectAddressIdByRetailerId(fofoOrder.getFofoId());

                        Address retailerAddress = addressRepository.selectById(retailerAddressId);
                        CustomerAddress customerAddress = customerAddressRepository.selectById(fofoOrder.getCustomerAddressId());
                        Integer stateId = null;
                        if (customerAddress.getState().equals(retailerAddress.getState())) {
                                try {
                                        stateId = stateRepository.selectByName(customerAddress.getState()).getId();
                                } catch (Exception e) {
                                        LOGGER.error("Cannot found state named {}", customerAddress.getState());
                                        continue;
                                }
                        }
                        Map<Integer, GstRate> itemIdStateTaxRateMap = null;
                        Map<Integer, Float> itemIdIgstTaxRateMap = null;

                        List<FofoOrderItem> fofoOrderItems = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId());
                        List<Integer> itemIds = fofoOrderItems.stream().map(x -> x.getItemId()).collect(Collectors.toList());
                        if (stateId != null) {
                                itemIdStateTaxRateMap = stateGstRateRepository.getStateTaxRate(itemIds, stateId);
                        } else {
                                itemIdIgstTaxRateMap = stateGstRateRepository.getIgstTaxRate(itemIds);
                        }

                        for (FofoOrderItem foi : fofoOrderItems) {
                                float sgstRate = foi.getSgstRate();
                                float cgstRate = foi.getCgstRate();
                                float igstRate = foi.getIgstRate();
                                if (stateId == null && igstRate == 0) {

                                        foi.setSgstRate(0);
                                        foi.setCgstRate(0);
                                        foi.setIgstRate(itemIdIgstTaxRateMap.get(foi.getItemId()));

                                        LOGGER.info("Invoice {}, Date {}", fofoOrder.getInvoiceNumber(), fofoOrder.getCreateTimestamp());
                                        LOGGER.info("customerAddress.getState() {}, retailerAddress.getState() {}",
                                                        customerAddress.getState(), retailerAddress.getState());
                                        LOGGER.info("Rates getIgstRate() {}", itemIdIgstTaxRateMap.get(foi.getItemId()));

                                } else if (stateId != null && sgstRate == 0 && cgstRate == 0) {

                                        foi.setIgstRate(0);
                                        foi.setCgstRate(itemIdStateTaxRateMap.get(foi.getItemId()).getCgstRate());
                                        foi.setSgstRate(itemIdStateTaxRateMap.get(foi.getItemId()).getSgstRate());

                                        LOGGER.info("Invoice {}, Date {}", fofoOrder.getInvoiceNumber(), fofoOrder.getCreateTimestamp());
                                        LOGGER.info("customerAddress.getState() {}, retailerAddress.getState() {}",
                                                        customerAddress.getState(), retailerAddress.getState());
                                        LOGGER.info("Rates getCgstRate() {}, getSgstRate() {}",
                                                        itemIdStateTaxRateMap.get(foi.getItemId()).getCgstRate(),
                                                        itemIdStateTaxRateMap.get(foi.getItemId()).getSgstRate());
                                }
                        }
                }

        }

        public void schemewalletmismatch() {
                LocalDate dateToReconcile = LocalDate.of(2018, 4, 1);
                while (dateToReconcile.isBefore(LocalDate.now())) {
                        reconcileSchemes(dateToReconcile);
                        // reconcileOrders(dateTime);
                        // reconcileRecharges(dateTime);
                        dateToReconcile = dateToReconcile.plusDays(1);
                }
        }

        private void reconcileSchemes(LocalDate date) {
                LocalDateTime startDate = date.atStartOfDay();
                LocalDateTime endDate = startDate.plusDays(1);
                List<SchemeInOut> siosCreated = schemeInOutRepository.selectAllByCreateDate(startDate, endDate);
                List<SchemeInOut> siosRefunded = schemeInOutRepository.selectAllByRefundDate(startDate, endDate);
                double totalSchemeDisbursed = siosCreated.stream().mapToDouble(x -> x.getAmount()).sum();
                double totalSchemeRolledback = siosRefunded.stream().mapToDouble(x -> x.getAmount()).sum();
                double netSchemeDisbursed = totalSchemeDisbursed - totalSchemeRolledback;
                List<WalletReferenceType> walletReferenceTypes = Arrays.asList(WalletReferenceType.SCHEME_IN,
                                WalletReferenceType.SCHEME_OUT);
                List<UserWalletHistory> history = userWalletHistoryRepository.selectAllByDateType(startDate, endDate,
                                walletReferenceTypes);
                double schemeAmountWalletTotal = history.stream().mapToDouble(x -> x.getAmount()).sum();
                if (Math.abs(netSchemeDisbursed - schemeAmountWalletTotal) > 10d) {
                        LOGGER.info("Scheme Amount mismatched for Date {}", date);

                        Map<Integer, Double> inventoryItemSchemeIO = siosCreated.stream().collect(Collectors
                                        .groupingBy(x -> x.getInventoryItemId(), Collectors.summingDouble(SchemeInOut::getAmount)));

                        Map<Integer, Double> userSchemeMap = inventoryItemRepository.selectByIds(inventoryItemSchemeIO.keySet())
                                        .stream().collect(Collectors.groupingBy(x -> x.getFofoId(),
                                                        Collectors.summingDouble(x -> inventoryItemSchemeIO.get(x.getId()))));

                        Map<Integer, Double> inventoryItemSchemeIORefunded = siosRefunded.stream().collect(Collectors
                                        .groupingBy(x -> x.getInventoryItemId(), Collectors.summingDouble(SchemeInOut::getAmount)));

                        Map<Integer, Double> userSchemeRefundedMap = inventoryItemRepository
                                        .selectByIds(inventoryItemSchemeIORefunded.keySet()).stream()
                                        .collect(Collectors.groupingBy(x -> x.getFofoId(),
                                                        Collectors.summingDouble(x -> inventoryItemSchemeIORefunded.get(x.getId()))));

                        Map<Integer, Double> finalUserSchemeAmountMap = new HashMap<>();

                        for (Map.Entry<Integer, Double> schemeAmount : userSchemeRefundedMap.entrySet()) {
                                if (!finalUserSchemeAmountMap.containsKey(schemeAmount.getKey())) {
                                        finalUserSchemeAmountMap.put(schemeAmount.getKey(), schemeAmount.getValue());
                                } else {
                                        finalUserSchemeAmountMap.put(schemeAmount.getKey(),
                                                        finalUserSchemeAmountMap.get(schemeAmount.getKey()) + schemeAmount.getValue());
                                }
                        }
                        Map<Integer, Integer> userWalletMap = userWalletRepository
                                        .selectByRetailerIds(finalUserSchemeAmountMap.keySet()).stream()
                                        .collect(Collectors.toMap(UserWallet::getUserId, UserWallet::getId));

                        Map<Integer, Double> walletAmountMap = history.stream().collect(Collectors.groupingBy(
                                        UserWalletHistory::getWalletId, Collectors.summingDouble((UserWalletHistory::getAmount))));
                        for (Map.Entry<Integer, Double> userAmount : walletAmountMap.entrySet()) {
                                double diff = Math.abs(finalUserSchemeAmountMap.get(userAmount.getKey()) - userAmount.getValue());
                                if (diff > 5) {
                                        LOGGER.info("Partner scheme mismatched for Userid {}", userWalletMap.get(userAmount.getKey()));
                                }
                        }
                }

        }

        public void dryRunSchemeReco() throws Exception {
                Map<Integer, Integer> userWalletMap = userWalletRepository.selectAll().stream()
                                .collect(Collectors.toMap(UserWallet::getUserId, UserWallet::getId));

                List<UserWalletHistory> userWalletHistory = new ArrayList<>();
                List<SchemeInOut> rolledbackSios = new ArrayList<>();
                Map<Integer, SchemeType> schemeTypeMap = schemeRepository.selectAll().stream()
                                .collect(Collectors.toMap(Scheme::getId, Scheme::getType));
                Set<String> serialNumbersConsidered = new HashSet<>();

                LocalDateTime startDate = LocalDate.of(2018, 3, 1).atStartOfDay();
                LocalDateTime endDate = LocalDate.now().atStartOfDay();
                List<Purchase> purchases = purchaseRepository.selectAllBetweenPurchaseDate(startDate, endDate);

                Map<Integer, String> storeNameMap = fofoStoreRepository.getStoresMap();
                purchases.stream().forEach(purchase -> {
                        float amountToRollback = 0;
                        String description = "Adjustment of Duplicate Scheme for Purchase Invoice "
                                        + purchase.getPurchaseReference();
                        Map<Integer, String> inventorySerialNumberMap = inventoryItemRepository.selectByPurchaseId(purchase.getId())
                                        .stream().filter(ii -> ii.getSerialNumber() != null)
                                        .collect(Collectors.toMap(InventoryItem::getId, InventoryItem::getSerialNumber));
                        if (inventorySerialNumberMap.size() > 0) {
                                for (Map.Entry<Integer, String> inventorySerialNumberEntry : inventorySerialNumberMap.entrySet()) {
                                        String serialNumber = inventorySerialNumberEntry.getValue();
                                        int inventoryItemId = inventorySerialNumberEntry.getKey();
                                        if (serialNumbersConsidered.contains(serialNumber)) {
                                                // This will rollback scheme for differenct orders for same serial
                                                List<SchemeInOut> sios = schemeInOutRepository
                                                                .selectByInventoryItemIds(new HashSet<>(Arrays.asList(inventoryItemId))).stream()
                                                                .filter(x -> x.getRolledBackTimestamp() == null
                                                                                && schemeTypeMap.get(x.getSchemeId()).equals(SchemeType.IN))
                                                                .collect(Collectors.toList());
                                                Collections.reverse(sios);
                                                for (SchemeInOut sio : sios) {
                                                        sio.setRolledBackTimestamp(LocalDateTime.now());
                                                        amountToRollback += sio.getAmount();
                                                        // sio.setSchemeType(SchemeType.OUT);
                                                        sio.setSerialNumber(serialNumber);
                                                        rolledbackSios.add(sio);
                                                }
                                                description = description.concat(" " + serialNumber + " ");
                                        } else {
                                                serialNumbersConsidered.add(serialNumber);
                                                List<Integer> schemesConsidered = new ArrayList<>();
                                                List<SchemeInOut> sios = schemeInOutRepository
                                                                .selectByInventoryItemIds(new HashSet<>(Arrays.asList(inventoryItemId))).stream()
                                                                .filter(x -> x.getRolledBackTimestamp() == null
                                                                                && schemeTypeMap.get(x.getSchemeId()).equals(SchemeType.IN))
                                                                .collect(Collectors.toList());
                                                Collections.reverse(sios);
                                                for (SchemeInOut sio : sios) {
                                                        if (!schemesConsidered.contains(sio.getSchemeId())) {
                                                                schemesConsidered.add(sio.getSchemeId());
                                                                continue;
                                                        }
                                                        sio.setRolledBackTimestamp(LocalDateTime.now());
                                                        amountToRollback += sio.getAmount();
                                                        // sio.setSchemeType(SchemeType.OUT);
                                                        sio.setSerialNumber(serialNumber);
                                                        sio.setStoreCode(storeNameMap.get(purchase.getFofoId()));
                                                        sio.setReference(purchase.getId());
                                                        rolledbackSios.add(sio);
                                                }
                                        }

                                }
                        }
                        if (amountToRollback > 0) {
                                // Address address =
                                // addressRepository.selectAllByRetailerId(purchase.getFofoId(), 0, 10).get(0);
                                UserWalletHistory uwh = new UserWalletHistory();
                                uwh.setAmount(Math.round(amountToRollback));
                                uwh.setDescription(description);
                                uwh.setTimestamp(LocalDateTime.now());
                                uwh.setReferenceType(WalletReferenceType.SCHEME_IN);
                                uwh.setReference(purchase.getId());
                                uwh.setWalletId(userWalletMap.get(purchase.getFofoId()));
                                uwh.setFofoId(purchase.getFofoId());
                                uwh.setStoreCode(storeNameMap.get(purchase.getFofoId()));
                                userWalletHistory.add(uwh);
                        }
                });
                ByteArrayOutputStream baos = FileUtil.getCSVByteStream(
                                Arrays.asList("User Id", "Store Code", "Reference Type", "Reference", "Amount", "Description",
                                                "Timestamp"),
                                userWalletHistory.stream()
                                                .map(x -> Arrays.asList(x.getWalletId(), x.getStoreCode(), x.getReferenceType(),
                                                                x.getReference(), x.getAmount(), x.getDescription(), x.getTimestamp()))
                                                .collect(Collectors.toList()));

                ByteArrayOutputStream baosOuts = FileUtil.getCSVByteStream(
                                Arrays.asList("Scheme ID", "SchemeType", "Reference", "Store Code", "Serial Number", "Amount",
                                                "Created", "Rolledback"),
                                rolledbackSios.stream()
                                                .map(x -> Arrays.asList(x.getSchemeId(), x.getSchemeType(), x.getReference(), x.getStoreCode(),
                                                                x.getSerialNumber(), x.getAmount(), x.getCreateTimestamp(), x.getRolledBackTimestamp()))
                                                .collect(Collectors.toList()));

                Utils.sendMailWithAttachments(googleMailSender, new String[] { "amit.gupta@shop2020.in" }, null,
                                "Partner Excess Amount Scheme In", "PFA",
                                new Attachment[] { new Attachment("WalletSummary.csv", new ByteArrayResource(baos.toByteArray())),
                                                new Attachment("SchemeInRolledback.csv", new ByteArrayResource(baosOuts.toByteArray())) });

                throw new Exception();

        }

        public void dryRunOutSchemeReco() throws Exception {
                List<UserWalletHistory> userWalletHistory = new ArrayList<>();
                List<SchemeInOut> rolledbackSios = new ArrayList<>();
                Map<Integer, Integer> userWalletMap = userWalletRepository.selectAll().stream()
                                .collect(Collectors.toMap(UserWallet::getUserId, UserWallet::getId));
                Map<Integer, SchemeType> schemeTypeMap = schemeRepository.selectAll().stream()
                                .collect(Collectors.toMap(Scheme::getId, Scheme::getType));
                LocalDateTime startDate = LocalDate.of(2019, 5, 1).atStartOfDay();
                LocalDateTime endDate = LocalDate.now().atStartOfDay();
                List<FofoOrder> allOrders = fofoOrderRepository.selectBetweenSaleDate(startDate, endDate);
                // Collections.reverse(allOrders);
                // List<FofoOrder> allOrders =
                // List<FofoOrder> allOrders =
                // Arrays.asList(fofoOrderRepository.selectByInvoiceNumber("UPGZ019/25"));
                Set<String> serialNumbersConsidered = new HashSet<>();
                allOrders.stream().forEach(fofoOrder -> {
                        String description = "Adjustment of Duplicate Scheme for Sale Invoice " + fofoOrder.getInvoiceNumber();
                        Map<Integer, String> inventorySerialNumberMap = new HashMap<>();
                        float amountToRollback = 0;
                        List<FofoOrderItem> orderItems = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId());
                        orderItems.forEach(x -> {
                                inventorySerialNumberMap.putAll(x.getFofoLineItems().stream().filter(li -> li.getSerialNumber() != null)
                                                .collect(Collectors.toMap(FofoLineItem::getInventoryItemId, FofoLineItem::getSerialNumber)));
                        });
                        if (inventorySerialNumberMap.size() > 0) {
                                for (Map.Entry<Integer, String> inventorySerialNumberEntry : inventorySerialNumberMap.entrySet()) {
                                        String serialNumber = inventorySerialNumberEntry.getValue();
                                        int inventoryItemId = inventorySerialNumberEntry.getKey();
                                        if (serialNumbersConsidered.contains(serialNumber)) {
                                                // This will rollback scheme for differenct orders for same serial
                                                List<SchemeInOut> sios = schemeInOutRepository
                                                                .selectByInventoryItemIds(new HashSet<>(Arrays.asList(inventoryItemId))).stream()
                                                                .filter(x -> x.getRolledBackTimestamp() == null
                                                                                && schemeTypeMap.get(x.getSchemeId()).equals(SchemeType.OUT))
                                                                .collect(Collectors.toList());
                                                Collections.reverse(sios);
                                                for (SchemeInOut sio : sios) {
                                                        sio.setRolledBackTimestamp(LocalDateTime.now());
                                                        amountToRollback += sio.getAmount();
                                                        // sio.setSchemeType(SchemeType.OUT);
                                                        sio.setSerialNumber(serialNumber);
                                                        sio.setStoreCode(fofoOrder.getInvoiceNumber().split("/")[0]);
                                                        sio.setReference(fofoOrder.getId());
                                                        rolledbackSios.add(sio);
                                                }
                                                description = description.concat(" " + serialNumber + " ");
                                        } else {
                                                serialNumbersConsidered.add(serialNumber);
                                                List<Integer> schemesConsidered = new ArrayList<>();
                                                List<SchemeInOut> sios = schemeInOutRepository
                                                                .selectByInventoryItemIds(new HashSet<>(Arrays.asList(inventoryItemId))).stream()
                                                                .filter(x -> x.getRolledBackTimestamp() == null
                                                                                && schemeTypeMap.get(x.getSchemeId()).equals(SchemeType.OUT))
                                                                .collect(Collectors.toList());
                                                Collections.reverse(sios);
                                                for (SchemeInOut sio : sios) {
                                                        if (!schemesConsidered.contains(sio.getSchemeId())) {
                                                                schemesConsidered.add(sio.getSchemeId());
                                                                continue;
                                                        }
                                                        sio.setRolledBackTimestamp(LocalDateTime.now());
                                                        amountToRollback += sio.getAmount();
                                                        // sio.setSchemeType(SchemeType.OUT);
                                                        sio.setReference(fofoOrder.getId());
                                                        sio.setSerialNumber(serialNumber);
                                                        sio.setStoreCode(fofoOrder.getInvoiceNumber().split("/")[0]);
                                                        rolledbackSios.add(sio);
                                                }
                                        }

                                }
                        }
                        if (amountToRollback > 0) {
                                UserWalletHistory uwh = new UserWalletHistory();
                                uwh.setAmount(Math.round(amountToRollback));
                                uwh.setDescription(description);
                                uwh.setTimestamp(LocalDateTime.now());
                                uwh.setReferenceType(WalletReferenceType.SCHEME_OUT);
                                uwh.setReference(fofoOrder.getId());
                                uwh.setWalletId(userWalletMap.get(fofoOrder.getFofoId()));
                                uwh.setFofoId(fofoOrder.getFofoId());
                                uwh.setStoreCode(fofoOrder.getInvoiceNumber().split("/")[0]);
                                userWalletHistory.add(uwh);
                        }
                });

                ByteArrayOutputStream baos = FileUtil.getCSVByteStream(
                                Arrays.asList("Wallet Id", "Store Code", "Reference Type", "Reference", "Amount", "Description",
                                                "Timestamp"),
                                userWalletHistory.stream()
                                                .map(x -> Arrays.asList(x.getWalletId(), x.getStoreCode(), x.getReferenceType(),
                                                                x.getReference(), x.getAmount(), x.getDescription(), x.getTimestamp()))
                                                .collect(Collectors.toList()));

                ByteArrayOutputStream baosOuts = FileUtil.getCSVByteStream(
                                Arrays.asList("Scheme ID", "SchemeType", "Store Code", "Serial Number", "Amount", "Created",
                                                "Rolledback"),
                                rolledbackSios.stream()
                                                .map(x -> Arrays.asList(x.getSchemeId(), x.getSchemeType(), x.getStoreCode(),
                                                                x.getSerialNumber(), x.getAmount(), x.getCreateTimestamp(), x.getRolledBackTimestamp()))
                                                .collect(Collectors.toList()));

                Utils.sendMailWithAttachments(googleMailSender, new String[] { "amit.gupta@shop2020.in" }, null,
                                "Partner Excess Amount Scheme Out", "PFA",
                                new Attachment[] { new Attachment("WalletSummary.csv", new ByteArrayResource(baos.toByteArray())),
                                                new Attachment("SchemeOutRolledback.csv", new ByteArrayResource(baosOuts.toByteArray())) });

                throw new Exception();
        }

        public void dryRunSchemeOutReco1() throws Exception {
                List<Integer> references = Arrays.asList(6744, 7347, 8320, 8891, 9124, 9217, 9263, 9379);
                List<UserWalletHistory> userWalletHistory = new ArrayList<>();
                List<SchemeInOut> rolledbackSios = new ArrayList<>();
                Map<Integer, Integer> userWalletMap = userWalletRepository.selectAll().stream()
                                .collect(Collectors.toMap(UserWallet::getUserId, UserWallet::getId));
                Map<Integer, SchemeType> schemeTypeMap = schemeRepository.selectAll().stream()
                                .collect(Collectors.toMap(Scheme::getId, Scheme::getType));
                references.stream().forEach(reference -> {
                        FofoOrder fofoOrder = null;
                        try {
                                fofoOrder = fofoOrderRepository.selectByOrderId(reference);
                        } catch (Exception e) {

                        }
                        String description = "Adjustment of Duplicate Scheme for Sale Invoice " + fofoOrder.getInvoiceNumber();
                        Map<Integer, String> inventorySerialNumberMap = new HashMap<>();
                        float amountToRollback = 0;
                        List<FofoOrderItem> orderItems = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId());
                        orderItems.forEach(x -> {
                                inventorySerialNumberMap.putAll(x.getFofoLineItems().stream().filter(li -> li.getSerialNumber() != null)
                                                .collect(Collectors.toMap(FofoLineItem::getInventoryItemId, FofoLineItem::getSerialNumber)));
                        });
                        if (inventorySerialNumberMap.size() > 0) {
                                List<SchemeInOut> sios = schemeInOutRepository
                                                .selectByInventoryItemIds(inventorySerialNumberMap.keySet()).stream()
                                                .filter(x -> schemeTypeMap.get(x.getSchemeId()).equals(SchemeType.OUT))
                                                .collect(Collectors.toList());
                                LOGGER.info("Found {} duplicate schemeouts for Orderid {}", sios.size(), fofoOrder.getId());
                                UserWalletHistory uwh = new UserWalletHistory();
                                Map<Integer, List<SchemeInOut>> inventoryIdSouts = sios.stream()
                                                .collect(Collectors.groupingBy(SchemeInOut::getInventoryItemId, Collectors.toList()));
                                for (Map.Entry<Integer, List<SchemeInOut>> inventorySioEntry : inventoryIdSouts.entrySet()) {
                                        List<SchemeInOut> outList = inventorySioEntry.getValue();
                                        if (outList.size() > 1) {

                                        }
                                }
                                uwh.setAmount(Math.round(amountToRollback));
                                uwh.setDescription(description);
                                uwh.setTimestamp(LocalDateTime.now());
                                uwh.setReferenceType(WalletReferenceType.SCHEME_OUT);
                                uwh.setReference(fofoOrder.getId());
                                uwh.setWalletId(userWalletMap.get(fofoOrder.getFofoId()));
                                uwh.setFofoId(fofoOrder.getFofoId());
                                uwh.setStoreCode(fofoOrder.getInvoiceNumber().split("/")[0]);
                                userWalletHistory.add(uwh);
                        }
                });

                ByteArrayOutputStream baos = FileUtil.getCSVByteStream(
                                Arrays.asList("User Id", "Reference Type", "Reference", "Amount", "Description", "Timestamp"),
                                userWalletHistory.stream().map(x -> Arrays.asList(x.getWalletId(), x.getReferenceType(),
                                                x.getReference(), x.getAmount(), x.getDescription(), x.getTimestamp()))
                                                .collect(Collectors.toList()));

                ByteArrayOutputStream baosOuts = FileUtil.getCSVByteStream(
                                Arrays.asList("Scheme ID", "SchemeType", "Store Code", "Serial Number", "Amount", "Created",
                                                "Rolledback"),
                                rolledbackSios.stream()
                                                .map(x -> Arrays.asList(x.getSchemeId(), x.getSchemeType(), x.getStoreCode(),
                                                                x.getSerialNumber(), x.getAmount(), x.getCreateTimestamp(), x.getRolledBackTimestamp()))
                                                .collect(Collectors.toList()));

                Utils.sendMailWithAttachments(googleMailSender,
                                new String[] { "amit.gupta@shop2020.in", "neeraj.gupta@smartdukaan.com" }, null,
                                "Partner Excess Amount", "PFA",
                                new Attachment[] { new Attachment("WalletSummary.csv", new ByteArrayResource(baos.toByteArray())),
                                                new Attachment("SchemeOutRolledback.csv", new ByteArrayResource(baosOuts.toByteArray())) });

                throw new Exception();

        }

        public void sendDailySalesNotificationToPartner(Integer fofoIdInt) throws Exception {

                LocalDateTime now = LocalDateTime.now();
                LocalDateTime from = now.with(LocalTime.MIN);
                String timeString = "Today %s";
                // Send yesterday's report
                /*
                 * if (now.getHour() < 13) { timeString = "Yesterday %s"; from =
                 * now.minusDays(1).; now = from.with(LocalTime.MAX);
                 *
                 * }
                 */
                List<Integer> fofoIds = null;
                if (fofoIdInt == null) {
                        fofoIds = fofoStoreRepository.selectAll().stream().filter(x -> x.isActive()).map(x -> x.getId())
                                        .collect(Collectors.toList());
                } else {
                        fofoIds = Arrays.asList(fofoIdInt);
                }
                DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("h:m a");

                Map<Integer, Float> partnerPolicyAmountMap = insurancePolicyRepository.selectAmountSumGroupByRetailerId(now,
                                null);
                Map<Integer, Long> partnerPolicyQtyMap = insurancePolicyRepository.selectQtyGroupByRetailerId(now, null);

                Map<Integer, Double> spPartnerOrderValMap = fofoOrderItemRepository.selectSumAmountGroupByRetailer(from, now, 0,
                                true);

                Map<Integer, Double> spPartner3DaysOrderValMap = fofoOrderItemRepository
                                .selectSumAmountGroupByRetailer(from.minusDays(3), now, 0, true);
                Map<Integer, Long> spPartnerOrderQtyMap = fofoOrderItemRepository.selectQtyGroupByRetailer(from, now, 0, true);

                Map<Integer, Double> partnerOrderValMap = fofoOrderItemRepository.selectSumAmountGroupByRetailer(from, now, 0,
                                false);
                Map<Integer, Long> partnerOrderQtyMap = fofoOrderItemRepository.selectQtyGroupByRetailer(from, now, 0, false);

                Map<Integer, SaleTargetReportModel> saleTargetReportModelMap = new HashMap<>();
                for (int fofoId : fofoIds) {
                        SaleTargetReportModel model = new SaleTargetReportModel();
                        model.setInsuranceSale(
                                        partnerPolicyAmountMap.containsKey(fofoId) ? partnerPolicyAmountMap.get(fofoId).doubleValue() : 0);
                        model.setInsruanceQty(partnerPolicyQtyMap.containsKey(fofoId) ? partnerPolicyQtyMap.get(fofoId) : 0);
                        model.setSmartphoneSale(spPartnerOrderValMap.containsKey(fofoId) ? spPartnerOrderValMap.get(fofoId) : 0);
                        model.setSmartphoneQty(spPartnerOrderQtyMap.containsKey(fofoId) ? spPartnerOrderQtyMap.get(fofoId) : 0);
                        model.setTotalSale(partnerOrderValMap.containsKey(fofoId) ? partnerOrderValMap.get(fofoId) : 0);
                        model.setTotalQty(partnerOrderQtyMap.containsKey(fofoId) ? partnerOrderQtyMap.get(fofoId) : 0);
                        model.setPast3daysSale(
                                        spPartner3DaysOrderValMap.containsKey(fofoId) ? spPartner3DaysOrderValMap.get(fofoId) : 0);
                        model.setFofoId(fofoId);
                        saleTargetReportModelMap.put(fofoId, model);
                }

                Map<Integer, FofoReportingModel> partnerSalesHeadersMap = this.getPartnerIdSalesHeaders();
                for (Integer fofoId : fofoIds) {
                        SaleTargetReportModel model = saleTargetReportModelMap.get(fofoId);

                        // com.spice.profitmandi.dao.entity.user.User user =
                        // userUserRepository.selectById(fofoId);

                        // Address address = addressRepository.selectById(user.getAddressId());

                        String title = "Sale Update";
                        String messageTemplate = String.format("Smartphones Rs.%.0f, Insurance Rs.%.0f, Total Rs.%.0f till %s.",
                                        model.getSmartphoneSale(), model.getInsuranceSale(), model.getTotalSale(),
                                        String.format(timeString, now.format(timeFormatter)));
                        SendNotificationModel sendNotificationModel = new SendNotificationModel();
                        sendNotificationModel.setCampaignName("Sales update alert");
                        sendNotificationModel.setTitle(title);
                        sendNotificationModel.setMessage(messageTemplate);
                        sendNotificationModel.setType("url");
                        sendNotificationModel.setUrl("https://app.smartdukaan.com/pages/home/notifications");
                        sendNotificationModel.setExpiresat(LocalDateTime.now().plusDays(1));
                        sendNotificationModel.setMessageType(MessageType.notification);
                        int userId = userAccountRepository.selectUserIdByRetailerId(fofoId);
                        sendNotificationModel.setUserIds(Arrays.asList(userId));
                        notificationService.sendNotification(sendNotificationModel);
                        String whatsappMessageTemplate = String.format(
                                        "Dear Partner, Your sale update is Smartphones Rs.%.0f, Insurance Rs.%.0f, Total Rs.%.0f till %s.",
                                        model.getSmartphoneSale(), model.getInsuranceSale(), model.getTotalSale(),
                                        String.format(timeString, now.format(timeFormatter)));
                        // notificationService.sendWhatsappMessage(whatsappMessageTemplate, title,
                        // address.getPhoneNumber());

                }
                // String saleReport = this.getDailySalesReportHtml(partnerSalesHeadersMap,
                // saleTargetReportModelMap);
                this.getStateWiseSales(saleTargetReportModelMap, partnerSalesHeadersMap);
                /*
                 * String cc[] = { "tarun.verma@smartdukaan.com",
                 * "kamini.sharma@smartdukaan.com", "niranjan.kala@smartdukaan.com",
                 * "sm@smartdukaan.com" };
                 *
                 * String subject = String.format("Sale till %s", String.format(timeString,
                 * now.format(timeFormatter))); //
                 * this.sendMailOfHtmlFomat("amit.gupta@smartukaan.com", saleReport, cc, //
                 * subject); this.sendMailOfHtmlFormat("amit.gupta@smartdukaan.com",
                 * statewiseSaleReport, cc, "Statewise" + subject);
                 */
        }

        public void checkRazorPayPaymentStatus() throws Exception {
                List<PendingOrder> pendingOrder = pendingOrderRepository
                                .selectAllByStatus(com.spice.profitmandi.dao.enumuration.transaction.OrderStatus.PENDING);

                for (PendingOrder po : pendingOrder) {
                        RazorPay razorPay = razorPayRepository.selectByOrdeId(po.getId());
                        List<PendingOrderItem> poItems = pendingOrderItemRepository.selectByOrderId(po.getId());

                        LOGGER.info("razorPay" + razorPay);
                        if (razorPay != null) {
                                List<Payment> payments = razorPaymentService.fetchOrderForPayment(razorPay.getRazorOrderId());

                                if (!payments.isEmpty()) {
                                        List<String> statusList = new ArrayList<>();
                                        for (Payment payment : payments) {

                                                JSONObject jsonObj = new JSONObject(payment.toString());

                                                String status = jsonObj.getString("status");

                                                statusList.add(status);

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

                                        if (statusList.contains("authorized") || statusList.contains("captured")) {
                                                po.setStatus(com.spice.profitmandi.dao.enumuration.transaction.OrderStatus.PROCESSING);
                                                po.setPaidAmount(po.getTotalAmount());
                                                for (PendingOrderItem poi : poItems) {
                                                        poi.setStatus(com.spice.profitmandi.dao.enumuration.transaction.OrderStatus.PROCESSING);
                                                }
                                                Map<String, Object> emailModel = pendingOrderService.sendCreateOrderMail(po);

                                                CustomRetailer customRetailer = retailerService.getFofoRetailer(po.getFofoId());
                                                Customer customer = customerRepository.selectById(po.getCustomerId());
                                                String[] customerEmail = null;
                                                if (customer.getEmailId() != null) {
                                                        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",
                                                                "tejbeer.kaur@shop2020.in", customRetailer.getEmail());
                                                List<String> authUserEmails = csService.getAuthUserByPartnerId(customRetailer.getPartnerId());
                                                if (authUserEmails != null) {
                                                        authUserEmails = new ArrayList<>();
                                                }
                                                authUserEmails.addAll(bccTo);

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

                                        } else if (statusList.contains("refunded") || statusList.contains("failed")) {
                                                for (PendingOrderItem poi : poItems) {
                                                        poi.setStatus(com.spice.profitmandi.dao.enumuration.transaction.OrderStatus.FAILED);
                                                }

                                                po.setStatus(com.spice.profitmandi.dao.enumuration.transaction.OrderStatus.FAILED);
                                        }

                                }
                                // LOGGER.info("payment" + payments);

                        }
                }
        }

        public static class SaleTargetReportModel {
                private double totalSale;
                private long totalQty;
                private double past3daysSale;
                private int fofoId;

                public int getFofoId() {
                        return fofoId;
                }

                public void setFofoId(int fofoId) {
                        this.fofoId = fofoId;
                }

                private double smartphoneSale;
                private long smartphoneQty;
                private double insuranceSale;
                private long insruanceQty;

                public long getTotalQty() {
                        return totalQty;
                }

                public void setTotalQty(long totalQty) {
                        this.totalQty = totalQty;
                }

                public double getPast3daysSale() {
                        return past3daysSale;
                }

                public void setPast3daysSale(double past3daysSale) {
                        this.past3daysSale = past3daysSale;
                }

                @Override
                public int hashCode() {
                        final int prime = 31;
                        int result = 1;
                        result = prime * result + fofoId;
                        result = prime * result + (int) (insruanceQty ^ (insruanceQty >>> 32));
                        long temp;
                        temp = Double.doubleToLongBits(insuranceSale);
                        result = prime * result + (int) (temp ^ (temp >>> 32));
                        result = prime * result + (int) (smartphoneQty ^ (smartphoneQty >>> 32));
                        temp = Double.doubleToLongBits(smartphoneSale);
                        result = prime * result + (int) (temp ^ (temp >>> 32));
                        result = prime * result + (int) (totalQty ^ (totalQty >>> 32));
                        temp = Double.doubleToLongBits(totalSale);
                        result = prime * result + (int) (temp ^ (temp >>> 32));
                        return result;
                }

                @Override
                public boolean equals(Object obj) {
                        if (this == obj)
                                return true;
                        if (obj == null)
                                return false;
                        if (getClass() != obj.getClass())
                                return false;
                        SaleTargetReportModel other = (SaleTargetReportModel) obj;
                        if (fofoId != other.fofoId)
                                return false;
                        if (insruanceQty != other.insruanceQty)
                                return false;
                        if (Double.doubleToLongBits(insuranceSale) != Double.doubleToLongBits(other.insuranceSale))
                                return false;
                        if (smartphoneQty != other.smartphoneQty)
                                return false;
                        if (Double.doubleToLongBits(smartphoneSale) != Double.doubleToLongBits(other.smartphoneSale))
                                return false;
                        if (totalQty != other.totalQty)
                                return false;
                        if (Double.doubleToLongBits(totalSale) != Double.doubleToLongBits(other.totalSale))
                                return false;
                        return true;
                }

                public double getTotalSale() {
                        return totalSale;
                }

                public void setTotalSale(double totalSale) {
                        this.totalSale = totalSale;
                }

                public double getSmartphoneSale() {
                        return smartphoneSale;
                }

                public void setSmartphoneSale(double smartphoneSale) {
                        this.smartphoneSale = smartphoneSale;
                }

                public long getSmartphoneQty() {
                        return smartphoneQty;
                }

                public void setSmartphoneQty(long smartphoneQty) {
                        this.smartphoneQty = smartphoneQty;
                }

                public double getInsuranceSale() {
                        return insuranceSale;
                }

                public void setInsuranceSale(double insuranceSale) {
                        this.insuranceSale = insuranceSale;
                }

                public long getInsruanceQty() {
                        return insruanceQty;
                }

                public void setInsruanceQty(long insruanceQty) {
                        this.insruanceQty = insruanceQty;
                }

                @Override
                public String toString() {
                        return "SaleTargetReportModel [totalSale=" + totalSale + ", totalQty=" + totalQty + ", past3daysSale="
                                        + past3daysSale + ", fofoId=" + fofoId + ", smartphoneSale=" + smartphoneSale + ", smartphoneQty="
                                        + smartphoneQty + ", insuranceSale=" + insuranceSale + ", insruanceQty=" + insruanceQty + "]";
                }

        }

        private void getStateWiseSales(Map<Integer, SaleTargetReportModel> saleTargetReportModelMap,
                        Map<Integer, FofoReportingModel> partnerSalesHeadersMap) throws Exception {
                String timeString = "Today %s";
                LocalDateTime now = LocalDateTime.now();

                DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("h:m a");
                List<Integer> categoryIds = Arrays.asList(ProfitMandiConstants.TICKET_CATEGORY_LOGISTICS,
                                ProfitMandiConstants.TICKET_CATEGORY_FINANCIAL_SERVICES, ProfitMandiConstants.TICKET_CATEGORY_CATEGORY,
                                ProfitMandiConstants.TICKET_CATEGORY_RBM, ProfitMandiConstants.TICKET_CATEGORY_SALES,
                                ProfitMandiConstants.TICKET_CATEGORY_MARKETING, ProfitMandiConstants.TICKET_CATEGORY_ACCOUNTS,
                                ProfitMandiConstants.TICKET_CATEGORY_BUSINESSINTELLIGENT,
                                ProfitMandiConstants.TICKET_CATEGORY_TECHNOLOGY);

                Map<String, Set<Integer>> storeGuyMap = csService.getAuthUserPartnerIdMappingByCategoryIds(categoryIds);

                for (Entry<String, Set<Integer>> storeGuyEntry : storeGuyMap.entrySet()) {
                        String email = storeGuyEntry.getKey();
                        Set<Integer> fofoIds = storeGuyEntry.getValue();
                        LOGGER.info("fofoIds {}", fofoIds);

                        if (!fofoIds.isEmpty()) {
                                List<FofoStore> stores = fofoStoreRepository
                                                .selectActivePartnersByRetailerIds(new ArrayList<>(fofoIds));

                                Map<String, List<Integer>> stateMap = stores.stream().collect(Collectors.groupingBy(
                                                x -> x.getCode().substring(0, 2), Collectors.mapping(x -> x.getId(), Collectors.toList())));
                                List<List<Serializable>> stateWiseSales = new ArrayList<>();
                                for (Map.Entry<String, List<Integer>> stateMapEntry : stateMap.entrySet()) {
                                        long totalQty = stateMapEntry.getValue().stream()
                                                        .collect(Collectors.summingLong(x -> saleTargetReportModelMap.get(x).getTotalQty()));
                                        double totalSale = stateMapEntry.getValue().stream()
                                                        .collect(Collectors.summingDouble(x -> saleTargetReportModelMap.get(x).getTotalSale()));
                                        long smartPhoneQty = stateMapEntry.getValue().stream()
                                                        .collect(Collectors.summingLong(x -> saleTargetReportModelMap.get(x).getSmartphoneQty()));
                                        double smartPhoneSale = stateMapEntry.getValue().stream().collect(
                                                        Collectors.summingDouble(x -> saleTargetReportModelMap.get(x).getSmartphoneSale()));
                                        stateWiseSales.add(
                                                        Arrays.asList(stateMapEntry.getKey(), smartPhoneQty, smartPhoneSale, totalQty, totalSale));
                                }
                                StringBuilder sb = new StringBuilder();
                                sb.append("<html><body>");
                                sb.append("<p>Statewise Sale Report:</p><br/><table style='border:1px solid black';cellspacing=0>");
                                sb.append("<tbody>\n" + "           <tr>"
                                                + "                                             <th style='border:1px solid black;padding: 5px'>State</th>"
                                                + "                                             <th style='border:1px solid black;padding: 5px'>SmartPhone Qty</th>"
                                                + "                                             <th style='border:1px solid black;padding: 5px'>SmartPhone Value</th>"
                                                + "                                             <th style='border:1px solid black;padding: 5px'>Total Qty</th>"
                                                + "                                             <th style='border:1px solid black;padding: 5px'>Total Value</th>"
                                                + "                                     </tr>");
                                for (List<Serializable> stateSale : stateWiseSales) {
                                        sb.append("<tr>");
                                        sb.append("<td style='border:1px solid black;padding: 5px'>" + stateSale.get(0) + "</td>");
                                        sb.append("<td style='border:1px solid black;padding: 5px'>" + stateSale.get(1) + "</td>");
                                        sb.append("<td style='border:1px solid black;padding: 5px'>" + stateSale.get(2) + "</td>");
                                        sb.append("<td style='border:1px solid black;padding: 5px'>" + stateSale.get(3) + "</td>");
                                        sb.append("<td style='border:1px solid black;padding: 5px'>" + stateSale.get(4) + "</td>");
                                        sb.append("</tr>");
                                }
                                sb.append("</tbody></table><br><br>");

                                sb.append("<p>Sale Report:</p><br/><table style='border:1px solid black';cellspacing=0>");
                                sb.append("<tbody>\n" + "                                       <tr>\n"
                                                + "                                             <th style='border:1px solid black;padding: 5px'>Code</th>"
                                                + "                                             <th style='border:1px solid black;padding: 5px'>Business Name</th>"
                                                + "                                             <th style='border:1px solid black;padding: 5px'>Regional Manager</th>"
                                                + "                                             <th style='border:1px solid black;padding: 5px'>Territory Manager</th>"
                                                + "                                             <th style='border:1px solid black;padding: 5px'>Sale</th>"
                                                + "                                             <th style='border:1px solid black;padding: 5px'>Smartphone Sale</th>"
                                                + "                                             <th style='border:1px solid black;padding: 5px'>SmartPhone Qty</th>"
                                                + "                                     </tr>");

                                /*
                                 * List<Integer> sortedPartnerSalesHeaders =
                                 * partnerSalesHeadersMap.values().stream()
                                 * .sorted(Comparator.comparing(FofoReportingModel::getCode)
                                 * .thenComparing(FofoReportingModel::getRegionalManager)
                                 * .thenComparing(FofoReportingModel::getTerritoryManager))
                                 * .map(FofoReportingModel::getFofoId).collect(Collectors.toList());
                                 */

                                List<Integer> sortedSaleTargetReport = saleTargetReportModelMap.values().stream()
                                                .filter(x -> fofoIds.contains(x.getFofoId()))
                                                .sorted(Comparator.comparing(SaleTargetReportModel::getTotalSale))
                                                .map(SaleTargetReportModel::getFofoId).collect(Collectors.toList());
                                for (Integer fofoId : sortedSaleTargetReport) {
                                        if (saleTargetReportModelMap.get(fofoId).getPast3daysSale() == 0) {
                                                sb.append("<tr style='background-color:red'>");
                                        } else {
                                                sb.append("<tr>");
                                        }
                                        sb.append("<td style='border:1px solid black;padding: 5px'>"
                                                        + partnerSalesHeadersMap.get(fofoId).getCode() + "</td>");
                                        sb.append("<td style='border:1px solid black;padding: 5px'>"
                                                        + partnerSalesHeadersMap.get(fofoId).getBusinessName() + "</td>");
                                        sb.append("<td style='border:1px solid black;padding: 5px'>"
                                                        + partnerSalesHeadersMap.get(fofoId).getRegionalManager() + "</td>");
                                        sb.append("<td style='border:1px solid black;padding: 5px'>"
                                                        + partnerSalesHeadersMap.get(fofoId).getTerritoryManager() + "</td>");
                                        sb.append("<td style='border:1px solid black;padding: 5px'>"
                                                        + saleTargetReportModelMap.get(fofoId).getTotalSale() + "</td>");
                                        sb.append("<td style='border:1px solid black;padding: 5px'>"
                                                        + saleTargetReportModelMap.get(fofoId).getSmartphoneSale() + "</td>");
                                        sb.append("<td style='border:1px solid black;padding: 5px'>"
                                                        + saleTargetReportModelMap.get(fofoId).getSmartphoneQty() + "</td>");
                                        sb.append("</tr>");
                                }

                                sb.append("</tr>");

                                sb.append("</body></html>");

                                String statewiseSaleReport = sb.toString();

                                String subject = String.format("Sale till %s", String.format(timeString, now.format(timeFormatter)));
                                // this.sendMailOfHtmlFomat("amit.gupta@smartukaan.com", saleReport, cc,
                                // subject);
                                this.sendMailOfHtmlFormat(email, statewiseSaleReport, null, "Statewise" + subject);
                        }
                }
        }

        private void sendMailOfHtmlFormat(String email, String body, String cc[], String subject)
                        throws MessagingException, ProfitMandiBusinessException, IOException {
                MimeMessage message = mailSender.createMimeMessage();
                MimeMessageHelper helper = new MimeMessageHelper(message);
                helper.setSubject(subject);
                helper.setText(body, true);
                helper.setTo(email);
                if (cc != null) {
                        helper.setCc(cc);
                }
                InternetAddress senderAddress = new InternetAddress("noreply@smartdukaan.com", "Smart Dukaan");
                helper.setFrom(senderAddress);
                mailSender.send(message);
        }

        public void sendNotification() throws Exception {
                List<PushNotifications> pushNotifications = pushNotificationRepository.selectAllByTimestamp();
                if (!pushNotifications.isEmpty()) {
                        for (PushNotifications pushNotification : pushNotifications) {
                                Device device = deviceRepository.selectById(pushNotification.getDeviceId());
                                NotificationCampaign notificationCampaign = notificationCampaignRepository
                                                .selectById(pushNotification.getNotificationCampaignid());
                                SimpleCampaignParams scp = gson.fromJson(notificationCampaign.getImplementationParams(),
                                                SimpleCampaignParams.class);
                                Campaign campaign = new SimpleCampaign(scp);
                                String result_url = campaign.getUrl() + "&user_id=" + device.getUser_id();
                                JSONObject json = new JSONObject();
                                json.put("to", device.getFcmId());
                                JSONObject jsonObj = new JSONObject();
                                jsonObj.put("message", campaign.getMessage());
                                jsonObj.put("title", campaign.getTitle());
                                jsonObj.put("type", campaign.getType());
                                jsonObj.put("url", result_url);
                                jsonObj.put("time_to_live", campaign.getExpireTimestamp());
                                jsonObj.put("image", campaign.getImageUrl());
                                jsonObj.put("largeIcon", "large_icon");
                                jsonObj.put("smallIcon", "small_icon");
                                jsonObj.put("vibrate", 1);
                                jsonObj.put("pid", pushNotification.getId());
                                jsonObj.put("sound", 1);
                                jsonObj.put("priority", "high");
                                json.put("data", jsonObj);
                                try {
                                        CloseableHttpClient client = HttpClients.createDefault();
                                        HttpPost httpPost = new HttpPost(FCM_URL);

                                        httpPost.setHeader("Content-Type", "application/json; utf-8");
                                        httpPost.setHeader("authorization", "key=" + FCM_API_KEY);
                                        StringEntity entity = new StringEntity(json.toString());
                                        httpPost.setEntity(entity);
                                        CloseableHttpResponse response = client.execute(httpPost);

                                        if (response.getStatusLine().getStatusCode() == 200) {
                                                pushNotification.setSentTimestamp(LocalDateTime.now());
                                        } else {
                                                pushNotification.setSentTimestamp(LocalDateTime.of(1970, 1, 1, 00, 00));
                                                LOGGER.info("message" + "not sent");
                                                response.toString();
                                        }

                                } catch (Exception e) {
                                        e.printStackTrace();
                                        pushNotification.setSentTimestamp(LocalDateTime.of(1970, 1, 1, 00, 00));
                                        LOGGER.info("message " + "not sent " + e.getMessage());
                                }
                        }
                }
        }

        public void grouping() throws Exception {
                DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MM-dd-yyyy hh:mm");
                List<PriceDropIMEI> priceDropImeis = priceDropIMEIRepository.selectByStatus(PriceDropImeiStatus.APPROVED);
                System.out.println(String.join("\t",
                                Arrays.asList("IMEI", "ItemId", "Brand", "Model Name", "Model Number", "Franchise Id", "Franchise Name",
                                                "Grn On", "Price Dropped On", "Approved On", "Returned On", "Price Drop Paid", "Is Doa")));
                Map<Integer, CustomRetailer> retailersMap = retailerService.getFofoRetailers(false);
                for (PriceDropIMEI priceDropIMEI : priceDropImeis) {
                        if (priceDropIMEI.getPartnerId() == 0)
                                continue;
                        HashSet<String> imeis = new HashSet<>();
                        PriceDrop priceDrop = priceDropRepository.selectById(priceDropIMEI.getPriceDropId());
                        imeis.add(priceDropIMEI.getImei());
                        List<InventoryItem> inventoryItems = inventoryItemRepository
                                        .selectByFofoIdSerialNumbers(priceDropIMEI.getPartnerId(), imeis, false);
                        if (inventoryItems.size() == 0) {
                                LOGGER.info("Need to investigate partnerId - {} imeis - {}", priceDropIMEI.getPartnerId(), imeis);
                                continue;
                        }
                        InventoryItem inventoryItem = inventoryItems.get(0);
                        CustomRetailer customRetailer = retailersMap.get(inventoryItem.getFofoId());
                        if (inventoryItem.getLastScanType().equals(ScanType.DOA_OUT)
                                        || inventoryItem.getLastScanType().equals(ScanType.PURCHASE_RET)) {
                                // check if pricedrop has been rolled out
                                List<UserWalletHistory> uwh = walletService.getAllByReference(inventoryItem.getFofoId(),
                                                priceDropIMEI.getPriceDropId(), WalletReferenceType.PRICE_DROP);
                                if (uwh.size() > 0) {
                                        Item item = itemRepository.selectById(inventoryItem.getItemId());
                                        System.out.println(String.join("\t",
                                                        Arrays.asList(priceDropIMEI.getImei(), inventoryItem.getItemId() + "", item.getBrand(),
                                                                        item.getModelName(), item.getModelNumber(), inventoryItem.getFofoId() + "",
                                                                        customRetailer.getBusinessName(), inventoryItem.getCreateTimestamp().format(dtf),
                                                                        priceDrop.getAffectedOn().format(dtf),
                                                                        priceDropIMEI.getUpdateTimestamp().format(dtf),
                                                                        inventoryItem.getUpdateTimestamp().format(dtf),
                                                                        priceDrop.getAutoPartnerPayout(inventoryItem.getUpdateTimestamp()) + "",
                                                                        inventoryItem.getLastScanType().equals(ScanType.DOA_OUT) + "")));
                                }
                        }
                }
        }

        public void toffeeRollback() throws Exception {
                toffeeService.cancelPolicyCopy("110143521986");
                toffeeService.getOrderId("110143521986");
        }

        public void attachToffeeInvoices() throws Exception {
                List<InsurancePolicy> insurancePolicies = insurancePolicyRepository.selectAllByProviderId(3,
                                Optional.of(false));
                for (InsurancePolicy insurancePolicy : insurancePolicies) {
                        String invoiceNumber = insurancePolicy.getInvoiceNumber();
                        FofoOrder fofoOrder = fofoOrderRepository.selectByInvoiceNumber(invoiceNumber);
                        InvoicePdfModel pdfModel = orderService.getInvoicePdfModel(fofoOrder.getId());
                        java.io.ByteArrayOutputStream byteArrayOutputStream = new java.io.ByteArrayOutputStream();
                        PdfUtils.generateAndWrite(Arrays.asList(pdfModel), byteArrayOutputStream);
                        String pdfInvoiceString = "data:application/pdf;base64,"
                                        + Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
                        boolean attached = toffeeService.attachInvoice(insurancePolicy.getPolicyNumber().split("#")[1],
                                        pdfInvoiceString);
                        if (attached) {
                                insurancePolicy.setPosted(true);
                        }
                }
        }

        public void sendBAGPendingPolicies() throws Exception {
                List<InsurancePolicy> insurancePolicies = insurancePolicyRepository.selectAllByProviderId(4,
                                Optional.of(false));
                for (InsurancePolicy insurancePolicy : insurancePolicies) {
                        String invoiceNumber = insurancePolicy.getInvoiceNumber();
                        FofoOrder fofoOrder = fofoOrderRepository.selectByInvoiceNumber(invoiceNumber);
                        FofoOrderItem fofoOrderItem = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId()).get(0);
                        CustomerAddress customerAddress = customerAddressRepository.selectById(fofoOrder.getCustomerAddressId());
                        Customer customer = customerRepository.selectById(fofoOrder.getCustomerId());
                        BAGInsuranceModel bagInsuranceModel = new BAGInsuranceModel();
                        // bagInsuranceModel.setModelId();
                        bagInsuranceModel.setAddressLine1(customerAddress.getLine1());
                        bagInsuranceModel.setAddressLine2(customerAddress.getLine2());
                        bagInsuranceModel.setCity(customerAddress.getCity());
                        bagInsuranceModel.setBrandWarranty("1 Year");
                        Item item = itemRepository.selectById(fofoOrderItem.getId());
                        bagInsuranceModel.setModelName(item.getItemDescription());
                        bagInsuranceModel.setDateOfPurchase(fofoOrder.getFormattedDate());
                        bagInsuranceModel.setEmail(customer.getEmailId());
                        bagInsuranceModel.setImei1(insurancePolicy.getSerialNumber());
                        bagInsuranceModel.setFirstName(customer.getFirstName());
                        bagInsuranceModel.setLastName(customer.getLastName());
                        bagInsuranceModel.setMobileNumber(customer.getMobileNumber());
                        bagInsuranceModel.setPlanId("");
                        insurancePolicy.setPosted(true);
                }
        }

        public void schemeRollback(List<String> schemeIds) throws Exception {
                List<Integer> schemeIdsInt = schemeIds.stream().map(x -> Integer.parseInt(x)).collect(Collectors.toList());
                Map<Integer, Scheme> schemesMap = schemeRepository.selectBySchemeIds(schemeIdsInt, 0, schemeIds.size()).stream()
                                .collect(Collectors.toMap(x -> x.getId(), x -> x));
                List<SchemeInOut> schemeInOuts = schemeInOutRepository.selectBySchemeIds(new HashSet<>(schemeIdsInt));
                for (SchemeInOut sio : schemeInOuts) {
                        Scheme scheme = schemesMap.get(sio.getSchemeId());
                        if (scheme.getType().equals(SchemeType.IN)) {

                        } else if (scheme.getType().equals(SchemeType.OUT)) {
                                InventoryItem inventoryItem = inventoryItemRepository.selectById(sio.getInventoryItemId());
                                List<ScanRecord> sr = scanRecordRepository.selectByInventoryItemId(sio.getInventoryItemId());
                                ScanRecord scanRecord = sr.stream().filter(x -> x.getType().equals(ScanType.SALE))
                                                .max((x1, x2) -> x1.getCreateTimestamp().compareTo(x2.getCreateTimestamp())).get();
                                if (scanRecord.getCreateTimestamp().isAfter(scheme.getEndDateTime())
                                                || scanRecord.getCreateTimestamp().isBefore(scheme.getStartDateTime())) {
                                        sio.setRolledBackTimestamp(LocalDateTime.now());
                                        FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(scanRecord.getOrderId());
                                        String rollbackReason = "Scheme reversed for "
                                                        + itemRepository.selectById(inventoryItem.getItemId()).getItemDescription() + "/Inv - "
                                                        + fofoOrder.getInvoiceNumber();
                                        walletService.rollbackAmountFromWallet(scanRecord.getFofoId(), sio.getAmount(),
                                                        scanRecord.getOrderId(), WalletReferenceType.SCHEME_OUT, rollbackReason,
                                                        LocalDateTime.now());
                                        System.out.printf("Amount %f,SchemeId %d,Reason %s\n", sio.getAmount(), sio.getSchemeId(),
                                                        rollbackReason);
                                }
                        }
                }
                // throw new Exception();
        }

        public void checkfocusedModelInPartnerStock() throws Exception {

                List<Integer> fofoIds = fofoStoreRepository.selectAll().stream().filter(x -> x.isActive()).map(x -> x.getId())
                                .collect(Collectors.toList());
                Map<Integer, Map<Integer, List<SaholicCIS>>> warehouseItemAvailabilityMap = saholicInventoryService
                                .getSaholicStock();
                Map<Integer, String> warehouseMap = ProfitMandiConstants.WAREHOUSE_MAP;
                Map<Integer, FofoReportingModel> partnerIdSalesHeadersMap = this.getPartnerIdSalesHeaders();

                Map<Integer, Map<Integer, List<SaholicPOItem>>> warehousePoItemAvailabilityMap = saholicInventoryService
                                .getSaholicPOItems();
                Map<Integer, List<FocusedModelShortageModel>> focusedModelShortageReportMap = new HashMap<>();
                for (Integer fofoId : fofoIds) {
                        List<FocusedModelShortageModel> focusedModelShortageList = new ArrayList<>();
                        focusedModelShortageReportMap.put(fofoId, focusedModelShortageList);
                        CustomRetailer customRetailer = retailerService.getFofoRetailer(fofoId);
                        Map<Integer, Integer> processingOrderMap = null;
                        Map<Integer, Integer> catalogIdAndQtyMap = null;
                        Map<Integer, Integer> grnPendingOrdersMap = null;

                        Map<Integer, Integer> currentInventorySnapshot = currentInventorySnapshotRepository.selectByFofoId(fofoId)
                                        .stream().collect(Collectors.toMap(x -> x.getItemId(), x -> x.getAvailability()));

                        if (!currentInventorySnapshot.isEmpty()) {
                                catalogIdAndQtyMap = itemRepository.selectByIds(currentInventorySnapshot.keySet()).stream()
                                                .collect(Collectors.groupingBy(x -> x.getCatalogItemId(),
                                                                Collectors.summingInt(x -> currentInventorySnapshot.get(x.getId()))));

                        }

                        Map<Integer, Integer> grnPendingOrders = orderRepository.selectPendingGrnOrders(fofoId).stream()
                                        .collect(Collectors.groupingBy(x -> x.getLineItem().getItemId(),
                                                        Collectors.summingInt(x -> x.getLineItem().getQuantity())));
                        if (!grnPendingOrders.isEmpty()) {
                                grnPendingOrdersMap = itemRepository.selectByIds(grnPendingOrders.keySet()).stream()
                                                .collect(Collectors.groupingBy(x -> x.getCatalogItemId(),
                                                                Collectors.summingInt(x -> grnPendingOrders.get(x.getId()))));

                        }

                        Map<Integer, Integer> processingOrder = orderRepository.selectOrders(fofoId, orderStatusList).stream()
                                        .collect(Collectors.groupingBy(x -> x.getLineItem().getItemId(),
                                                        Collectors.summingInt(x -> x.getLineItem().getQuantity())));
                        if (!processingOrder.isEmpty()) {
                                processingOrderMap = itemRepository.selectByIds(processingOrder.keySet()).stream()
                                                .collect(Collectors.groupingBy(x -> x.getCatalogItemId(),
                                                                Collectors.summingInt(x -> processingOrder.get(x.getId()))));

                        }

                        List<String> brands = mongoClient.getMongoBrands(fofoId, null, 3).stream().map(x -> (String) x.get("name"))
                                        .collect(Collectors.toList());

                        List<Integer> regionIds = partnerRegionRepository.selectByfofoId(fofoId).stream().map(x -> x.getRegionId())
                                        .collect(Collectors.toList());
                        LOGGER.info("regionIds" + regionIds);
                        if (regionIds.size() == 0) {
                                LOGGER.info("No region found for partner {}", fofoId);
                                continue;
                        }
                        Map<Integer, Optional<Integer>> focusedCatalogIdAndQtyMap = focusedModelRepository
                                        .selectAllByRegionIds(regionIds).stream().collect(Collectors.groupingBy(FocusedModel::getCatalogId,
                                                        Collectors.mapping(FocusedModel::getObsMinimumQty, Collectors.maxBy(Integer::compareTo))));

                        LOGGER.info("focusedCatalogIdAndQtyMap" + focusedCatalogIdAndQtyMap);

                        for (Map.Entry<Integer, Optional<Integer>> entry : focusedCatalogIdAndQtyMap.entrySet()) {
                                int minQty = entry.getValue().get();
                                int inStockQty = 0;
                                int processingQty = 0;
                                int grnPendingQty = 0;
                                int allColorNetAvailability = 0;
                                int allColorPoAvailability = 0;
                                if (processingOrderMap != null) {
                                        processingQty = (processingOrderMap.get(entry.getKey()) == null) ? 0
                                                        : processingOrderMap.get(entry.getKey());

                                }
                                if (grnPendingOrdersMap != null) {
                                        grnPendingQty = (grnPendingOrdersMap.get(entry.getKey()) == null) ? 0
                                                        : grnPendingOrdersMap.get(entry.getKey());

                                }
                                if (catalogIdAndQtyMap != null) {
                                        inStockQty = (catalogIdAndQtyMap.get(entry.getKey()) == null) ? 0
                                                        : catalogIdAndQtyMap.get(entry.getKey());

                                }

                                int grnStockQty = grnPendingQty + inStockQty;
                                int totalQty = processingQty + grnPendingQty + inStockQty;

                                int shortageQty = minQty - totalQty;
                                List<Item> item = itemRepository.selectAllByCatalogItemId(entry.getKey());
                                FofoStore fofoStore = fofoStoreRepository.selectByRetailerId(fofoId);

                                Map<Integer, List<SaholicCIS>> itemAvailabilityMap = warehouseItemAvailabilityMap
                                                .get(fofoStore.getWarehouseId());

                                Map<Integer, List<SaholicPOItem>> poItemAvailabilityMap = warehousePoItemAvailabilityMap
                                                .get(fofoStore.getWarehouseId());

                                for (Item it : item) {
                                        List<SaholicCIS> currentAvailability = null;
                                        List<SaholicPOItem> poItemAvailability = null;
                                        if (itemAvailabilityMap != null) {
                                                currentAvailability = itemAvailabilityMap.get(it.getId());
                                        }

                                        if (poItemAvailabilityMap != null) {
                                                poItemAvailability = poItemAvailabilityMap.get(it.getId());
                                        }
                                        if (currentAvailability != null) {
                                                allColorNetAvailability += currentAvailability.stream()
                                                                .collect(Collectors.summingInt(SaholicCIS::getNetavailability));
                                        }

                                        if (poItemAvailability != null) {
                                                allColorPoAvailability += poItemAvailability.stream()
                                                                .collect(Collectors.summingInt(SaholicPOItem::getUnfulfilledQty));
                                        }

                                }

                                FocusedModelShortageModel fm = new FocusedModelShortageModel();
                                fm.setFofoId(fofoId);
                                fm.setStoreCode(fofoStore.getCode());
                                fm.setStoreName(customRetailer.getBusinessName());
                                fm.setBrandName(item.get(0).getBrand());
                                fm.setModelName(item.get(0).getModelName());
                                fm.setModelNumber(item.get(0).getModelNumber());
                                fm.setGrnStockQty(grnStockQty);
                                fm.setPendingIndentQty(processingQty);
                                fm.setShortageQty(shortageQty);
                                fm.setPoAvailabitiy(allColorPoAvailability);
                                fm.setWarehouseName(warehouseMap.get(customRetailer.getWarehouseId()));
                                fm.setStateManager(partnerIdSalesHeadersMap.get(fofoId).getRegionalManager());
                                fm.setTerritoryManager(partnerIdSalesHeadersMap.get(fofoId).getTerritoryManager());
                                fm.setItemName(item.get(0).getBrand() + item.get(0).getModelNumber() + item.get(0).getModelName());
                                fm.setAvailabitiy(allColorNetAvailability);

                                focusedModelShortageList.add(fm);
                        }

                        /*
                         * if (!focusedModelShortageList.isEmpty()) { String subject = "Stock Alert";
                         * String messageText = this.getMessage(focusedModelShortageList);
                         *
                         * this.sendMailWithAttachments(subject, messageText,
                         * customRetailer.getEmail()); String notificationMessage =
                         * this.getNotificationMessage(focusedModelShortageList);
                         *
                         * LOGGER.info("notificationMessage" + notificationMessage);
                         *
                         * SendNotificationModel sendNotificationModel = new SendNotificationModel();
                         * sendNotificationModel.setCampaignName("Stock Alert");
                         * sendNotificationModel.setTitle("Alert");
                         * sendNotificationModel.setMessage(notificationMessage);
                         * sendNotificationModel.setType("url"); sendNotificationModel.setUrl(
                         * "https://app.smartdukaan.com/pages/home/notifications");
                         * sendNotificationModel.setExpiresat(LocalDateTime.now().plusDays(2));
                         * sendNotificationModel.setMessageType(MessageType.notification); int userId =
                         * userAccountRepository.selectUserIdByRetailerId(fofoId);
                         * sendNotificationModel.setUserIds(Arrays.asList(userId));
                         * notificationService.sendNotification(sendNotificationModel);
                         *
                         * }
                         */

                }
                if (!focusedModelShortageReportMap.isEmpty()) {
                        String fileName = "Stock Alert-" + FormattingUtils.formatDate(LocalDateTime.now()) + ".csv";
                        Map<String, Set<Integer>> storeGuyMap = csService.getAuthUserPartnerIdMapping();
                        Map<String, List<List<?>>> emailRowsMap = new HashMap<>();

                        focusedModelShortageReportMap.entrySet().forEach(x -> {
                                storeGuyMap.entrySet().forEach(y -> {

                                        if (y.getValue().contains(x.getKey())) {
                                                if (!emailRowsMap.containsKey(y.getKey())) {
                                                        emailRowsMap.put(y.getKey(), new ArrayList<>());
                                                }
                                                List<List<? extends Serializable>> fms = x.getValue().stream()
                                                                .map(r -> Arrays.asList(r.getStoreCode(), r.getStoreName(), r.getBrandName(),
                                                                                r.getModelName(), r.getModelNumber(), r.getWarehouseName(), r.getStateManager(),
                                                                                r.getTerritoryManager(), r.getPendingIndentQty(), r.getGrnStockQty(),
                                                                                r.getShortageQty(), r.getAvailabitiy()))
                                                                .collect(Collectors.toList());
                                                emailRowsMap.get(y.getKey()).addAll(fms);

                                        }

                                });

                        });

                        List<String> headers = Arrays.asList("Store Code", "Store Name", "Brand", "Model Name", "Model Number",
                                        "Warehouse Name", "State Manager", "Territory Manager", "Pending Indent", "InStock", "Shortage Qty",
                                        "Availability");
                        emailRowsMap.entrySet().forEach(entry -> {

                                ByteArrayOutputStream baos = null;
                                try {
                                        baos = FileUtil.getCSVByteStream(headers, entry.getValue());
                                } catch (Exception e2) {
                                        e2.printStackTrace();
                                }
                                String[] sendToArray = new String[] {

                                                entry.getKey()

                                };

                                try {
                                        Utils.sendMailWithAttachment(googleMailSender, sendToArray, null, "Stock Alert", "PFA", fileName,
                                                        new ByteArrayResource(baos.toByteArray()));
                                } catch (Exception e1) { // TODO Auto-generated catch block
                                        e1.printStackTrace();
                                }

                        });
                }
        }

        private String getNotificationMessage(List<FocusedModelShortageModel> focusedModelShortageModel) {
                StringBuilder sb = new StringBuilder();
                sb.append("Focused Model Shortage in Your Stock : \n");
                for (FocusedModelShortageModel entry : focusedModelShortageModel) {

                        sb.append(entry.getItemName() + "-" + entry.getShortageQty());
                        sb.append(String.format("%n", ""));
                }
                return sb.toString();
        }

        private void sendMailWithAttachments(String subject, String messageText, String email) throws Exception {
                MimeMessage message = mailSender.createMimeMessage();
                MimeMessageHelper helper = new MimeMessageHelper(message, true);

                helper.setSubject(subject);
                helper.setText(messageText, true);
                helper.setTo(email);
                InternetAddress senderAddress = new InternetAddress("noreply@smartdukaan.com", "Smartdukaan Alerts");
                helper.setFrom(senderAddress);
                mailSender.send(message);

        }

        private String getMessage(List<FocusedModelShortageModel> focusedModelShortageModel) {
                StringBuilder sb = new StringBuilder();
                sb.append("<html><body><p>Alert</p><p>Focused Model Shortage in Your Stock:-</p>"
                                + "<br/><table style='border:1px solid black ;padding: 5px';>");
                sb.append("<tbody>\n" + "                                       <tr>\n"
                                + "                                             <th style='border:1px solid black;padding: 5px'>Item</th>\n"
                                + "                                             <th style='border:1px solid black;padding: 5px'>Shortage Qty</th>\n"
                                + "                                     </tr>");
                for (FocusedModelShortageModel entry : focusedModelShortageModel) {

                        sb.append("<tr>");
                        sb.append("<td style='border:1px solid black;padding: 5px'>" + entry.getItemName() + "</td>");

                        sb.append("<td style='border:1px solid black;padding: 5px'>" + entry.getShortageQty() + "</td>");

                        sb.append("</tr>");

                }

                sb.append("</tbody></table></body></html>");

                return sb.toString();
        }

        public void notifyLead() throws Exception {
                List<Lead> leadsToNotify = leadRepository.selectLeadsScheduledBetweenDate(null,
                                LocalDateTime.now().minusDays(15), LocalDateTime.now().plusHours(4));
                Map<Integer, String> authUserEmailMap = authRepository.selectAllActiveUser().stream()
                                .collect(Collectors.toMap(x -> x.getId(), x -> x.getEmailId()));
                LOGGER.info("authUserEmailMap {}", authUserEmailMap);
                Map<String, Integer> dtrEmailMap = dtrUserRepository
                                .selectAllByEmailIds(new ArrayList<>(authUserEmailMap.values())).stream()
                                .collect(Collectors.toMap(x -> x.getEmailId(), x -> x.getId()));

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

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

                for (Map.Entry<Integer, String> authUserEmail : authUserEmailMap.entrySet()) {
                        int authId = authUserEmail.getKey();
                        String email = authUserEmail.getValue();
                        authUserKeyMap.put(authId, dtrEmailMap.get(email));
                }
                LOGGER.info("authUserKeyMap", authUserKeyMap);
                LOGGER.info("leadsToNotify {}", leadsToNotify);

                String templateMessage = "Lead followup for %s %s, %s, %s is due by %s";
                for (Lead lead : leadsToNotify) {
                        if (authUserKeyMap.get(lead.getAssignTo()) == null) {
                                LOGGER.info("Assignee no longer part of system {}", lead.getAssignTo());
                                continue;
                        }
                        String title = "Leads followup Reminder";
                        String notificationMessage = String.format(templateMessage, lead.getFirstName(), lead.getLastName(),
                                        lead.getAddress(), lead.getLeadMobile(), leadTimeFormatter.format(lead.getScheduledTimestamp()));
                        String url = "https://app.smartdukaan.com/pages/home/leadUpdate?leadId=" + lead.getId();
                        SendNotificationModel sendNotificationModel = new SendNotificationModel();
                        sendNotificationModel.setCampaignName("Lead Reminder");
                        sendNotificationModel.setTitle(title);
                        sendNotificationModel.setMessage(notificationMessage);
                        sendNotificationModel.setType("url");
                        sendNotificationModel.setUrl(url);
                        sendNotificationModel.setExpiresat(LocalDateTime.now().plusDays(2));
                        sendNotificationModel.setMessageType(MessageType.reminder);
                        sendNotificationModel.setUserIds(Arrays.asList(authUserKeyMap.get(lead.getAssignTo())));
                        System.out.println(sendNotificationModel);
                        notificationService.sendNotification(sendNotificationModel);
                        AuthUser authUser = authRepository.selectById(lead.getAssignTo());
                        // notificationService.sendWhatsappMessage(notificationMessage, title,
                        // authUser.getMobileNumber());
                }
        }

        public void notifyVisits() throws Exception {
                List<FranchiseeVisit> franchiseeVisits = franchiseeVisitRepository
                                .selectVisitsScheduledBetweenDate(LocalDateTime.now().minusDays(15), LocalDateTime.now().plusHours(4));
                Map<Integer, String> authUserEmailMap = authRepository.selectAllActiveUser().stream()
                                .collect(Collectors.toMap(x -> x.getId(), x -> x.getEmailId()));
                Map<String, Integer> dtrEmailMap = dtrUserRepository
                                .selectAllByEmailIds(new ArrayList<>(authUserEmailMap.values())).stream()
                                .collect(Collectors.toMap(x -> x.getEmailId(), x -> x.getId()));
                Map<Integer, Integer> authUserKeyMap = new HashMap<>();

                for (Map.Entry<Integer, String> authUserEmail : authUserEmailMap.entrySet()) {
                        int authId = authUserEmail.getKey();
                        String email = authUserEmail.getValue();
                        authUserKeyMap.put(authId, dtrEmailMap.get(email));
                }
                String visitTemplate = "Planned visit to franchisee %s is due by %s";
                String followupTemplate = "Lead followup for franchisee %s is due by %s";
                DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("MMM 7, EEEE h:m a");
                for (FranchiseeVisit visit : franchiseeVisits) {
                        if (authUserKeyMap.containsKey(visit.getAuthId())) {
                                continue;
                        }
                        SendNotificationModel sendNotificationModel = new SendNotificationModel();
                        String message = null;
                        if (visit.getFranchiseActivityId() == 0) {
                                message = String.format(visitTemplate, visit.getPartnerName(),
                                                timeFormatter.format(visit.getScheduleTimestamp()));
                                sendNotificationModel.setCampaignName("Franchisee visit Reminder");
                        } else {
                                message = String.format(followupTemplate, visit.getPartnerName(),
                                                timeFormatter.format(visit.getScheduleTimestamp()));
                                sendNotificationModel.setCampaignName("Franchisee followup Reminder");
                        }
                        sendNotificationModel.setMessage(message);
                        sendNotificationModel.setType("url");
                        sendNotificationModel.setUrl("https://app.smartdukaan.com/pages/home/notifications");
                        sendNotificationModel.setExpiresat(LocalDateTime.now().plusDays(2));
                        sendNotificationModel.setMessageType(MessageType.reminder);
                        sendNotificationModel.setUserIds(Arrays.asList(authUserKeyMap.get(visit.getAuthId())));
                        // notificationService.sendNotification(sendNotificationModel);
                }
        }

        public void ticketClosed() throws Exception {

                List<Ticket> tickets = ticketRepository.selectAllNotClosedTicketsWithStatus(ActivityType.RESOLVED);
                for (Ticket ticket : tickets) {
                        if (ticket.getUpdateTimestamp().toLocalDate().isBefore(LocalDate.now().minusDays(7))) {
                                ticket.setCloseTimestamp(LocalDateTime.now());
                                ticket.setLastActivity(ActivityType.RESOLVED_ACCEPTED);
                                ticket.setUpdateTimestamp(LocalDateTime.now());
                                ticketRepository.persist(ticket);
                        }
                }

        }

        public void checkValidateReferral() throws Exception {

                List<Refferal> referrals = refferalRepository.selectByStatus(RefferalStatus.pending);
                LOGGER.info("referrals" + referrals);
                if (!referrals.isEmpty()) {
                        String subject = "Referral Request";
                        String messageText = this.getMessageForReferral(referrals);

                        MimeMessage message = mailSender.createMimeMessage();
                        MimeMessageHelper helper = new MimeMessageHelper(message, true);
                        String[] email = { "kamini.sharma@smartdukaan.com", "tarun.verma@smartdukaan.com" };
                        helper.setSubject(subject);
                        helper.setText(messageText, true);
                        helper.setTo(email);
                        InternetAddress senderAddress = new InternetAddress("noreply@smartdukaan.com", "Smartdukaan Alerts");
                        helper.setFrom(senderAddress);
                        mailSender.send(message);

                }
        }

        private String getMessageForReferral(List<Refferal> referrals) {
                StringBuilder sb = new StringBuilder();
                sb.append("<html><body><p>Alert</p><p>Pending Referrals:-</p>"
                                + "<br/><table style='border:1px solid black ;padding: 5px';>");
                sb.append("<tbody>\n" + "                                       <tr>\n"
                                + "                                             <th style='border:1px solid black;padding: 5px'>RefereeName</th>\n"
                                + "                                             <th style='border:1px solid black;padding: 5px'>Referee Email</th>\n"
                                + "                                             <th style='border:1px solid black;padding: 5px'>Referral Name</th>\n"
                                + "                                             <th style='border:1px solid black;padding: 5px'>Refferal Mobile</th>\n"
                                + "                                             <th style='border:1px solid black;padding: 5px'>city</th>\n"
                                + "                                             <th style='border:1px solid black;padding: 5px'>state</th>\n"
                                + "                                     </tr>");
                for (Refferal entry : referrals) {

                        sb.append("<tr>");
                        sb.append("<td style='border:1px solid black;padding: 5px'>" + entry.getRefereeName() + "</td>");

                        sb.append("<td style='border:1px solid black;padding: 5px'>" + entry.getRefereeEmail() + "</td>");
                        sb.append("<td style='border:1px solid black;padding: 5px'>" + entry.getFirstName() + "</td>");
                        sb.append("<td style='border:1px solid black;padding: 5px'>" + entry.getMobile() + "</td>");
                        sb.append("<td style='border:1px solid black;padding: 5px'>" + entry.getCity() + "</td>");
                        sb.append("<td style='border:1px solid black;padding: 5px'>" + entry.getState() + "</td>");

                        sb.append("</tr>");

                }

                sb.append("</tbody></table></body></html>");

                return sb.toString();
        }

        private String getMessageForUncontacblePartner(List<PartnerCollectionRemark> pcrs)
                        throws ProfitMandiBusinessException {
                StringBuilder sb = new StringBuilder();
                sb.append("<html><body><p>Alert</p><p>Not Responding Partner:-</p>"
                                + "<br/><table style='border:1px solid black ;padding: 5px';>");
                sb.append("<tbody>\n" + "                                       <tr>\n"
                                + "                                             <th style='border:1px solid black;padding: 5px'>PartnerName</th>\n"
                                + "                                             <th style='border:1px solid black;padding: 5px'>from</th>\n"

                                + "                                     </tr>");
                for (PartnerCollectionRemark entry : pcrs) {

                        CustomRetailer customRetailer = retailerService.getFofoRetailer(entry.getFofoId());

                        sb.append("<tr>");
                        sb.append("<td style='border:1px solid black;padding: 5px'>" + customRetailer.getBusinessName() + "("
                                        + customRetailer.getCode() + ")" + "</td>");

                        sb.append("<td style='border:1px solid black;padding: 5px'>"
                                        + entry.getCreateTimestamp().format(DateTimeFormatter.ofPattern("dd/MM/yyyy")) + "</td>");

                        sb.append("</tr>");

                }

                sb.append("</tbody></table></body></html>");

                return sb.toString();
        }

        public void reverseWallet() throws Exception {
                LocalDate localDate = LocalDate.of(2020, 10, 28);
                List<UserWalletHistory> uwhList = userWalletHistoryRepository.selectAllByDateType(localDate.atStartOfDay(),
                                localDate.plusDays(1).atStartOfDay(),
                                Arrays.asList(WalletReferenceType.SCHEME_IN, WalletReferenceType.SCHEME_OUT));
                for (UserWalletHistory uwh : uwhList) {
                        if (uwh.getBusinessTimestamp().getMonth().equals(Month.SEPTEMBER)) {
                                UserWallet uw = userWalletRepository.selectById(uwh.getWalletId());
                                // LOGGER.info("UWH - {}", uwh);
                                // amount += uwh.getAmount();
                                // System.out.println("Amount is - " + amount);
                                // walletService.rollbackAmountFromWallet(uw.getUserId(), uwh.getAmount(),
                                // uwh.getReference(), uwh.getReferenceType(), "Margin reversal for error prone
                                // run", uwh.getBusinessTimestamp());
                                int orderId = uwh.getReference();
                                FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(orderId);
                                int inventoryItemId = 0;
                                // fofoOrderRepository.delete(fofoOrder);
                                List<FofoOrderItem> fofoOrderItems = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId());
                                /*
                                 * List<PaymentOptionTransaction> paymentOptionTransactions =
                                 * paymentOptionTransactionRepository.selectByReferenceIdAndType(fofoOrder.getId
                                 * (), PaymentOptionReferenceType.ORDER); for(PaymentOptionTransaction
                                 * paymentOptionTransaction : paymentOptionTransactions) {
                                 * //paymentOptionTransactionRepository.delete(paymentOptionTransaction); }
                                 */
                                for (FofoOrderItem foi : fofoOrderItems) {
                                        // fofoOrderItemRepository.delete(foi);
                                        List<FofoLineItem> flis = fofoLineItemRepository.selectByFofoOrderItemId(foi.getId());
                                        for (FofoLineItem fli : flis) {
                                                // fofoLineItemRepository.delete(fli);
                                                inventoryItemId = fli.getInventoryItemId();
                                        }
                                }
                                List<SchemeInOut> schemeInOuts = schemeInOutRepository.selectByInventoryItemIds(
                                                java.util.stream.Stream.of(inventoryItemId).collect(Collectors.toSet()));
                                for (SchemeInOut sio : schemeInOuts) {
                                        if (sio.getCreateTimestamp().toLocalDate().equals(localDate)) {
                                                LOGGER.info("SIO - {}", sio);
                                                sio.setRolledBackTimestamp(LocalDateTime.now());
                                        }
                                }

                        }
                }

        }

        public void partnerProblemAlert() throws Exception {
                LocalDateTime curDate = LocalDate.now().atStartOfDay();
                Map<Integer, Double> lmtdSale = fofoOrderItemRepository.selectSumMopGroupByRetailer(
                                curDate.withDayOfMonth(1).minusMonths(1), curDate.with(LocalTime.MAX).minusMonths(1), 0, false);
                Map<Integer, Double> mtdSales = fofoOrderItemRepository.selectSumMopGroupByRetailer(curDate.withDayOfMonth(1),
                                curDate.with(LocalTime.MAX), 0, false);
                Map<Integer, PartnerDailyInvestment> pdi = partnerDailyInvestmentRepository.selectAll(LocalDate.now()).stream()
                                .collect(Collectors.toMap(x -> x.getFofoId(), x -> x));

                for (Entry<Integer, Double> ls : lmtdSale.entrySet()) {

                        double lmtdTwentyPercentSale = ls.getValue() * 0.2;

                        LOGGER.info("lmtdTwentyPercentSale" + lmtdTwentyPercentSale);

                        double mtdSale = mtdSales.get(ls.getKey()) == null ? 0 : mtdSales.get(ls.getKey());

                        LOGGER.info("mtdSale" + mtdSale);

                        double totalSixtyPercentInvestment = pdi.get(ls.getKey()) == null ? 0
                                        : pdi.get(ls.getKey()).getTotalInvestment() * 0.6;

                        LOGGER.info("totalSixtyPercentInvestment" + totalSixtyPercentInvestment);

                        double stockInvestment = pdi.get(ls.getKey()) == null ? 0 : pdi.get(ls.getKey()).getInStockAmount();

                        LOGGER.info("stockInvestment" + stockInvestment);

                        boolean Investmentvalue = partnerInvestmentService.isInvestmentBelow(ls.getKey(), 25);

                        PartnerProblem partnerProblem = partnerProblemRepository.selectByFofoId(ls.getKey());

                        if (partnerProblem == null) {
                                partnerProblem = new PartnerProblem();
                                partnerProblem.setFofoId(ls.getKey());
                                if (mtdSale < lmtdTwentyPercentSale) {
                                        partnerProblem.setMtd(1);
                                }
                                if (Investmentvalue) {
                                        partnerProblem.setInvestment(1);
                                }

                                if (stockInvestment < totalSixtyPercentInvestment) {
                                        partnerProblem.setInvestment(1);
                                }

                                partnerProblemRepository.persist(partnerProblem);
                        } else {
                                if (mtdSale < lmtdTwentyPercentSale) {
                                        partnerProblem.setMtd(partnerProblem.getMtd() + 1);

                                } else {
                                        partnerProblem.setMtd(0);

                                }
                                if (Investmentvalue) {
                                        partnerProblem.setInvestment(partnerProblem.getInvestment() + 1);
                                } else {
                                        partnerProblem.setInvestment(0);

                                }
                                if (stockInvestment < totalSixtyPercentInvestment) {
                                        partnerProblem.setStockInvestment(partnerProblem.getStockInvestment() + 1);
                                } else {
                                        partnerProblem.setStockInvestment(0);
                                }

                        }

                }

                List<PartnerProblem> partnerProblems = partnerProblemRepository.selectAll().stream()
                                .filter(x -> x.getMtd() + x.getInvestment() + x.getStockInvestment() > 0).collect(Collectors.toList());

                partnerProblems = partnerProblems.stream().sorted((x1, x2) -> {
                        return x1.getMtd() + x1.getInvestment() + x1.getStockInvestment() < x2.getMtd() + x2.getInvestment()
                                        + x2.getStockInvestment() ? 1 : -1;
                }).collect(Collectors.toList());

                Map<Integer, PartnerProblem> partnerProblemMap = partnerProblems.stream().sorted((x1, x2) -> {
                        return x1.getMtd() + x1.getInvestment() + x1.getStockInvestment() < x2.getMtd() + x2.getInvestment()
                                        + x2.getStockInvestment() ? 1 : -1;
                }).collect(Collectors.toMap(x -> x.getFofoId(), x -> x));

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

                List<Integer> assignTo = Arrays.asList(15, 9, 54, 53);

                Map<Integer, AuthUser> assignAuthUserMap = authRepository.selectAllAuthUserByIds(assignTo).stream()
                                .collect(Collectors.toMap(x -> x.getId(), x -> x));

                List<String> sendTo = Arrays.asList("kamini.sharma@smartdukaan.com", "tarun.verma@smartdukaan.com",
                                "niranjan.kala@smartdukaan.com", "sm@smartdukaan.com");
                LOGGER.info("partnerProblem" + partnerProblems);
                StringBuilder sb = new StringBuilder();
                sb.append("<htl><body>");
                sb.append(
                                "<p>Number against MTD or Investment are the count of days the MTD is low VS LMTD OR Investment is below 75%.</p><br/><p>These partners needs immediate attention.</p><br/><table style='border:1px solid black';cellspacing=0>");
                sb.append("<tbody>\n" + "           <tr>"
                                + "                                             <th style='border:1px solid black;padding: 5px'>Partner Name</th>"
                                + "                         <th style='border:1px solid black;padding: 5px'>Assign TO</th>"
                                + "                                             <th style='border:1px solid black;padding: 5px'>Mtd</th>"
                                + "                                             <th style='border:1px solid black;padding: 5px'>Investment</th>"
                                + "                                             <th style='border:1px solid black;padding: 5px'>Stock</th>"
                                + "                                             <th style='border:1px solid black;padding: 5px'>Manager</th>"

                                + "                                     </tr>");

                for (PartnerProblem pp : partnerProblems) {
                        int value = pp.getFofoId() % 4;

                        Map<EscalationType, AuthUser> authUserMap = csService.getAuthUserAndEsclationByPartnerId(pp.getFofoId());
                        LOGGER.info("authUserMap" + authUserMap);
                        sb.append("<tr>");
                        sb.append("<td style='border:1px solid black;padding: 5px'>"
                                        + customRetailers.get(pp.getFofoId()).getBusinessName() + "</td>");
                        sb.append("<td style='border:1px solid black;padding: 5px'>"
                                        + assignAuthUserMap.get(assignTo.get(value)).getName() + "</td>");
                        sb.append("<td style='border:1px solid black;padding: 5px'>" + pp.getMtd() + "</td>");
                        sb.append("<td style='border:1px solid black;padding: 5px'>" + pp.getInvestment() + "</td>");
                        sb.append("<td style='border:1px solid black;padding: 5px'>" + pp.getStockInvestment() + "</td>");
                        sb.append("<td style='border:1px solid black;padding: 5px'>"
                                        + (authUserMap.get(EscalationType.L1) == null ? "N/A"
                                                        : authUserMap.get(EscalationType.L1).getFirstName())
                                        + " ," + (authUserMap.get(EscalationType.L2) == null ? "N/A"
                                                        : authUserMap.get(EscalationType.L2).getFirstName())
                                        + "</td>");

                        sb.append("</tr>");
                }
                sb.append("</tbody></table><br><br>");
                String subject = "Partner Problem Alert!";
                String[] email = sendTo.toArray(new String[sendTo.size()]);

                this.sendMailHtmlFormat(email, sb.toString(), null, subject);

                Map<Integer, List<Integer>> authUserPartnerMapping = csService.getAuthUserIdPartnerIdMapping();

                for (Entry<Integer, List<Integer>> authUserPartner : authUserPartnerMapping.entrySet()) {
                        AuthUser authUser = authRepository.selectById(authUserPartner.getKey());
                        for (Integer patnerId : authUserPartner.getValue()) {
                                if (partnerProblemMap.get(patnerId) != null) {

                                        StringBuilder sbbuilder = new StringBuilder();
                                        sbbuilder.append("<hml><body>");
                                        sb.append(
                                                        "<p>Number against MTD or Investment are the count of days the MTD is low VS LMTD OR Investment is below 75%.</p><br/><p>These partners needs immediate attention.</p><br/><table style='border:1px solid black';cellspacing=0>");
                                        sbbuilder.append("<tbody>\n" + "            <tr>"
                                                        + "                                             <th style='border:1px solid black;padding: 5px'>Partner Name</th>"
                                                        + "                                             <th style='border:1px solid black;padding: 5px'>Mtd</th>"
                                                        + "                                             <th style='border:1px solid black;padding: 5px'>Investment</th>"
                                                        + "                                             <th style='border:1px solid black;padding: 5px'>Stock</th>"

                                                        + "                                     </tr>");

                                        for (Integer partnerId : authUserPartner.getValue()) {
                                                if (partnerProblemMap.get(partnerId) != null) {
                                                        PartnerProblem pp = partnerProblemMap.get(partnerId);
                                                        sbbuilder.append("<tr>");
                                                        sbbuilder.append("<td style='border:1px solid black;padding: 5px'>"
                                                                        + customRetailers.get(pp.getFofoId()).getBusinessName() + "</td>");
                                                        sbbuilder
                                                                        .append("<td style='border:1px solid black;padding: 5px'>" + pp.getMtd() + "</td>");
                                                        sbbuilder.append(
                                                                        "<td style='border:1px solid black;padding: 5px'>" + pp.getInvestment() + "</td>");
                                                        sbbuilder.append("<td style='border:1px solid black;padding: 5px'>"
                                                                        + pp.getStockInvestment() + "</td>");

                                                        sbbuilder.append("</tr>");
                                                }

                                        }
                                        sbbuilder.append("</tbody></table><br><br>");

                                        this.sendMailOfHtmlFormat(authUser.getEmailId(), sbbuilder.toString(), null, subject);
                                        break;
                                }

                        }
                }
        }

        private void sendMailHtmlFormat(String email[], String body, String cc[], String subject)
                        throws MessagingException, ProfitMandiBusinessException, IOException {
                MimeMessage message = mailSender.createMimeMessage();
                MimeMessageHelper helper = new MimeMessageHelper(message);
                helper.setSubject(subject);
                helper.setText(body, true);
                helper.setTo(email);
                if (cc != null) {
                        helper.setCc(cc);
                }
                InternetAddress senderAddress = new InternetAddress("noreply@smartdukaan.com", "Smart Dukaan");
                helper.setFrom(senderAddress);
                mailSender.send(message);
        }

        @Autowired
        WarehouseRepository warehouseRepository;

        public void getVendorWarehouses(int warehouseId) {
                LOGGER.info("Warehouses - {}", warehouseRepository.getVendorWarehouses().get(warehouseId));

        }

        public void checkImeiActivation() {

                try {
                        vivoImeiActivationService.checkImeiActivation();
                } catch (ProfitMandiBusinessException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }

        }

        public void checkItelImeiActivation(LocalDate date, Integer day) {
                LOGGER.info("Hello - {}", "hhh");

                try {
                        itelImeiActivationService.checkItelImeiActivation(date, day);
                } catch (ProfitMandiBusinessException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }

        }

        public void selectFinServiceFollowUpDateByCurrDate(LocalDate currentDate)
                        throws MessagingException, ProfitMandiBusinessException, IOException {
                LOGGER.info("selectfinServiceFollow - {}", "selectfinServiceFollowUpDateByCurrDate");

                serviceConfigService.selectFinServicePartnerfollowUpDateByCurrentDate(currentDate);

        }

        public void checkTecnoImeiActivation(LocalDate date, Integer day) {
                LOGGER.info("Hello - {}", "hhh");

                try {
                        tecnoImeiActivation.checkTecnoImeiActivation(date, day);
                } catch (ProfitMandiBusinessException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }

        }

        public void checkCancellationMargin() throws Exception {
                LocalDateTime startDate = LocalDate.of(2021, 4, 1).atStartOfDay();
                List<FofoOrder> fofoOrders = fofoOrderRepository.selectCancelledBetweenSaleDate(startDate, LocalDateTime.now());
                LOGGER.info("Total Orders =  {}", fofoOrders.size());
                for (FofoOrder fofoOrder : fofoOrders) {
                        List<UserWalletHistory> history = userWalletHistoryRepository
                                        .selectAllByreferenceIdandreferenceType(fofoOrder.getId(), WalletReferenceType.SCHEME_OUT);
                        history.addAll(userWalletHistoryRepository.selectAllByreferenceIdandreferenceType(fofoOrder.getId(),
                                        WalletReferenceType.ACTIVATION_SCHEME));
                        int walletSum = history.stream().mapToInt(x -> x.getAmount()).sum();
                        if (Math.abs(walletSum) > 1) {
                                // LOGGER.info("Cancelled invoice {}, Order Id = {}, = havent rolledback, Value
                                // = {}", fofoOrder.getInvoiceNumber(), fofoOrder.getId(), walletSum);
                                List<FofoOrderItem> fofoOrderItems = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId());
                                List<FofoLineItem> flis = fofoLineItemRepository.selectByFofoOrderItemId(fofoOrderItems.get(0).getId());
                                FofoLineItem fli = flis.get(0);
                                if (StringUtils.isEmpty(fli.getSerialNumber()))
                                        continue;
                                List<SchemeInOut> schemeInOuts = schemeInOutRepository
                                                .selectByInventoryItemIds(new HashSet<>(Arrays.asList(fli.getInventoryItemId())));
                                InventoryItem inventoryItem = inventoryItemRepository.selectById(fli.getInventoryItemId());
                                double schemeSum = schemeInOuts.stream().filter(x -> x.getRolledBackTimestamp() == null)
                                                .mapToDouble(x -> x.getAmount()).sum();
                                /*
                                 * if(inventoryItem.getGoodQuantity()==1) {
                                 * LOGGER.info("GoodQty, Serial Number {}, InventoryItem = {}, Billed on {}",
                                 * inventoryItem.getSerialNumber(), inventoryItem.getId(),
                                 * inventoryItem.getUpdateTimestamp()); } else
                                 * if(inventoryItem.getBadQuantity()==1){
                                 * LOGGER.info("Bad Qty, Serial Number {}, InventoryItem = {}, Billed on {}",
                                 * inventoryItem.getSerialNumber(), inventoryItem.getId(),
                                 * inventoryItem.getUpdateTimestamp()); } else if
                                 * (inventoryItem.getLastScanType().equals(ScanType.SALE)) { LOGGER.
                                 * info("Problem Sold, Serial Number {}, InventoryItem = {}, Billed on {}",
                                 * inventoryItem.getSerialNumber(), inventoryItem.getId(),
                                 * inventoryItem.getUpdateTimestamp()); }
                                 */
                                if (inventoryItem.getLastScanType().equals(ScanType.SALE)
                                                || inventoryItem.getLastScanType().equals(ScanType.SALE_RET)) {
                                        Map<String, Double> map = schemeInOuts.stream()
                                                        .collect(
                                                                        Collectors.groupingBy(
                                                                                        x -> DateTimeFormatter.ofPattern("yyyyMMddHH")
                                                                                                        .format(x.getCreateTimestamp()) + "- " + x.getSchemeId(),
                                                                                        Collectors.summingDouble(x -> x.getAmount())));
                                        for (Map.Entry<String, Double> entry : map.entrySet()) {
                                                LOGGER.info("{} = {}", entry.getKey(), entry.getValue());
                                        }
                                        LOGGER.info("id- {}, imei- {}, lastScan = {}, Scheme sum - {}", inventoryItem.getId(),
                                                        inventoryItem.getSerialNumber(), inventoryItem.getLastScanType(), schemeSum);
                                }
                        }
                }

        }

        public static String readFileAsString(String file) throws Exception {
                String data = "";
                data = new String(Files.readAllBytes(Paths.get(file)));
                return data;
        }

        public void markDelhiveryOrderDelivered() throws ProfitMandiBusinessException, IOException {
                List<Order> orders = orderRepository.selectOrderByProviderIdAndStatus(ProfitMandiConstants.DELHIVERY_PROVIDERID,
                                OrderStatus.SHIPPED_FROM_WH);

                if (!orders.isEmpty()) {
                        Set<String> airwayBill = orders.stream().map(x -> x.getAirwayBillNumber()).collect(Collectors.toSet());

                        int arraylength = airwayBill.size();

                        if (arraylength >= 75) {

                                airwayBill = airwayBill.stream().limit(74).collect(Collectors.toSet());
                        }
                        LOGGER.info("airwayBill" + airwayBill);
                        String url = "https://track.delhivery.com/api/v1/packages/json/";

                        OkHttpClient client = new OkHttpClient();

                        Request request1 = new Request.Builder()
                                        .url(url + "?waybill=" + String.join(",", airwayBill) + "&token=" + token).get().build();

                        LOGGER.info("request1" + request1);

                        Response response = client.newCall(request1).execute();

                        LOGGER.info("jsonbj" + response.body());

                        JSONObject jsonObj = new JSONObject(response.body().string());

                        LOGGER.info("jsonObj" + jsonObj);

                        JSONArray shipmentData = jsonObj.getJSONArray("ShipmentData");
                        Set<String> airwaybillStatus = new HashSet<>();
                        for (int i = 0; i < shipmentData.length(); i++) {
                                JSONObject jsonObject = shipmentData.getJSONObject(i);
                                JSONObject shipment = jsonObject.getJSONObject("Shipment");

                                LOGGER.info("shipment" + shipment);
                                JSONObject statusDescription = shipment.getJSONObject("Status");
                                String awb = shipment.getString("AWB");

                                String status = statusDescription.getString("Status");
                                LOGGER.info("status" + status);

                                LOGGER.info("awb" + awb);
                                if (status.equals("Delivered")) {
                                        airwaybillStatus.add(awb);
                                }

                        }
                        markOrderDelivered(airwaybillStatus);
                }
        }

        public void markBlueDartOrderDelivered() throws ProfitMandiBusinessException, IOException {

                String loginId = "DEL81122";

                String licencekey = "uhfhlg2jpmnqfhfrlsgzfr1nhu1qfvel";

                List<Order> orders = orderRepository.selectOrderByProviderIdAndStatus(ProfitMandiConstants.BLUEDART_PROVIDERID,
                                OrderStatus.SHIPPED_FROM_WH);

                if (!orders.isEmpty()) {

                        Set<String> airwayBillNo = orders.stream().map(x -> x.getAirwayBillNumber()).collect(Collectors.toSet());

                        LOGGER.info("airwayBill" + airwayBillNo);
                        String url = "https://api.bluedart.com/servlet/RoutingServlet?handler=tnt&action=custawbquery";

                        String response = restClient.get(url + "&loginid=" + loginId + "&awb=awb&numbers="
                                        + String.join(",", airwayBillNo) + "&format=xml&lickey=" + licencekey + "&verno=1.3&scan=1", null,
                                        null);

                        JSONObject updateJson = XML.toJSONObject(response);

                        JSONObject shipmentData = updateJson.getJSONObject("ShipmentData");
                        Object shipmentObject = shipmentData.get("Shipment");

                        Set<String> airwaybillStatus = new HashSet<>();

                        if (shipmentObject instanceof JSONArray) {
                                JSONArray shipments = (JSONArray) shipmentObject;
                                for (int i = 0; i < shipments.length(); i++) {
                                        JSONObject jsonObject = shipments.getJSONObject(i);

                                        Number awb = jsonObject.getNumber("WaybillNo");
                                        String status = jsonObject.getString("Status");

                                        if (status.equals("SHIPMENT DELIVERED")) {
                                                airwaybillStatus.add(awb.toString());
                                        }

                                }
                        } else {
                                JSONObject jsonObject = (JSONObject) shipmentObject;
                                Number awb = jsonObject.getNumber("WaybillNo");
                                String status = jsonObject.getString("Status");

                                if (status.equals("SHIPMENT DELIVERED")) {
                                        airwaybillStatus.add(awb.toString());
                                }

                        }

                        LOGGER.info("airwaybillStatus" + airwaybillStatus);

                        markOrderDelivered(airwaybillStatus);
                }

        }

        private void markOrderDelivered(Set<String> airwaybillStatus)
                        throws ProfitMandiBusinessException, HttpHostConnectException {
                if (!airwaybillStatus.isEmpty()) {
                        for (String aws : airwaybillStatus) {

                                List<Order> deliverdOrders = orderRepository.selectByAirwayBillNumber(aws);

                                int fofoId = deliverdOrders.get(0).getRetailerId();
                                for (Order dlo : deliverdOrders) {
                                        dlo.setStatus(OrderStatus.DELIVERY_SUCCESS);
                                        dlo.setStatusDescription("Order Delivered");
                                        dlo.setDeliveryTimestamp(LocalDateTime.now());
                                }

                                com.spice.profitmandi.dao.entity.user.User user = userUserRepository.selectById(fofoId);

                                Address address = addressRepository.selectById(user.getAddressId());

                                String title = "Order Delivered";

                                String message = String.format("Dear partner, Your SmartDukaan Order " + aws
                                                + " has been delivered to you in a safe sealed bag.");

                                SendNotificationModel sendNotificationModel = new SendNotificationModel();
                                sendNotificationModel.setCampaignName("Order Delivered");
                                sendNotificationModel.setTitle(title);
                                sendNotificationModel.setMessage(message);
                                sendNotificationModel.setType("url");
                                sendNotificationModel.setUrl("https://app.smartdukaan.com/pages/home/notifications");
                                sendNotificationModel.setExpiresat(LocalDateTime.now().plusDays(1));
                                sendNotificationModel.setMessageType(MessageType.notification);
                                int userId = userAccountRepository.selectUserIdByRetailerId(fofoId);
                                sendNotificationModel.setUserIds(Arrays.asList(userId));
                                notificationService.sendNotification(sendNotificationModel);

                                notificationService.sendWhatsappMessage(message, title, address.getPhoneNumber());

                        }
                }
        }

        public void partnerWiseCreditAccount() throws Exception {

                List<FofoStore> fofoStores = fofoStoreRepository.selectActiveStores();

                for (FofoStore fs : fofoStores) {

                        if (fs.getPan() != null) {
                                AccountStatusResponseOut accountStatusResponseOut = mandiiService.getStatus(fs.getPan());

                                LOGGER.info("accountStatusResponseOut" + accountStatusResponseOut);
                                CreditAccount creditAccount = creditAccountRepository.selectByFofoIdAndGateway(fs.getId(),
                                                Gateway.MANDII);

                                if (creditAccount == null) {

                                        creditAccount = new CreditAccount();

                                        creditAccount.setFofoId(fs.getId());
                                        creditAccount.setGateway(Gateway.MANDII);

                                }

                                if (accountStatusResponseOut == null) {
                                        creditAccount.setCreditStatus(CreditStatus.UNKNOWN);
                                        creditAccount.setDescription("User company not found");

                                } else {
                                        if (accountStatusResponseOut.getSanctionLimit() != null) {
                                                creditAccount.setSanctionedAmount(accountStatusResponseOut.getSanctionLimit().floatValue());
                                        } else {
                                                creditAccount.setSanctionedAmount(0);
                                        }

                                        creditAccount.setInterestRate(accountStatusResponseOut.getRateOfInterest());
                                        if (accountStatusResponseOut.getBalanceAmount() != null) {
                                                creditAccount.setAvailableAmount(accountStatusResponseOut.getBalanceAmount().floatValue());
                                        } else {
                                                creditAccount.setAvailableAmount(0);
                                        }

                                        if (accountStatusResponseOut.getCurrentStage() != null) {
                                                creditAccount.setDescription(accountStatusResponseOut.getCurrentStage().toString());
                                        }
                                        if (accountStatusResponseOut.getStatus().equals(EligibilityStatusEnum.SANCTION_AVAILABLE)) {
                                                creditAccount.setCreditStatus(CreditStatus.SANCTIONED);
                                        } else if (accountStatusResponseOut.getStatus().equals(EligibilityStatusEnum.IN_ELIGIBLE)) {
                                                creditAccount.setCreditStatus(CreditStatus.INELIGIBLE);
                                        } else {

                                                creditAccount.setCreditStatus(CreditStatus.TO_BE_EVALUATED);
                                        }
                                }

                                creditAccount.setUpdatedOn(LocalDateTime.now());
                                creditAccountRepository.persist(creditAccount);
                        }
                }
        }

        @Autowired
        private PartnerCollectionRemarkRepository partnerCollectionRemarkRepository;

        public void reviewUncontactablePartner()
                        throws ProfitMandiBusinessException, MessagingException, UnsupportedEncodingException {

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

                List<Integer> pcrms = partnerCollectionRemarkRepository
                                .selectMaxRemarkId(new ArrayList<>(customRetailerMap.keySet()));

                if (!pcrms.isEmpty()) {
                        Map<Integer, PartnerCollectionRemark> partnerCollectionRemarksMap = partnerCollectionRemarkRepository
                                        .selectByIds(pcrms).stream().filter(x -> x.getRemark().equals(CollectionRemark.NOT_RESPONDING))
                                        .collect(Collectors.toMap(x -> x.getFofoId(), x -> x));

                        if (!partnerCollectionRemarksMap.isEmpty()) {
                                for (Map.Entry<String, Set<Integer>> storeGuyEntry : csService.getAuthUserPartnerIdMapping()
                                                .entrySet()) {
                                        List<PartnerCollectionRemark> filteredRows = storeGuyEntry.getValue().stream()
                                                        .map(x -> partnerCollectionRemarksMap.get(x)).filter(x -> x != null)
                                                        .collect(Collectors.toList());
                                        String subject = "UNCONTACTABLE PARTNERS";
                                        String messageText = this.getMessageForUncontacblePartner(filteredRows);

                                        MimeMessage message = mailSender.createMimeMessage();
                                        MimeMessageHelper helper = new MimeMessageHelper(message, true);
                                        String[] email = new String[] { storeGuyEntry.getKey() };

                                        helper.setSubject(subject);
                                        helper.setText(messageText, true);
                                        helper.setTo(email);
                                        InternetAddress senderAddress = new InternetAddress("noreply@smartdukaan.com",
                                                        "Smartdukaan Alerts");
                                        helper.setFrom(senderAddress);
                                        mailSender.send(message);

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

                                }
                        }

                }
        }

        @Autowired
        private LoanRepository loanRepository;

        @Autowired
        private LoanStatementRepository loanStatementRepository;

        @Autowired
        private SDCreditService sdCreditService;

        @Autowired
        private SDCreditRequirementRepository sdCreditRequirementRepository;

        @Autowired
        private CurrentPartnerDailyInvestmentRepository currentPartnerDailyInvestmentRepository;

        @Autowired
        private TransactionRepository transactionRepository;

        @Autowired
        private SanctionRequestRepository sanctionRequestRepository;

        public void calculateInterestAccured() throws ProfitMandiBusinessException {

                List<Loan> loans = loanRepository.selectAllActiveLoan();

                if (!loans.isEmpty()) {

                        for (Loan loan : loans) {

                                List<LoanStatement> loanStatements = loanStatementRepository.selectByLoanId(loan.getId());

                                Map<LoanReferenceType, Double> loanStatusAmount = loanStatements.stream().collect(Collectors.groupingBy(
                                                x -> x.getLoanReferenceType(), Collectors.summingDouble(x -> x.getAmount().doubleValue())));

                                if (loan.getFreeDays() > 0) {
                                        LocalDateTime freeDaysLimitDate = loan.getCreatedOn().plusDays(loan.getFreeDays() - 1);

                                        LOGGER.info("freeDaysLimitDate {}", freeDaysLimitDate);
                                        if (LocalDateTime.now().isAfter(freeDaysLimitDate)) {
                                                int loanStatementId = loanStatementRepository.selectLatestLoanSatement(loan.getFofoId(),
                                                                loan.getId());
                                                LOGGER.info("loanStatementId {}", loanStatementId);

                                                if (loanStatementId != 0) {

                                                        this.calculateInterest(loan, loanStatusAmount, loanStatementId);

                                                } else {
                                                        sdCreditService.addInterest(freeDaysLimitDate.toLocalDate(), LocalDate.now(), loan,
                                                                        loanStatusAmount);
                                                }

                                        }
                                } else {

                                        int loanStatementId = loanStatementRepository.selectLatestLoanSatement(loan.getFofoId(),
                                                        loan.getId());
                                        LOGGER.info("loanStatementId2 {}", loanStatementId);

                                        this.calculateInterest(loan, loanStatusAmount, loanStatementId);

                                }

                        }
                }

        }

        private void calculateInterest(Loan loan, Map<LoanReferenceType, Double> loanStatusAmount, int loanStatementId)
                        throws ProfitMandiBusinessException {
                LoanStatement loanStatement = loanStatementRepository.selectById(loanStatementId);

                if (loanStatement.getLoanId() == loan.getId()) {

                        sdCreditService.addInterest(loanStatement.getCreatedAt().toLocalDate(), LocalDate.now(), loan,
                                        loanStatusAmount);

                } else {
                        throw new ProfitMandiBusinessException("loanstament", loanStatement.getLoanId(), "Invalid LoanId");
                }
        }

        public void loanSettlement() throws Exception {
                List<Loan> loans = loanRepository.selectAllActiveLoan();

                if (!loans.isEmpty()) {

                        for (Loan loan : loans) {

                                UserWallet userWallet = userWalletRepository.selectByRetailerId(loan.getFofoId());
                                SDCreditRequirement sdCreditRequirement = sdCreditRequirementRepository
                                                .selectByFofoId(loan.getFofoId());

                                if (userWallet.getAmount() >= 100) {
                                        List<LoanStatement> loanStatements = loanStatementRepository.selectByLoanId(loan.getId());

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

                                        Map<LoanReferenceType, Double> loanStatusAmount = loanStatements.stream()
                                                        .collect(Collectors.groupingBy(x -> x.getLoanReferenceType(),
                                                                        Collectors.summingDouble(x -> FormattingUtils.serialize(x.getAmount()))));

                                        LOGGER.info("loanStatusAmount {}", loanStatusAmount);
                                        Double interestAmount = loanStatusAmount.get(LoanReferenceType.INTEREST);

                                        if (interestAmount == null) {
                                                interestAmount = (double) 0;
                                        }

                                        double principalAmount = loanStatusAmount.get(LoanReferenceType.PRINCIPAL);
                                        double paidAmount = 0;
                                        if (userWallet.getAmount() > Math.abs(interestAmount)) {

                                                LOGGER.info("interestAmount b {}", interestAmount);

                                                if (interestAmount < 0) {
                                                        LOGGER.info("interestAmount a {}", interestAmount);

                                                        settledLoanStatement(LoanReferenceType.INTEREST, BigDecimal.valueOf(interestAmount),
                                                                        loan.getFofoId(), loan.getId(), "Amount adjusted against loan",
                                                                        LocalDateTime.now());
                                                        loan.setInterestPaid(loan.getInterestPaid().add(BigDecimal.valueOf(interestAmount).abs()));

                                                        paidAmount += Math.abs(interestAmount);
                                                }

                                                double userWalletAmount = userWallet.getAmount() - Math.abs(interestAmount);

                                                if (userWalletAmount > Math.abs(principalAmount) && principalAmount < 0) {

                                                        settledLoanStatement(LoanReferenceType.PRINCIPAL, BigDecimal.valueOf(principalAmount),
                                                                        loan.getFofoId(), loan.getId(), "Amount adjusted against loan",
                                                                        LocalDateTime.now());
                                                        double amount = userWalletAmount - Math.abs(principalAmount);

                                                        paidAmount += Math.abs(principalAmount);

                                                        userWallet.setAmount((int) amount);

                                                        BigDecimal utilizationAmount = sdCreditRequirement.getUtilizedAmount()
                                                                        .subtract(BigDecimal.valueOf(principalAmount).abs());

                                                        sdCreditRequirement.setUtilizedAmount(utilizationAmount);

                                                        CreditAccount creditAccount = creditAccountRepository
                                                                        .selectByFofoIdAndGateway(loan.getFofoId(), Gateway.SDDIRECT);

                                                        creditAccount.setAvailableAmount(sdCreditRequirement.getAvailableLimit().floatValue());
                                                        creditAccount.setUpdatedOn(LocalDateTime.now());

                                                        loan.setPendingAmount(BigDecimal.ZERO);

                                                } else if (principalAmount < 0) {

                                                        settledLoanStatement(LoanReferenceType.PRINCIPAL, BigDecimal.valueOf(userWalletAmount),
                                                                        loan.getFofoId(), loan.getId(), "Amount adjusted against loan",
                                                                        LocalDateTime.now());

                                                        paidAmount += Math.abs(userWalletAmount);

                                                        BigDecimal availableLimit = sdCreditRequirement.getAvailableLimit()
                                                                        .add(BigDecimal.valueOf(userWalletAmount)).abs();

                                                        BigDecimal utilizationAmount = sdCreditRequirement.getUtilizedAmount()
                                                                        .subtract(BigDecimal.valueOf(userWalletAmount)).abs();

                                                        sdCreditRequirement.setUtilizedAmount(utilizationAmount);

                                                        CreditAccount creditAccount = creditAccountRepository
                                                                        .selectByFofoIdAndGateway(loan.getFofoId(), Gateway.SDDIRECT);

                                                        creditAccount.setAvailableAmount(sdCreditRequirement.getAvailableLimit().floatValue());
                                                        creditAccount.setUpdatedOn(LocalDateTime.now());
                                                        userWallet.setAmount(0);

                                                        loan.setPendingAmount(
                                                                        loan.getPendingAmount().subtract(BigDecimal.valueOf(userWalletAmount)));

                                                }

                                                createUserWalletHistory(userWallet.getId(), userWallet.getUserId(),
                                                                WalletReferenceType.LOAN_REPAYMENT, loan.getId(), Math.abs(paidAmount));

                                        } else {

                                                settledLoanStatement(LoanReferenceType.INTEREST, BigDecimal.valueOf(userWallet.getAmount()),
                                                                loan.getFofoId(), loan.getId(), "Amount adjusted against loan", LocalDateTime.now());

                                                paidAmount += Math.abs(userWallet.getAmount());

                                                createUserWalletHistory(userWallet.getId(), userWallet.getUserId(),
                                                                WalletReferenceType.LOAN_REPAYMENT, loan.getId(), Math.abs(paidAmount));

                                                loan.setInterestPaid(
                                                                loan.getInterestPaid().add(BigDecimal.valueOf(userWallet.getAmount()).abs()));

                                                userWallet.setAmount(0);
                                        }

                                }
                        }

                        List<Order> allOrders = orderRepository.selectHoldOrder();

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

                        if (!allOrders.isEmpty()) {
                                Map<Integer, List<Order>> transactionOrdersMap = allOrders.stream()
                                                .collect(Collectors.groupingBy(Order::getTransactionId, Collectors.toList()));
                                LinkedHashMap<Integer, List<Order>> sortedTransactionOrdersMap = new LinkedHashMap<>();
                                transactionOrdersMap.entrySet().stream().sorted(Map.Entry.comparingByKey())
                                                .forEachOrdered(x -> sortedTransactionOrdersMap.put(x.getKey(), x.getValue()));
                                LOGGER.info("sortedTransactionOrdersMap {}", sortedTransactionOrdersMap);

                                for (Entry<Integer, List<Order>> transactionOrdersEntry : sortedTransactionOrdersMap.entrySet()) {

                                        List<Order> orders = transactionOrdersEntry.getValue();

                                        double totalAmount = orders.stream().collect(Collectors.summingDouble(x -> x.getTotalAmount()));

                                        LocalDateTime createDate = orders.get(0).getCreateTimestamp();

                                        int fofoId = orders.get(0).getRetailerId();

                                        int transactionId = transactionOrdersEntry.getKey();

                                        SanctionRequest sanctionRequest = sanctionRequestRepository.selectByTransactionId(transactionId);

                                        double loanSettleAmount = loanStatementRepository.selectByDateAndFofoId(createDate, fofoId).stream()
                                                        .filter(x -> x.getAmount().doubleValue() > 0)
                                                        .collect(Collectors.summingDouble(x -> x.getAmount().doubleValue()));

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

                                        LOGGER.info("totalAmount {}", totalAmount);
                                        if (loanSettleAmount >= sanctionRequest.getUtilizationAmount().doubleValue()) {

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

                                                orders.forEach(x -> x.setShipmentHold(false));

                                                List<String> authUserEmail = csService.getAuthUserIdByPartnerId(orders.get(0).getRetailerId())
                                                                .stream().map(x -> x.getEmailId()).collect(Collectors.toList());
                                                authUserEmail.add("vinay.p@smartdukaan.com");
                                                authUserEmail.add("shivam.gupta@smartdukaan.com");

                                                String[] emailTo = authUserEmail.toArray(new String[authUserEmail.size()]);

                                                String[] ccTo = { "tarun.verma@smartdukaan.com", "kamini.sharma@smartdukaan.com" };

                                                String subject = "Dispatched " + (orders.get(0).getRetailerName());
                                                String message = String.format("Dear Team, \n" + "kindly note the material for the "
                                                                + orders.get(0).getRetailerName() + "of Rs." + totalAmount + "is dispatched.");

                                                Utils.sendMailWithAttachments(mailSender, emailTo, ccTo, subject, message);

                                        }

                                }
                        }

                }

        }

        private void settledLoanStatement(LoanReferenceType loanReferneceType, BigDecimal amount, int fofoId, int loanId,
                        String description, LocalDateTime now) {

                sdCreditService.createLoanStatement(loanReferneceType, amount.abs(), fofoId, loanId, description,
                                LocalDateTime.now());

        }

        private void createUserWalletHistory(int walletId, int userId, WalletReferenceType referenceType, int loanId,
                        double interestAmount) {
                UserWalletHistory uwh = new UserWalletHistory();
                uwh.setWalletId(walletId);
                uwh.setFofoId(userId);
                uwh.setBusinessTimestamp(LocalDateTime.now());
                uwh.setReferenceType(referenceType);
                uwh.setReference(loanId);
                uwh.setTimestamp(LocalDateTime.now());
                uwh.setAmount((int) -(interestAmount));
                uwh.setDescription("Amount adjusted against loan");
                userWalletHistoryRepository.persist(uwh);

        }

        public void dailyLoanAlert()
                        throws ProfitMandiBusinessException, HttpHostConnectException, UnsupportedEncodingException {
                List<Loan> loans = loanRepository.selectAllActiveLoan();

                Map<Integer, Double> partnerLoanAmount = new HashMap<>();

                if (!loans.isEmpty()) {

                        for (Loan loan : loans) {

                                List<LoanStatement> loanStatements = loanStatementRepository.selectByLoanId(loan.getId());

                                double amount = loanStatements.stream().map(x -> x.getAmount())
                                                .collect(Collectors.summingDouble(x -> x.doubleValue()));
                                if (partnerLoanAmount.get(loan.getFofoId()) != null) {
                                        amount += partnerLoanAmount.get(loan.getFofoId());
                                        partnerLoanAmount.put(loan.getFofoId(), amount);
                                } else {
                                        partnerLoanAmount.put(loan.getFofoId(), amount);
                                }

                        }

                }

                if (!partnerLoanAmount.isEmpty()) {

                        for (Entry<Integer, Double> partnerLoanAmountEnrty : partnerLoanAmount.entrySet()) {

                                int fofoId = partnerLoanAmountEnrty.getKey();

                                com.spice.profitmandi.dao.entity.user.User user = userUserRepository.selectById(fofoId);

                                Address address = addressRepository.selectById(user.getAddressId());

                                String title = "Alert Credit Outstanding!";
                                String url = "http://app.smartdukaan.com/pages/home/credit";
                                String message = "Your total pending Loan amount is Rs."
                                                + FormattingUtils.formatDecimal(Math.abs(partnerLoanAmountEnrty.getValue())) + ".";
                                notificationService.sendNotification(fofoId, title, MessageType.notification, title, message, url);

                                notificationService.sendWhatsappMessage(message, title, address.getPhoneNumber());

                        }

                }

        }

        public void processActivatedImeisForSchemes() throws ProfitMandiBusinessException {
                schemeService.processActivatedImeisForSchemes();
        }

        public void updatePartnerLimit() throws ProfitMandiBusinessException {
                Map<Integer, CustomRetailer> customRetailerMap = retailerService.getFofoRetailers(true);

                Map<Integer, SDCreditRequirement> sdCreditRequirementMap = sdCreditRequirementRepository.selectAll().stream()
                                .collect(Collectors.toMap(x -> x.getFofoId(), x -> x));
                Map<Integer, CurrentPartnerDailyInvestment> currentPartnerDailyInvestmentMap = currentPartnerDailyInvestmentRepository
                                .selectAll().stream().collect(Collectors.toMap(x -> x.getFofoId(), x -> x));
                double limitValue = 100000;
                for (Entry<Integer, CustomRetailer> customRetailerEntry : customRetailerMap.entrySet()) {
                        int fofoId = customRetailerEntry.getKey();
                        SDCreditRequirement sdCreditRequirement = sdCreditRequirementMap.get(customRetailerEntry.getKey());
                        LocalDateTime firstBillingDate = transactionRepository.getFirstBillingDate(fofoId);
                        CurrentPartnerDailyInvestment currentPartnerDailyInvestment = currentPartnerDailyInvestmentMap.get(fofoId);
                        BigDecimal suggestedAmount = BigDecimal.ZERO;
                        if (currentPartnerDailyInvestment != null) {
                                suggestedAmount = BigDecimal.valueOf(currentPartnerDailyInvestment.getTotalInvestment() * 0.1);
                        }

                        if (suggestedAmount.doubleValue() > limitValue) {

                                suggestedAmount = BigDecimal.valueOf(limitValue);

                        }

                        if (suggestedAmount.doubleValue() < 0) {
                                suggestedAmount = BigDecimal.ZERO;
                        }

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

                        if (sdCreditRequirement == null) {
                                sdCreditRequirement = new SDCreditRequirement();
                                sdCreditRequirement.setFofoId(fofoId);
                                sdCreditRequirement.setCreditDays(15);
                                sdCreditRequirement.setInterestRate(BigDecimal.valueOf(0.05));
                                sdCreditRequirement.setSuggestedLimit(suggestedAmount);
                                sdCreditRequirement.setRisk(CreditRisk.HIGH_RISK);
                                sdCreditRequirement.setLimit(suggestedAmount);
                                sdCreditRequirement.setUtilizedAmount(BigDecimal.ZERO);
                                sdCreditRequirement.setCreateTimestamp(LocalDateTime.now());
                                sdCreditRequirement.setUpdateTimestamp(LocalDateTime.now());
                                sdCreditRequirementRepository.persist(sdCreditRequirement);
                        }

                        CreditRisk creditRisk = sdCreditService.getCurrentRisk(sdCreditRequirement, firstBillingDate);

                        sdCreditRequirement.setRisk(creditRisk);

                        sdCreditRequirement.setSuggestedLimit(suggestedAmount);
                        sdCreditRequirement.setLimit(suggestedAmount);
                        BigDecimal utilizedLimit = new BigDecimal(sdCreditService.getUtilizationAmount(fofoId));

                        BigDecimal availableLimit = sdCreditRequirement.getLimit().subtract(utilizedLimit);

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

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

                        sdCreditRequirement.setUtilizedAmount(utilizedLimit);

                        sdCreditRequirement.setUpdateTimestamp(LocalDateTime.now());

                        CreditAccount creditAccount = creditAccountRepository
                                        .selectByFofoIdAndGateway(sdCreditRequirement.getFofoId(), Gateway.SDDIRECT);
                        if (creditAccount != null) {

                                creditAccount.setInterestRate(sdCreditRequirement.getInterestRate().floatValue());
                                creditAccount.setSanctionedAmount(sdCreditRequirement.getLimit().floatValue());
                                creditAccount.setAvailableAmount(availableLimit.floatValue());
                                creditAccount.setFreeDays(sdCreditRequirement.getFreeDays());
                                creditAccount.setUpdatedOn(LocalDateTime.now());
                        }

                }

        }

        public void notifyDefaultLoans() throws ProfitMandiBusinessException, MessagingException, IOException {

                sdCreditService.updateRisk();
                List<Loan> defaultLoans = sdCreditService.getDefaultLoan();
                if (!defaultLoans.isEmpty()) {
                        this.sendDefaultLoanAlert(defaultLoans);
                }

        }

        public void sendDefaultLoanAlert(List<Loan> defaultLoans)
                        throws ProfitMandiBusinessException, MessagingException, IOException {
                String subject = "Default Partners";

                List<Integer> categoryIds = Arrays.asList(ProfitMandiConstants.TICKET_CATEGORY_CATEGORY,
                                ProfitMandiConstants.TICKET_CATEGORY_RBM, ProfitMandiConstants.TICKET_CATEGORY_SALES,
                                ProfitMandiConstants.TICKET_CATEGORY_ACCOUNTS,
                                ProfitMandiConstants.TICKET_CATEGORY_BUSINESSINTELLIGENT);

                for (Map.Entry<String, Set<Integer>> storeGuyEntry : csService
                                .getAuthUserPartnerIdMappingByCategoryIds(categoryIds).entrySet()) {
                        List<Loan> filteredRows = new ArrayList<>();
                        for (Loan loan : defaultLoans) {

                                if (storeGuyEntry.getValue().contains(loan.getFofoId())) {

                                        filteredRows.add(loan);
                                }
                        }
                        if (!filteredRows.isEmpty()) {
                                String messageText = this.getMessageForDueDateExtend(filteredRows);
                                String[] email = new String[] { storeGuyEntry.getKey() };

                                this.sendMailHtmlFormat(email, messageText, null, subject);

                        }

                }

                for (Loan defaultLoan : defaultLoans) {
                        List<LoanStatement> loanStatements = loanStatementRepository.selectByLoanId(defaultLoan.getId());

                        double amount = loanStatements.stream().map(x -> x.getAmount())
                                        .collect(Collectors.summingDouble(x -> x.doubleValue()));

                        com.spice.profitmandi.dao.entity.user.User user = userUserRepository.selectById(defaultLoan.getFofoId());

                        Address address = addressRepository.selectById(user.getAddressId());

                        String title = "Loan Amount Overdue!";
                        String url = "http://app.smartdukaan.com/pages/home/credit";
                        String message = "Your loan due date "
                                        + defaultLoan.getDueDate().toLocalDate().format(DateTimeFormatter.ofPattern("dd-MM-yyyy"))
                                        + " has been exceeded. Additional penal interest of "
                                        + defaultLoan.getInterestRate().setScale(2, RoundingMode.HALF_UP)
                                        + "%  and Rs.100 shall be levied on daily basis." + " Your total pending Loan amount is Rs."
                                        + FormattingUtils.formatDecimal(Math.abs(amount)) + ". !!Pay Now!!";
                        notificationService.sendNotification(defaultLoan.getFofoId(), title, MessageType.notification, title,
                                        message, url);

                        notificationService.sendWhatsappMessage(message, title, address.getPhoneNumber());

                }
        }

        private String getMessageForDueDateExtend(List<Loan> loans) throws ProfitMandiBusinessException {
                StringBuilder sb = new StringBuilder();
                sb.append(
                                "<html><body><p>Alert</p><p>Default Partners :-</p>" + "<br/><p>EveryDay Rs.100 charged as Penalty</p>"
                                                + "<br/><table style='border:1px solid black ;padding: 5px';>");
                sb.append("<tbody>\n" + "                                       <tr>\n"
                                + "                                             <th style='border:1px solid black;padding: 5px'>PartnerName</th>\n"
                                + "                                             <th style='border:1px solid black;padding: 5px'>due date</th>\n"
                                + "                                             <th style='border:1px solid black;padding: 5px'>Days</th>\n"
                                + "                                             <th style='border:1px solid black;padding: 5px'>Pending Amount</th>\n"

                                + "                                     </tr>");
                for (Loan entry : loans) {

                        List<LoanStatement> loanStatements = loanStatementRepository.selectByLoanId(entry.getId());

                        double amount = loanStatements.stream().map(x -> x.getAmount())
                                        .collect(Collectors.summingDouble(x -> x.doubleValue()));

                        long noOfdaysBetween = ChronoUnit.DAYS.between(entry.getDueDate().toLocalDate(), LocalDateTime.now());

                        CustomRetailer customRetailer = retailerService.getFofoRetailer(entry.getFofoId());

                        sb.append("<tr>");
                        sb.append("<td style='border:1px solid black;padding: 5px'>" + customRetailer.getBusinessName() + "("
                                        + customRetailer.getCode() + ")" + "</td>");

                        sb.append("<td style='border:1px solid black;padding: 5px'>"
                                        + entry.getDueDate().format(DateTimeFormatter.ofPattern("dd/MM/yyyy")) + "</td>");
                        sb.append("<td style='border:1px solid black;padding: 5px'>" + noOfdaysBetween + "</td>");
                        sb.append("<td style='border:1px solid black;padding: 5px'>"
                                        + new DecimalFormat("#.##").format(Math.abs(amount)) + "</td>");

                        sb.append("</tr>");

                }

                sb.append("</tbody></table></body></html>");

                return sb.toString();
        }

        public void notifyLoanDueDateCross() throws ProfitMandiBusinessException, MessagingException, IOException {

                List<Loan> loans = loanRepository.selectAllActiveLoan().stream()
                                .filter(x -> x.getDueDate().isBefore(LocalDateTime.now())).collect(Collectors.toList());
                if (!loans.isEmpty()) {
                        for (Loan loan : loans) {

                                long noOfdaysBetween = ChronoUnit.DAYS.between(loan.getDueDate().toLocalDate(), LocalDate.now());

                                com.spice.profitmandi.dao.entity.user.User user = userUserRepository.selectById(loan.getFofoId());

                                Address address = addressRepository.selectById(user.getAddressId());

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

                                if (noOfdaysBetween <= 15 && noOfdaysBetween >= 0) {
                                        List<LoanStatement> loanStatements = loanStatementRepository.selectByLoanId(loan.getId());

                                        double amount = loanStatements.stream().map(x -> x.getAmount())
                                                        .collect(Collectors.summingDouble(x -> x.doubleValue()));

                                        String url = "http://app.smartdukaan.com/pages/home/credit";

                                        String title = "Alert!";
                                        String message = "Your loan due date "
                                                        + loan.getDueDate().toLocalDate().format(DateTimeFormatter.ofPattern("dd-MM-yyyy"))
                                                        + " has been exceeded. Additional penal interest of "
                                                        + loan.getInterestRate().setScale(2, RoundingMode.HALF_UP)
                                                        + "% shall be levied on daily basis. Your total pending loan amount is Rs."
                                                        + FormattingUtils.formatDecimal(Math.abs(amount)) + ". !!Pay Now!!";

                                        notificationService.sendNotification(loan.getFofoId(), title, MessageType.notification, title,
                                                        message, url);

                                        notificationService.sendWhatsappMessage(message, title, address.getPhoneNumber());

                                }
                        }
                }

        }

        public void alertForDueDate() throws ProfitMandiBusinessException, MessagingException, IOException {

                List<Loan> loans = loanRepository.selectAllActiveLoan();

                if (!loans.isEmpty()) {
                        for (Loan loan : loans) {

                                com.spice.profitmandi.dao.entity.user.User user = userUserRepository.selectById(loan.getFofoId());

                                Address address = addressRepository.selectById(user.getAddressId());

                                long noOfdaysBetween = ChronoUnit.DAYS.between(LocalDate.now(), loan.getDueDate().toLocalDate());

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

                                if (noOfdaysBetween <= 4 && noOfdaysBetween >= 0) {
                                        List<LoanStatement> loanStatements = loanStatementRepository.selectByLoanId(loan.getId());
                                        double amount = loanStatements.stream().map(x -> x.getAmount())
                                                        .collect(Collectors.summingDouble(x -> x.doubleValue()));

                                        String title = "Alert!";
                                        String url = "http://app.smartdukaan.com/pages/home/credit";
                                        String message = null;
                                        if (noOfdaysBetween == 0) {

                                                message = "Your total pending Loan amount is Rs."
                                                                + FormattingUtils.formatDecimal(Math.abs(amount)) + " is due for Today, Pay Now!!";

                                        } else {

                                                message = "Your total pending Loan amount is Rs."
                                                                + FormattingUtils.formatDecimal(Math.abs(amount)) + " is due by "
                                                                + loan.getDueDate().toLocalDate().format(DateTimeFormatter.ofPattern("dd-MM-yyyy"))
                                                                + " , Pay Now!!";

                                        }
                                        notificationService.sendNotification(loan.getFofoId(), title, MessageType.notification, title,
                                                        message, url);
                                        notificationService.sendWhatsappMessage(message, title, address.getPhoneNumber());

                                }
                        }
                }

        }

        public void userMobileNumberOptIn() throws HttpHostConnectException, ProfitMandiBusinessException {

                List<FofoStore> fofoStores = fofoStoreRepository.selectActiveStores();

                List<com.spice.profitmandi.dao.entity.user.User> users = userUserRepository
                                .selectByIds(fofoStores.stream().map(x -> x.getId()).collect(Collectors.toList()));

                List<Address> addresses = addressRepository
                                .selectByIds(users.stream().map(x -> x.getAddressId()).collect(Collectors.toList()));

                LOGGER.info("addresses" + addresses);

                for (Address address : addresses) {
                        Map<String, String> requestheaders = new HashMap<>();
                        requestheaders.put("Content-Type", "application/x-www-form-urlencoded");
                        Map<String, String> requestParams = new HashMap<>();
                        requestParams.put("userid", String.valueOf(2000215976));
                        requestParams.put("password", "MFRd!BBL");
                        requestParams.put("phone_number", address.getPhoneNumber());
                        requestParams.put("auth_scheme", "plain");
                        requestParams.put("v", "1.1");
                        requestParams.put("format", "json");

                        requestParams.put("method", "OPT_IN");

                        requestParams.put("channel", "WHATSAPP");
                        String response = restClient.get("https://media.smsgupshup.com/GatewayAPI/rest", requestParams,
                                        requestheaders);
                        LOGGER.info("response" + response);
                }

        }

        public void authUserMobileNumberOptIn() throws HttpHostConnectException, ProfitMandiBusinessException {

                List<AuthUser> authUsers = authRepository.selectAllActiveUser();
                LOGGER.info("authUsers" + authUsers);

                for (AuthUser authUser : authUsers) {
                        Map<String, String> requestheaders = new HashMap<>();
                        requestheaders.put("Content-Type", "application/x-www-form-urlencoded");
                        Map<String, String> requestParams = new HashMap<>();
                        requestParams.put("userid", String.valueOf(2000215976));
                        requestParams.put("password", "MFRd!BBL");
                        requestParams.put("phone_number", authUser.getMobileNumber());
                        requestParams.put("auth_scheme", "plain");
                        requestParams.put("v", "1.1");
                        requestParams.put("format", "json");

                        requestParams.put("method", "OPT_IN");

                        requestParams.put("channel", "WHATSAPP");
                        String response = restClient.get("https://media.smsgupshup.com/GatewayAPI/rest", requestParams,
                                        requestheaders);
                        LOGGER.info("response" + response);
                }

        }

        @Autowired
        private HygieneDataRepository hygieneDataRepository;

        public void hygineAlertForPartner() throws ProfitMandiBusinessException, MessagingException, IOException {

                List<String> remarks = new ArrayList<>();
                remarks.add("Out of Service");
                remarks.add("Duplicate number");
                remarks.add("Partner number");
                List<HygieneData> hygieneData = hygieneDataRepository.selectAllByDisposedDateAndRemark(LocalDate.now(),
                                remarks);

                if (!hygieneData.isEmpty()) {

                        Map<Integer, List<HygieneData>> partnerHygieneDataMap = hygieneData.stream()
                                        .collect(Collectors.groupingBy(x -> x.getFofoId()));

                        for (Entry<Integer, List<HygieneData>> partnerHygieneDataMapEntry : partnerHygieneDataMap.entrySet()) {

                                CustomRetailer customRetailer = retailerService.getFofoRetailer(partnerHygieneDataMapEntry.getKey());

                                StringBuilder sb = new StringBuilder();
                                sb.append("<html><body><p>Dear Partner,"
                                                + "</p><br/><p>It has been observed in our calls to the respective customers that the contact no is either not correct or does not have incoming calls.\n"

                                                + " </p>"
                                                + "<p>We would like to inform you that this will hinder all our marketing initiatives to bring this customer back to our smartdukaan or cross sell any product from your inventory."
                                                + "</p><p>Kindly ensure going forward that the details are correct so to avoid 1% margin loss.\n"
                                                + "</p><p>In case the data is found to be incorrect there is a loss of 1% margin on this sales under SmartDukaan hygiene guidelines.\n"
                                                + "                             " + "</p>"

                                                + "<br/><table style='border:1px solid black ;padding: 5px';>");
                                sb.append("<tbody>\n" + "       " + "                                   " + "<tr>\n");
                                sb.append("<th style='border:1px solid black;padding: 5px'>Invoice Number</th>\n");
                                sb.append("<th style='border:1px solid black;padding: 5px'>Customer Name</th>\n");
                                sb.append("<th style='border:1px solid black;padding: 5px'>Customer Number</th>\n");
                                sb.append("</tr>\n");

                                List<HygieneData> hygienes = partnerHygieneDataMapEntry.getValue();

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

                                List<FofoOrder> fofoOrders = fofoOrderRepository.selectAllByOrderIds(orderIds);

                                for (FofoOrder fofoOrder : fofoOrders) {
                                        Customer customer = customerRepository.selectById(fofoOrder.getCustomerId());
                                        sb.append("<tr>");
                                        sb.append("<td style='border:1px solid black;padding: 5px'>" + fofoOrder.getInvoiceNumber()
                                                        + "</td>\n");
                                        sb.append("<td style='border:1px solid black;padding: 5px'>" + customer.getFirstName() + ""
                                                        + customer.getLastName() + "</td>\n");
                                        sb.append("<td style='border:1px solid black;padding: 5px'>" + customer.getMobileNumber()
                                                        + "</td>\n");

                                        sb.append("</tr>\n");
                                }

                                sb.append("</tbody></table></body></html>");
                                String subject = "Customer Info - Hygiene Alert";

                                this.sendMailOfHtmlFormat(customRetailer.getEmail(), sb.toString(), null, subject);

                        }

                }

        }

        public void hygineAlertForInternalTeam() throws ProfitMandiBusinessException, MessagingException, IOException {

                List<String> remarks = new ArrayList<>();
                remarks.add("Out of Service");
                remarks.add("Duplicate number");
                remarks.add("Partner number");
                List<HygieneData> hygieneDataLastThreeMonth = hygieneDataRepository
                                .selectDisposedDateAndRemarks(
                                                LocalDate.now().withDayOfMonth(1).minusMonths(3).atStartOfDay(), LocalDate.now().minusMonths(1)
                                                                .withDayOfMonth(LocalDate.now().minusMonths(1).lengthOfMonth()).atTime(LocalTime.MAX),
                                                remarks);

                List<HygieneData> hygieneDataRecentMonth = hygieneDataRepository
                                .selectDisposedDateAndRemarks(LocalDate.now().withDayOfMonth(1), remarks);
                Map<String, Set<Integer>> storeGuyMap = csService.getAuthUserPartnerIdMapping();
                Map<Integer, List<HygieneData>> partnerHygieneLastThreeMonthMap = null;

                Map<Integer, List<HygieneData>> partnerHygieneDataRecentMonth = null;

                if (!hygieneDataLastThreeMonth.isEmpty()) {
                        partnerHygieneLastThreeMonthMap = hygieneDataLastThreeMonth.stream()
                                        .collect(Collectors.groupingBy(x -> x.getFofoId()));

                }

                if (!hygieneDataRecentMonth.isEmpty()) {
                        partnerHygieneDataRecentMonth = hygieneDataRecentMonth.stream()
                                        .collect(Collectors.groupingBy(x -> x.getFofoId()));
                }

                for (Entry<String, Set<Integer>> storeGuyEntry : storeGuyMap.entrySet()) {

                        String email = storeGuyEntry.getKey();

                        List<Integer> fofoIds = new ArrayList<>(storeGuyEntry.getValue());

                        Map<Integer, Map<YearMonth, List<HygieneData>>> partnerYearMonthData = new HashMap<>();
                        Map<Integer, Map<LocalDate, List<HygieneData>>> partnerDateWiseData = new HashMap<>();
                        for (Integer fofoId : fofoIds) {

                                partnerYearMonthData.put(fofoId, null);
                                partnerDateWiseData.put(fofoId, null);
                                if (!partnerHygieneLastThreeMonthMap.isEmpty()) {
                                        List<HygieneData> hygienes = partnerHygieneLastThreeMonthMap.get(fofoId);

                                        if (hygienes != null) {
                                                Map<YearMonth, List<HygieneData>> yearMonthData = hygienes.stream()
                                                                .collect(Collectors.groupingBy(x -> YearMonth.from(x.getDisposedTimestamp())));

                                                partnerYearMonthData.put(fofoId, yearMonthData);

                                        }
                                        List<HygieneData> dateWiseHygienes = partnerHygieneDataRecentMonth.get(fofoId);

                                        if (dateWiseHygienes != null) {

                                                Map<LocalDate, List<HygieneData>> dateWiseData = hygienes.stream()
                                                                .collect(Collectors.groupingBy(x -> (x.getDisposedTimestamp()).toLocalDate()));

                                                partnerDateWiseData.put(fofoId, dateWiseData);

                                        }

                                }

                        }

                        String subject = "Customer Info - Hygiene Alert";

                        LOGGER.info("hygieneData {}", partnerDateWiseData.values());

                        boolean partnerDateWise = partnerDateWiseData.values().stream().allMatch(Objects::isNull);

                        boolean partnerYearMonth = partnerYearMonthData.values().stream().allMatch(Objects::isNull);

                        if (!partnerDateWise && !partnerYearMonth) {
                                String sb = this.getMessageHygieneAlertForPartner(partnerYearMonthData, partnerDateWiseData);
                                this.sendMailOfHtmlFormat(email, sb, null, subject);
                        }

                }

        }

        private String getMessageHygieneAlertForPartner(
                        Map<Integer, Map<YearMonth, List<HygieneData>>> partnerYearMonthData,
                        Map<Integer, Map<LocalDate, List<HygieneData>>> partnerDateWiseData) {

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

                LocalDateTime startDate = LocalDate.now().withDayOfMonth(1).atStartOfDay();
                LocalDateTime endDate = LocalDateTime.now();

                LocalDateTime startYearMonth = LocalDate.now().withDayOfMonth(1).minusMonths(3).atStartOfDay();
                LocalDateTime endYearMonth = LocalDate.now().minusMonths(1)
                                .withDayOfMonth(LocalDate.now().minusMonths(1).lengthOfMonth()).atTime(LocalTime.MAX);

                DateTimeFormatter dateYearMonthFormatter = DateTimeFormatter.ofPattern("MMM''uu");

                List<YearMonth> yearMonthRange = new ArrayList<>();
                yearMonthRange.add(YearMonth.from(startYearMonth));

                yearMonthRange.add(YearMonth.from(startYearMonth.plusMonths(1)));

                yearMonthRange.add(YearMonth.from(endYearMonth));

                long noOfDaysBetween = ChronoUnit.DAYS.between(startDate, endDate.plusDays(1));

                List<LocalDate> dateRange = Stream.iterate(startDate.toLocalDate(), date -> date.plusDays(1))
                                .limit(noOfDaysBetween).collect(Collectors.toList());

                StringBuilder sb = new StringBuilder();
                sb.append("<html><body><p>Hi,"
                                + "</p><br/><p>Kindly advise below mentioned partner to input correct details in the system else this will hinder all our marketing initiatives to bring this customer back to our smartdukaan or cross sell any product from partner's inventory.\n"
                                + " </p>" + "<p>Kindly ensure going forward that the details are correct so to avoid 1% margin loss.\n"
                                + "</p><p>In case the data is found to be incorrect there is a loss of 1% margin on this sales under SmartDukaan hygiene guidelines.\n</p>"

                                + "<table style='border:1px solid black ;padding: 5px';>");
                sb.append("<tbody>\n" + "       " + "                                   " + "<tr>\n");
                sb.append("<th style='border:1px solid black;padding: 5px'>Partner Name</th>\n");

                for (YearMonth yearMonth : yearMonthRange) {
                        sb.append("<th style='border:1px solid black;padding: 5px'>" + yearMonth.format(dateYearMonthFormatter)
                                        + "</th>\n");
                }

                for (LocalDate localDate : dateRange) {
                        sb.append("<th style='border:1px solid black;padding: 5px'>" + localDate + "</th>\n");
                }

                sb.append("</tr>\n");

                for (Entry<Integer, Map<YearMonth, List<HygieneData>>> partnerYearMonthEntry : partnerYearMonthData
                                .entrySet()) {

                        int fofoId = partnerYearMonthEntry.getKey();

                        Map<YearMonth, List<HygieneData>> yearMonthData = partnerYearMonthEntry.getValue();

                        Map<LocalDate, List<HygieneData>> dateWiseData = partnerDateWiseData.get(fofoId);

                        if (yearMonthData == null && dateWiseData == null) {
                                continue;
                        }

                        sb.append("<tr>");
                        sb.append("<td style='border:1px solid black;padding: 5px'>"
                                        + customeRetailerMap.get(fofoId).getBusinessName() + "</td>\n");
                        for (YearMonth yearMonth : yearMonthRange) {

                                if (yearMonthData == null) {
                                        sb.append("<td style='border:1px solid black;padding: 5px'>-</td>\n");

                                } else {
                                        List<HygieneData> hygieneList = yearMonthData.get(yearMonth);

                                        if (hygieneList != null) {
                                                sb.append("<td style='border:1px solid black;padding: 5px'>" + hygieneList.size() + "</td>\n");

                                        } else {
                                                sb.append("<td style='border:1px solid black;padding: 5px'>-</td>\n");

                                        }
                                }
                        }

                        for (LocalDate localDate : dateRange) {

                                if (dateWiseData == null) {
                                        sb.append("<td style='border:1px solid black;padding: 5px'>-</td>\n");

                                } else {
                                        List<HygieneData> hygieneList = dateWiseData.get(localDate);

                                        if (hygieneList != null) {
                                                sb.append("<td style='border:1px solid black;padding: 5px'>" + hygieneList.size() + "</td>\n");

                                        } else {
                                                sb.append("<td style='border:1px solid black;padding: 5px'>-</td>\n");

                                        }
                                }
                        }
                        sb.append("</tr>");

                }

                sb.append("</tbody></table></body></html>");

                return sb.toString();
        }

        @Autowired
        private MonthlyTargetRepository monthlyTargetRepository;

        public void monthlyTargetForPartner() throws MessagingException, ProfitMandiBusinessException, IOException {

                LocalDateTime curDate = LocalDateTime.now();
                List<MonthlyTarget> monthlyTargets = monthlyTargetRepository.selectByDate(YearMonth.now());

                Map<Integer, MonthlyTarget> partnersMonthlyTarget = monthlyTargets.stream()
                                .collect(Collectors.toMap(x -> x.getFofoId(), x -> x));

                Map<Integer, Double> secondaryMtd = orderRepository
                                .selectBillingDatesBetweenSumGroupByRetailerId(curDate.withDayOfMonth(1), curDate.with(LocalTime.MAX));
                Map<Integer, Double> todaytertiary = fofoOrderItemRepository.selectSumMopGroupByRetailer(curDate,
                                curDate.with(LocalTime.MAX), 0, false);

                String subject = "Monthly Target Vs Achievement";

                for (Entry<Integer, MonthlyTarget> partnerMonthlyTargetEntry : partnersMonthlyTarget.entrySet()) {

                        int fofoId = partnerMonthlyTargetEntry.getKey();

                        CustomRetailer customRetailer = retailerService.getFofoRetailer(fofoId);

                        Double purchaseTarget = partnerMonthlyTargetEntry.getValue().getPurchaseTarget();

                        Double saleTarget = partnerMonthlyTargetEntry.getValue().getSaleTarget();

                        if (purchaseTarget > 0) {
                                Double purchase = secondaryMtd.get(fofoId);

                                if (purchase == null) {
                                        purchase = 0.0;
                                }

                                Double balanceTarget = purchaseTarget - purchase;

                                if (balanceTarget <= 0) {
                                        balanceTarget = 0.0;
                                }

                                StringBuilder sb = new StringBuilder();
                                sb.append("<html><body><p>Dear Partner,\n");
                                sb.append("<p>Pls note your agreed monthly target is Rs." + purchaseTarget
                                                + " and your achievement till date is Rs." + purchase + "</p>");
                                sb.append("<p>Pls note that your balance target is Rs." + balanceTarget + "</p>\n");
                                sb.append(
                                                "<p>We wish you all the best and we are confident that this focussed approach towards our outlet sales will help us take our outlet to the best SmartDukaan in your city.\n"
                                                                + "</p>\n");

                                this.sendMailOfHtmlFormat(customRetailer.getEmail(), sb.toString(), null, subject);

                                // this.sendMailOfHtmlFormat("tejbeer.kaur@smartdukaan.com", sb.toString(),
                                // null, subject);

                        }

                }

        }

        public void monthlyTargetForInternalTeam() throws MessagingException, ProfitMandiBusinessException, IOException {

                LocalDateTime curDate = LocalDateTime.now();

                List<Integer> categoryIds = Arrays.asList(ProfitMandiConstants.TICKET_CATEGORY_CATEGORY,
                                ProfitMandiConstants.TICKET_CATEGORY_RBM, ProfitMandiConstants.TICKET_CATEGORY_SALES,
                                ProfitMandiConstants.TICKET_CATEGORY_MARKETING, ProfitMandiConstants.TICKET_CATEGORY_ACCOUNTS,
                                ProfitMandiConstants.TICKET_CATEGORY_BUSINESSINTELLIGENT);

                Map<String, Set<Integer>> storeGuyMap = csService.getAuthUserPartnerIdMappingByCategoryIds(categoryIds);

                List<MonthlyTarget> monthlyTargets = monthlyTargetRepository.selectByDate(YearMonth.now());

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

                Map<Integer, MonthlyTarget> partnersMonthlyTarget = monthlyTargets.stream()
                                .collect(Collectors.toMap(x -> x.getFofoId(), x -> x));

                Map<Integer, Double> secondaryMtd = orderRepository
                                .selectBillingDatesBetweenSumGroupByRetailerId(curDate.withDayOfMonth(1), curDate.with(LocalTime.MAX));
                Map<Integer, Double> todaytertiary = fofoOrderItemRepository.selectSumMopGroupByRetailer(curDate,
                                curDate.with(LocalTime.MAX), 0, false);

                String subject = "Monthly Target Vs Achievement";

                for (Entry<String, Set<Integer>> storeGuyEntry : storeGuyMap.entrySet()) {

                        String email = storeGuyEntry.getKey();

                        List<Integer> fofoIds = new ArrayList<>(storeGuyEntry.getValue());
                        Map<Integer, MonthlyTarget> monthlyTargetAchievement = new HashMap<>();
                        for (Integer fofoId : fofoIds) {

                                MonthlyTarget monthlyTarget = partnersMonthlyTarget.get(fofoId);
                                if (monthlyTarget != null) {
                                        Double purchaseTarget = monthlyTarget.getPurchaseTarget();

                                        Double saleTarget = monthlyTarget.getSaleTarget();

                                        if (purchaseTarget != null && purchaseTarget > 0) {
                                                Double purchase = secondaryMtd.get(fofoId);
                                                if (purchase == null) {
                                                        purchase = 0.0;
                                                }
                                                monthlyTarget.setPurchaseAchievement(purchase);
                                                monthlyTargetAchievement.put(fofoId, monthlyTarget);

                                        }
                                }
                        }

                        if (!monthlyTargetAchievement.isEmpty()) {

                                StringBuilder sb = new StringBuilder();

                                sb.append("<html><body><p>Hi,\n");
                                sb.append("<p>Pls note your Partners agreed monthly target foolowing are :</p>\n"
                                                + " <table style='border:1px solid black ;padding: 5px';>");
                                sb.append("<tbody>\n" + "       " + "                                   " + "<tr>\n");
                                sb.append("<th style='border:1px solid black;padding: 5px'>Partner Name</th>\n");

                                sb.append("<th style='border:1px solid black;padding: 5px'>Purchase Target</th>\n");

                                sb.append("<th style='border:1px solid black;padding: 5px'>Purchase Achievement</th>\n");
                                sb.append("</tr>\n");

                                for (Entry<Integer, MonthlyTarget> monthlyTargetAchievementEntry : monthlyTargetAchievement
                                                .entrySet()) {
                                        sb.append("<tr>");
                                        int fofoId = monthlyTargetAchievementEntry.getKey();

                                        MonthlyTarget monthlyTarget = monthlyTargetAchievementEntry.getValue();
                                        sb.append("<td style='border:1px solid black;padding: 5px'>"
                                                        + customeRetailerMap.get(fofoId).getBusinessName() + "</td>\n");

                                        sb.append("<td style='border:1px solid black;padding: 5px'>" + monthlyTarget.getPurchaseTarget()
                                                        + "</td>\n");

                                        sb.append("<td style='border:1px solid black;padding: 5px'>"
                                                        + monthlyTarget.getPurchaseAchievement() + "</td>\n");

                                        sb.append("</tr>\n");

                                }

                                this.sendMailOfHtmlFormat(email, sb.toString(), null, subject);
                                // this.sendMailOfHtmlFormat("tejbeer.kaur@smartdukaan.com", sb.toString(),
                                // null, subject);

                        }

                }

        }

}
// 2284'