Subversion Repositories SmartDukaan

Rev

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

Rev 37497 Rev 37505
Line 512... Line 512...
512
        setSalesTargetsForDate(LocalDate.now());
512
        setSalesTargetsForDate(LocalDate.now());
513
    }
513
    }
514
 
514
 
515
    @Override
515
    @Override
516
    public void setSalesTargetsForDate(LocalDate date) {
516
    public void setSalesTargetsForDate(LocalDate date) {
517
        LocalDateTime dayStart = date.atStartOfDay();
517
        // Sales target for a person = (own_monthly_target − MTD_own_achievement) /
518
        LocalDateTime dayEnd = date.plusDays(1).atStartOfDay();
518
        // remainingDays, then split by warehouse stock mix — exactly like RBM, but
519
 
-
 
520
        // Persisted RBM snapshots for the target date (one row per RBM × warehouse).
519
        // scoped to the Sales person's OWN assigned partners (no RBM roll-up).
521
        List<RbmTargets> todayRbmSnapshots = rbmTargetsRepository.selectTargetsByDates(dayStart, dayEnd);
-
 
522
        if (todayRbmSnapshots.isEmpty()) {
520
        LocalDate monthStart = date.withDayOfMonth(1);
523
            LOGGER.warn("setSalesTargetsForDate: no RBM snapshots for {}; run pushRbmTargets first", date);
521
        int remainingWorkingDays = (int) getRemainingDaysInMonth(date);
524
            return;
-
 
525
        }
-
 
526
 
522
 
527
        // Index snapshots by (rbmAuthId, warehouseId) for O(1) roll-up.
523
        // Warehouse-level stock mix (same source used by setMovementWiseRbmTargets).
528
        // rbm_auth_id → warehouseId → snapshot row.
-
 
529
        Map<Integer, Map<Integer, RbmTargets>> byRbmByWh = new HashMap<>();
524
        Map<Integer, WarehouseMobileStockByMovementModel> whStockByWh = new HashMap<>();
530
        for (RbmTargets s : todayRbmSnapshots) {
525
        for (WarehouseMobileStockByMovementModel s : getWarehouseMobileStockByMovement()) {
531
            byRbmByWh.computeIfAbsent(s.getRbmAuthId(), k -> new HashMap<>()).put(s.getWarehouseId(), s);
526
            whStockByWh.put(s.getWarehouseId(), s);
532
        }
527
        }
533
        Set<Integer> allSnapshotRbms = byRbmByWh.keySet();
-
 
534
 
528
 
535
        // Sales roles + their (categoryId, escalationType) mapping — mirrors
-
 
536
        // MonitorController /indent/today_po_table_fragment so both places agree.
-
 
537
        String[][] roles = {
529
        String[][] roles = {
538
                {"ASM", "4", "L1"}, {"CM", "4", "L2"}, {"DM", "4", "L3"},
530
                {"ASM", "4", "L1"}, {"CM", "4", "L2"}, {"DM", "4", "L3"},
539
                {"BM", "4", "L4"}, {"RSM", "4", "L5"}, {"NSM", "4", "L6"}
531
                {"BM", "4", "L4"}, {"RSM", "4", "L5"}, {"NSM", "4", "L6"}
540
        };
532
        };
541
 
533
 
542
        int written = 0;
-
 
543
        // Stamp rows within the target day so date-range queries pick them up
-
 
544
        // for the right day, even during backfill of a past date.
-
 
545
        LocalDate today = LocalDate.now();
534
        LocalDate today = LocalDate.now();
546
        LocalDateTime stamp = date.equals(today) ? LocalDateTime.now() : date.atTime(java.time.LocalTime.NOON);
535
        LocalDateTime stamp = date.equals(today) ? LocalDateTime.now() : date.atTime(java.time.LocalTime.NOON);
-
 
536
        int written = 0, zeroTargetSkipped = 0;
-
 
537
 
547
        for (String[] r : roles) {
538
        for (String[] r : roles) {
548
            String role = r[0];
539
            String role = r[0];
549
            int catId = Integer.parseInt(r[1]);
540
            int catId = Integer.parseInt(r[1]);
550
            EscalationType level = EscalationType.valueOf(r[2]);
-
 
551
            for (AuthUser sales : csService.getAuthUserByCategoryId(catId, level)) {
-
 
552
                if (!sales.isActive()) continue;
541
            String levelStr = r[2];
553
 
542
 
554
                // Downline authIds (includes self; we skip self since Sales users
543
            // Monthly target per (authId × warehouse) for this role.
555
                // aren't RBMs and won't appear in snapshot).
544
            // Use the target date's month so backfills for past months work correctly.
556
                Set<Integer> downline = new HashSet<>();
-
 
557
                downline.add(sales.getId());
-
 
558
                List<Integer> reportees = authService.getAllReportees(sales.getId());
545
            List<SalesHierarchyMonthlyTargetModel> monthlyTgts = getSalesMonthlyTargetByRole(catId, levelStr, date);
559
                if (reportees != null) downline.addAll(reportees);
546
            if (monthlyTgts.isEmpty()) continue;
560
                downline.retainAll(allSnapshotRbms);  // keep only RBMs with today's snapshot
-
 
561
                if (downline.isEmpty()) continue;      // no RBMs under this Sales person today
-
 
562
 
547
 
563
                // Aggregate per warehouse across the downline RBMs.
548
            // MTD achieved per (authId × warehouse) for this role. Same-day date range → MTD.
564
                Map<Integer, float[]> perWh = new LinkedHashMap<>();  // wh → [hid, fast, run, slow, other]
-
 
565
                for (int rbmAuthId : downline) {
549
            Map<String, Double> mtdByKey = new HashMap<>();
566
                    Map<Integer, RbmTargets> whMap = byRbmByWh.get(rbmAuthId);
-
 
567
                    if (whMap == null) continue;
550
            for (SalesHierarchyAchievedByMovementModel a :
568
                    for (Map.Entry<Integer, RbmTargets> e : whMap.entrySet()) {
551
                    getSalesAchievementByRole(catId, levelStr, monthStart, date.plusDays(1))) {
569
                        RbmTargets t = e.getValue();
552
                double totBilled =
570
                        float[] acc = perWh.computeIfAbsent(e.getKey(), k -> new float[5]);
-
 
571
                        acc[0] += t.getHidTarget();
553
                        a.getHidBilled()
572
                        acc[1] += t.getFastMovingTarget();
554
                                + a.getFastMovingBilled()
573
                        acc[2] += t.getRunningtarget();
555
                                + (a.getRunningBilled() != null ? a.getRunningBilled() : 0)
574
                        acc[3] += t.getSlowMovingtarget();
556
                                + (a.getSlowMovingBilled() != null ? a.getSlowMovingBilled() : 0)
575
                        acc[4] += t.getOtherTarget();
557
                                + (a.getOtherBilled() != null ? a.getOtherBilled() : 0);
576
                    }
558
                mtdByKey.merge(a.getAuthId() + "-" + a.getWarehouseId(), totBilled, Double::sum);
577
                }
559
            }
578
 
560
 
579
                for (Map.Entry<Integer, float[]> e : perWh.entrySet()) {
561
            for (SalesHierarchyMonthlyTargetModel mt : monthlyTgts) {
580
                    float[] acc = e.getValue();
-
 
581
                    SalesTargets st = new SalesTargets();
-
 
582
                    st.setSalesAuthId(sales.getId());
-
 
583
                    st.setSalesName(sales.getFullName());
-
 
584
                    st.setRole(role);
-
 
585
                    st.setWarehouseId(e.getKey());
-
 
586
                    st.setHidTarget(acc[0]);
-
 
587
                    st.setFastMovingTarget(acc[1]);
-
 
588
                    st.setRunningTarget(acc[2]);
562
                if (mt.getMonthlyTarget() <= 0) {
589
                    st.setSlowMovingTarget(acc[3]);
-
 
590
                    st.setOtherTarget(acc[4]);
563
                    zeroTargetSkipped++;
591
                    st.setCreateTimestamp(stamp);
-
 
592
                    salesTargetsRepository.persist(st);
-
 
593
                    written++;
564
                    continue;
594
                }
565
                }
-
 
566
                double achieved = mtdByKey.getOrDefault(mt.getAuthId() + "-" + mt.getWarehouseId(), 0.0);
-
 
567
                double remaining = mt.getMonthlyTarget() - achieved;
-
 
568
                double todayTarget = (remainingWorkingDays > 0 && remaining > 0)
-
 
569
                        ? remaining / remainingWorkingDays : 0;
-
 
570
 
-
 
571
                WarehouseMobileStockByMovementModel stock = whStockByWh.get(mt.getWarehouseId());
-
 
572
                if (stock == null || stock.getTotalAvailabilityPrice() <= 0) continue;
-
 
573
                float total = stock.getTotalAvailabilityPrice();
-
 
574
 
-
 
575
                SalesTargets st = new SalesTargets();
-
 
576
                st.setSalesAuthId(mt.getAuthId());
-
 
577
                st.setSalesName(mt.getName());
-
 
578
                st.setRole(role);
-
 
579
                st.setWarehouseId(mt.getWarehouseId());
-
 
580
                st.setHidTarget((float) ((stock.getTotalHidCatalogPrice() / total) * todayTarget));
-
 
581
                st.setFastMovingTarget((float) ((stock.getTotalFastMovingCatalogPrice() / total) * todayTarget));
-
 
582
                st.setSlowMovingTarget((float) ((stock.getTotalSlowMovingCatalogPrice() / total) * todayTarget));
-
 
583
                st.setRunningTarget((float) ((stock.getTotalRunningCatalogPrice() / total) * todayTarget));
-
 
584
                st.setOtherTarget((float) ((stock.getTotalOtherCategoryCatalogPrice() / total) * todayTarget));
-
 
585
                st.setCreateTimestamp(stamp);
-
 
586
                salesTargetsRepository.persist(st);
-
 
587
                written++;
595
            }
588
            }
596
        }
589
        }
597
        LOGGER.info("setSalesTargetsForDate: wrote {} sales_targets rows for {}", written, date);
590
        LOGGER.info("setSalesTargetsForDate: wrote {} sales_targets rows for {} ({} rows skipped due to zero monthly target)",
-
 
591
                written, date, zeroTargetSkipped);
598
    }
592
    }
