Subversion Repositories SmartDukaan

Rev

Rev 37013 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 37013 Rev 37022
Line 1333... Line 1333...
1333
 
1333
 
1334
        long calledCount = calledFofoIds.size() + calledNumbersWithoutFofoId.size();
1334
        long calledCount = calledFofoIds.size() + calledNumbersWithoutFofoId.size();
1335
        return new long[]{calledCount, totalRecordingCalls, uniqueRecordingNumbers.size()};
1335
        return new long[]{calledCount, totalRecordingCalls, uniqueRecordingNumbers.size()};
1336
    }
1336
    }
1337
 
1337
 
-
 
1338
    // Same rule as computeUniqueTriedCount but restricted to fofoIds in the target set.
-
 
1339
    // Used to compute "TGT Calls" — how many of THIS RBM's Calling Target partners were
-
 
1340
    // actually engaged today. Off-target activity is silently excluded.
-
 
1341
    private long computeUniqueTriedCountForTargets(List<AgentCallLog> callLogs,
-
 
1342
                                                   Map<String, Integer> mobileToFofoIdMap,
-
 
1343
                                                   Set<Integer> targetFofoIds) {
-
 
1344
        if (callLogs == null || callLogs.isEmpty()) return 0L;
-
 
1345
        if (targetFofoIds == null || targetFofoIds.isEmpty()) return 0L;
-
 
1346
        Map<Integer, List<AgentCallLog>> byFofoId = new HashMap<>();
-
 
1347
        for (AgentCallLog log : callLogs) {
-
 
1348
            String num = log.getCustomerNumber();
-
 
1349
            if (num == null) continue;
-
 
1350
            String normalized = num.startsWith("+91") ? num.substring(3) : num;
-
 
1351
            Integer fofoId = mobileToFofoIdMap != null ? mobileToFofoIdMap.get(normalized) : null;
-
 
1352
            if (fofoId == null) continue;
-
 
1353
            if (!targetFofoIds.contains(fofoId)) continue; // off-target, skip
-
 
1354
            byFofoId.computeIfAbsent(fofoId, k -> new ArrayList<>()).add(log);
-
 
1355
        }
-
 
1356
        long count = 0L;
-
 
1357
        for (List<AgentCallLog> logs : byFofoId.values()) {
-
 
1358
            boolean hasNonMissed = false;
-
 
1359
            for (AgentCallLog l : logs) {
-
 
1360
                if (!isMissedCustomerStatus(l.getCustomerStatus())) {
-
 
1361
                    hasNonMissed = true;
-
 
1362
                    break;
-
 
1363
                }
-
 
1364
            }
-
 
1365
            if (hasNonMissed) count++;
-
 
1366
            else if (logs.size() >= 3) count++;
-
 
1367
        }
-
 
1368
        return count;
-
 
1369
    }
-
 
1370
 
1338
    // Matches "Missed", "MISSED", "No Answer", "NO_ANSWER", "no-answer" etc.
1371
    // Matches "Missed", "MISSED", "No Answer", "NO_ANSWER", "no-answer" etc.
1339
    // Kommuno currently emits "Missed" — kept liberal so we're covered if the tag changes.
1372
    // Kommuno currently emits "Missed" — kept liberal so we're covered if the tag changes.
