Subversion Repositories SmartDukaan

Rev

Rev 36613 | 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)) {
36534 aman 272
                // Block all PO creation while a first PO is pending approval for this partner
273
                if (transactionApprovalRepository.hasPendingFirstPoByRetailerId(fofoId)) {
274
                    if (type.equals(ProfitMandiConstants.PO_TYPE.MANUAL)) {
275
                        throw new ProfitMandiBusinessException(
276
                                "First PO is pending approval",
277
                                fofoId,
278
                                "First PO is already pending approval for this partner. Please wait for approval or rejection before creating another order.");
279
                    } else {
280
                        LOGGER.warn("Skipping AUTO PO for fofoId={}: first PO is pending approval", fofoId);
281
                        continue;
282
                    }
283
                }
284
 
36518 aman 285
                // First PO if: no transactions at all, OR all previous first-PO approvals were REJECTED
286
                boolean isFirstPO = !transactionRepository.hasTransactionsByRetailerId(fofoId)
287
                        || transactionApprovalRepository.allFirstPoRejectedByRetailerId(fofoId);
35971 aman 288
 
36518 aman 289
                if (isFirstPO) {
290
                    // Block if a first PO is already pending approval
291
                    if (transactionApprovalRepository.hasPendingFirstPoByRetailerId(fofoId)) {
292
                        throw new ProfitMandiBusinessException(
293
                                "First PO is pending approval",
294
                                fofoId,
295
                                "First PO is already pending approval. Please wait for approval or rejection before creating another order.");
296
                    }
297
 
298
                    // Block first PO if FULL_STOCK_PAYMENT is not done (for LOI-flow partners only)
299
                    if (fofoStore != null && !fofoStore.isInternal() && fofoStore.getCode() != null) {
300
                        com.spice.profitmandi.dao.entity.fofo.PartnerOnBoardingPanel pob =
301
                                partnerOnBoardingPanelRepository.selectByCode(fofoStore.getCode());
302
                        if (pob != null) {
303
                            StoreTimelinetb fspEntry = storeTimelinetbRepository.selectByOnboardingIdAndEvent(
304
                                    pob.getId(), StoreTimeline.FULL_STOCK_PAYMENT);
305
                            if (fspEntry == null) {
306
                                LOGGER.warn("PO creation blocked for fofoId={}, onboardingId={}: FULL_STOCK_PAYMENT not done", fofoId, pob.getId());
307
                                throw new ProfitMandiBusinessException(
308
                                        "Full Stock Payment is required before creating PO",
309
                                        fofoStore.getCode(),
310
                                        "Full Stock Payment must be completed before first PO can be created");
311
                            }
35971 aman 312
                        }
313
                    }
314
                }
315
 
34959 amit 316
                LOGGER.info("totalPayableAmount - {}", totalPayableAmount);
34573 vikas.jang 317
                int transactionId = transactionService.createTransactionInternally(userCart, totalPayableAmount, 0);
318
                //Set here created by
319
                Transaction transaction = transactionRepository.selectById(transactionId);
320
                transaction.setCreatedBy(creatorId);
34637 vikas.jang 321
                LOGGER.info("transaction created by {}", transaction.getCreatedBy());
34573 vikas.jang 322
                commonPaymentService.payThroughWallet(transactionId);
35995 aman 323
 
324
                // First PO always requires approval
325
                if (isFirstPO) {
326
                    approvalRequired = true;
327
                }
328
 
34573 vikas.jang 329
                if (approvalRequired) {
35995 aman 330
                    this.createApproval(transactionId, isFirstPO);
34573 vikas.jang 331
                    if (loanId > 0) {
332
                        LoanTransaction loanTransaction = new LoanTransaction();
333
                        loanTransaction.setLoanId(loanId);
334
                        loanTransaction.setTransactionId(transactionId);
335
                        loanTransactionRepository.persist(loanTransaction);
336
                    }
337
                } else {
338
                    transactionService.processTransaction(transactionId, loanId);
339
                }
35971 aman 340
 
35995 aman 341
                // Send approval email and track timeline for first PO
35971 aman 342
                if (isFirstPO) {
343
                    try {
344
                        sendFirstPOApprovalEmail(fofoStore, transactionId, totalPayableAmount, creatorId);
345
                    } catch (Exception e) {
346
                        LOGGER.error("Failed to send first PO approval email for fofoId: " + fofoId, e);
347
                    }
36518 aman 348
                    // Track PO_CREATION on timeline for first PO (direct call like BILLING — bypasses BLOCKER_MAP
349
                    // since the PO is actually being created, the timeline must record it)
35971 aman 350
                    try {
351
                        if (fofoStore != null && fofoStore.getCode() != null) {
352
                            com.spice.profitmandi.dao.entity.fofo.PartnerOnBoardingPanel pob =
353
                                    partnerOnBoardingPanelRepository.selectByCode(fofoStore.getCode());
354
                            if (pob != null) {
36518 aman 355
                                storeTimelineTatService.createStoreTimelinetb(pob.getId(), StoreTimeline.PO_CREATION);
35971 aman 356
                            }
357
                        }
358
                    } catch (Exception e) {
359
                        LOGGER.error("Failed to track PO_CREATION timeline for fofoId: " + fofoId, e);
360
                    }
361
                }
33213 tejus.loha 362
            }