599
 
593
 
600
    @Override
594
    @Override
601
    public List<SalesTargets> getSalesTargetsByDates(LocalDate startDate, LocalDate endDate) {
595
    public List<SalesTargets> getSalesTargetsByDates(LocalDate startDate, LocalDate endDate) {
602
        return salesTargetsRepository.selectTargetsByDates(startDate.atStartOfDay(), endDate.atStartOfDay());
596
        return salesTargetsRepository.selectTargetsByDates(startDate.atStartOfDay(), endDate.atStartOfDay());
603
    }
597
    }
604
 
598
 
605
    @Override
599
    @Override
-
 
600
    public List<SalesHierarchyAchievedByMovementModel> getSalesAchievementByRole(
-
 
601
            int categoryId, String escalationType, LocalDate startDate, LocalDate endDate) {
-
 
602
        Session session = sessionFactory.getCurrentSession();
-
 
603
        TypedQuery<SalesHierarchyAchievedByMovementModel> q = session.createNamedQuery(
-
 
604
                "RbmDrr.SalesHierarchyAchievedByMovement", SalesHierarchyAchievedByMovementModel.class);
-
 
605
        q.setParameter("categoryId", categoryId);
-
 
606
        q.setParameter("escalationType", escalationType);
-
 
607
        q.setParameter("startDate", startDate);
-
 
608
        q.setParameter("endDate", endDate);
-
 
609
        return q.getResultList();
-
 
610
    }
