Subversion Repositories SmartDukaan

Rev

Rev 36399 | Rev 36534 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
33172 tejus.loha 1
package com.spice.profitmandi.service.order;
2
 
3
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
4
import com.spice.profitmandi.common.model.BulkOrderModel;
33341 tejus.loha 5
import com.spice.profitmandi.common.model.LineItemModel;
33547 tejus.loha 6
import com.spice.profitmandi.common.model.ProfitMandiConstants;
33341 tejus.loha 7
import com.spice.profitmandi.common.model.TransactionApprovalModel;
33172 tejus.loha 8
import com.spice.profitmandi.common.util.ExcelUtils;
35971 aman 9
import com.spice.profitmandi.common.util.Utils;
33172 tejus.loha 10
import com.spice.profitmandi.dao.cart.CartService;
33341 tejus.loha 11
import com.spice.profitmandi.dao.entity.auth.AuthUser;
34443 vikas.jang 12
import com.spice.profitmandi.dao.entity.catalog.Bid;
34832 ranu 13
import com.spice.profitmandi.dao.entity.catalog.Item;
33172 tejus.loha 14
import com.spice.profitmandi.dao.entity.catalog.TagListing;
34856 ranu 15
import com.spice.profitmandi.dao.entity.fofo.FofoStore;
34566 ranu 16
import com.spice.profitmandi.dao.entity.fofo.LoanTransaction;
34674 aman.kumar 17
import com.spice.profitmandi.dao.entity.transaction.LineItem;
18
import com.spice.profitmandi.dao.entity.transaction.Order;
19
import com.spice.profitmandi.dao.entity.transaction.Transaction;
20
import com.spice.profitmandi.dao.entity.transaction.TransactionApproval;
35971 aman 21
import com.spice.profitmandi.dao.entity.user.StoreTimelinetb;
22
import com.spice.profitmandi.dao.enumuration.cs.EscalationType;
23
import com.spice.profitmandi.dao.enumuration.dtr.StoreTimeline;
33213 tejus.loha 24
import com.spice.profitmandi.dao.enumuration.transaction.TransactionApprovalStatus;
33172 tejus.loha 25
import com.spice.profitmandi.dao.model.CartItem;
26
import com.spice.profitmandi.dao.model.UserCart;
33341 tejus.loha 27
import com.spice.profitmandi.dao.repository.auth.AuthRepository;
34468 vikas.jang 28
import com.spice.profitmandi.dao.repository.catalog.BidRepository;
34832 ranu 29
import com.spice.profitmandi.dao.repository.catalog.ItemRepository;
34468 vikas.jang 30
import com.spice.profitmandi.dao.repository.catalog.LiquidationRepository;
33172 tejus.loha 31
import com.spice.profitmandi.dao.repository.catalog.TagListingRepository;
34443 vikas.jang 32
import com.spice.profitmandi.dao.repository.cs.CsService;
34856 ranu 33
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
33172 tejus.loha 34
import com.spice.profitmandi.dao.repository.dtr.UserRepository;
34566 ranu 35
import com.spice.profitmandi.dao.repository.fofo.LoanTransactionRepository;
33341 tejus.loha 36
import com.spice.profitmandi.dao.repository.transaction.OrderRepository;
33338 amit.gupta 37
import com.spice.profitmandi.dao.repository.transaction.SDCreditRequirementRepository;
33213 tejus.loha 38
import com.spice.profitmandi.dao.repository.transaction.TransactionApprovalRepository;
39
import com.spice.profitmandi.dao.repository.transaction.TransactionRepository;
40
import com.spice.profitmandi.dao.repository.user.AddressRepository;
34468 vikas.jang 41
import com.spice.profitmandi.dao.service.BidService;
34832 ranu 42
import com.spice.profitmandi.service.catalog.BrandsService;
34661 ranu 43
import com.spice.profitmandi.service.transaction.BlockLoanIdSanctionId;
33338 amit.gupta 44
import com.spice.profitmandi.service.transaction.SDCreditService;
33172 tejus.loha 45
import com.spice.profitmandi.service.transaction.TransactionService;
46
import com.spice.profitmandi.service.wallet.CommonPaymentService;
47
import com.spice.profitmandi.service.wallet.WalletService;
48
import org.apache.logging.log4j.LogManager;
49
import org.apache.logging.log4j.Logger;
33213 tejus.loha 50
import org.apache.poi.ss.usermodel.Cell;
33172 tejus.loha 51
import org.apache.poi.ss.usermodel.Row;
52
import org.apache.poi.xssf.usermodel.XSSFRow;
53
import org.apache.poi.xssf.usermodel.XSSFSheet;
54
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
55
import org.springframework.beans.factory.annotation.Autowired;
35971 aman 56
import org.springframework.mail.javamail.JavaMailSender;
33213 tejus.loha 57
import org.springframework.stereotype.Service;
33172 tejus.loha 58
import org.springframework.web.multipart.MultipartFile;
59
 