363
 
33172 tejus.loha 364
        }
34592 vikas.jang 365
        return finalBidStatus;
33172 tejus.loha 366
    }
367
 
35995 aman 368
    public void createApproval(int transactionId, boolean firstPo) {
33213 tejus.loha 369
        TransactionApproval transactionApproval = new TransactionApproval();
370
        transactionApproval.setId(transactionId);
371
        transactionApproval.setStatus(TransactionApprovalStatus.PENDING);
35995 aman 372
        transactionApproval.setFirstPo(firstPo);
33213 tejus.loha 373
        transactionApprovalRepository.persist(transactionApproval);
374
    }
375
 
33172 tejus.loha 376
    private BulkOrderModel createBulkModel(XSSFRow row) throws ProfitMandiBusinessException {
377
        BulkOrderModel bulkOrderModel = new BulkOrderModel();
378
        int i = 0;
379
        bulkOrderModel.setRowIndex(row.getRowNum());
380
        try {
33696 amit.gupta 381
            Cell partnerName = row.getCell(i++);
382
            if (partnerName == null)
33213 tejus.loha 383
                bulkOrderModel.setPartnerName("");
384
            else
33696 amit.gupta 385
                bulkOrderModel.setPartnerName(partnerName.getStringCellValue().trim());
33213 tejus.loha 386
            Cell description = row.getCell(i++);
387
            if (description == null)
388
                bulkOrderModel.setDescription("");
389
            else
390
                bulkOrderModel.setDescription(description.getStringCellValue().trim());
391
 
33172 tejus.loha 392
            bulkOrderModel.setFofoId((int) row.getCell(i++).getNumericCellValue());
393
            bulkOrderModel.setItemId((int) row.getCell(i++).getNumericCellValue());
33213 tejus.loha 394
            bulkOrderModel.setItemPrice(row.getCell(i++).getNumericCellValue());
33172 tejus.loha 395
            bulkOrderModel.setQuantity((int) row.getCell(i++).getNumericCellValue());
396
        } catch (Throwable e) {
397
            LOGGER.info(e.getCause());
33213 tejus.loha 398
            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 399
        }
400
        LOGGER.info(bulkOrderModel);
401
        return bulkOrderModel;
402
    }
403
 
33341 tejus.loha 404
    // create model for transaction Approval so that finance team see all order and approve