1340
    private static boolean isMissedCustomerStatus(String status) {
1373
    private static boolean isMissedCustomerStatus(String status) {
1341
        if (status == null) return false;
1374
        if (status == null) return false;
1342
        String s = status.trim().toLowerCase().replace('_', ' ').replace('-', ' ').replaceAll("\\s+", " ");
1375
        String s = status.trim().toLowerCase().replace('_', ' ').replace('-', ' ').replaceAll("\\s+", " ");
Line 1703... Line 1736...
1703
            List<AgentCallLog> l1Logs = callLogsByAuthId.get((long) rbmAuthId);
1736
            List<AgentCallLog> l1Logs = callLogsByAuthId.get((long) rbmAuthId);
1704
            long[] callStats = getCallStatsFromLogs(l1Logs, mobileToFofoIdMap);
1737
            long[] callStats = getCallStatsFromLogs(l1Logs, mobileToFofoIdMap);
1705
            targetModel.setValueTargetAchieved(callStats[0]);
1738
            targetModel.setValueTargetAchieved(callStats[0]);
1706
            targetModel.setTotalRecordingCalls(callStats[1]);
1739
            targetModel.setTotalRecordingCalls(callStats[1]);
1707
            targetModel.setUniqueRecordingCalls(callStats[2]);
1740
            targetModel.setUniqueRecordingCalls(callStats[2]);
1708
            targetModel.setTriedUniqueCalls(computeUniqueTriedCount(l1Logs));
1741
            targetModel.setTriedUniqueCalls(computeUniqueTriedCount(l1Logs, mobileToFofoIdMap));
-
 
1742
            targetModel.setTgtCalls(computeUniqueTriedCountForTargets(l1Logs, mobileToFofoIdMap, todayTargetPartners));
1709
 
1743
 
1710
            // Keep todayRemarks for movedToFuture calculation
1744
            // Keep todayRemarks for movedToFuture calculation
1711
            List<PartnerCollectionRemark> todayRemarks = remarksByAuthId.getOrDefault(rbmAuthId, Collections.emptyList());
1745
            List<PartnerCollectionRemark> todayRemarks = remarksByAuthId.getOrDefault(rbmAuthId, Collections.emptyList());
1712
 
1746
 
1713
            // Moved to Future = Partners in Future Plan category who have a remark today
1747
            // Moved to Future = Partners in Future Plan category who have a remark today
Line 1737... Line 1771...
1737
            List<Integer> l2FofoIdList = l2AuthIdToFofoIds.getOrDefault(l2AuthId, Collections.emptyList());
1771
            List<Integer> l2FofoIdList = l2AuthIdToFofoIds.getOrDefault(l2AuthId, Collections.emptyList());
1738
 
1772
 
1739
            // For L2, use unique fofoIds with RBM_L2_ESCALATION remark as target
1773
            // For L2, use unique fofoIds with RBM_L2_ESCALATION remark as target
1740
            Set<Integer> l2TargetFofoIds = new HashSet<>(l2FofoIdList);
1774
            Set<Integer> l2TargetFofoIds = new HashSet<>(l2FofoIdList);
1741
 
1775
 
-
 
1776
            // Collected from the L1-merge branch below when the user is also L1. Used later
-
 
1777
            // for the TGT Calls scope: L2 escalation + L1 target buckets.
-
 
1778
            Set<Integer> l1MergedTargetPartners = new HashSet<>();
-
 
1779
 
1742
            RbmCallTargetModel l2Model = new RbmCallTargetModel();
1780
            RbmCallTargetModel l2Model = new RbmCallTargetModel();
1743
            l2Model.setAuthId(l2AuthId);
1781
            l2Model.setAuthId(l2AuthId);
1744
            l2Model.setRbmName(authUser.getFullName() + " (L2)");
1782
            l2Model.setRbmName(authUser.getFullName() + " (L2)");
1745
            l2Model.setL2Position(true);
1783
            l2Model.setL2Position(true);
1746
            l2Model.setL2CallingList(l2TargetFofoIds.size());
1784
            l2Model.setL2CallingList(l2TargetFofoIds.size());
Line 1837... Line 1875...
1837
                l2Model.setRevival(revivalPartners.size());
1875
                l2Model.setRevival(revivalPartners.size());
1838
 
1876
 
1839
                long l1OwnTarget = planTodayPartners.size() + carryForwardPartners.size()
1877
                long l1OwnTarget = planTodayPartners.size() + carryForwardPartners.size()
1840
                        + zeroBillingPartners.size() + untouchedPartners.size();
1878
                        + zeroBillingPartners.size() + untouchedPartners.size();
1841
 
1879
 
-
 
1880
                // Feed the L1 target sets up to the outer scope so TGT Calls can include them.
-
 
1881
                l1MergedTargetPartners.addAll(planTodayPartners);
-
 
1882
                l1MergedTargetPartners.addAll(carryForwardPartners);
-
 
1883
                l1MergedTargetPartners.addAll(zeroBillingPartners);
-
 
1884
                l1MergedTargetPartners.addAll(untouchedPartners);
-
 
1885
 
1842
                // Today Target = own L1 target + L2 escalation
1886
                // Today Target = own L1 target + L2 escalation
1843
                l2Model.setTodayTargetOfCall(l2TargetFofoIds.size() + l1OwnTarget);
1887
                l2Model.setTodayTargetOfCall(l2TargetFofoIds.size() + l1OwnTarget);
1844
 
1888
 
1845
                // Moved to Future from L1 partners
1889
                // Moved to Future from L1 partners
1846
                List<PartnerCollectionRemark> todayRemarks = remarksByAuthId.getOrDefault(l2AuthId, Collections.emptyList());
1890
                List<PartnerCollectionRemark> todayRemarks = remarksByAuthId.getOrDefault(l2AuthId, Collections.emptyList());
Line 1860... Line 1904...
1860
            List<AgentCallLog> l2Logs = callLogsByAuthId.get((long) l2AuthId);
1904
            List<AgentCallLog> l2Logs = callLogsByAuthId.get((long) l2AuthId);
1861
            long[] l2CallStats = getCallStatsFromLogs(l2Logs, mobileToFofoIdMap);
1905
            long[] l2CallStats = getCallStatsFromLogs(l2Logs, mobileToFofoIdMap);
1862
            l2Model.setValueTargetAchieved(l2CallStats[0]);
1906
            l2Model.setValueTargetAchieved(l2CallStats[0]);
1863
            l2Model.setTotalRecordingCalls(l2CallStats[1]);
1907
            l2Model.setTotalRecordingCalls(l2CallStats[1]);
1864
            l2Model.setUniqueRecordingCalls(l2CallStats[2]);
1908
            l2Model.setUniqueRecordingCalls(l2CallStats[2]);
1865
            l2Model.setTriedUniqueCalls(computeUniqueTriedCount(l2Logs));
1909
            l2Model.setTriedUniqueCalls(computeUniqueTriedCount(l2Logs, mobileToFofoIdMap));
-
 
1910
 
-
 
1911
            // TGT Calls scope: L2 escalation + (if user is also L1) the L1 target buckets.
-
 
1912
            Set<Integer> l2TgtSet = new HashSet<>(l2TargetFofoIds);
-
 
1913
            l2TgtSet.addAll(l1MergedTargetPartners);
-
 
1914
            l2Model.setTgtCalls(computeUniqueTriedCountForTargets(l2Logs, mobileToFofoIdMap, l2TgtSet));
1866
 
1915
 
1867
            l2Model.setOutOfSequenceCount(outOfSequenceCountByAuthId.getOrDefault(l2AuthId, 0L));
1916
            l2Model.setOutOfSequenceCount(outOfSequenceCountByAuthId.getOrDefault(l2AuthId, 0L));
1868
            rbmCallTargetModels.add(l2Model);
1917
            rbmCallTargetModels.add(l2Model);
1869
        }
1918
        }
