Subversion Repositories SmartDukaan

Rev

Rev 36103 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 36103 Rev 36397
Line 885... Line 885...
885
                inventoryItems = inventoryItems.stream().filter(x -> !agedSerialNumbers.contains(x.getSerialNumber())).collect(Collectors.toSet());
885
                inventoryItems = inventoryItems.stream().filter(x -> !agedSerialNumbers.contains(x.getSerialNumber())).collect(Collectors.toSet());
886
            }
886
            }
887
 
887
 
888
            if (inventoryItems.size() == 0) return 0;
888
            if (inventoryItems.size() == 0) return 0;
889
 
889
 
890
            Map<Integer, List<InventoryItem>> catalogInventoryItemMap = inventoryItems.stream().collect(Collectors.groupingBy(x -> x.getItem().getCatalogItemId()));
890
            // Resolve GRN billing date per inventory item: InventoryItem.purchaseId -> Purchase.purchaseReference -> Order.billingTimestamp.
891
            Map<CatalogSummaryModel, List<SchemeSummaryModel>> catalogSchemeSummaryMap = tagListingRepository.getModelSchemesByCatalogIdsAndType(retailerId,
891
            // Scheme resolution for OUT must use each item's own GRN billing date, not fofoOrder.createTimestamp.
892
                    partnerType, new ArrayList<>(catalogInventoryItemMap.keySet()), fofoOrder.getCreateTimestamp());
892
            Set<Integer> purchaseIds = inventoryItems.stream().map(InventoryItem::getPurchaseId).collect(Collectors.toSet());
-
 
893
            Map<Integer, LocalDateTime> purchaseBillingDateMap = new HashMap<>();
-
 
894
            for (Integer purchaseId : purchaseIds) {
-
 
895
                purchaseBillingDateMap.put(purchaseId, purchaseService.getBillingDateOfPurchase(purchaseId));
-
 
896
            }
893
 
897
 
-
 
898
            // Group items by (GRN billingDate -> catalogId -> items). Items with identical GRN billing date share a scheme lookup.
-
 
899
            Map<LocalDateTime, Map<Integer, List<InventoryItem>>> billingDateCatalogItemsMap = inventoryItems.stream()
-
 
900
                    .collect(Collectors.groupingBy(
894
            LOGGER.info("catalogSchemeSummaryMap - {}", catalogSchemeSummaryMap);
901
                            x -> purchaseBillingDateMap.get(x.getPurchaseId()),
-
 
902
                            Collectors.groupingBy(x -> x.getItem().getCatalogItemId())));
895
 
903
 
896
            // N+1 fix: Batch fetch all SchemeInOut records for all inventoryItems at once
904
            // N+1 fix: Batch fetch all SchemeInOut records for all inventoryItems at once
897
            Set<Integer> allInventoryItemIds = inventoryItems.stream().map(InventoryItem::getId).collect(Collectors.toSet());
905
            Set<Integer> allInventoryItemIds = inventoryItems.stream().map(InventoryItem::getId).collect(Collectors.toSet());
898
            List<SchemeInOut> allSchemeInOuts = schemeInOutRepository.selectByInventoryItemIds(allInventoryItemIds);
906
            List<SchemeInOut> allSchemeInOuts = schemeInOutRepository.selectByInventoryItemIds(allInventoryItemIds);
899
            Map<Integer, List<SchemeInOut>> schemeInOutByInventoryItemId = allSchemeInOuts.stream()
907
            Map<Integer, List<SchemeInOut>> schemeInOutByInventoryItemId = allSchemeInOuts.stream()
900
                    .collect(Collectors.groupingBy(SchemeInOut::getInventoryItemId));
908
                    .collect(Collectors.groupingBy(SchemeInOut::getInventoryItemId));
901
 
909
 
902
            int count = 0;
910
            int count = 0;
-
 