405
    public List<TransactionApprovalModel> getAllPendingTransactionApproval() throws ProfitMandiBusinessException {
406
        List<TransactionApproval> transactionApprovals = transactionApprovalRepository.selectAllPending();
407
        LOGGER.info("list of Approval transaction Id " + transactionApprovals);
408
        List<TransactionApprovalModel> approvalModelList = new ArrayList<>();
409
        for (TransactionApproval transactionApproval : transactionApprovals) {
410
            List<Order> orderList = orderRepository.selectAllByTransactionId(transactionApproval.getId());
411
            Transaction transaction = transactionRepository.selectById(transactionApproval.getId());
412
            List<LineItemModel> lineItemModelList = new ArrayList<>();
35995 aman 413
 
414
            // Fetch stock availability for all items in this order
415
            Map<Integer, List<com.spice.profitmandi.model.WarehouseItemQtyModel>> stockMap = Collections.emptyMap();
416
            try {
417
                int retailerId = transaction.getRetailerId();
418
                FofoStore fofoStore = fofoStoreRepository.selectByRetailerId(retailerId);
419
                if (fofoStore != null) {
420
                    List<Integer> itemIds = orderList.stream()
421
                            .map(o -> o.getLineItem().getItemId())
422
                            .collect(java.util.stream.Collectors.toList());
423
                    stockMap = orderRepository.getItemAvailability(fofoStore.getWarehouseId(), itemIds);
424
                }
425
            } catch (Exception e) {
426
                LOGGER.error("Failed to fetch stock availability for transactionId: {}", transactionApproval.getId(), e);
427
            }
428
 
33341 tejus.loha 429
            for (Order order : orderList) {
430
                LineItem lineItem = order.getLineItem();
431
                LineItemModel lineItemModel = new LineItemModel();
432
                lineItemModel.setItemId(lineItem.getItemId());
433
                lineItemModel.setItemName(lineItem.getItem().getItemDescription());
434
                lineItemModel.setItemQuantity(lineItem.getQuantity());
435
                lineItemModel.setSellingPrice(lineItem.getUnitPrice());
436
                lineItemModel.setDp(tagListingRepository.selectByItemId(lineItem.getItemId()).getSellingPrice());
35995 aman 437
                // Set available stock (show 0 if negative — negative means over-committed)
438
                List<com.spice.profitmandi.model.WarehouseItemQtyModel> itemStock = stockMap.get(lineItem.getItemId());
439
                if (itemStock != null && !itemStock.isEmpty()) {
440
                    int totalAvailable = itemStock.stream().mapToInt(s -> s.getNetAvailability()).sum();
441
                    lineItemModel.setAvailableStock(Math.max(0, totalAvailable));
442
                }
33341 tejus.loha 443
                lineItemModelList.add(lineItemModel);
444
            }
445
            AuthUser authUser = authRepository.selectById(transaction.getCreatedBy());
446
            TransactionApprovalModel transactionApprovalModel = new TransactionApprovalModel();
447
            String retailerName = " ";
448
            retailerName = orderList.get(0).getRetailerName();
449
            transactionApprovalModel.setRetailerName(retailerName);
34573 vikas.jang 450
            if (authUser == null) {
451
                transactionApprovalModel.setCreatedBy(retailerName);
452
            } else {
453
                transactionApprovalModel.setCreatedBy(authUser.getFullName());
454
            }
33341 tejus.loha 455
            transactionApprovalModel.setCreatedOn(transaction.getCreateTimestamp());
456
            transactionApprovalModel.setTransactionId(transactionApproval.getId());
457
            transactionApprovalModel.setLineItemModels(lineItemModelList);
35995 aman 458
            transactionApprovalModel.setFirstPo(transactionApproval.isFirstPo());
33341 tejus.loha 459
            approvalModelList.add(transactionApprovalModel);
33172 tejus.loha 460
 
33341 tejus.loha 461
        }
462
        return approvalModelList;
463
    }
464
 
35956 amit 465
    public List<TransactionApprovalModel> getBulkOrderApprovalReport(LocalDateTime startDate, LocalDateTime endDate) throws ProfitMandiBusinessException {
466
        List<TransactionApproval> transactionApprovals = transactionApprovalRepository.selectAllByDateRange(startDate, endDate);
467
        LOGGER.info("Approval report: found {} records", transactionApprovals.size());
468
        List<TransactionApprovalModel> approvalModelList = new ArrayList<>();
469
        for (TransactionApproval transactionApproval : transactionApprovals) {
470
            List<Order> orderList = orderRepository.selectAllByTransactionId(transactionApproval.getId());
471
            Transaction transaction = transactionRepository.selectById(transactionApproval.getId());
472
            List<LineItemModel> lineItemModelList = new ArrayList<>();
473
            for (Order order : orderList) {
474
                LineItem lineItem = order.getLineItem();
475
                LineItemModel lineItemModel = new LineItemModel();
476
                lineItemModel.setItemId(lineItem.getItemId());
477
                lineItemModel.setItemName(lineItem.getItem().getItemDescription());
478
                lineItemModel.setItemQuantity(lineItem.getQuantity());
479
                lineItemModel.setSellingPrice(lineItem.getUnitPrice());
480
                lineItemModel.setDp(tagListingRepository.selectByItemId(lineItem.getItemId()).getSellingPrice());
481
                lineItemModelList.add(lineItemModel);
482
            }
483
            AuthUser authUser = authRepository.selectById(transaction.getCreatedBy());
484
            TransactionApprovalModel model = new TransactionApprovalModel();
485
            String retailerName = orderList.isEmpty() ? "" : orderList.get(0).getRetailerName();
486
            model.setRetailerName(retailerName);
487
            if (authUser == null) {
488
                model.setCreatedBy(retailerName);
489
            } else {
490
                model.setCreatedBy(authUser.getFullName());
491
            }
492
            model.setCreatedOn(transaction.getCreateTimestamp());
493
            model.setTransactionId(transactionApproval.getId());
494
            model.setLineItemModels(lineItemModelList);
495
            model.setStatus(transactionApproval.getStatus().name());
496
            model.setApprovedBy(transactionApproval.getApprovedBy());
497
            model.setApprovedOn(transactionApproval.getApprovedOn());
498
            model.setRemark(transactionApproval.getRemark());
35995 aman 499
            model.setFirstPo(transactionApproval.isFirstPo());
35956 amit 500
            approvalModelList.add(model);
501
        }
502
        return approvalModelList;
503
    }