1870
 
1919
 
Line 1903... Line 1952...
1903
            List<AgentCallLog> l3Logs = callLogsByAuthId.get((long) l3AuthId);
1952
            List<AgentCallLog> l3Logs = callLogsByAuthId.get((long) l3AuthId);
1904
            long[] l3CallStats = getCallStatsFromLogs(l3Logs, mobileToFofoIdMap);
1953
            long[] l3CallStats = getCallStatsFromLogs(l3Logs, mobileToFofoIdMap);
1905
            l3Model.setValueTargetAchieved(l3CallStats[0]);
1954
            l3Model.setValueTargetAchieved(l3CallStats[0]);
1906
            l3Model.setTotalRecordingCalls(l3CallStats[1]);
1955
            l3Model.setTotalRecordingCalls(l3CallStats[1]);
1907
            l3Model.setUniqueRecordingCalls(l3CallStats[2]);
1956
            l3Model.setUniqueRecordingCalls(l3CallStats[2]);
1908
            l3Model.setTriedUniqueCalls(computeUniqueTriedCount(l3Logs));
1957
            l3Model.setTriedUniqueCalls(computeUniqueTriedCount(l3Logs, mobileToFofoIdMap));
-
 
1958
            // L3 TGT Calls scope: L3 escalation partners.