33338 amit.gupta 60
import java.math.BigDecimal;
35956 amit 61
import java.time.LocalDateTime;
35995 aman 62
import java.util.*;
33172 tejus.loha 63
import java.util.stream.Collectors;
64
 
33213 tejus.loha 65
@Service
33172 tejus.loha 66
public class BulkOrderService {
67
    private static final Logger LOGGER = LogManager.getLogger(BulkOrderService.class);
68
    @Autowired
69
    CartService cartService;
70
    @Autowired
71
    TransactionService transactionService;
72
    @Autowired
73
    CommonPaymentService commonPaymentService;
74
    @Autowired
75
    TagListingRepository tagListingRepository;
76
    @Autowired
77
    WalletService walletService;
78
    @Autowired
79
    UserRepository userRepository;
33213 tejus.loha 80
    @Autowired
81
    TransactionRepository transactionRepository;
82
    @Autowired
83
    TransactionApprovalRepository transactionApprovalRepository;
84
    @Autowired
85
    AddressRepository addressRepository;
33341 tejus.loha 86
    @Autowired
87
    OrderRepository orderRepository;
34443 vikas.jang 88
    //TODO:Tejus need to check
33341 tejus.loha 89
    @Autowired
90
    SDCreditRequirementRepository sdCreditRequirementRepository;
33338 amit.gupta 91
    @Autowired
92
    SDCreditService sdCreditService;
34443 vikas.jang 93
    @Autowired
94
    private CsService csService;
95
    @Autowired
34468 vikas.jang 96
    private AuthRepository authRepository;
34443 vikas.jang 97
    @Autowired
34468 vikas.jang 98
    private BidRepository bidRepository;
99
    @Autowired
100
    private BidService bidService;
101
    @Autowired
34832 ranu 102
    ItemRepository itemRepository;
103
    @Autowired
104
    private BrandsService brandsService;
105
    @Autowired
34566 ranu 106
    private LoanTransactionRepository loanTransactionRepository;
107
 
108
    @Autowired
34468 vikas.jang 109
    private LiquidationRepository liquidationRepository;
33338 amit.gupta 110
 
34674 aman.kumar 111
    @Autowired
112
    com.spice.profitmandi.dao.repository.user.UserRepository user_userRepository;
33338 amit.gupta 113
 
34856 ranu 114
    @Autowired
115
    FofoStoreRepository fofoStoreRepository;
34674 aman.kumar 116
 
35971 aman 117
    @Autowired
36399 amit 118
    JavaMailSender gmailRelaySender;
34856 ranu 119
 
35971 aman 120
    @Autowired
121
    com.spice.profitmandi.service.user.StoreTimelineTatService storeTimelineTatService;
122
 
123
    @Autowired
124
    com.spice.profitmandi.dao.repository.dtr.PartnerOnBoardingPanelRepository partnerOnBoardingPanelRepository;
125
 
126
    @Autowired
127
    com.spice.profitmandi.dao.repository.user.StoreTimelinetbRepository storeTimelinetbRepository;
128
 
129
 
34468 vikas.jang 130
    public void parseBulkOrders(MultipartFile file, int creatorId) throws Exception {
33172 tejus.loha 131
        XSSFWorkbook myWorkBook = new XSSFWorkbook(file.getInputStream());
132
 
133
        myWorkBook.setMissingCellPolicy(Row.MissingCellPolicy.RETURN_BLANK_AS_NULL);
134
        // Return first sheet from the XLSX workbook
135
        XSSFSheet mySheet = myWorkBook.getSheetAt(0);
136
        LOGGER.info("rowCellNum {}", mySheet.getLastRowNum());
137
        List<BulkOrderModel> bulkOrderModels = new ArrayList<>();
33547 tejus.loha 138
        LOGGER.info("mySheet.getLastRowNum() - {}", mySheet.getLastRowNum());
33172 tejus.loha 139
        for (int rowNumber = 1; rowNumber <= mySheet.getLastRowNum(); rowNumber++) {
140
            XSSFRow row = mySheet.getRow(rowNumber);
33547 tejus.loha 141
            LOGGER.info("Row - {}", row);
142
            if (row != null) {
143
                BulkOrderModel bulkOrderModel = this.createBulkModel(row);
144
                bulkOrderModels.add(bulkOrderModel);
145
            } else {
146
                break;
147
            }
33172 tejus.loha 148
        }
34468 vikas.jang 149
        this.generatePurchaseOrder(bulkOrderModels, creatorId, ProfitMandiConstants.PO_TYPE.MANUAL, ProfitMandiConstants.BID_CRON_ENUM.TODAY);
34443 vikas.jang 150
    }
151
 
34592 vikas.jang 152
    public ProfitMandiConstants.BID_ENUM generatePurchaseOrder(List<BulkOrderModel> bulkOrderModels, int creatorId, ProfitMandiConstants.PO_TYPE type, ProfitMandiConstants.BID_CRON_ENUM scheduleType) throws Exception {
33172 tejus.loha 153
        Map<Integer, List<BulkOrderModel>> fofoBulkOrdersMap = bulkOrderModels.stream().collect(Collectors.groupingBy(x -> x.getFofoId()));
34443 vikas.jang 154
        boolean approvalRequired = false;
34592 vikas.jang 155
        ProfitMandiConstants.BID_ENUM finalBidStatus = ProfitMandiConstants.BID_ENUM.CLOSED;
33172 tejus.loha 156
        for (Map.Entry<Integer, List<BulkOrderModel>> fofoBulkOrderEntry : fofoBulkOrdersMap.entrySet()) {
157
            int fofoId = fofoBulkOrderEntry.getKey();
158
            List<BulkOrderModel> fofoBulkOrderModels = fofoBulkOrderEntry.getValue();
159
            Map<Integer, Long> orderItemCountMap = fofoBulkOrderModels.stream().collect(Collectors.groupingBy(x -> x.getItemId(), Collectors.counting()));
160
 
161
            if (orderItemCountMap.entrySet().stream().filter(x -> x.getValue() > 1).count() > 0) {
162
                throw new ProfitMandiBusinessException("Fofo ID", fofoId, "Duplicate in items");
163
            }
164
 
165
            boolean hasZeroQuantity = fofoBulkOrderModels.stream().filter(x -> x.getQuantity() <= 0).count() > 0;
166
            if (hasZeroQuantity) {
167
                throw new ProfitMandiBusinessException("Item Quantity", "", "Should be greater than 0");
168
            }
169
 
35690 amit 170
            // Batch-fetch per-fofo data once (instead of per-item)
171
            FofoStore fofoStore = fofoStoreRepository.selectByRetailerId(fofoId);
172
            List<String> partnerIneligibleBrands = brandsService.partnerIneligibleBrands(fofoId);
173
 
174
            // Batch-fetch items and tag listings for all items in this fofo's order (2 queries instead of 2N)
175
            Set<Integer> allItemIds = fofoBulkOrderModels.stream().map(BulkOrderModel::getItemId).collect(Collectors.toSet());
176
            Map<Integer, TagListing> tagListingMap = tagListingRepository.selectByItemIds(allItemIds);
177
            Map<Integer, Item> itemMap = itemRepository.selectByIds(allItemIds).stream()
178
                    .collect(Collectors.toMap(Item::getId, item -> item));
179
 
33172 tejus.loha 180
            List<CartItem> cartItems = new ArrayList<>();
33338 amit.gupta 181
            double totalPayableAmount = 0;
34957 amit 182
            BigDecimal totalPayableAmountBD = new BigDecimal(0);
33172 tejus.loha 183
            for (BulkOrderModel fofoBulkOrderModel : fofoBulkOrderModels) {
184
                CartItem cartItem = new CartItem();
185
                cartItem.setQuantity(fofoBulkOrderModel.getQuantity());
186
                cartItem.setItemId(fofoBulkOrderModel.getItemId());
35690 amit 187
                TagListing tagListing = tagListingMap.get(fofoBulkOrderModel.getItemId());
33556 amit.gupta 188
                if (tagListing == null) {
189
                    String message = "Pricing Does not exist for " + fofoBulkOrderModel.getItemId() + "(" + fofoBulkOrderModel.getDescription() + ")";
190
                    throw new ProfitMandiBusinessException(message, message, message);
191
                }
35690 amit 192
                Item item = itemMap.get(fofoBulkOrderModel.getItemId());
193
                if (item == null) {
194
                    throw new ProfitMandiBusinessException("Item not found", fofoBulkOrderModel.getItemId(), "Item does not exist: " + fofoBulkOrderModel.getItemId());
195
                }
34856 ranu 196
                if (!fofoStore.isInternal()) {
197
                    if (partnerIneligibleBrands.contains(item.getBrand())) {
198
                        throw new ProfitMandiBusinessException("Brand is not allowed", "Brand ( " + item.getBrand() + ") is not allowed for this partner", "");
199
                    }
34832 ranu 200
                }
201
 
33213 tejus.loha 202
                double itemSellingPrice = tagListing.getSellingPrice();
33597 tejus.loha 203
                boolean isActualPrice = fofoBulkOrderModel.getItemPrice() == itemSellingPrice;
204
                boolean isPriceZero = fofoBulkOrderModel.getItemPrice() == 0d;
33213 tejus.loha 205
                double customSellingPrice = fofoBulkOrderModel.getItemPrice();
206
                int itemId = cartItem.getItemId();
33597 tejus.loha 207
                if (isPriceZero || isActualPrice) {
33213 tejus.loha 208
                    cartItem.setSellingPrice(itemSellingPrice);
209
                } else {
33216 tejus.loha 210
                    if (customSellingPrice <= tagListing.getMrp() || customSellingPrice <= tagListing.getMop()) {
33213 tejus.loha 211
                        cartItem.setSellingPrice(customSellingPrice);
34443 vikas.jang 212
                        approvalRequired = true;
33213 tejus.loha 213
 
214
                    } else {
215
                        throw new ProfitMandiBusinessException("Given price is greater than selling price for item Id - ", itemId, " it should be less or equal of DP");
216
                    }
217
 
218
                }
34958 amit 219
                totalPayableAmountBD = totalPayableAmountBD.add(new BigDecimal(String.valueOf(cartItem.getSellingPrice())).multiply(new BigDecimal(cartItem.getQuantity())));
33172 tejus.loha 220
                cartItems.add(cartItem);
221
            }
34957 amit 222
            totalPayableAmount = totalPayableAmountBD.doubleValue();
34501 vikas.jang 223
            Bid bid = null;
224
            if (type.equals(ProfitMandiConstants.PO_TYPE.AUTO)) {
225
                bid = bidRepository.selectById(fofoBulkOrderModels.get(0).getRowIndex());
34592 vikas.jang 226
                approvalRequired = false;
34957 amit 227
                totalPayableAmount = totalPayableAmountBD.doubleValue() - ProfitMandiConstants.BID_CHARGES;
34501 vikas.jang 228
            }
33338 amit.gupta 229
            LOGGER.info("totalAmount of item " + totalPayableAmount);
33172 tejus.loha 230
            double walletAmount = walletService.getWalletAmount(fofoId);
33338 amit.gupta 231
 
232
            BigDecimal creditAvailability = sdCreditService.getAvailableAmount(fofoId);
233
 
234
            double netAmountInHand = creditAvailability.doubleValue() + walletAmount;
33442 tejus.loha 235
            LOGGER.info("netAmountInHand - " + netAmountInHand);
33547 tejus.loha 236
            if (totalPayableAmount > ProfitMandiConstants.MAX_NEGATIVE_WALLET_VALUE && netAmountInHand < totalPayableAmount) {
34468 vikas.jang 237
                if (type.equals(ProfitMandiConstants.PO_TYPE.MANUAL)) {
34695 aman.kumar 238
                    throw new ProfitMandiBusinessException("Skipping order due to insufficient balance for id - ", fofoId, String.valueOf(fofoId));
34443 vikas.jang 239
                } else {
34468 vikas.jang 240
                    if (scheduleType.equals(ProfitMandiConstants.BID_CRON_ENUM.TODAY)) {
34592 vikas.jang 241
                        finalBidStatus = bidService.sendMailToRBM(netAmountInHand, totalPayableAmount, fofoId);
34572 vikas.jang 242
                        LOGGER.info("Skipping order due to insufficient balance for id - "+ fofoId+ " Sending mail to RBM");
243
                        //throw new ProfitMandiBusinessException("Skipping order due to insufficient balance for id - ", fofoId, " ,Sending mail to RBM");
34468 vikas.jang 244
                    } else {
34592 vikas.jang 245
                        finalBidStatus = bidService.cancelYesterdayProcessBid(bid);
34572 vikas.jang 246
                        LOGGER.info("Skipping order due to insufficient balance for id - "+ fofoId+ " Cancelling the BID");
247
                        //throw new ProfitMandiBusinessException("Skipping order due to insufficient balance for id - ", fofoId, " ,Cancelling the BID");
34468 vikas.jang 248
                    }
34443 vikas.jang 249
                }
33172 tejus.loha 250
            }
251
            UserCart userCart = cartService.setCartItems(fofoId, cartItems);
33213 tejus.loha 252
            // createtransactionInternally set the value in transaction table
33338 amit.gupta 253
 
33351 amit.gupta 254
            double creditAmountRequired = totalPayableAmount - walletAmount;
34312 ranu 255
            int loanId = 0;
34492 vikas.jang 256
            try {
257
                if (creditAmountRequired > ProfitMandiConstants.MAX_NEGATIVE_WALLET_VALUE) {
34576 vikas.jang 258
                    LOGGER.info("Creating new loan for: {}",userCart.getUserId());
34675 aman.kumar 259
                    BlockLoanIdSanctionId loan = sdCreditService.createSDDirectOrder(userCart.getUserId(), totalPayableAmount, 0);
34661 ranu 260
                    loanId = loan.getLoanId();
34492 vikas.jang 261
                }
262
            } catch (Exception exception){
34501 vikas.jang 263
                if (type.equals(ProfitMandiConstants.PO_TYPE.AUTO)) {
34592 vikas.jang 264
                    finalBidStatus = bidService.sendMailToRBM(netAmountInHand, totalPayableAmount, fofoId);
34572 vikas.jang 265
                    LOGGER.info("Skipping order due to insufficient balance for id - "+ fofoId+ " Cancelling the BID");
266
                    //throw new ProfitMandiBusinessException("Skipping order unable to create load for id - ", fofoId, " ,Sending mail to RBM");
34501 vikas.jang 267
                }
33338 amit.gupta 268
            }
34443 vikas.jang 269
 
34576 vikas.jang 270
            LOGGER.info("finalBidStatus: {}",finalBidStatus);
34573 vikas.jang 271
            if (finalBidStatus.equals(ProfitMandiConstants.BID_ENUM.CLOSED)) {
36518 aman 272
                // First PO if: no transactions at all, OR all previous first-PO approvals were REJECTED
273
                boolean isFirstPO = !transactionRepository.hasTransactionsByRetailerId(fofoId)
274
                        || transactionApprovalRepository.allFirstPoRejectedByRetailerId(fofoId);
35971 aman 275
 
36518 aman 276
                if (isFirstPO) {
277
                    // Block if a first PO is already pending approval
278
                    if (transactionApprovalRepository.hasPendingFirstPoByRetailerId(fofoId)) {
279
                        throw new ProfitMandiBusinessException(
280
                                "First PO is pending approval",
281
                                fofoId,
282
                                "First PO is already pending approval. Please wait for approval or rejection before creating another order.");
283
                    }
284
 
285
                    // Block first PO if FULL_STOCK_PAYMENT is not done (for LOI-flow partners only)
286
                    if (fofoStore != null && !fofoStore.isInternal() && fofoStore.getCode() != null) {
287
                        com.spice.profitmandi.dao.entity.fofo.PartnerOnBoardingPanel pob =
288
                                partnerOnBoardingPanelRepository.selectByCode(fofoStore.getCode());
289
                        if (pob != null) {
290
                            StoreTimelinetb fspEntry = storeTimelinetbRepository.selectByOnboardingIdAndEvent(
291
                                    pob.getId(), StoreTimeline.FULL_STOCK_PAYMENT);
292
                            if (fspEntry == null) {
293
                                LOGGER.warn("PO creation blocked for fofoId={}, onboardingId={}: FULL_STOCK_PAYMENT not done", fofoId, pob.getId());
294
                                throw new ProfitMandiBusinessException(
295
                                        "Full Stock Payment is required before creating PO",
296
                                        fofoStore.getCode(),
297
                                        "Full Stock Payment must be completed before first PO can be created");
298
                            }
35971 aman 299
                        }
300
                    }
301
                }
302
 
34959 amit 303
                LOGGER.info("totalPayableAmount - {}", totalPayableAmount);
34573 vikas.jang 304
                int transactionId = transactionService.createTransactionInternally(userCart, totalPayableAmount, 0);
305
                //Set here created by
306
                Transaction transaction = transactionRepository.selectById(transactionId);
307
                transaction.setCreatedBy(creatorId);
34637 vikas.jang 308
                LOGGER.info("transaction created by {}", transaction.getCreatedBy());
34573 vikas.jang 309
                commonPaymentService.payThroughWallet(transactionId);
35995 aman 310
 
311
                // First PO always requires approval
312
                if (isFirstPO) {
313
                    approvalRequired = true;
314
                }
315
 
34573 vikas.jang 316
                if (approvalRequired) {
35995 aman 317
                    this.createApproval(transactionId, isFirstPO);
34573 vikas.jang 318
                    if (loanId > 0) {
319
                        LoanTransaction loanTransaction = new LoanTransaction();
320
                        loanTransaction.setLoanId(loanId);
321
                        loanTransaction.setTransactionId(transactionId);
322
                        loanTransactionRepository.persist(loanTransaction);
323
                    }
324
                } else {
325
                    transactionService.processTransaction(transactionId, loanId);
326
                }
35971 aman 327
 
35995 aman 328
                // Send approval email and track timeline for first PO
35971 aman 329
                if (isFirstPO) {
330
                    try {
331
                        sendFirstPOApprovalEmail(fofoStore, transactionId, totalPayableAmount, creatorId);
332
                    } catch (Exception e) {
333
                        LOGGER.error("Failed to send first PO approval email for fofoId: " + fofoId, e);
334
                    }
36518 aman 335
                    // Track PO_CREATION on timeline for first PO (direct call like BILLING — bypasses BLOCKER_MAP
336
                    // since the PO is actually being created, the timeline must record it)
35971 aman 337
                    try {
338
                        if (fofoStore != null && fofoStore.getCode() != null) {
339
                            com.spice.profitmandi.dao.entity.fofo.PartnerOnBoardingPanel pob =
340
                                    partnerOnBoardingPanelRepository.selectByCode(fofoStore.getCode());
341
                            if (pob != null) {
36518 aman 342
                                storeTimelineTatService.createStoreTimelinetb(pob.getId(), StoreTimeline.PO_CREATION);
35971 aman 343
                            }
344
                        }
345
                    } catch (Exception e) {
346
                        LOGGER.error("Failed to track PO_CREATION timeline for fofoId: " + fofoId, e);
347
                    }
348
                }
33213 tejus.loha 349
            }
350
 
33172 tejus.loha 351
        }
34592 vikas.jang 352
        return finalBidStatus;
33172 tejus.loha 353
    }
354
 
35995 aman 355
    public void createApproval(int transactionId, boolean firstPo) {
33213 tejus.loha 356
        TransactionApproval transactionApproval = new TransactionApproval();
357
        transactionApproval.setId(transactionId);
358
        transactionApproval.setStatus(TransactionApprovalStatus.PENDING);
35995 aman 359
        transactionApproval.setFirstPo(firstPo);
33213 tejus.loha 360
        transactionApprovalRepository.persist(transactionApproval);
361
    }
362
 
33172 tejus.loha 363
    private BulkOrderModel createBulkModel(XSSFRow row) throws ProfitMandiBusinessException {
364
        BulkOrderModel bulkOrderModel = new BulkOrderModel();
365
        int i = 0;
366
        bulkOrderModel.setRowIndex(row.getRowNum());
367
        try {
33696 amit.gupta 368
            Cell partnerName = row.getCell(i++);
369
            if (partnerName == null)
33213 tejus.loha 370
                bulkOrderModel.setPartnerName("");
371
            else
33696 amit.gupta 372
                bulkOrderModel.setPartnerName(partnerName.getStringCellValue().trim());
33213 tejus.loha 373
            Cell description = row.getCell(i++);
374
            if (description == null)
375
                bulkOrderModel.setDescription("");
376
            else
377
                bulkOrderModel.setDescription(description.getStringCellValue().trim());
378
 
33172 tejus.loha 379
            bulkOrderModel.setFofoId((int) row.getCell(i++).getNumericCellValue());
380
            bulkOrderModel.setItemId((int) row.getCell(i++).getNumericCellValue());
33213 tejus.loha 381
            bulkOrderModel.setItemPrice(row.getCell(i++).getNumericCellValue());
33172 tejus.loha 382
            bulkOrderModel.setQuantity((int) row.getCell(i++).getNumericCellValue());
383
        } catch (Throwable e) {
384
            LOGGER.info(e.getCause());
33213 tejus.loha 385
            throw new ProfitMandiBusinessException("Field", "Field at row - " + row.getRowNum() + ", column - " + (i - 1), "Invalid field value at - " + ExcelUtils.toAlphabet(i - 1) + (row.getRowNum() + 1) + ", " + ExcelUtils.getCellValue(row.getCell(i - 1)));
33172 tejus.loha 386
        }
387
        LOGGER.info(bulkOrderModel);
388
        return bulkOrderModel;
389
    }
390
 
33341 tejus.loha 391
    // create model for transaction Approval so that finance team see all order and approve
392
    public List<TransactionApprovalModel> getAllPendingTransactionApproval() throws ProfitMandiBusinessException {
393
        List<TransactionApproval> transactionApprovals = transactionApprovalRepository.selectAllPending();
394
        LOGGER.info("list of Approval transaction Id " + transactionApprovals);
395
        List<TransactionApprovalModel> approvalModelList = new ArrayList<>();
396
        for (TransactionApproval transactionApproval : transactionApprovals) {
397
            List<Order> orderList = orderRepository.selectAllByTransactionId(transactionApproval.getId());
398
            Transaction transaction = transactionRepository.selectById(transactionApproval.getId());
399
            List<LineItemModel> lineItemModelList = new ArrayList<>();
35995 aman 400
 
401
            // Fetch stock availability for all items in this order
402
            Map<Integer, List<com.spice.profitmandi.model.WarehouseItemQtyModel>> stockMap = Collections.emptyMap();
403
            try {
404
                int retailerId = transaction.getRetailerId();
405
                FofoStore fofoStore = fofoStoreRepository.selectByRetailerId(retailerId);
406
                if (fofoStore != null) {
407
                    List<Integer> itemIds = orderList.stream()
408
                            .map(o -> o.getLineItem().getItemId())
409
                            .collect(java.util.stream.Collectors.toList());
410
                    stockMap = orderRepository.getItemAvailability(fofoStore.getWarehouseId(), itemIds);
411
                }
412
            } catch (Exception e) {
413
                LOGGER.error("Failed to fetch stock availability for transactionId: {}", transactionApproval.getId(), e);
414
            }
415
 
33341 tejus.loha 416
            for (Order order : orderList) {
417
                LineItem lineItem = order.getLineItem();
418
                LineItemModel lineItemModel = new LineItemModel();
419
                lineItemModel.setItemId(lineItem.getItemId());
420
                lineItemModel.setItemName(lineItem.getItem().getItemDescription());
421
                lineItemModel.setItemQuantity(lineItem.getQuantity());
422
                lineItemModel.setSellingPrice(lineItem.getUnitPrice());
423
                lineItemModel.setDp(tagListingRepository.selectByItemId(lineItem.getItemId()).getSellingPrice());
35995 aman 424
                // Set available stock (show 0 if negative — negative means over-committed)
425
                List<com.spice.profitmandi.model.WarehouseItemQtyModel> itemStock = stockMap.get(lineItem.getItemId());
426
                if (itemStock != null && !itemStock.isEmpty()) {
427
                    int totalAvailable = itemStock.stream().mapToInt(s -> s.getNetAvailability()).sum();
428
                    lineItemModel.setAvailableStock(Math.max(0, totalAvailable));
429
                }
33341 tejus.loha 430
                lineItemModelList.add(lineItemModel);
431
            }
432
            AuthUser authUser = authRepository.selectById(transaction.getCreatedBy());
433
            TransactionApprovalModel transactionApprovalModel = new TransactionApprovalModel();
434
            String retailerName = " ";
435
            retailerName = orderList.get(0).getRetailerName();
436
            transactionApprovalModel.setRetailerName(retailerName);
34573 vikas.jang 437
            if (authUser == null) {
438
                transactionApprovalModel.setCreatedBy(retailerName);
439
            } else {
440
                transactionApprovalModel.setCreatedBy(authUser.getFullName());
441
            }
33341 tejus.loha 442
            transactionApprovalModel.setCreatedOn(transaction.getCreateTimestamp());
443
            transactionApprovalModel.setTransactionId(transactionApproval.getId());
444
            transactionApprovalModel.setLineItemModels(lineItemModelList);
35995 aman 445
            transactionApprovalModel.setFirstPo(transactionApproval.isFirstPo());
33341 tejus.loha 446
            approvalModelList.add(transactionApprovalModel);
33172 tejus.loha 447
 
33341 tejus.loha 448
        }
449
        return approvalModelList;
450
    }
451
 
35956 amit 452
    public List<TransactionApprovalModel> getBulkOrderApprovalReport(LocalDateTime startDate, LocalDateTime endDate) throws ProfitMandiBusinessException {
453
        List<TransactionApproval> transactionApprovals = transactionApprovalRepository.selectAllByDateRange(startDate, endDate);
454
        LOGGER.info("Approval report: found {} records", transactionApprovals.size());
455
        List<TransactionApprovalModel> approvalModelList = new ArrayList<>();
456
        for (TransactionApproval transactionApproval : transactionApprovals) {
457
            List<Order> orderList = orderRepository.selectAllByTransactionId(transactionApproval.getId());
458
            Transaction transaction = transactionRepository.selectById(transactionApproval.getId());
459
            List<LineItemModel> lineItemModelList = new ArrayList<>();
460
            for (Order order : orderList) {
461
                LineItem lineItem = order.getLineItem();
462
                LineItemModel lineItemModel = new LineItemModel();
463
                lineItemModel.setItemId(lineItem.getItemId());
464
                lineItemModel.setItemName(lineItem.getItem().getItemDescription());
465
                lineItemModel.setItemQuantity(lineItem.getQuantity());
466
                lineItemModel.setSellingPrice(lineItem.getUnitPrice());
467
                lineItemModel.setDp(tagListingRepository.selectByItemId(lineItem.getItemId()).getSellingPrice());
468
                lineItemModelList.add(lineItemModel);
469
            }
470
            AuthUser authUser = authRepository.selectById(transaction.getCreatedBy());
471
            TransactionApprovalModel model = new TransactionApprovalModel();
472
            String retailerName = orderList.isEmpty() ? "" : orderList.get(0).getRetailerName();
473
            model.setRetailerName(retailerName);
474
            if (authUser == null) {
475
                model.setCreatedBy(retailerName);
476
            } else {
477
                model.setCreatedBy(authUser.getFullName());
478
            }
479
            model.setCreatedOn(transaction.getCreateTimestamp());
480
            model.setTransactionId(transactionApproval.getId());
481
            model.setLineItemModels(lineItemModelList);
482
            model.setStatus(transactionApproval.getStatus().name());
483
            model.setApprovedBy(transactionApproval.getApprovedBy());
484
            model.setApprovedOn(transactionApproval.getApprovedOn());
485
            model.setRemark(transactionApproval.getRemark());
35995 aman 486
            model.setFirstPo(transactionApproval.isFirstPo());
35956 amit 487
            approvalModelList.add(model);
488
        }
489
        return approvalModelList;
490
    }
491
 
35971 aman 492
    private void sendFirstPOApprovalEmail(FofoStore fofoStore, int transactionId, double totalAmount, int creatorId) throws Exception {
493
        String partnerName = "Partner";
494
        if (fofoStore.getUserAddress() != null && fofoStore.getUserAddress().getName() != null) {
495
            partnerName = fofoStore.getUserAddress().getName();
496
        }
497
        String storeCode = fofoStore.getCode() != null ? fofoStore.getCode() : "";
498
 
499
        String createdByName = "";
500
        if (creatorId > 0) {
501
            AuthUser creator = authRepository.selectById(creatorId);
502
            if (creator != null) {
503
                createdByName = creator.getFullName();
504
            }
505
        }
506
 
507
        String subject = "First PO Created - Approval Required - " + partnerName + " (" + storeCode + ")";
508
 
509
        StringBuilder sb = new StringBuilder();
510
        sb.append("<html><body>");
511
        sb.append("<p>Dear Team,</p>");
512
        sb.append("<p>The <strong>first Purchase Order</strong> has been created for the below partner. Please review and approve.</p><br/>");
513
        sb.append("<table style='border:1px solid black; border-collapse: collapse;'>");
514
        sb.append("<tbody>");
515
        sb.append("<tr>");
516
        sb.append("<th style='border:1px solid black; padding: 5px;'>Partner Name</th>");
517
        sb.append("<th style='border:1px solid black; padding: 5px;'>Store Code</th>");
518
        sb.append("<th style='border:1px solid black; padding: 5px;'>Transaction ID</th>");
519
        sb.append("<th style='border:1px solid black; padding: 5px;'>Total Amount</th>");
520
        sb.append("<th style='border:1px solid black; padding: 5px;'>Created By</th>");
521
        sb.append("</tr>");
522
        sb.append("<tr>");
523
        sb.append("<td style='border:1px solid black; padding: 5px;'>").append(partnerName).append("</td>");
524
        sb.append("<td style='border:1px solid black; padding: 5px;'>").append(storeCode).append("</td>");
525
        sb.append("<td style='border:1px solid black; padding: 5px;'>").append(transactionId).append("</td>");
526
        sb.append("<td style='border:1px solid black; padding: 5px;'>").append(String.format("%.2f", totalAmount)).append("</td>");
527
        sb.append("<td style='border:1px solid black; padding: 5px;'>").append(createdByName).append("</td>");
528
        sb.append("</tr>");
529
        sb.append("</tbody></table>");
530
        sb.append("<br/><p>Please approve this order from the <strong>Transaction Approvals</strong> panel.</p>");
531
        sb.append("<br/><p>Regards,<br/>Smart Dukaan</p>");
532
        sb.append("</body></html>");
533
 
534
        // Send to Sales L3
535
        List<AuthUser> salesL3Users = csService.getAuthUserByCategoryId(
536
                ProfitMandiConstants.TICKET_CATEGORY_SALES, EscalationType.L3);
537
 
538
        List<String> sendTo = new ArrayList<>();
539
        if (!salesL3Users.isEmpty()) {
540
            sendTo.addAll(salesL3Users.stream().map(AuthUser::getEmailId).collect(Collectors.toList()));
541
        }
542
 
543
        if (!sendTo.isEmpty()) {
544
            String[] emailArray = sendTo.toArray(new String[0]);
36064 aman 545
            String[] bccArray = {"tarun.verma@smartdukaan.com", "aman.gupta@smartdukaan.com"};
36399 amit 546
            Utils.sendMailWithAttachments(gmailRelaySender, emailArray, null, bccArray, subject, sb.toString(), true);
35971 aman 547
            LOGGER.info("First PO approval email sent for fofoId: {} transactionId: {}", fofoStore.getId(), transactionId);
548
        }
549
    }
550
 
33172 tejus.loha 551
}