-
 
611
 
-
 
612
    @Override
-
 
613
    public List<SalesHierarchyMonthlyTargetModel> getSalesMonthlyTargetByRole(
-
 
614
            int categoryId, String escalationType, LocalDate refDate) {
-
 
615
        Session session = sessionFactory.getCurrentSession();
-
 
616
        TypedQuery<SalesHierarchyMonthlyTargetModel> q = session.createNamedQuery(
-
 
617
                "RbmDrr.SalesHierarchyMonthlyTarget", SalesHierarchyMonthlyTargetModel.class);
-
 
618
        q.setParameter("categoryId", categoryId);
-
 
619
        q.setParameter("escalationType", escalationType);
-
 
620
        q.setParameter("refDate", refDate);
-
 
621
        return q.getResultList();
-
 
622
    }
-
 
623
 
-
 
624
    @Override
606
    public void setSalesAchievements() {
625
    public void setSalesAchievements() {
607
        setSalesAchievementsForDate(LocalDate.now());
626
        setSalesAchievementsForDate(LocalDate.now());
608
    }
627
    }
609
 
628
 
610
    @Override
629
    @Override
611
    public void setSalesAchievementsForDate(LocalDate date) {
630
    public void setSalesAchievementsForDate(LocalDate date) {
612
        // ACH per (RBM authId × warehouse) for the target date, from the live
631
        // Sales ACH per (auth × warehouse) — direct query scoped to each Sales
613
        // order SQL. Same source used everywhere else.
632
        // person's OWN partners (no RBM roll-up). Same source-of-truth orders SQL.
614
        List<TodayAchievedMovementModel> achModels =
-
 
615
                getMovementWiseAchievementByDate(date, date.plusDays(1));
-
 
616
        if (achModels.isEmpty()) {
-
 
617
            LOGGER.warn("setSalesAchievementsForDate: no orders on {}; nothing to snapshot", date);
-
 
618
            return;
-
 
619
        }
-
 
620
 
-
 
621
        // Sales roles + (categoryId, escalationType) — same mapping used elsewhere.
-
 
622
        String[][] roles = {
633
        String[][] roles = {
623
                {"ASM", "4", "L1"}, {"CM", "4", "L2"}, {"DM", "4", "L3"},
634
                {"ASM", "4", "L1"}, {"CM", "4", "L2"}, {"DM", "4", "L3"},
624
                {"BM", "4", "L4"}, {"RSM", "4", "L5"}, {"NSM", "4", "L6"}
635
                {"BM", "4", "L4"}, {"RSM", "4", "L5"}, {"NSM", "4", "L6"}
625
        };
636
        };
626
 
637
 
627
        // Stamp within the target date so date-range queries pick these rows
-
 
628
        // up for the correct day even during backfill.
-
 
629
        LocalDate today = LocalDate.now();
638
        LocalDate today = LocalDate.now();
630
        LocalDateTime stamp = date.equals(today) ? LocalDateTime.now() : date.atTime(java.time.LocalTime.NOON);
639
        LocalDateTime stamp = date.equals(today) ? LocalDateTime.now() : date.atTime(java.time.LocalTime.NOON);
631
 
-
 
632
        int written = 0;
640
        int written = 0;
-
 
641
 
633
        for (String[] r : roles) {
642
        for (String[] r : roles) {
634
            String role = r[0];
643
            String role = r[0];
635
            int catId = Integer.parseInt(r[1]);
644
            int catId = Integer.parseInt(r[1]);
636
            EscalationType level = EscalationType.valueOf(r[2]);
-
 
637
            for (AuthUser sales : csService.getAuthUserByCategoryId(catId, level)) {
-
 
638
                if (!sales.isActive()) continue;
-
 
639
 
-
 
640
                // Downline authIds (include self).
-
 
641
                Set<Integer> downline = new HashSet<>();
-
 
642
                downline.add(sales.getId());
645
            String levelStr = r[2];
643
                List<Integer> reportees = authService.getAllReportees(sales.getId());
-
 
644
                if (reportees != null) downline.addAll(reportees);
-
 
645
 
-
 
646
                // Aggregate ACH per warehouse across downline RBMs.
-
 
647
                Map<Integer, float[]> perWh = new LinkedHashMap<>();  // wh → [hid, fast, run, slow, other]
-
 
648
                for (TodayAchievedMovementModel a : achModels) {
-
 
649
                    if (!downline.contains(a.getAuthId())) continue;
-
 
650
                    float[] acc = perWh.computeIfAbsent(a.getWarehouseId(), k -> new float[5]);
-
 
651
                    acc[0] += a.getHidBilled();
-
 
652
                    acc[1] += a.getFastMovingBilled();
-
 
653
                    acc[2] += a.getRunningBilled() != null ? a.getRunningBilled() : 0f;
-
 
654
                    acc[3] += a.getSlowMovinBilled() != null ? a.getSlowMovinBilled() : 0f;
-
 
655
                    acc[4] += a.getOtherBilled() != null ? a.getOtherBilled() : 0f;
-
 
656
                }
-
 
657
                if (perWh.isEmpty()) continue;
-
 
658
 
646
 
659
                for (Map.Entry<Integer, float[]> e : perWh.entrySet()) {
647
            for (SalesHierarchyAchievedByMovementModel a :
660
                    float[] acc = e.getValue();
648
                    getSalesAchievementByRole(catId, levelStr, date, date.plusDays(1))) {
661
                    SalesAchievements sa = new SalesAchievements();
649
                SalesAchievements sa = new SalesAchievements();
662
                    sa.setSalesAuthId(sales.getId());
650
                sa.setSalesAuthId(a.getAuthId());
663
                    sa.setSalesName(sales.getFullName());
651
                sa.setSalesName(a.getName());
664
                    sa.setRole(role);
652
                sa.setRole(role);
665
                    sa.setWarehouseId(e.getKey());
653
                sa.setWarehouseId(a.getWarehouseId());
666
                    sa.setAchievedHidTarget(acc[0]);
654
                sa.setAchievedHidTarget(a.getHidBilled());
667
                    sa.setAchievedFastMovingTarget(acc[1]);
655
                sa.setAchievedFastMovingTarget(a.getFastMovingBilled());
668
                    sa.setAchievedRunningTarget(acc[2]);
656
                sa.setAchievedRunningTarget(a.getRunningBilled() != null ? a.getRunningBilled() : 0f);
669
                    sa.setAchievedSlowMovingTarget(acc[3]);
657
                sa.setAchievedSlowMovingTarget(a.getSlowMovingBilled() != null ? a.getSlowMovingBilled() : 0f);
670
                    sa.setAchievedOtherTarget(acc[4]);
658
                sa.setAchievedOtherTarget(a.getOtherBilled() != null ? a.getOtherBilled() : 0f);
671
                    sa.setCreateTimestamp(stamp);
659
                sa.setCreateTimestamp(stamp);
672
                    salesAchievementsRepository.persist(sa);
660
                salesAchievementsRepository.persist(sa);
673
                    written++;
661
                written++;
674
                }
-
 
675
            }
662
            }
676
        }
663
        }
677
        LOGGER.info("setSalesAchievementsForDate: wrote {} sales_achievements rows for {}", written, date);
664
        LOGGER.info("setSalesAchievementsForDate: wrote {} sales_achievements rows for {}", written, date);
678
    }
665
    }
679
 
666