911
            for (Map.Entry<LocalDateTime, Map<Integer, List<InventoryItem>>> billingDateEntry : billingDateCatalogItemsMap.entrySet()) {
-
 
912
                LocalDateTime grnBillingDate = billingDateEntry.getKey();
-
 
913
                Map<Integer, List<InventoryItem>> catalogInventoryItemMap = billingDateEntry.getValue();
-
 
914
                Map<CatalogSummaryModel, List<SchemeSummaryModel>> catalogSchemeSummaryMap = tagListingRepository.getModelSchemesByCatalogIdsAndType(retailerId,
-
 
915
                        partnerType, new ArrayList<>(catalogInventoryItemMap.keySet()), grnBillingDate);
-
 
916
 
-
 
917
                LOGGER.info("catalogSchemeSummaryMap (grnBillingDate={}) - {}", grnBillingDate, catalogSchemeSummaryMap);
-
 
918
 
903
            for (Map.Entry<CatalogSummaryModel, List<SchemeSummaryModel>> catalogSummaryModelListEntry : catalogSchemeSummaryMap.entrySet()) {
919
                for (Map.Entry<CatalogSummaryModel, List<SchemeSummaryModel>> catalogSummaryModelListEntry : catalogSchemeSummaryMap.entrySet()) {
904
                CatalogSummaryModel catalogSummaryModel = catalogSummaryModelListEntry.getKey();
920
                    CatalogSummaryModel catalogSummaryModel = catalogSummaryModelListEntry.getKey();
905
                List<SchemeSummaryModel> schemeSummaryModels = catalogSummaryModelListEntry.getValue().stream().filter(x -> x != null).collect(Collectors.toList());
921
                    List<SchemeSummaryModel> schemeSummaryModels = catalogSummaryModelListEntry.getValue().stream().filter(x -> x != null).collect(Collectors.toList());
906
 
922
 
907
                schemeSummaryModels.stream().filter(x -> x.getSchemeType().getTransactionType().equals(StockTransactionType.OUT)).forEach(x -> x.setProcess(true));
923
                    schemeSummaryModels.stream().filter(x -> x.getSchemeType().getTransactionType().equals(StockTransactionType.OUT)).forEach(x -> x.setProcess(true));
908
                if (schemeSummaryModels.stream().filter(x -> x.isProcess()).count() == 0) continue;
924
                    if (schemeSummaryModels.stream().filter(x -> x.isProcess()).count() == 0) continue;
909
 
925
 
910
                // Create map once per catalog instead of per inventoryItem
926
                    // Create map once per catalog instead of per inventoryItem
911
                Map<Integer, SchemeSummaryModel> schemeSummaryModelMap = schemeSummaryModels.stream().collect(Collectors.toMap(x -> x.getSchemeId(), x -> x));
927
                    Map<Integer, SchemeSummaryModel> schemeSummaryModelMap = schemeSummaryModels.stream().collect(Collectors.toMap(x -> x.getSchemeId(), x -> x));
912
 
928
 
913
                List<InventoryItem> modelInventoryItems = catalogInventoryItemMap.get(catalogSummaryModel.getCatalogId());
929
                    List<InventoryItem> modelInventoryItems = catalogInventoryItemMap.get(catalogSummaryModel.getCatalogId());
914
                for (InventoryItem inventoryItem : modelInventoryItems) {
930
                    for (InventoryItem inventoryItem : modelInventoryItems) {
915
                    // N+1 fix: Use pre-fetched schemeInOut map instead of querying per inventoryItem
931
                    // N+1 fix: Use pre-fetched schemeInOut map instead of querying per inventoryItem
916
                    List<SchemeInOut> sios = schemeInOutByInventoryItemId.getOrDefault(inventoryItem.getId(), Collections.emptyList());
932
                    List<SchemeInOut> sios = schemeInOutByInventoryItemId.getOrDefault(inventoryItem.getId(), Collections.emptyList());
917
 
933
 
918
                    List<Integer> creditedSchemeIds = sios.stream()
934
                    List<Integer> creditedSchemeIds = sios.stream()
919
                            .filter(x -> x.getStatus().equals(SchemePayoutStatus.CREDITED))
935
                            .filter(x -> x.getStatus().equals(SchemePayoutStatus.CREDITED))
Line 951... Line 967...
951
                    if (inventoryItemCashback > 0 || sioRejectedValue > 0) {
967
                    if (inventoryItemCashback > 0 || sioRejectedValue > 0) {
952
                        count++;
968
                        count++;
953
                        totalCashback += inventoryItemCashback - sioRejectedValue;
969
                        totalCashback += inventoryItemCashback - sioRejectedValue;
954
                    }
970
                    }
955
                }
971
                }
-
 
972
                }
956
            }
973
            }