-
 
1959
            l3Model.setTgtCalls(computeUniqueTriedCountForTargets(l3Logs, mobileToFofoIdMap, l3TargetFofoIds));
1909
 
1960
 
1910
            l3Model.setOutOfSequenceCount(outOfSequenceCountByAuthId.getOrDefault(l3AuthId, 0L));
1961
            l3Model.setOutOfSequenceCount(outOfSequenceCountByAuthId.getOrDefault(l3AuthId, 0L));
1911
            rbmCallTargetModels.add(l3Model);
1962
            rbmCallTargetModels.add(l3Model);
1912
        }
1963
        }
1913
 
1964
 
Line 2098... Line 2149...
2098
     *   - Else (every call to this number was Missed) → count only if attempts >= 3
2149
     *   - Else (every call to this number was Missed) → count only if attempts >= 3
2099
     *     (persistence credit).
2150
     *     (persistence credit).
2100
     * null/empty customerStatus is treated as "not Missed" (favours counting when
2151
     * null/empty customerStatus is treated as "not Missed" (favours counting when
2101
     * the vendor didn't classify the outcome).
2152
     * the vendor didn't classify the outcome).
2102
     */
2153
     */
2103
    private long computeUniqueTriedCount(List<AgentCallLog> callLogs) {
2154
    private long computeUniqueTriedCount(List<AgentCallLog> callLogs,
-
 
2155
                                         Map<String, Integer> mobileToFofoIdMap) {
2104
        if (callLogs == null || callLogs.isEmpty()) return 0L;
2156
        if (callLogs == null || callLogs.isEmpty()) return 0L;
-
 
2157
        // Group by fofoId (not raw number) — numbers that don't resolve to a partner via
-
 
2158
        // retailer_contact/address are skipped. Once a number gets added to retailer_contact
-
 
2159
        // it'll automatically resolve and start counting on the next page load.
2105
        Map<String, List<AgentCallLog>> byNumber = new HashMap<>();
2160
        Map<Integer, List<AgentCallLog>> byFofoId = new HashMap<>();
2106
        for (AgentCallLog log : callLogs) {
2161
        for (AgentCallLog log : callLogs) {
2107
            String num = log.getCustomerNumber();
2162
            String num = log.getCustomerNumber();
2108
            if (num == null) continue;
2163
            if (num == null) continue;
2109
            String normalized = num.startsWith("+91") ? num.substring(3) : num;
2164
            String normalized = num.startsWith("+91") ? num.substring(3) : num;
-
 
2165
            Integer fofoId = mobileToFofoIdMap != null ? mobileToFofoIdMap.get(normalized) : null;
-
 
2166
            if (fofoId == null) continue; // unknown number — excluded from Tried
2110
            byNumber.computeIfAbsent(normalized, k -> new ArrayList<>()).add(log);
2167
            byFofoId.computeIfAbsent(fofoId, k -> new ArrayList<>()).add(log);
2111
        }
2168
        }
2112
        long count = 0L;
2169
        long count = 0L;
2113
        for (List<AgentCallLog> logs : byNumber.values()) {
2170
        for (List<AgentCallLog> logs : byFofoId.values()) {
2114
            boolean hasNonMissed = false;
2171
            boolean hasNonMissed = false;
2115
            for (AgentCallLog l : logs) {
2172
            for (AgentCallLog l : logs) {
2116
                if (!isMissedCustomerStatus(l.getCustomerStatus())) {
2173
                if (!isMissedCustomerStatus(l.getCustomerStatus())) {
2117
                    hasNonMissed = true;
2174
                    hasNonMissed = true;
2118
                    break;
2175
                    break;