504
 
35971 aman 505
    private void sendFirstPOApprovalEmail(FofoStore fofoStore, int transactionId, double totalAmount, int creatorId) throws Exception {
506
        String partnerName = "Partner";
507
        if (fofoStore.getUserAddress() != null && fofoStore.getUserAddress().getName() != null) {
508
            partnerName = fofoStore.getUserAddress().getName();
509
        }
510
        String storeCode = fofoStore.getCode() != null ? fofoStore.getCode() : "";
511
 
512
        String createdByName = "";
513
        if (creatorId > 0) {
514
            AuthUser creator = authRepository.selectById(creatorId);
515
            if (creator != null) {
516
                createdByName = creator.getFullName();
517
            }
518
        }
519
 
520
        String subject = "First PO Created - Approval Required - " + partnerName + " (" + storeCode + ")";
521
 
522
        StringBuilder sb = new StringBuilder();
523
        sb.append("<html><body>");
524
        sb.append("<p>Dear Team,</p>");
525
        sb.append("<p>The <strong>first Purchase Order</strong> has been created for the below partner. Please review and approve.</p><br/>");
526
        sb.append("<table style='border:1px solid black; border-collapse: collapse;'>");
527
        sb.append("<tbody>");
528
        sb.append("<tr>");
529
        sb.append("<th style='border:1px solid black; padding: 5px;'>Partner Name</th>");
530
        sb.append("<th style='border:1px solid black; padding: 5px;'>Store Code</th>");
531
        sb.append("<th style='border:1px solid black; padding: 5px;'>Transaction ID</th>");
532
        sb.append("<th style='border:1px solid black; padding: 5px;'>Total Amount</th>");
533
        sb.append("<th style='border:1px solid black; padding: 5px;'>Created By</th>");
534
        sb.append("</tr>");
535
        sb.append("<tr>");
536
        sb.append("<td style='border:1px solid black; padding: 5px;'>").append(partnerName).append("</td>");
537
        sb.append("<td style='border:1px solid black; padding: 5px;'>").append(storeCode).append("</td>");
538
        sb.append("<td style='border:1px solid black; padding: 5px;'>").append(transactionId).append("</td>");
539
        sb.append("<td style='border:1px solid black; padding: 5px;'>").append(String.format("%.2f", totalAmount)).append("</td>");
540
        sb.append("<td style='border:1px solid black; padding: 5px;'>").append(createdByName).append("</td>");
541
        sb.append("</tr>");
542
        sb.append("</tbody></table>");
543
        sb.append("<br/><p>Please approve this order from the <strong>Transaction Approvals</strong> panel.</p>");
544
        sb.append("<br/><p>Regards,<br/>Smart Dukaan</p>");
545
        sb.append("</body></html>");
546
 
547
        // Send to Sales L3
548
        List<AuthUser> salesL3Users = csService.getAuthUserByCategoryId(
36613 aman 549
                ProfitMandiConstants.TICKET_CATEGORY_SALES, EscalationType.L4);
35971 aman 550
 
551
        List<String> sendTo = new ArrayList<>();
552
        if (!salesL3Users.isEmpty()) {
553
            sendTo.addAll(salesL3Users.stream().map(AuthUser::getEmailId).collect(Collectors.toList()));
554
        }
555
 
556
        if (!sendTo.isEmpty()) {
557
            String[] emailArray = sendTo.toArray(new String[0]);
36936 vikas 558
            String[] bccArray = {"tarun.verma@smartdukaan.com"};
36399 amit 559
            Utils.sendMailWithAttachments(gmailRelaySender, emailArray, null, bccArray, subject, sb.toString(), true);
35971 aman 560
            LOGGER.info("First PO approval email sent for fofoId: {} transactionId: {}", fofoStore.getId(), transactionId);
561
        }
562
    }
563
 
33172 tejus.loha 564
}