957
 
974
 
958
            if (count > 0) {
975
            if (count > 0) {
959
                walletService.addAmountToWallet(
976
                walletService.addAmountToWallet(
960
                        retailerId, fofoOrderId, WalletReferenceType.SCHEME_OUT, "Sales margin for invoice number "
977
                        retailerId, fofoOrderId, WalletReferenceType.SCHEME_OUT, "Sales margin for invoice number "
Line 1257... Line 1274...
1257
        }
1274
        }
1258
    }
1275
    }
1259
 
1276
 
1260
 
1277
 
1261
    @Override
1278
    @Override
1262
    public double getTotalMargin(int itemId, PartnerType partnerType, LocalDateTime dateTime) {
-
 
1263
        Session session = sessionFactory.getCurrentSession();
-
 
1264
        CriteriaBuilder cb = session.getCriteriaBuilder();
-
 
1265
        CriteriaQuery<Double> criteriaQuery = cb.createQuery(Double.class);
-
 
1266
        Root<SchemeItem> schemeItem = criteriaQuery.from(SchemeItem.class);
-
 
1267
        Root<Scheme> scheme = criteriaQuery.from(Scheme.class);
-
 
1268
        Predicate schemePredicate = cb.equal(scheme.get(ProfitMandiConstants.AMOUNT_TYPE), AmountType.PERCENTAGE);
-
 
1269
        Predicate lessThanPredicate = cb.lessThanOrEqualTo(scheme.get(ProfitMandiConstants.END_DATE_TIME), dateTime);
-
 
1270
        Predicate greaterThanPredicate = cb.greaterThanOrEqualTo(scheme.get(ProfitMandiConstants.START_DATE_TIME),
-
 
1271
                dateTime);
-
 
1272
        Predicate joinPredicate = cb.equal(scheme.get("id"), schemeItem.get("schemeId"));
-
 
1273
        Predicate schemeItemPredicate = cb.equal(schemeItem.get(ProfitMandiConstants.ITEM_ID), itemId);
-
 
1274
        criteriaQuery.select(cb.sum(scheme.get(ProfitMandiConstants.AMOUNT))).where(schemePredicate, lessThanPredicate,
-
 
1275
                greaterThanPredicate, schemeItemPredicate, joinPredicate);
-
 
1276
 
-
 
1277
        Query<Double> query = session.createQuery(criteriaQuery);
-
 
1278
        return query.getSingleResult() + ProfitMandiConstants.SCHEME_INVESTMENT_MARGIN;
-
 
1279
 
-
 
1280
    }
-
 
1281
 
-
 
1282
 
-
 
1283
    @Override
-
 
1284
    public Map<Integer, Float> getCatalogSchemeCashBack(int fofoId, List<Integer> catalogIds) throws
1279
    public Map<Integer, Float> getCatalogSchemeCashBack(int fofoId, List<Integer> catalogIds) throws
1285
            ProfitMandiBusinessException {
1280
            ProfitMandiBusinessException {
1286
        PartnerType partnerType = partnerTypeChangeService.getTypeOnDate(fofoId, LocalDate.now());
1281
        PartnerType partnerType = partnerTypeChangeService.getTypeOnDate(fofoId, LocalDate.now());
1287
        Map<CatalogSummaryModel, List<SchemeSummaryModel>> catalogModelMap = tagListingRepository.getModelSchemesByCatalogIdsAndType(fofoId, partnerType, catalogIds, LocalDate.now().atStartOfDay());
1282
        Map<CatalogSummaryModel, List<SchemeSummaryModel>> catalogModelMap = tagListingRepository.getModelSchemesByCatalogIdsAndType(fofoId, partnerType, catalogIds, LocalDate.now().atStartOfDay());
1288
 
1283
 
Line 1551... Line 1546...
1551
                    schemeInOutRepository.persist(sio);
1546
                    schemeInOutRepository.persist(sio);
1552
                }
1547
                }
