| Line 9... |
Line 9... |
| 9 |
import com.spice.profitmandi.dao.entity.auth.RbmCallSequenceLog;
|
9 |
import com.spice.profitmandi.dao.entity.auth.RbmCallSequenceLog;
|
| 10 |
import com.spice.profitmandi.dao.entity.cs.Position;
|
10 |
import com.spice.profitmandi.dao.entity.cs.Position;
|
| 11 |
import com.spice.profitmandi.dao.entity.cs.Ticket;
|
11 |
import com.spice.profitmandi.dao.entity.cs.Ticket;
|
| 12 |
import com.spice.profitmandi.dao.entity.fofo.FofoStore;
|
12 |
import com.spice.profitmandi.dao.entity.fofo.FofoStore;
|
| 13 |
import com.spice.profitmandi.dao.entity.fofo.MonthlyTarget;
|
13 |
import com.spice.profitmandi.dao.entity.fofo.MonthlyTarget;
|
| - |
|
14 |
import com.spice.profitmandi.dao.entity.fofo.RetailerContact;
|
| 14 |
import com.spice.profitmandi.dao.entity.inventory.RbmAchievements;
|
15 |
import com.spice.profitmandi.dao.entity.inventory.RbmAchievements;
|
| 15 |
import com.spice.profitmandi.dao.entity.inventory.RbmTargets;
|
16 |
import com.spice.profitmandi.dao.entity.inventory.RbmTargets;
|
| - |
|
17 |
import com.spice.profitmandi.dao.entity.user.Address;
|
| 16 |
import com.spice.profitmandi.dao.enumuration.auth.CollectionRemark;
|
18 |
import com.spice.profitmandi.dao.enumuration.auth.CollectionRemark;
|
| 17 |
import com.spice.profitmandi.dao.enumuration.cs.EscalationType;
|
19 |
import com.spice.profitmandi.dao.enumuration.cs.EscalationType;
|
| 18 |
import com.spice.profitmandi.dao.model.*;
|
20 |
import com.spice.profitmandi.dao.model.*;
|
| 19 |
import com.spice.profitmandi.dao.repository.auth.AuthRepository;
|
21 |
import com.spice.profitmandi.dao.repository.auth.AuthRepository;
|
| 20 |
import com.spice.profitmandi.dao.repository.auth.PartnerCollectionRemarkRepository;
|
22 |
import com.spice.profitmandi.dao.repository.auth.PartnerCollectionRemarkRepository;
|
| Line 22... |
Line 24... |
| 22 |
import com.spice.profitmandi.dao.repository.catalog.RbmAchievementsRepository;
|
24 |
import com.spice.profitmandi.dao.repository.catalog.RbmAchievementsRepository;
|
| 23 |
import com.spice.profitmandi.dao.repository.catalog.RbmTargetsRepository;
|
25 |
import com.spice.profitmandi.dao.repository.catalog.RbmTargetsRepository;
|
| 24 |
import com.spice.profitmandi.dao.repository.cs.CsService;
|
26 |
import com.spice.profitmandi.dao.repository.cs.CsService;
|
| 25 |
import com.spice.profitmandi.dao.repository.cs.PositionRepository;
|
27 |
import com.spice.profitmandi.dao.repository.cs.PositionRepository;
|
| 26 |
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
|
28 |
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
|
| - |
|
29 |
import com.spice.profitmandi.dao.repository.dtr.RetailerContactRepository;
|
| 27 |
import com.spice.profitmandi.dao.repository.fofo.MonthlyTargetRepository;
|
30 |
import com.spice.profitmandi.dao.repository.fofo.MonthlyTargetRepository;
|
| 28 |
import com.spice.profitmandi.dao.repository.logistics.PublicHolidaysRepository;
|
31 |
import com.spice.profitmandi.dao.repository.logistics.PublicHolidaysRepository;
|
| 29 |
import com.spice.profitmandi.dao.repository.transaction.LoanRepository;
|
32 |
import com.spice.profitmandi.dao.repository.transaction.LoanRepository;
|
| 30 |
import com.spice.profitmandi.dao.repository.transaction.OrderRepository;
|
33 |
import com.spice.profitmandi.dao.repository.transaction.OrderRepository;
|
| - |
|
34 |
import com.spice.profitmandi.dao.repository.user.AddressRepository;
|
| 31 |
import com.spice.profitmandi.service.user.RetailerService;
|
35 |
import com.spice.profitmandi.service.user.RetailerService;
|
| 32 |
import org.apache.logging.log4j.LogManager;
|
36 |
import org.apache.logging.log4j.LogManager;
|
| 33 |
import org.apache.logging.log4j.Logger;
|
37 |
import org.apache.logging.log4j.Logger;
|
| 34 |
import org.hibernate.Session;
|
38 |
import org.hibernate.Session;
|
| 35 |
import org.hibernate.SessionFactory;
|
39 |
import org.hibernate.SessionFactory;
|
| Line 593... |
Line 597... |
| 593 |
com.spice.profitmandi.dao.repository.cs.TicketRepository ticketRepository;
|
597 |
com.spice.profitmandi.dao.repository.cs.TicketRepository ticketRepository;
|
| 594 |
|
598 |
|
| 595 |
@Autowired
|
599 |
@Autowired
|
| 596 |
com.spice.profitmandi.dao.repository.cs.AgentCallLogRepository agentCallLogRepository;
|
600 |
com.spice.profitmandi.dao.repository.cs.AgentCallLogRepository agentCallLogRepository;
|
| 597 |
|
601 |
|
| - |
|
602 |
@Autowired
|
| - |
|
603 |
RetailerContactRepository retailerContactRepository;
|
| - |
|
604 |
|
| - |
|
605 |
@Autowired
|
| - |
|
606 |
AddressRepository addressRepository;
|
| - |
|
607 |
|
| 598 |
@Override
|
608 |
@Override
|
| 599 |
public List<RbmCallTargetModel> getRbmCallTargetModels() throws Exception {
|
609 |
public List<RbmCallTargetModel> getRbmCallTargetModels() throws Exception {
|
| 600 |
long methodStart = System.currentTimeMillis();
|
610 |
long methodStart = System.currentTimeMillis();
|
| 601 |
List<RbmCallTargetModel> rbmCallTargetModels = new ArrayList<>();
|
611 |
List<RbmCallTargetModel> rbmCallTargetModels = new ArrayList<>();
|
| 602 |
|
612 |
|
| Line 1029... |
Line 1039... |
| 1029 |
return getCalledPartnerDetails(authId, LocalDate.now());
|
1039 |
return getCalledPartnerDetails(authId, LocalDate.now());
|
| 1030 |
}
|
1040 |
}
|
| 1031 |
|
1041 |
|
| 1032 |
@Override
|
1042 |
@Override
|
| 1033 |
public List<CalledPartnerDetailModel> getCalledPartnerDetails(int authId, LocalDate date) throws ProfitMandiBusinessException {
|
1043 |
public List<CalledPartnerDetailModel> getCalledPartnerDetails(int authId, LocalDate date) throws ProfitMandiBusinessException {
|
| 1034 |
LocalDate today = date;
|
- |
|
| 1035 |
LocalDateTime startDate = today.atStartOfDay();
|
- |
|
| 1036 |
LocalDate firstOfMonth = today.withDayOfMonth(1);
|
- |
|
| 1037 |
LocalDate endOfMonth = today.withDayOfMonth(today.lengthOfMonth()).plusDays(1);
|
- |
|
| 1038 |
|
- |
|
| 1039 |
// Get auth user
|
- |
|
| 1040 |
List<AuthUser> authUsers = authRepository.selectByIds(Collections.singletonList(authId));
|
- |
|
| 1041 |
if (authUsers.isEmpty()) {
|
- |
|
| 1042 |
return Collections.emptyList();
|
- |
|
| 1043 |
}
|
- |
|
| 1044 |
AuthUser authUser = authUsers.get(0);
|
- |
|
| 1045 |
|
- |
|
| 1046 |
// Check if L1 or L2
|
- |
|
| 1047 |
List<Position> positions = positionRepository.selectPositionByAuthIds(Collections.singletonList(authId));
|
- |
|
| 1048 |
boolean isL2 = positions.stream()
|
- |
|
| 1049 |
.anyMatch(p -> ProfitMandiConstants.TICKET_CATEGORY_RBM == p.getCategoryId()
|
- |
|
| 1050 |
&& EscalationType.L2.equals(p.getEscalationType()));
|
- |
|
| 1051 |
|
- |
|
| 1052 |
// Get fofo IDs for this RBM
|
1044 |
// Get all call logs for this auth user on this date
|
| 1053 |
List<Integer> fofoIdList;
|
- |
|
| 1054 |
if (isL2) {
|
- |
|
| 1055 |
// L2: get fofo IDs from escalated tickets (all escalated tickets are target)
|
- |
|
| 1056 |
List<Ticket> escalatedTickets = ticketRepository.selectOpenEscalatedTicketsByAuthIds(Collections.singletonList(authId));
|
1045 |
List<com.spice.profitmandi.dao.entity.cs.AgentCallLog> callLogs = agentCallLogRepository.findByAuthIdAndDate(authId, date);
|
| 1057 |
fofoIdList = escalatedTickets.stream()
|
- |
|
| 1058 |
.filter(t -> t.getL2AuthUser() == authId
|
- |
|
| 1059 |
|| t.getL3AuthUser() == authId
|
- |
|
| 1060 |
|| t.getL4AuthUser() == authId
|
- |
|
| 1061 |
|| t.getL5AuthUser() == authId)
|
- |
|
| 1062 |
.map(Ticket::getFofoId)
|
- |
|
| 1063 |
.distinct()
|
- |
|
| 1064 |
.collect(Collectors.toList());
|
- |
|
| 1065 |
|
- |
|
| 1066 |
// Get today's remarks created by L2 (all remarks, not deduplicated)
|
- |
|
| 1067 |
List<PartnerCollectionRemark> todayRemarks = partnerCollectionRemarkRepository
|
- |
|
| 1068 |
.selectAllByAuthIdsOnDate(Collections.singletonList(authId), today);
|
- |
|
| 1069 |
|
- |
|
| 1070 |
return buildCalledPartnerResult(todayRemarks);
|
- |
|
| 1071 |
}
|
- |
|
| 1072 |
|
1046 |
|
| 1073 |
// L1 Logic
|
- |
|
| 1074 |
Map<String, Set<Integer>> storeGuyMap;
|
- |
|
| 1075 |
try {
|
- |
|
| 1076 |
storeGuyMap = csService.getAuthUserPartnerIdMapping();
|
- |
|
| 1077 |
} catch (ProfitMandiBusinessException e) {
|
1047 |
if (callLogs.isEmpty()) {
|
| 1078 |
LOGGER.error("Error fetching store guy map", e);
|
- |
|
| 1079 |
return Collections.emptyList();
|
1048 |
return Collections.emptyList();
|
| 1080 |
}
|
1049 |
}
|
| 1081 |
|
1050 |
|
| 1082 |
if (!storeGuyMap.containsKey(authUser.getEmailId())) {
|
1051 |
// Build a map of normalized customer number -> fofoId
|
| - |
|
1052 |
Map<String, Integer> customerToFofoIdMap = new HashMap<>();
|
| - |
|
1053 |
Set<String> normalizedNumbers = new HashSet<>();
|
| - |
|
1054 |
|
| - |
|
1055 |
for (com.spice.profitmandi.dao.entity.cs.AgentCallLog callLog : callLogs) {
|
| - |
|
1056 |
String customerNumber = callLog.getCustomerNumber();
|
| 1083 |
return Collections.emptyList();
|
1057 |
if (customerNumber != null) {
|
| - |
|
1058 |
String normalized = customerNumber.startsWith("+91") ? customerNumber.substring(3) : customerNumber;
|
| - |
|
1059 |
normalizedNumbers.add(normalized);
|
| - |
|
1060 |
}
|
| 1084 |
}
|
1061 |
}
|
| 1085 |
fofoIdList = new ArrayList<>(storeGuyMap.get(authUser.getEmailId()));
|
- |
|
| 1086 |
|
1062 |
|
| - |
|
1063 |
// For each normalized number, find fofoId from retailer_contact first, then address
|
| - |
|
1064 |
for (String mobile : normalizedNumbers) {
|
| - |
|
1065 |
Integer fofoId = findFofoIdByMobile(mobile);
|
| 1087 |
if (fofoIdList.isEmpty()) {
|
1066 |
if (fofoId != null) {
|
| 1088 |
return Collections.emptyList();
|
1067 |
customerToFofoIdMap.put(mobile, fofoId);
|
| - |
|
1068 |
}
|
| 1089 |
}
|
1069 |
}
|
| 1090 |
|
1070 |
|
| 1091 |
// Get fofo stores for filtering
|
1071 |
// Get unique fofoIds for retailer lookup
|
| - |
|
1072 |
Set<Integer> fofoIds = new HashSet<>(customerToFofoIdMap.values());
|
| 1092 |
Map<Integer, FofoStore> fofoStoresMap;
|
1073 |
Map<Integer, CustomRetailer> retailerMap = Collections.emptyMap();
|
| - |
|
1074 |
if (!fofoIds.isEmpty()) {
|
| 1093 |
try {
|
1075 |
try {
|
| 1094 |
fofoStoresMap = fofoStoreRepository.selectByRetailerIds(fofoIdList).stream()
|
1076 |
retailerMap = retailerService.getFofoRetailers(new ArrayList<>(fofoIds));
|
| 1095 |
.collect(Collectors.toMap(FofoStore::getId, x -> x, (a, b) -> a));
|
- |
|
| 1096 |
} catch (ProfitMandiBusinessException e) {
|
1077 |
} catch (ProfitMandiBusinessException e) {
|
| 1097 |
LOGGER.error("Error fetching fofo stores", e);
|
1078 |
LOGGER.error("Error fetching fofo stores", e);
|
| 1098 |
return Collections.emptyList();
|
1079 |
}
|
| 1099 |
}
|
1080 |
}
|
| 1100 |
|
1081 |
|
| 1101 |
// Filter escalated partners for L1
|
1082 |
// Get today's remarks for these fofoIds
|
| 1102 |
List<Integer> allRemarkIds = partnerCollectionRemarkRepository.selectMaxRemarkId(fofoIdList);
|
1083 |
Map<Integer, List<PartnerCollectionRemark>> fofoRemarkMap = new HashMap<>();
|
| 1103 |
if (!allRemarkIds.isEmpty()) {
|
1084 |
if (!fofoIds.isEmpty()) {
|
| 1104 |
Map<Integer, PartnerCollectionRemark> partnerCollectionRemarks = partnerCollectionRemarkRepository.selectByIds(allRemarkIds).stream()
|
1085 |
List<PartnerCollectionRemark> todayRemarks = partnerCollectionRemarkRepository
|
| 1105 |
.collect(Collectors.toMap(PartnerCollectionRemark::getFofoId, x -> x, (a, b) -> a));
|
1086 |
.selectAllByFofoIdsOnDate(new ArrayList<>(fofoIds), date);
|
| 1106 |
fofoIdList = partnerCollectionRemarks.entrySet().stream()
|
- |
|
| 1107 |
.filter(entry -> {
|
- |
|
| 1108 |
PartnerCollectionRemark pcrMap = entry.getValue();
|
1087 |
for (PartnerCollectionRemark remark : todayRemarks) {
|
| 1109 |
return !(CollectionRemark.RBM_L2_ESCALATION.equals(pcrMap.getRemark())
|
1088 |
fofoRemarkMap.computeIfAbsent(remark.getFofoId(), k -> new ArrayList<>()).add(remark);
|
| 1110 |
|| CollectionRemark.SALES_ESCALATION.equals(pcrMap.getRemark()));
|
- |
|
| 1111 |
})
|
1089 |
}
|
| 1112 |
.map(Map.Entry::getKey)
|
- |
|
| 1113 |
.collect(Collectors.toList());
|
- |
|
| 1114 |
}
|
1090 |
}
|
| 1115 |
|
1091 |
|
| 1116 |
// Filter to only external, ACTIVE stores
|
- |
|
| 1117 |
List<Integer> validFofoIds = fofoIdList.stream()
|
- |
|
| 1118 |
.filter(fofoId -> {
|
- |
|
| 1119 |
FofoStore store = fofoStoresMap.get(fofoId);
|
1092 |
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("hh:mm a");
|
| 1120 |
if (store == null || store.isInternal()) {
|
- |
|
| 1121 |
return false;
|
- |
|
| 1122 |
}
|
- |
|
| 1123 |
return ActivationType.ACTIVE.equals(store.getActivationType());
|
1093 |
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy hh:mm a");
|
| 1124 |
})
|
- |
|
| 1125 |
.collect(Collectors.toList());
|
1094 |
List<CalledPartnerDetailModel> result = new ArrayList<>();
|
| 1126 |
|
1095 |
|
| - |
|
1096 |
for (com.spice.profitmandi.dao.entity.cs.AgentCallLog callLog : callLogs) {
|
| - |
|
1097 |
String customerNumber = callLog.getCustomerNumber();
|
| 1127 |
if (validFofoIds.isEmpty()) {
|
1098 |
if (customerNumber == null) {
|
| 1128 |
return Collections.emptyList();
|
1099 |
continue;
|
| 1129 |
}
|
1100 |
}
|
| 1130 |
|
1101 |
|
| 1131 |
// Get collection rank map
|
- |
|
| 1132 |
Map<Integer, Integer> collectionRankMap;
|
- |
|
| 1133 |
try {
|
- |
|
| 1134 |
collectionRankMap = partnerCollectionService.getCollectionRankMap(validFofoIds, startDate);
|
1102 |
String normalized = customerNumber.startsWith("+91") ? customerNumber.substring(3) : customerNumber;
|
| 1135 |
} catch (ProfitMandiBusinessException e) {
|
- |
|
| 1136 |
LOGGER.error("Error fetching collection rank map", e);
|
1103 |
Integer fofoId = customerToFofoIdMap.get(normalized);
|
| 1137 |
collectionRankMap = new HashMap<>();
|
- |
|
| 1138 |
}
|
- |
|
| 1139 |
|
1104 |
|
| 1140 |
// Get MTD billing data for zero billing check
|
1105 |
String partyName = "Unknown";
|
| - |
|
1106 |
String code = "-";
|
| - |
|
1107 |
|
| - |
|
1108 |
if (fofoId != null) {
|
| 1141 |
List<RbmWeeklyBillingModel> mtdBillingData = getWeeklyBillingDataForMonth(firstOfMonth, endOfMonth);
|
1109 |
CustomRetailer retailer = retailerMap.get(fofoId);
|
| - |
|
1110 |
if (retailer != null) {
|
| 1142 |
Set<Integer> mtdBilledFofoIds = mtdBillingData.stream()
|
1111 |
partyName = retailer.getBusinessName();
|
| 1143 |
.filter(RbmWeeklyBillingModel::isMtdBilled)
|
1112 |
code = retailer.getCode();
|
| - |
|
1113 |
} else {
|
| 1144 |
.map(RbmWeeklyBillingModel::getFofoId)
|
1114 |
partyName = "Unknown (" + fofoId + ")";
|
| - |
|
1115 |
}
|
| - |
|
1116 |
} else {
|
| 1145 |
.collect(Collectors.toSet());
|
1117 |
partyName = "Unknown (" + normalized + ")";
|
| - |
|
1118 |
}
|
| 1146 |
|
1119 |
|
| - |
|
1120 |
// Get remark if available
|
| - |
|
1121 |
String remarkValue = "-";
|
| - |
|
1122 |
String messageValue = "-";
|
| - |
|
1123 |
String remarkTime = "-";
|
| - |
|
1124 |
|
| 1147 |
// Build target partner set (PlanToday + CarryForward + ZeroBilling + Untouched)
|
1125 |
if (fofoId != null && fofoRemarkMap.containsKey(fofoId)) {
|
| 1148 |
Set<Integer> targetFofoIds = new HashSet<>();
|
1126 |
List<PartnerCollectionRemark> remarks = fofoRemarkMap.get(fofoId);
|
| 1149 |
for (Integer fofoId : validFofoIds) {
|
1127 |
if (!remarks.isEmpty()) {
|
| 1150 |
int rank = collectionRankMap.getOrDefault(fofoId, 5);
|
1128 |
PartnerCollectionRemark remark = remarks.get(0);
|
| - |
|
1129 |
remarkValue = remark.getRemark() != null ? remark.getRemark().getValue() : "-";
|
| 1151 |
boolean hasZeroBilling = !mtdBilledFofoIds.contains(fofoId);
|
1130 |
messageValue = remark.getMessage() != null ? remark.getMessage() : "-";
|
| - |
|
1131 |
remarkTime = remark.getCreateTimestamp() != null ? remark.getCreateTimestamp().format(timeFormatter) : "-";
|
| - |
|
1132 |
}
|
| - |
|
1133 |
}
|
| 1152 |
|
1134 |
|
| - |
|
1135 |
// Build call log data
|
| 1153 |
// Same priority logic as in getRbmCallTargetModels
|
1136 |
String recordingUrl = callLog.getRecordingUrl();
|
| - |
|
1137 |
String callStatus = callLog.getCallStatus();
|
| 1154 |
if (rank == 1 || rank == 2 || hasZeroBilling || rank == 3) {
|
1138 |
String callDuration = callLog.getCallDuration();
|
| 1155 |
targetFofoIds.add(fofoId);
|
1139 |
String callDateTime = null;
|
| - |
|
1140 |
if (callLog.getCallDate() != null && callLog.getCallTime() != null) {
|
| - |
|
1141 |
LocalDateTime callDateTimeObj = LocalDateTime.of(callLog.getCallDate(), callLog.getCallTime());
|
| - |
|
1142 |
callDateTime = callDateTimeObj.format(dateTimeFormatter);
|
| 1156 |
}
|
1143 |
}
|
| - |
|
1144 |
|
| - |
|
1145 |
result.add(new CalledPartnerDetailModel(partyName, code, remarkValue, messageValue, remarkTime,
|
| 1157 |
// rank 4 (FuturePlan) and rank 5 (Normal) are NOT in target
|
1146 |
recordingUrl, callStatus, callDuration, callDateTime));
|
| 1158 |
}
|
1147 |
}
|
| 1159 |
|
1148 |
|
| - |
|
1149 |
return result;
|
| - |
|
1150 |
}
|
| - |
|
1151 |
|
| - |
|
1152 |
private Integer findFofoIdByMobile(String mobile) {
|
| 1160 |
// Get today's remarks created by L1 (all remarks, not deduplicated)
|
1153 |
// First check retailer_contact
|
| 1161 |
List<PartnerCollectionRemark> todayRemarks = partnerCollectionRemarkRepository
|
1154 |
List<RetailerContact> contacts = retailerContactRepository.selectByMobile(mobile);
|
| - |
|
1155 |
if (contacts != null && !contacts.isEmpty()) {
|
| - |
|
1156 |
return contacts.get(0).getFofoId();
|
| - |
|
1157 |
}
|
| - |
|
1158 |
|
| - |
|
1159 |
// Fallback to user.address
|
| 1162 |
.selectAllByAuthIdsOnDate(Collections.singletonList(authId), today);
|
1160 |
Address address = addressRepository.selectByPhoneNumber(mobile);
|
| - |
|
1161 |
if (address != null) {
|
| - |
|
1162 |
return address.getRetaierId();
|
| - |
|
1163 |
}
|
| 1163 |
|
1164 |
|
| 1164 |
return buildCalledPartnerResult(todayRemarks);
|
1165 |
return null;
|
| 1165 |
}
|
1166 |
}
|
| 1166 |
|
1167 |
|
| 1167 |
private List<CalledPartnerDetailModel> buildCalledPartnerResult(List<PartnerCollectionRemark> allRemarks) {
|
1168 |
private List<CalledPartnerDetailModel> buildCalledPartnerResult(List<PartnerCollectionRemark> allRemarks) {
|
| 1168 |
if (allRemarks.isEmpty()) {
|
1169 |
if (allRemarks.isEmpty()) {
|
| 1169 |
return Collections.emptyList();
|
1170 |
return Collections.emptyList();
|