1553
            }
1548
            }
1554
        }
1549
        }
1555
    }
1550
    }
-
 
1551
 
-
 
1552
    @Override
-
 
1553
    public void updateSchemeItemWindow(long schemeItemId, LocalDateTime startDate, LocalDateTime endDate, int updatedBy)
-
 
1554
            throws ProfitMandiBusinessException {
-
 
1555
        SchemeItem item = schemeItemRepository.selectById(schemeItemId);
-
 
1556
        if (item == null) {
-
 
1557
            throw new ProfitMandiBusinessException("schemeItemId", String.valueOf(schemeItemId), "Scheme item not found");
-
 
1558
        }
-
 
1559
 
-
 
1560
        Scheme scheme = schemeRepository.selectById(item.getSchemeId());
-
 
1561
        if (scheme == null) {
-
 
1562
            throw new ProfitMandiBusinessException("schemeId", String.valueOf(item.getSchemeId()), "Scheme not found");
-
 
1563
        }
-
 
1564
 
-
 
1565
        if (startDate.isAfter(endDate)) {
-
 
1566
            throw new ProfitMandiBusinessException("startDate, endDate",
-
 
1567
                    FormattingUtils.formatDate(startDate) + ", " + FormattingUtils.formatDate(endDate),
-
 
1568
                    "Start date must be before end date");
-
 
1569
        }
-
 
1570
 
-
 
1571
        // Containment: item window must be within scheme window
-
 
1572
        if (startDate.isBefore(scheme.getStartDateTime()) || endDate.isAfter(scheme.getEndDateTime())) {
-
 
1573
            throw new ProfitMandiBusinessException("startDate, endDate",
-
 
1574
                    FormattingUtils.formatDate(startDate) + ", " + FormattingUtils.formatDate(endDate),
-
 
1575
                    "Item dates must be within scheme window ["
-
 
1576
                            + FormattingUtils.formatDate(scheme.getStartDateTime()) + " - "
-
 
1577
                            + FormattingUtils.formatDate(scheme.getEndDateTime()) + "]");
-
 
1578
        }
-
 
1579
 
-
 
1580
        // Non-overlap check within same (catalogId, schemeId)
-
 
1581
        if (schemeItemRepository.existsOverlapping(item.getCatalogId(), item.getSchemeId(), startDate, endDate, item.getId())) {
-
 
1582
            throw new ProfitMandiBusinessException("startDate, endDate",
-
 
1583
                    FormattingUtils.formatDate(startDate) + ", " + FormattingUtils.formatDate(endDate),
-
 
1584
                    "Date range overlaps with existing entry for this model in this scheme");
-
 
1585
        }
-
 
1586
 
-
 
1587
        item.setStartDate(startDate);
-
 
1588
        item.setEndDate(endDate);
-
 
1589
        item.setUpdatedBy(updatedBy);
-
 
1590
        item.setUpdatedOn(LocalDateTime.now());
-
 
1591
        schemeItemRepository.persist(item);
-
 
1592
    }
-
 
1593
 
-
 
1594
    @Override
-
 
1595
    public SchemeItem addSchemeItemWithDates(int schemeId, int catalogId, LocalDateTime startDate, LocalDateTime endDate, int createdBy)
-
 
1596
            throws ProfitMandiBusinessException {
-
 
1597
        Scheme scheme = schemeRepository.selectById(schemeId);
-
 
1598
        if (scheme == null) {
-
 
1599
            throw new ProfitMandiBusinessException("schemeId", String.valueOf(schemeId), "Scheme not found");
-
 
1600
        }
-
 
1601
 
-
 
1602
        if (startDate.isAfter(endDate)) {
-
 
1603
            throw new ProfitMandiBusinessException("startDate, endDate",
-
 
1604
                    FormattingUtils.formatDate(startDate) + ", " + FormattingUtils.formatDate(endDate),
-
 
1605
                    "Start date must be before end date");
-
 
1606
        }
-
 
1607
 
-
 
1608
        // Containment
-
 
1609
        if (startDate.isBefore(scheme.getStartDateTime()) || endDate.isAfter(scheme.getEndDateTime())) {
-
 
1610
            throw new ProfitMandiBusinessException("startDate, endDate",
-
 
1611
                    FormattingUtils.formatDate(startDate) + ", " + FormattingUtils.formatDate(endDate),
-
 
1612
                    "Item dates must be within scheme window ["
-
 
1613
                            + FormattingUtils.formatDate(scheme.getStartDateTime()) + " - "
-
 
1614
                            + FormattingUtils.formatDate(scheme.getEndDateTime()) + "]");
-
 
1615
        }
-
 
1616
 
-
 
1617
        // Non-overlap
-
 
1618
        if (schemeItemRepository.existsOverlapping(catalogId, schemeId, startDate, endDate, 0)) {
-
 
1619
            throw new ProfitMandiBusinessException("startDate, endDate",
-
 
1620
                    FormattingUtils.formatDate(startDate) + ", " + FormattingUtils.formatDate(endDate),
-
 
1621
                    "Date range overlaps with existing entry for this model in this scheme");
-
 
1622
        }
-
 
1623
 
-
 
1624
        SchemeItem item = new SchemeItem();
-
 
1625
        item.setSchemeId(schemeId);
-
 
1626
        item.setCatalogId(catalogId);
-
 
1627
        item.setStartDate(startDate);
-
 
1628
        item.setEndDate(endDate);
-
 
1629
        item.setCreateTimestamp(LocalDateTime.now());
-
 
1630
        item.setUpdatedBy(createdBy);
-
 
1631
        item.setUpdatedOn(LocalDateTime.now());
-
 
1632
        schemeItemRepository.persist(item);
-
 
1633
        return item;
-
 
1634
    }
-
 
1635
 
-
 
1636
    @Override
-
 
1637
    public List<SchemeItem> clampSchemeItems(int schemeId, LocalDateTime newStart, LocalDateTime newEnd, int updatedBy)
-
 
1638
            throws ProfitMandiBusinessException {
-
 
1639
        List<SchemeItem> outsideItems = schemeItemRepository.selectItemsOutsideWindow(schemeId, newStart, newEnd);
-
 
1640
        List<SchemeItem> clamped = new ArrayList<>();
-
 
1641
 
-
 
1642
        for (SchemeItem item : outsideItems) {
-
 
1643
            LocalDateTime clampedStart = item.getStartDate().isBefore(newStart) ? newStart : item.getStartDate();
-
 
1644
            LocalDateTime clampedEnd = item.getEndDate().isAfter(newEnd) ? newEnd : item.getEndDate();
-
 
1645
 
-
 
1646
            if (clampedStart.isAfter(clampedEnd) || clampedStart.isEqual(clampedEnd)) {
-
 
1647
                throw new ProfitMandiBusinessException("schemeId, catalogId",
-
 
1648
                        schemeId + ", " + item.getCatalogId(),
-
 
1649
                        "Cannot clamp: item window for catalogId " + item.getCatalogId()
-
 
1650
                                + " (" + FormattingUtils.formatDate(item.getStartDate()) + " - " + FormattingUtils.formatDate(item.getEndDate()) + ")"
-
 
1651
                                + " falls entirely outside new scheme window ("
-
 
1652
                                + FormattingUtils.formatDate(newStart) + " - " + FormattingUtils.formatDate(newEnd)
-
 
1653
                                + "). Adjust this item first.");
-
 
1654
            }
-
 
1655
 
-
 
1656
            item.setStartDate(clampedStart);
-
 
1657
            item.setEndDate(clampedEnd);
-
 
1658
            item.setUpdatedBy(updatedBy);
-
 
1659
            item.setUpdatedOn(LocalDateTime.now());
-
 
1660
            schemeItemRepository.persist(item);
-
 
1661
            clamped.add(item);
-
 
1662
        }
-
 
1663
        return clamped;
-
 
1664
    }
1556
}
1665
}