| 33917 |
ranu |
1 |
package com.spice.profitmandi.service;
|
|
|
2 |
|
| 35631 |
ranu |
3 |
import com.spice.profitmandi.common.enumuration.ActivationType;
|
|
|
4 |
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
|
|
|
5 |
import com.spice.profitmandi.common.model.CustomRetailer;
|
| 33917 |
ranu |
6 |
import com.spice.profitmandi.common.model.ProfitMandiConstants;
|
| 35631 |
ranu |
7 |
import com.spice.profitmandi.dao.entity.auth.AuthUser;
|
|
|
8 |
import com.spice.profitmandi.dao.entity.auth.PartnerCollectionRemark;
|
|
|
9 |
import com.spice.profitmandi.dao.entity.auth.RbmCallSequenceLog;
|
| 35761 |
ranu |
10 |
import com.spice.profitmandi.dao.entity.cs.AgentCallLog;
|
| 35631 |
ranu |
11 |
import com.spice.profitmandi.dao.entity.cs.Position;
|
|
|
12 |
import com.spice.profitmandi.dao.entity.cs.Ticket;
|
|
|
13 |
import com.spice.profitmandi.dao.entity.fofo.FofoStore;
|
| 34397 |
ranu |
14 |
import com.spice.profitmandi.dao.entity.fofo.MonthlyTarget;
|
| 35759 |
ranu |
15 |
import com.spice.profitmandi.dao.entity.fofo.RetailerContact;
|
| 33985 |
ranu |
16 |
import com.spice.profitmandi.dao.entity.inventory.RbmAchievements;
|
| 33926 |
ranu |
17 |
import com.spice.profitmandi.dao.entity.inventory.RbmTargets;
|
| 35759 |
ranu |
18 |
import com.spice.profitmandi.dao.entity.user.Address;
|
| 35631 |
ranu |
19 |
import com.spice.profitmandi.dao.enumuration.auth.CollectionRemark;
|
|
|
20 |
import com.spice.profitmandi.dao.enumuration.cs.EscalationType;
|
| 33917 |
ranu |
21 |
import com.spice.profitmandi.dao.model.*;
|
| 35631 |
ranu |
22 |
import com.spice.profitmandi.dao.repository.auth.AuthRepository;
|
|
|
23 |
import com.spice.profitmandi.dao.repository.auth.PartnerCollectionRemarkRepository;
|
|
|
24 |
import com.spice.profitmandi.dao.repository.auth.RbmCallSequenceLogRepository;
|
| 33985 |
ranu |
25 |
import com.spice.profitmandi.dao.repository.catalog.RbmAchievementsRepository;
|
| 33926 |
ranu |
26 |
import com.spice.profitmandi.dao.repository.catalog.RbmTargetsRepository;
|
| 35631 |
ranu |
27 |
import com.spice.profitmandi.dao.repository.cs.CsService;
|
|
|
28 |
import com.spice.profitmandi.dao.repository.cs.PositionRepository;
|
|
|
29 |
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
|
| 35759 |
ranu |
30 |
import com.spice.profitmandi.dao.repository.dtr.RetailerContactRepository;
|
| 34397 |
ranu |
31 |
import com.spice.profitmandi.dao.repository.fofo.MonthlyTargetRepository;
|
| 34880 |
ranu |
32 |
import com.spice.profitmandi.dao.repository.logistics.PublicHolidaysRepository;
|
| 35631 |
ranu |
33 |
import com.spice.profitmandi.dao.repository.transaction.LoanRepository;
|
| 34397 |
ranu |
34 |
import com.spice.profitmandi.dao.repository.transaction.OrderRepository;
|
| 35759 |
ranu |
35 |
import com.spice.profitmandi.dao.repository.user.AddressRepository;
|
| 35631 |
ranu |
36 |
import com.spice.profitmandi.service.user.RetailerService;
|
| 33917 |
ranu |
37 |
import org.apache.logging.log4j.LogManager;
|
|
|
38 |
import org.apache.logging.log4j.Logger;
|
|
|
39 |
import org.hibernate.Session;
|
|
|
40 |
import org.hibernate.SessionFactory;
|
|
|
41 |
import org.hibernate.query.NativeQuery;
|
|
|
42 |
import org.springframework.beans.factory.annotation.Autowired;
|
| 36334 |
ranu |
43 |
import org.springframework.cache.annotation.Cacheable;
|
| 33917 |
ranu |
44 |
import org.springframework.stereotype.Component;
|
|
|
45 |
|
|
|
46 |
import javax.persistence.TypedQuery;
|
| 34880 |
ranu |
47 |
import java.time.*;
|
| 35631 |
ranu |
48 |
import java.time.format.DateTimeFormatter;
|
| 34880 |
ranu |
49 |
import java.time.temporal.ChronoUnit;
|
| 35631 |
ranu |
50 |
import java.util.*;
|
| 33997 |
ranu |
51 |
import java.util.stream.Collectors;
|
| 33917 |
ranu |
52 |
|
|
|
53 |
@Component
|
|
|
54 |
public class RbmTargetServiceImpl implements RbmTargetService {
|
|
|
55 |
private static final Logger LOGGER = LogManager.getLogger(RbmTargetServiceImpl.class);
|
|
|
56 |
|
|
|
57 |
@Autowired
|
|
|
58 |
SessionFactory sessionFactory;
|
|
|
59 |
|
| 33926 |
ranu |
60 |
@Autowired
|
|
|
61 |
RbmTargetsRepository rbmTargetsRepository;
|
| 33917 |
ranu |
62 |
|
| 33985 |
ranu |
63 |
@Autowired
|
|
|
64 |
RbmAchievementsRepository rbmAchievementsRepository;
|
|
|
65 |
|
| 34397 |
ranu |
66 |
@Autowired
|
|
|
67 |
MonthlyTargetRepository monthlyTargetRepository;
|
|
|
68 |
|
| 34880 |
ranu |
69 |
@Autowired
|
|
|
70 |
PublicHolidaysRepository publicHolidaysRepository;
|
|
|
71 |
|
| 35631 |
ranu |
72 |
@Autowired
|
|
|
73 |
RetailerService retailerService;
|
|
|
74 |
|
| 33917 |
ranu |
75 |
@Override
|
|
|
76 |
public List<WarehouseRbmTargetModel> getWarehouseWiseRbmMonthlyTarget() {
|
|
|
77 |
Session session = sessionFactory.getCurrentSession();
|
|
|
78 |
final TypedQuery<WarehouseRbmTargetModel> typedQuerySimilar = session.createNamedQuery("RbmTarget.getWarehouseWiseMonthlyTarget", WarehouseRbmTargetModel.class);
|
|
|
79 |
|
|
|
80 |
return typedQuerySimilar.getResultList();
|
|
|
81 |
|
|
|
82 |
}
|
|
|
83 |
|
|
|
84 |
@Override
|
|
|
85 |
public List<MTDAchievedTargetModel> getDateWiseAchievedTargetOfRbm(LocalDate startDate, LocalDate endDate) {
|
|
|
86 |
Session session = sessionFactory.getCurrentSession();
|
|
|
87 |
final TypedQuery<MTDAchievedTargetModel> typedQuerySimilar = session.createNamedQuery("RbmTarget.getRbmAchievedMonthlyTarget", MTDAchievedTargetModel.class);
|
|
|
88 |
typedQuerySimilar.setParameter("startDate", startDate);
|
|
|
89 |
typedQuerySimilar.setParameter("endDate", endDate);
|
|
|
90 |
return typedQuerySimilar.getResultList();
|
|
|
91 |
|
|
|
92 |
}
|
|
|
93 |
|
|
|
94 |
@Override
|
| 34055 |
ranu |
95 |
public List<TodayAchievedMovementModel> getMovementWiseAchievementByDate(LocalDate startDate, LocalDate endDate) {
|
| 33917 |
ranu |
96 |
LOGGER.info("start date {}, end date {}", startDate, endDate);
|
|
|
97 |
Session session = sessionFactory.getCurrentSession();
|
| 34055 |
ranu |
98 |
final TypedQuery<TodayAchievedMovementModel> typedQuerySimilar = session.createNamedQuery("RBMTarget.TodayAchivementByMovement", TodayAchievedMovementModel.class);
|
| 33917 |
ranu |
99 |
typedQuerySimilar.setParameter("startDate", startDate);
|
|
|
100 |
typedQuerySimilar.setParameter("endDate", endDate);
|
|
|
101 |
return typedQuerySimilar.getResultList();
|
|
|
102 |
|
|
|
103 |
}
|
|
|
104 |
|
|
|
105 |
@Override
|
|
|
106 |
public List<WarehouseMobileStockByMovementModel> getWarehouseMobileStockByMovement() {
|
|
|
107 |
Session session = sessionFactory.getCurrentSession();
|
|
|
108 |
final TypedQuery<WarehouseMobileStockByMovementModel> typedQuerySimilar = session.createNamedQuery("WarehouseStock.MovementWiseMobileStock", WarehouseMobileStockByMovementModel.class);
|
|
|
109 |
|
|
|
110 |
return typedQuerySimilar.getResultList();
|
|
|
111 |
|
|
|
112 |
}
|
|
|
113 |
|
| 33991 |
ranu |
114 |
@Override
|
|
|
115 |
public List<SoldCatalogsReportModel> getCatalogSoldReport(LocalDate startDate, LocalDate endDate) {
|
|
|
116 |
Session session = sessionFactory.getCurrentSession();
|
|
|
117 |
final TypedQuery<SoldCatalogsReportModel> typedQuerySimilar = session.createNamedQuery("CatalogsReport.SoldCatalogsReport", SoldCatalogsReportModel.class);
|
|
|
118 |
typedQuerySimilar.setParameter("startDate", startDate);
|
|
|
119 |
typedQuerySimilar.setParameter("endDate", endDate);
|
|
|
120 |
return typedQuerySimilar.getResultList();
|
| 33917 |
ranu |
121 |
|
| 33991 |
ranu |
122 |
}
|
|
|
123 |
|
|
|
124 |
|
| 33917 |
ranu |
125 |
public int getWorkingDaysCount(LocalDate startDate) {
|
|
|
126 |
Session session = sessionFactory.getCurrentSession();
|
|
|
127 |
|
|
|
128 |
// Convert the LocalDate to a format MySQL can interpret
|
|
|
129 |
String startDateString = startDate.toString();
|
|
|
130 |
|
|
|
131 |
final NativeQuery<?> nativeQuery = session.createNativeQuery(
|
|
|
132 |
"SELECT (DATEDIFF(LAST_DAY(:startDate), :startDate) + 1) " +
|
|
|
133 |
" - (FLOOR((DATEDIFF(LAST_DAY(:startDate), :startDate) + (WEEKDAY(:startDate) + 1)) / 7)) " +
|
|
|
134 |
" - (SELECT COUNT(*) " +
|
|
|
135 |
" FROM logistics.publicholidays " +
|
|
|
136 |
" WHERE date BETWEEN :startDate AND LAST_DAY(:startDate) " +
|
|
|
137 |
" AND WEEKDAY(date) != 6) AS working_days"
|
|
|
138 |
);
|
|
|
139 |
|
|
|
140 |
// Set the start date parameter for each placeholder
|
|
|
141 |
nativeQuery.setParameter("startDate", startDateString);
|
|
|
142 |
|
|
|
143 |
Object result = nativeQuery.getSingleResult();
|
|
|
144 |
return result != null ? ((Number) result).intValue() : 0;
|
|
|
145 |
}
|
|
|
146 |
|
|
|
147 |
|
| 35044 |
ranu |
148 |
|
| 33917 |
ranu |
149 |
@Override
|
|
|
150 |
public List<RbmArrViewModel> getRbmTodayArr() throws Exception {
|
|
|
151 |
LocalDate todayDate = LocalDate.now();
|
|
|
152 |
return getRbmTodayArr(todayDate);
|
|
|
153 |
}
|
|
|
154 |
|
|
|
155 |
@Override
|
| 33997 |
ranu |
156 |
public List<RbmTargetAndAchievementsModel> getRbmTargetsAndAchievemnts(LocalDate startDate, LocalDate endDate) {
|
|
|
157 |
|
| 34002 |
ranu |
158 |
List<RbmTargetsModel> rbmTargetsList = rbmTargetsRepository.selectTargetsModelListByDates(startDate.atStartOfDay(), endDate.atTime(LocalTime.MAX));
|
| 33997 |
ranu |
159 |
|
|
|
160 |
LOGGER.info("rbmTargetsList {}", rbmTargetsList);
|
|
|
161 |
// Group Targtes by RBM and Warehouse
|
| 34002 |
ranu |
162 |
Map<String, RbmTargetsModel> targetsMap = rbmTargetsList.stream()
|
| 33997 |
ranu |
163 |
.collect(Collectors.toMap(
|
|
|
164 |
a -> a.getRbmAuthId() + "-" + a.getWarehouseId(),
|
|
|
165 |
a -> a,
|
|
|
166 |
(a1, a2) -> mergeTargets(a1, a2) // Handle duplicates by merging
|
|
|
167 |
));
|
|
|
168 |
|
|
|
169 |
|
| 34002 |
ranu |
170 |
List<RbmAchievementsModel> rbmAchievements = rbmAchievementsRepository.selectAchievementsModelListByDates(startDate.atStartOfDay(), endDate.atTime(LocalTime.MAX));
|
| 33997 |
ranu |
171 |
LOGGER.info("rbmTargetsList {}", rbmAchievements);
|
|
|
172 |
// Group achievements by RBM and Warehouse
|
| 34002 |
ranu |
173 |
Map<String, RbmAchievementsModel> achievementMap = rbmAchievements.stream()
|
| 33997 |
ranu |
174 |
.collect(Collectors.toMap(
|
|
|
175 |
a -> a.getRbmAuthId() + "-" + a.getWarehouseId(),
|
|
|
176 |
a -> a,
|
|
|
177 |
(a1, a2) -> mergeAchievements(a1, a2) // Handle duplicates by merging
|
|
|
178 |
));
|
|
|
179 |
|
|
|
180 |
return targetsMap.keySet().stream()
|
|
|
181 |
.map(key -> {
|
|
|
182 |
String[] parts = key.split("-");
|
|
|
183 |
int rbmAuthId = Integer.parseInt(parts[0]);
|
|
|
184 |
int warehouseId = Integer.parseInt(parts[1]);
|
|
|
185 |
|
| 34002 |
ranu |
186 |
RbmTargetsModel target = targetsMap.get(key);
|
|
|
187 |
RbmAchievementsModel achievement = achievementMap.getOrDefault(key, new RbmAchievementsModel());
|
| 33997 |
ranu |
188 |
|
|
|
189 |
RbmTargetAndAchievementsModel model = new RbmTargetAndAchievementsModel();
|
|
|
190 |
model.setAuthId(rbmAuthId);
|
|
|
191 |
model.setRbmName(target.getRbmName());
|
|
|
192 |
model.setWarehouseName(ProfitMandiConstants.WAREHOUSE_MAP.getOrDefault(warehouseId, "Unknown"));
|
|
|
193 |
|
|
|
194 |
// Set target values
|
| 34006 |
ranu |
195 |
model.setHidTarget((long) target.getHidTarget());
|
| 34098 |
ranu |
196 |
model.setRunningTarget((long) target.getRunningTarget());
|
| 34006 |
ranu |
197 |
model.setFastMovingTarget((long) target.getFastMovingTarget());
|
|
|
198 |
model.setSlowMovingTarget((long) target.getSlowMovingTarget());
|
|
|
199 |
model.setOtherMovingTarget((long) target.getOtherTarget());
|
| 33997 |
ranu |
200 |
|
|
|
201 |
// Set achievement values
|
| 34006 |
ranu |
202 |
model.setAchievedHid((long) achievement.getAchievedHidTarget());
|
| 34098 |
ranu |
203 |
model.setAchievedRunning((long) achievement.getAchievedRunningTarget());
|
| 34006 |
ranu |
204 |
model.setAchievedFastMoving((long) achievement.getAchievedFastMovingTarget());
|
|
|
205 |
model.setAchievedSlowMoving((long) achievement.getAchievedSlowMovingTarget());
|
|
|
206 |
model.setAchievedOtherMoving((long) achievement.getAchievedOtherTarget());
|
| 33997 |
ranu |
207 |
|
|
|
208 |
model.setTotalTarget(
|
| 34006 |
ranu |
209 |
(long) target.getHidTarget() +
|
| 34098 |
ranu |
210 |
(long) target.getRunningTarget() +
|
| 34006 |
ranu |
211 |
(long) target.getFastMovingTarget() +
|
|
|
212 |
(long) target.getSlowMovingTarget() +
|
|
|
213 |
(long) target.getOtherTarget()
|
| 33997 |
ranu |
214 |
);
|
|
|
215 |
model.setTotalAchievemnt(
|
| 34006 |
ranu |
216 |
(long) achievement.getAchievedHidTarget() +
|
| 34098 |
ranu |
217 |
(long) achievement.getAchievedRunningTarget() +
|
| 34006 |
ranu |
218 |
(long) achievement.getAchievedFastMovingTarget() +
|
|
|
219 |
(long) achievement.getAchievedSlowMovingTarget() +
|
|
|
220 |
(long) achievement.getAchievedOtherTarget()
|
| 33997 |
ranu |
221 |
);
|
|
|
222 |
|
|
|
223 |
return model;
|
|
|
224 |
})
|
|
|
225 |
.collect(Collectors.toList());
|
|
|
226 |
|
|
|
227 |
}
|
|
|
228 |
|
| 34002 |
ranu |
229 |
private RbmTargetsModel mergeTargets(RbmTargetsModel a1, RbmTargetsModel a2) {
|
| 33997 |
ranu |
230 |
|
|
|
231 |
// Merge logic for achievements (aggregate the target and achieved values)
|
| 34006 |
ranu |
232 |
a1.setHidTarget((a1.getHidTarget()) +
|
|
|
233 |
(a2.getHidTarget()));
|
| 33997 |
ranu |
234 |
|
| 34006 |
ranu |
235 |
a1.setFastMovingTarget((a1.getFastMovingTarget()) +
|
|
|
236 |
(a2.getFastMovingTarget()));
|
| 33997 |
ranu |
237 |
|
| 34006 |
ranu |
238 |
a1.setSlowMovingTarget((a1.getSlowMovingTarget()) +
|
|
|
239 |
(a2.getSlowMovingTarget()));
|
| 33997 |
ranu |
240 |
|
| 34098 |
ranu |
241 |
a1.setRunningTarget((a1.getRunningTarget()) +
|
|
|
242 |
(a2.getRunningTarget()));
|
| 33997 |
ranu |
243 |
|
| 34006 |
ranu |
244 |
a1.setOtherTarget((a1.getOtherTarget()) +
|
|
|
245 |
(a2.getOtherTarget()));
|
| 33997 |
ranu |
246 |
return a1;
|
|
|
247 |
}
|
|
|
248 |
|
| 34002 |
ranu |
249 |
private RbmAchievementsModel mergeAchievements(RbmAchievementsModel a1, RbmAchievementsModel a2) {
|
| 33997 |
ranu |
250 |
// Merge logic for achievements (aggregate the target and achieved values)
|
| 34006 |
ranu |
251 |
a1.setAchievedHidTarget((a1.getAchievedHidTarget()) +
|
|
|
252 |
(a2.getAchievedHidTarget()));
|
| 33997 |
ranu |
253 |
|
| 34098 |
ranu |
254 |
a1.setAchievedRunningTarget((a1.getAchievedRunningTarget()) +
|
|
|
255 |
(a2.getAchievedRunningTarget()));
|
| 33997 |
ranu |
256 |
|
| 34006 |
ranu |
257 |
a1.setAchievedFastMovingTarget((a1.getAchievedFastMovingTarget()) +
|
|
|
258 |
(a2.getAchievedFastMovingTarget()));
|
| 33997 |
ranu |
259 |
|
| 34006 |
ranu |
260 |
a1.setAchievedSlowMovingTarget((a1.getAchievedSlowMovingTarget()) +
|
|
|
261 |
(a2.getAchievedSlowMovingTarget()));
|
| 33997 |
ranu |
262 |
|
| 34006 |
ranu |
263 |
a1.setAchievedOtherTarget((a1.getAchievedOtherTarget()) +
|
|
|
264 |
(a2.getAchievedOtherTarget()));
|
| 33997 |
ranu |
265 |
|
|
|
266 |
return a1;
|
|
|
267 |
}
|
| 34002 |
ranu |
268 |
|
| 33997 |
ranu |
269 |
@Override
|
| 33917 |
ranu |
270 |
public List<RbmArrViewModel> getRbmTodayArr(LocalDate todayDate) throws Exception {
|
|
|
271 |
|
|
|
272 |
LocalDate startDateOfMonthDay1 = LocalDate.now().withDayOfMonth(1);
|
|
|
273 |
|
| 34289 |
ranu |
274 |
List<WarehouseRbmTargetModel> warehouseRbmTargetModelList = this.getWarehouseWiseRbmMonthlyTarget();
|
|
|
275 |
List<WarehouseRbmTargetModel> warehouseRbmTargetModels = warehouseRbmTargetModelList.stream().filter(x -> x.getMonthlyTarget() > 0).collect(Collectors.toList());
|
|
|
276 |
LOGGER.info("warehouseRbmTargetModels {}", warehouseRbmTargetModels);
|
|
|
277 |
List<TodayAchievedMovementModel> todayAchievedMovementModels = getMovementWiseAchievementByDate(todayDate, todayDate.plusDays(1));
|
| 33917 |
ranu |
278 |
|
|
|
279 |
List<MTDAchievedTargetModel> mtdAchievedTargetModels = getDateWiseAchievedTargetOfRbm(startDateOfMonthDay1, todayDate);
|
|
|
280 |
|
| 35044 |
ranu |
281 |
int remainingWorkingDaysCount = (int) getRemainingDaysInMonth(todayDate);
|
| 33917 |
ranu |
282 |
|
| 33926 |
ranu |
283 |
List<RbmTargets> todayRbmTargetsList = rbmTargetsRepository.selectTargetsByDates(todayDate.atStartOfDay(), todayDate.atTime(LocalTime.MAX));
|
| 33917 |
ranu |
284 |
|
| 33926 |
ranu |
285 |
LOGGER.info("todayRbmTargetsList {}", todayRbmTargetsList);
|
| 33917 |
ranu |
286 |
|
|
|
287 |
List<RbmArrViewModel> rbmArrViewModels = new ArrayList<>();
|
|
|
288 |
|
| 34028 |
ranu |
289 |
if (!todayRbmTargetsList.isEmpty()) {
|
| 33917 |
ranu |
290 |
|
| 35454 |
amit |
291 |
// OPTIMIZED: Pre-build maps for O(1) lookup instead of O(n) filter in each iteration
|
|
|
292 |
// Map key: "authId-warehouseId"
|
|
|
293 |
Map<String, Double> mtdAchievedMap = mtdAchievedTargetModels.stream()
|
|
|
294 |
.collect(Collectors.groupingBy(
|
|
|
295 |
x -> x.getAuthId() + "-" + x.getWarehouseId(),
|
|
|
296 |
Collectors.summingDouble(MTDAchievedTargetModel::getAcheivedMonthlyTarget)
|
|
|
297 |
));
|
|
|
298 |
|
|
|
299 |
Map<String, TodayAchievedMovementModel> todayAchievedMap = todayAchievedMovementModels.stream()
|
|
|
300 |
.collect(Collectors.toMap(
|
|
|
301 |
x -> x.getAuthId() + "-" + x.getWarehouseId(),
|
|
|
302 |
x -> x,
|
|
|
303 |
(a, b) -> a
|
|
|
304 |
));
|
|
|
305 |
|
|
|
306 |
Map<String, RbmTargets> todayRbmTargetsMap = todayRbmTargetsList.stream()
|
|
|
307 |
.collect(Collectors.toMap(
|
|
|
308 |
x -> x.getRbmAuthId() + "-" + x.getWarehouseId(),
|
|
|
309 |
x -> x,
|
|
|
310 |
(a, b) -> a
|
|
|
311 |
));
|
|
|
312 |
|
| 34028 |
ranu |
313 |
for (WarehouseRbmTargetModel rbmTarget : warehouseRbmTargetModels) {
|
| 33917 |
ranu |
314 |
|
| 35454 |
amit |
315 |
String lookupKey = rbmTarget.getAuthId() + "-" + rbmTarget.getWarehouseId();
|
|
|
316 |
|
| 34028 |
ranu |
317 |
float monthlyTarget = rbmTarget.getMonthlyTarget();
|
| 35454 |
amit |
318 |
float achievedSoFar = mtdAchievedMap.getOrDefault(lookupKey, 0.0).floatValue();
|
| 33917 |
ranu |
319 |
|
| 34028 |
ranu |
320 |
float remainingTarget = monthlyTarget - achievedSoFar;
|
| 33953 |
ranu |
321 |
|
| 34028 |
ranu |
322 |
float todayTarget = (remainingWorkingDaysCount > 0 && remainingTarget > 0) ? remainingTarget / remainingWorkingDaysCount : 0;
|
|
|
323 |
|
| 33926 |
ranu |
324 |
String warehouseName = ProfitMandiConstants.WAREHOUSE_MAP.getOrDefault(rbmTarget.getWarehouseId(), "Unknown");
|
| 33917 |
ranu |
325 |
|
| 34288 |
ranu |
326 |
LOGGER.info("rbmTarget ==== {}", rbmTarget);
|
| 34281 |
ranu |
327 |
|
| 35454 |
amit |
328 |
TodayAchievedMovementModel todayAchievedMovementModel = todayAchievedMap.get(lookupKey);
|
| 34283 |
ranu |
329 |
|
| 35454 |
amit |
330 |
RbmTargets todayRbmTargets = todayRbmTargetsMap.get(lookupKey);
|
| 34285 |
ranu |
331 |
|
| 35454 |
amit |
332 |
if (todayRbmTargets != null) {
|
| 34034 |
ranu |
333 |
LOGGER.info("todayRbmTargets {}", todayRbmTargets);
|
|
|
334 |
RbmArrViewModel viewModel = new RbmArrViewModel();
|
| 33917 |
ranu |
335 |
|
| 34034 |
ranu |
336 |
viewModel.setAuthId(rbmTarget.getAuthId());
|
|
|
337 |
viewModel.setRbmName(rbmTarget.getRbmName());
|
|
|
338 |
viewModel.setWarehouseName(warehouseName);
|
|
|
339 |
viewModel.setTodayTarget(Math.round(todayTarget));
|
|
|
340 |
viewModel.setMonthlyTarget(Math.round(monthlyTarget));
|
|
|
341 |
viewModel.setMtdAchievedTarget(Math.round(achievedSoFar));
|
| 33926 |
ranu |
342 |
|
| 34034 |
ranu |
343 |
viewModel.setTodayHidTarget(Math.round((todayRbmTargets.getHidTarget())));
|
|
|
344 |
viewModel.setTodayFastMovingTarget(Math.round(todayRbmTargets.getFastMovingTarget()));
|
| 34098 |
ranu |
345 |
viewModel.setTodaySlowMovingTarget(Math.round(todayRbmTargets.getSlowMovingtarget()));
|
|
|
346 |
viewModel.setTodayRunningTarget(Math.round(todayRbmTargets.getRunningtarget()));
|
| 34034 |
ranu |
347 |
viewModel.setTodayOtherMovingTarget(Math.round(todayRbmTargets.getOtherTarget()));
|
| 33926 |
ranu |
348 |
|
| 34283 |
ranu |
349 |
if (todayAchievedMovementModel != null) {
|
|
|
350 |
viewModel.setTodayAchievedHidTarget(Math.round(todayAchievedMovementModel.getHidBilled()));
|
|
|
351 |
viewModel.setTodayAchievedFastMovingTarget(Math.round(todayAchievedMovementModel.getFastMovingBilled()));
|
|
|
352 |
viewModel.setTodayAchievedSlowMovingTarget(Math.round(todayAchievedMovementModel.getSlowMovinBilled()));
|
|
|
353 |
viewModel.setTodayAchievedRunningTarget(Math.round(todayAchievedMovementModel.getRunningBilled()));
|
|
|
354 |
viewModel.setTodayAchievedOtherMovingTarget(Math.round(todayAchievedMovementModel.getOtherBilled()));
|
|
|
355 |
viewModel.setTotalAchievedTarget(Math.round(todayAchievedMovementModel.getHidBilled() + todayAchievedMovementModel.getFastMovingBilled() + todayAchievedMovementModel.getSlowMovinBilled() + todayAchievedMovementModel.getRunningBilled() + todayAchievedMovementModel.getOtherBilled()));
|
|
|
356 |
} else {
|
|
|
357 |
viewModel.setTodayAchievedHidTarget(0);
|
|
|
358 |
viewModel.setTodayAchievedFastMovingTarget(0);
|
|
|
359 |
viewModel.setTodayAchievedSlowMovingTarget(0);
|
|
|
360 |
viewModel.setTodayAchievedRunningTarget(0);
|
|
|
361 |
viewModel.setTodayAchievedOtherMovingTarget(0);
|
|
|
362 |
viewModel.setTotalAchievedTarget(0);
|
|
|
363 |
}
|
| 34034 |
ranu |
364 |
rbmArrViewModels.add(viewModel);
|
|
|
365 |
} else {
|
|
|
366 |
LOGGER.info("No matching RbmTargets found for AuthId: {} and rbmname {} and WarehouseId: {}", rbmTarget.getAuthId(), rbmTarget.getRbmName(), rbmTarget.getWarehouseId());
|
|
|
367 |
}
|
| 33917 |
ranu |
368 |
|
| 34034 |
ranu |
369 |
|
|
|
370 |
|
| 34028 |
ranu |
371 |
}
|
| 33917 |
ranu |
372 |
}
|
|
|
373 |
|
|
|
374 |
LOGGER.info("rbmArrViewModels {}", rbmArrViewModels);
|
|
|
375 |
return rbmArrViewModels;
|
|
|
376 |
}
|
|
|
377 |
|
| 33926 |
ranu |
378 |
@Override
|
|
|
379 |
public void setMovementWiseRbmTargets() {
|
|
|
380 |
LocalDate todayDate = LocalDate.now();
|
| 33917 |
ranu |
381 |
|
| 33926 |
ranu |
382 |
LocalDate startDateOfMonthDay1 = LocalDate.now().withDayOfMonth(1);
|
|
|
383 |
|
|
|
384 |
List<WarehouseRbmTargetModel> warehouseRbmTargetModels = this.getWarehouseWiseRbmMonthlyTarget();
|
|
|
385 |
|
|
|
386 |
List<MTDAchievedTargetModel> mtdAchievedTargetModels = getDateWiseAchievedTargetOfRbm(startDateOfMonthDay1, todayDate);
|
|
|
387 |
|
|
|
388 |
|
| 35044 |
ranu |
389 |
int remainingWorkingDaysCount = (int) getRemainingDaysInMonth(todayDate);
|
| 33926 |
ranu |
390 |
|
|
|
391 |
List<WarehouseMobileStockByMovementModel> warehouseMobileStockByMovementModels = getWarehouseMobileStockByMovement();
|
|
|
392 |
|
| 35454 |
amit |
393 |
// OPTIMIZED: Pre-build maps for O(1) lookup instead of O(n) filter in each iteration
|
|
|
394 |
Map<String, Double> mtdAchievedMap = mtdAchievedTargetModels.stream()
|
|
|
395 |
.collect(Collectors.groupingBy(
|
|
|
396 |
x -> x.getAuthId() + "-" + x.getWarehouseId(),
|
|
|
397 |
Collectors.summingDouble(MTDAchievedTargetModel::getAcheivedMonthlyTarget)
|
|
|
398 |
));
|
|
|
399 |
|
|
|
400 |
Map<Integer, WarehouseMobileStockByMovementModel> warehouseStockMap = warehouseMobileStockByMovementModels.stream()
|
|
|
401 |
.collect(Collectors.toMap(
|
|
|
402 |
WarehouseMobileStockByMovementModel::getWarehouseId,
|
|
|
403 |
x -> x,
|
|
|
404 |
(a, b) -> a
|
|
|
405 |
));
|
|
|
406 |
|
| 33926 |
ranu |
407 |
for (WarehouseRbmTargetModel rbmTarget : warehouseRbmTargetModels) {
|
|
|
408 |
|
| 35454 |
amit |
409 |
String lookupKey = rbmTarget.getAuthId() + "-" + rbmTarget.getWarehouseId();
|
|
|
410 |
|
| 33926 |
ranu |
411 |
float monthlyTarget = rbmTarget.getMonthlyTarget();
|
| 35454 |
amit |
412 |
float achievedSoFar = mtdAchievedMap.getOrDefault(lookupKey, 0.0).floatValue();
|
| 33926 |
ranu |
413 |
|
|
|
414 |
|
|
|
415 |
float remainingTarget = monthlyTarget - achievedSoFar;
|
| 33953 |
ranu |
416 |
LOGGER.info("remainingTarget {}", remainingTarget);
|
| 33926 |
ranu |
417 |
|
| 33953 |
ranu |
418 |
float todayTarget = (remainingWorkingDaysCount > 0 && remainingTarget > 0) ? remainingTarget / remainingWorkingDaysCount : 0;
|
|
|
419 |
LOGGER.info("todayTarget {}", todayTarget);
|
|
|
420 |
|
| 33926 |
ranu |
421 |
// Get the warehouse stock data
|
| 35454 |
amit |
422 |
WarehouseMobileStockByMovementModel warehouseMobileStockByMovementModel = warehouseStockMap.get(rbmTarget.getWarehouseId());
|
| 33926 |
ranu |
423 |
|
|
|
424 |
|
|
|
425 |
if (warehouseMobileStockByMovementModel != null) {
|
|
|
426 |
|
|
|
427 |
// Total stock value for this warehouse
|
|
|
428 |
float totalStockValue = warehouseMobileStockByMovementModel.getTotalAvailabilityPrice();
|
|
|
429 |
|
|
|
430 |
// Calculate target allocation based on stock value proportion
|
|
|
431 |
float hidTarget = (warehouseMobileStockByMovementModel.getTotalHidCatalogPrice() / totalStockValue) * todayTarget;
|
|
|
432 |
float fastMovingTarget = (warehouseMobileStockByMovementModel.getTotalFastMovingCatalogPrice() / totalStockValue) * todayTarget;
|
|
|
433 |
float slowMovingTarget = (warehouseMobileStockByMovementModel.getTotalSlowMovingCatalogPrice() / totalStockValue) * todayTarget;
|
| 34098 |
ranu |
434 |
float runningTarget = (warehouseMobileStockByMovementModel.getTotalRunningCatalogPrice() / totalStockValue) * todayTarget;
|
| 33926 |
ranu |
435 |
float otherTarget = (warehouseMobileStockByMovementModel.getTotalOtherCategoryCatalogPrice() / totalStockValue) * todayTarget;
|
|
|
436 |
|
|
|
437 |
RbmTargets rbmTargets = new RbmTargets();
|
|
|
438 |
rbmTargets.setWarehouseId(rbmTarget.getWarehouseId());
|
|
|
439 |
rbmTargets.setRbmAuthId(rbmTarget.getAuthId());
|
|
|
440 |
rbmTargets.setRbmName(rbmTarget.getRbmName());
|
| 34098 |
ranu |
441 |
rbmTargets.setRunningtarget(runningTarget);
|
| 33926 |
ranu |
442 |
rbmTargets.setHidTarget(hidTarget);
|
|
|
443 |
rbmTargets.setFastMovingTarget(fastMovingTarget);
|
| 34098 |
ranu |
444 |
rbmTargets.setSlowMovingtarget(slowMovingTarget);
|
| 33926 |
ranu |
445 |
rbmTargets.setOtherTarget(otherTarget);
|
|
|
446 |
rbmTargets.setCreateTimestamp(LocalDateTime.now());
|
|
|
447 |
|
|
|
448 |
rbmTargetsRepository.persist(rbmTargets);
|
|
|
449 |
|
|
|
450 |
}
|
|
|
451 |
}
|
|
|
452 |
|
|
|
453 |
}
|
|
|
454 |
|
|
|
455 |
|
| 33985 |
ranu |
456 |
@Override
|
|
|
457 |
public void setMovementWiseRbmAchievement() {
|
|
|
458 |
LocalDate todayDate = LocalDate.now();
|
|
|
459 |
|
| 34055 |
ranu |
460 |
List<TodayAchievedMovementModel> todayAchievedMovementModels = getMovementWiseAchievementByDate(todayDate, todayDate.plusDays(1));
|
| 33985 |
ranu |
461 |
|
|
|
462 |
|
|
|
463 |
for (TodayAchievedMovementModel achievement : todayAchievedMovementModels) {
|
|
|
464 |
|
|
|
465 |
RbmAchievements rbmAchievements = new RbmAchievements();
|
|
|
466 |
|
|
|
467 |
rbmAchievements.setRbmAuthId(achievement.getAuthId());
|
|
|
468 |
rbmAchievements.setRbmName(achievement.getRbmName());
|
|
|
469 |
rbmAchievements.setWarehouseId(achievement.getWarehouseId());
|
|
|
470 |
rbmAchievements.setAchievedHidTarget(achievement.getHidBilled());
|
|
|
471 |
rbmAchievements.setAchievedFastMovingTarget(achievement.getFastMovingBilled());
|
| 34098 |
ranu |
472 |
rbmAchievements.setAchievedSlowMovingTarget(achievement.getSlowMovinBilled());
|
|
|
473 |
rbmAchievements.setAchievedRunningTarget(achievement.getRunningBilled());
|
| 34012 |
ranu |
474 |
rbmAchievements.setAchievedOtherTarget(achievement.getOtherBilled());
|
| 33985 |
ranu |
475 |
rbmAchievements.setCreateTimestamp(LocalDateTime.now());
|
|
|
476 |
|
|
|
477 |
rbmAchievementsRepository.persist(rbmAchievements);
|
|
|
478 |
|
|
|
479 |
}
|
|
|
480 |
|
|
|
481 |
}
|
|
|
482 |
|
| 34055 |
ranu |
483 |
@Override
|
|
|
484 |
public List<Sold15daysOldAgingModel> getAgingSale(LocalDate startDate, LocalDate endDate) {
|
|
|
485 |
Session session = sessionFactory.getCurrentSession();
|
|
|
486 |
final TypedQuery<Sold15daysOldAgingModel> typedQuerySimilar = session.createNamedQuery("Aging.SoldAgingModel", Sold15daysOldAgingModel.class);
|
| 34056 |
ranu |
487 |
typedQuerySimilar.setParameter("startDate", startDate);
|
|
|
488 |
typedQuerySimilar.setParameter("endDate", endDate);
|
| 34055 |
ranu |
489 |
return typedQuerySimilar.getResultList();
|
| 33985 |
ranu |
490 |
|
| 34055 |
ranu |
491 |
}
|
|
|
492 |
|
| 34103 |
ranu |
493 |
@Override
|
|
|
494 |
public List<RbmBilledFofoIdsModel> getDateWiseBilledFofoIdByRbm(LocalDate startDate, LocalDate endDate) {
|
|
|
495 |
Session session = sessionFactory.getCurrentSession();
|
|
|
496 |
final TypedQuery<RbmBilledFofoIdsModel> typedQuerySimilar = session.createNamedQuery("RBM.RbmBilledFofoId", RbmBilledFofoIdsModel.class);
|
|
|
497 |
typedQuerySimilar.setParameter("startDate", startDate);
|
|
|
498 |
typedQuerySimilar.setParameter("endDate", endDate);
|
|
|
499 |
return typedQuerySimilar.getResultList();
|
| 35453 |
amit |
500 |
}
|
| 34103 |
ranu |
501 |
|
| 35453 |
amit |
502 |
@Override
|
| 36296 |
amit |
503 |
@Cacheable(value = "rbmWeeklyBilling",
|
| 36329 |
amit |
504 |
cacheManager = "fiveMintimeoutCacheManager",
|
|
|
505 |
sync = true)
|
| 35453 |
amit |
506 |
public List<RbmWeeklyBillingModel> getWeeklyBillingDataForMonth(LocalDate monthStart, LocalDate monthEnd) {
|
|
|
507 |
Session session = sessionFactory.getCurrentSession();
|
|
|
508 |
final TypedQuery<RbmWeeklyBillingModel> typedQuery = session.createNamedQuery("RBM.WeeklyBilling", RbmWeeklyBillingModel.class);
|
|
|
509 |
typedQuery.setParameter("startDate", monthStart);
|
|
|
510 |
typedQuery.setParameter("endDate", monthEnd);
|
|
|
511 |
return typedQuery.getResultList();
|
| 34103 |
ranu |
512 |
}
|
|
|
513 |
|
| 34055 |
ranu |
514 |
public List<Our15DaysOldAgingStock> our15DaysAgingStock() {
|
|
|
515 |
Session session = sessionFactory.getCurrentSession();
|
|
|
516 |
final TypedQuery<Our15DaysOldAgingStock> typedQuerySimilar = session.createNamedQuery("Aging.15DaysOurStock", Our15DaysOldAgingStock.class);
|
|
|
517 |
return typedQuerySimilar.getResultList();
|
| 36334 |
ranu |
518 |
}
|
| 34055 |
ranu |
519 |
|
| 36334 |
ranu |
520 |
@Override
|
|
|
521 |
public List<WarehouseAgingStockModel> getWarehouseWiseAgingStock() {
|
|
|
522 |
Session session = sessionFactory.getCurrentSession();
|
|
|
523 |
final TypedQuery<WarehouseAgingStockModel> typedQuery = session.createNamedQuery("Aging.15DaysWarehouseWiseStock", WarehouseAgingStockModel.class);
|
|
|
524 |
return typedQuery.getResultList();
|
| 34055 |
ranu |
525 |
}
|
|
|
526 |
|
| 34397 |
ranu |
527 |
@Autowired
|
|
|
528 |
OrderRepository orderRepository;
|
| 34055 |
ranu |
529 |
|
| 34397 |
ranu |
530 |
@Override
|
| 34641 |
ranu |
531 |
public double calculateFofoIdTodayTarget(int fofoId, double secondryMtd,LocalDate date) {
|
| 34397 |
ranu |
532 |
|
|
|
533 |
MonthlyTarget monthlyTarget = monthlyTargetRepository.selectByDateAndFofoId(YearMonth.now(), fofoId);
|
| 34404 |
ranu |
534 |
if (monthlyTarget == null) {
|
|
|
535 |
// Log or handle as needed
|
|
|
536 |
return 0; // or -1 or some fallback
|
|
|
537 |
}
|
| 34397 |
ranu |
538 |
|
|
|
539 |
double remainingTarget = monthlyTarget.getPurchaseTarget() - secondryMtd;
|
| 34880 |
ranu |
540 |
// double remainingWorkingDays = getWorkingDaysCount(date);
|
|
|
541 |
double remainingWorkingDays = (double) getRemainingDaysInMonth(date);
|
| 34397 |
ranu |
542 |
|
|
|
543 |
|
| 34716 |
ranu |
544 |
|
| 34397 |
ranu |
545 |
if (remainingWorkingDays == 0) return remainingTarget; // Last day
|
| 34716 |
ranu |
546 |
LOGGER.info("remainingWorkingDays {}", remainingWorkingDays);
|
|
|
547 |
LOGGER.info("remainingTarget {}", remainingTarget);
|
| 34397 |
ranu |
548 |
|
|
|
549 |
return (int) Math.ceil(remainingTarget / remainingWorkingDays);
|
|
|
550 |
}
|
|
|
551 |
|
| 34880 |
ranu |
552 |
@Override
|
|
|
553 |
public long getRemainingDaysInMonth(LocalDate date) {
|
|
|
554 |
LocalDate lastDayOfMonth = YearMonth.from(date).atEndOfMonth();
|
| 34397 |
ranu |
555 |
|
| 34880 |
ranu |
556 |
long totalDays = ChronoUnit.DAYS.between(date, lastDayOfMonth) + 1;
|
| 34397 |
ranu |
557 |
|
| 34880 |
ranu |
558 |
// Count Sundays manually
|
|
|
559 |
long sundayCount = 0;
|
|
|
560 |
LocalDate current = date;
|
|
|
561 |
while (!current.isAfter(lastDayOfMonth)) {
|
|
|
562 |
if (current.getDayOfWeek() == DayOfWeek.SUNDAY) {
|
|
|
563 |
sundayCount++;
|
|
|
564 |
}
|
|
|
565 |
current = current.plusDays(1);
|
|
|
566 |
}
|
|
|
567 |
|
|
|
568 |
// Public holidays in the range
|
|
|
569 |
long publicHolidays = publicHolidaysRepository
|
|
|
570 |
.selectAllBetweenDates(date, lastDayOfMonth)
|
|
|
571 |
.size();
|
|
|
572 |
|
|
|
573 |
long remainingDays = totalDays - sundayCount - publicHolidays;
|
|
|
574 |
|
|
|
575 |
LOGGER.info("remainingDays {}", remainingDays);
|
|
|
576 |
LOGGER.info("totalDays {}", totalDays);
|
|
|
577 |
LOGGER.info("sundays {}", sundayCount);
|
|
|
578 |
LOGGER.info("publicHolidays {}", publicHolidays);
|
|
|
579 |
|
|
|
580 |
return remainingDays;
|
|
|
581 |
}
|
|
|
582 |
|
| 35631 |
ranu |
583 |
@Autowired
|
|
|
584 |
PositionRepository positionRepository;
|
| 34880 |
ranu |
585 |
|
| 35631 |
ranu |
586 |
@Autowired
|
|
|
587 |
CsService csService;
|
| 34880 |
ranu |
588 |
|
| 35631 |
ranu |
589 |
@Autowired
|
|
|
590 |
FofoStoreRepository fofoStoreRepository;
|
|
|
591 |
|
|
|
592 |
@Autowired
|
|
|
593 |
AuthRepository authRepository;
|
|
|
594 |
|
|
|
595 |
@Autowired
|
|
|
596 |
LoanRepository loanRepository;
|
|
|
597 |
|
|
|
598 |
@Autowired
|
|
|
599 |
PartnerCollectionService partnerCollectionService;
|
|
|
600 |
|
|
|
601 |
@Autowired
|
|
|
602 |
PartnerCollectionRemarkRepository partnerCollectionRemarkRepository;
|
|
|
603 |
|
|
|
604 |
@Autowired
|
|
|
605 |
RbmCallSequenceLogRepository rbmCallSequenceLogRepository;
|
|
|
606 |
|
|
|
607 |
@Autowired
|
|
|
608 |
com.spice.profitmandi.dao.repository.cs.TicketRepository ticketRepository;
|
|
|
609 |
|
| 35702 |
ranu |
610 |
@Autowired
|
|
|
611 |
com.spice.profitmandi.dao.repository.cs.AgentCallLogRepository agentCallLogRepository;
|
|
|
612 |
|
| 35759 |
ranu |
613 |
@Autowired
|
|
|
614 |
RetailerContactRepository retailerContactRepository;
|
|
|
615 |
|
|
|
616 |
@Autowired
|
|
|
617 |
AddressRepository addressRepository;
|
|
|
618 |
|
| 36225 |
ranu |
619 |
@Autowired
|
|
|
620 |
com.spice.profitmandi.dao.repository.cs.PartnerPositionRepository partnerPositionRepository;
|
|
|
621 |
|
| 35631 |
ranu |
622 |
@Override
|
|
|
623 |
public List<RbmCallTargetModel> getRbmCallTargetModels() throws Exception {
|
| 36234 |
ranu |
624 |
return getRbmCallTargetModels(LocalDate.now());
|
|
|
625 |
}
|
|
|
626 |
|
|
|
627 |
public List<RbmCallTargetModel> getRbmCallTargetModels(LocalDate queryDate) throws Exception {
|
| 35631 |
ranu |
628 |
long methodStart = System.currentTimeMillis();
|
|
|
629 |
List<RbmCallTargetModel> rbmCallTargetModels = new ArrayList<>();
|
|
|
630 |
|
|
|
631 |
// Get all RBM positions (L1 and L2)
|
|
|
632 |
long start = System.currentTimeMillis();
|
|
|
633 |
List<Position> allRbmPositions = positionRepository
|
|
|
634 |
.selectPositionByCategoryId(ProfitMandiConstants.TICKET_CATEGORY_RBM).stream()
|
| 36210 |
ranu |
635 |
.filter(x -> Arrays.asList(EscalationType.L1, EscalationType.L2, EscalationType.L3).contains(x.getEscalationType()))
|
| 35631 |
ranu |
636 |
.collect(Collectors.toList());
|
|
|
637 |
|
| 36210 |
ranu |
638 |
// Separate L1, L2 and L3 auth IDs
|
| 35631 |
ranu |
639 |
List<Integer> l1AuthIds = allRbmPositions.stream()
|
|
|
640 |
.filter(p -> EscalationType.L1.equals(p.getEscalationType()))
|
|
|
641 |
.map(Position::getAuthUserId).distinct().collect(Collectors.toList());
|
|
|
642 |
List<Integer> l2AuthIds = allRbmPositions.stream()
|
|
|
643 |
.filter(p -> EscalationType.L2.equals(p.getEscalationType()))
|
|
|
644 |
.map(Position::getAuthUserId).distinct().collect(Collectors.toList());
|
| 36210 |
ranu |
645 |
List<Integer> l3AuthIds = allRbmPositions.stream()
|
|
|
646 |
.filter(p -> EscalationType.L3.equals(p.getEscalationType()))
|
|
|
647 |
.map(Position::getAuthUserId).distinct().collect(Collectors.toList());
|
| 35631 |
ranu |
648 |
|
|
|
649 |
// Union of all auth IDs for batch fetching
|
|
|
650 |
List<Integer> rbmPositionsAuthIds = allRbmPositions.stream()
|
|
|
651 |
.map(Position::getAuthUserId).distinct().collect(Collectors.toList());
|
| 36210 |
ranu |
652 |
LOGGER.info("RBM Call Target - RBM positions fetch: {}ms, L1: {}, L2: {}, L3: {}", System.currentTimeMillis() - start, l1AuthIds.size(), l2AuthIds.size(), l3AuthIds.size());
|
| 35631 |
ranu |
653 |
|
|
|
654 |
start = System.currentTimeMillis();
|
|
|
655 |
Map<String, Set<Integer>> storeGuyMap = csService.getAuthUserPartnerIdMapping();
|
|
|
656 |
LOGGER.info("RBM Call Target - StoreGuyMap fetch: {}ms", System.currentTimeMillis() - start);
|
|
|
657 |
|
| 36234 |
ranu |
658 |
LocalDateTime startDate = queryDate.atStartOfDay();
|
|
|
659 |
LocalDate firstOfMonth = queryDate.withDayOfMonth(1);
|
|
|
660 |
LocalDate endOfMonth = queryDate.withDayOfMonth(queryDate.lengthOfMonth()).plusDays(1);
|
| 35631 |
ranu |
661 |
|
|
|
662 |
// Get auth user map
|
|
|
663 |
start = System.currentTimeMillis();
|
|
|
664 |
Map<Integer, AuthUser> authUserMap = authRepository.selectByIds(rbmPositionsAuthIds).stream()
|
|
|
665 |
.collect(Collectors.toMap(AuthUser::getId, au -> au));
|
|
|
666 |
LOGGER.info("RBM Call Target - AuthUser fetch: {}ms", System.currentTimeMillis() - start);
|
|
|
667 |
|
|
|
668 |
// Batch fetch positions by auth IDs (to check if RBM is L1)
|
|
|
669 |
start = System.currentTimeMillis();
|
|
|
670 |
Map<Integer, List<Position>> positionsByAuthId = positionRepository.selectPositionByAuthIds(rbmPositionsAuthIds).stream()
|
|
|
671 |
.collect(Collectors.groupingBy(Position::getAuthUserId));
|
|
|
672 |
LOGGER.info("RBM Call Target - Positions by AuthId fetch: {}ms", System.currentTimeMillis() - start);
|
|
|
673 |
|
|
|
674 |
// Get all fofo IDs for all RBMs
|
|
|
675 |
Set<Integer> allFofoIds = new HashSet<>();
|
|
|
676 |
Map<Integer, List<Integer>> rbmToFofoIdsMap = new HashMap<>();
|
|
|
677 |
for (int rbmAuthId : rbmPositionsAuthIds) {
|
|
|
678 |
AuthUser au = authUserMap.get(rbmAuthId);
|
|
|
679 |
if (au != null && storeGuyMap.containsKey(au.getEmailId())) {
|
|
|
680 |
List<Integer> fofoIds = new ArrayList<>(storeGuyMap.get(au.getEmailId()));
|
|
|
681 |
allFofoIds.addAll(fofoIds);
|
|
|
682 |
rbmToFofoIdsMap.put(rbmAuthId, fofoIds);
|
|
|
683 |
}
|
|
|
684 |
}
|
| 35816 |
ranu |
685 |
// Initialize L2 calling list map - will be populated after fetching remarks
|
| 35631 |
ranu |
686 |
Map<Integer, List<Integer>> l2AuthIdToFofoIds = new HashMap<>();
|
| 35816 |
ranu |
687 |
for (int l2AuthId : l2AuthIds) {
|
|
|
688 |
l2AuthIdToFofoIds.put(l2AuthId, new ArrayList<>());
|
| 35631 |
ranu |
689 |
}
|
| 36210 |
ranu |
690 |
// Initialize L3 calling list map - will be populated after fetching remarks
|
|
|
691 |
Map<Integer, List<Integer>> l3AuthIdToFofoIds = new HashMap<>();
|
|
|
692 |
for (int l3AuthId : l3AuthIds) {
|
|
|
693 |
l3AuthIdToFofoIds.put(l3AuthId, new ArrayList<>());
|
|
|
694 |
}
|
| 35631 |
ranu |
695 |
LOGGER.info("RBM Call Target - Total fofo IDs to process: {}", allFofoIds.size());
|
|
|
696 |
|
|
|
697 |
// Get only needed fofo stores (OPTIMIZED - was fetching ALL stores before)
|
|
|
698 |
start = System.currentTimeMillis();
|
|
|
699 |
Map<Integer, FofoStore> fofoStoresMap = new HashMap<>();
|
|
|
700 |
if (!allFofoIds.isEmpty()) {
|
|
|
701 |
try {
|
|
|
702 |
fofoStoresMap = fofoStoreRepository.selectByRetailerIds(new ArrayList<>(allFofoIds)).stream()
|
|
|
703 |
.collect(Collectors.toMap(FofoStore::getId, x -> x, (a, b) -> a));
|
|
|
704 |
} catch (ProfitMandiBusinessException e) {
|
|
|
705 |
LOGGER.error("Error fetching fofo stores", e);
|
|
|
706 |
}
|
|
|
707 |
}
|
|
|
708 |
LOGGER.info("RBM Call Target - FofoStores fetch (only needed): {}ms, count: {}", System.currentTimeMillis() - start, fofoStoresMap.size());
|
|
|
709 |
|
|
|
710 |
// Batch fetch max remark ids for all fofoIds (for escalation filtering)
|
|
|
711 |
start = System.currentTimeMillis();
|
|
|
712 |
Map<Integer, PartnerCollectionRemark> allPartnerCollectionRemarks = new HashMap<>();
|
|
|
713 |
if (!allFofoIds.isEmpty()) {
|
|
|
714 |
List<Integer> allRemarkIds = partnerCollectionRemarkRepository.selectMaxRemarkId(new ArrayList<>(allFofoIds));
|
|
|
715 |
if (!allRemarkIds.isEmpty()) {
|
|
|
716 |
allPartnerCollectionRemarks = partnerCollectionRemarkRepository.selectByIds(allRemarkIds).stream()
|
|
|
717 |
.collect(Collectors.toMap(PartnerCollectionRemark::getFofoId, x -> x, (a, b) -> a));
|
|
|
718 |
}
|
|
|
719 |
}
|
|
|
720 |
LOGGER.info("RBM Call Target - PartnerCollectionRemarks fetch: {}ms", System.currentTimeMillis() - start);
|
|
|
721 |
|
| 35816 |
ranu |
722 |
// Populate L2 calling list based on partners whose latest remark is RBM_L2_ESCALATION
|
|
|
723 |
// Find the L1 who has the partner and add to that L1's manager (L2) calling list
|
|
|
724 |
for (Map.Entry<Integer, PartnerCollectionRemark> entry : allPartnerCollectionRemarks.entrySet()) {
|
|
|
725 |
Integer fofoId = entry.getKey();
|
|
|
726 |
PartnerCollectionRemark remark = entry.getValue();
|
|
|
727 |
|
|
|
728 |
if (CollectionRemark.RBM_L2_ESCALATION.equals(remark.getRemark())) {
|
|
|
729 |
// Find which L1 RBM has this partner assigned
|
|
|
730 |
for (int l1AuthId : l1AuthIds) {
|
|
|
731 |
List<Integer> l1FofoIds = rbmToFofoIdsMap.getOrDefault(l1AuthId, Collections.emptyList());
|
|
|
732 |
if (l1FofoIds.contains(fofoId)) {
|
|
|
733 |
// Get L1's manager (L2)
|
|
|
734 |
AuthUser l1User = authUserMap.get(l1AuthId);
|
|
|
735 |
if (l1User != null && l2AuthIdToFofoIds.containsKey(l1User.getManagerId())) {
|
|
|
736 |
int l2ManagerId = l1User.getManagerId();
|
|
|
737 |
l2AuthIdToFofoIds.get(l2ManagerId).add(fofoId);
|
|
|
738 |
}
|
|
|
739 |
break; // Found the L1 for this fofoId
|
|
|
740 |
}
|
|
|
741 |
}
|
|
|
742 |
}
|
|
|
743 |
}
|
|
|
744 |
LOGGER.info("RBM Call Target - L2 calling lists populated from RBM_L2_ESCALATION remarks");
|
|
|
745 |
|
| 36210 |
ranu |
746 |
// Populate L3 calling list based on partners whose latest remark is RBM_L3_ESCALATION
|
| 36212 |
ranu |
747 |
// Find the L1 who originally has the partner, then:
|
|
|
748 |
// Case 1: L1 -> L3 directly (if L1's manager IS L3)
|
|
|
749 |
// Case 2: L1 -> L2 -> L3 (if L1's manager is L2, then L2's manager is L3)
|
| 36210 |
ranu |
750 |
for (Map.Entry<Integer, PartnerCollectionRemark> entry : allPartnerCollectionRemarks.entrySet()) {
|
|
|
751 |
Integer fofoId = entry.getKey();
|
|
|
752 |
PartnerCollectionRemark remark = entry.getValue();
|
|
|
753 |
|
|
|
754 |
if (CollectionRemark.RBM_L3_ESCALATION.equals(remark.getRemark())) {
|
|
|
755 |
// Find which L1 RBM originally has this partner assigned
|
|
|
756 |
for (int l1AuthId : l1AuthIds) {
|
|
|
757 |
List<Integer> l1FofoIds = rbmToFofoIdsMap.getOrDefault(l1AuthId, Collections.emptyList());
|
|
|
758 |
if (l1FofoIds.contains(fofoId)) {
|
|
|
759 |
AuthUser l1User = authUserMap.get(l1AuthId);
|
|
|
760 |
if (l1User != null) {
|
| 36212 |
ranu |
761 |
int l1ManagerId = l1User.getManagerId();
|
|
|
762 |
// Case 1: L1's manager IS L3 directly (L1 → L3, no L2 in between)
|
|
|
763 |
if (l3AuthIdToFofoIds.containsKey(l1ManagerId)) {
|
|
|
764 |
l3AuthIdToFofoIds.get(l1ManagerId).add(fofoId);
|
|
|
765 |
LOGGER.debug("L3 Calling List (direct): fofoId={} -> L1={} -> L3={}",
|
|
|
766 |
fofoId, l1AuthId, l1ManagerId);
|
|
|
767 |
} else {
|
|
|
768 |
// Case 2: L1 -> L2 -> L3
|
|
|
769 |
AuthUser l2User = authUserMap.get(l1ManagerId);
|
|
|
770 |
if (l2User != null && l3AuthIdToFofoIds.containsKey(l2User.getManagerId())) {
|
|
|
771 |
int l3ManagerId = l2User.getManagerId();
|
|
|
772 |
l3AuthIdToFofoIds.get(l3ManagerId).add(fofoId);
|
|
|
773 |
LOGGER.debug("L3 Calling List: fofoId={} -> L1={} -> L2={} -> L3={}",
|
|
|
774 |
fofoId, l1AuthId, l1ManagerId, l3ManagerId);
|
|
|
775 |
}
|
| 36210 |
ranu |
776 |
}
|
|
|
777 |
}
|
|
|
778 |
break; // Found the L1 for this fofoId
|
|
|
779 |
}
|
|
|
780 |
}
|
|
|
781 |
}
|
|
|
782 |
}
|
|
|
783 |
LOGGER.info("RBM Call Target - L3 calling lists populated from RBM_L3_ESCALATION remarks");
|
|
|
784 |
|
| 35631 |
ranu |
785 |
// Batch fetch collection RANK map for all fofoIds (OPTIMIZED - only fetches rank, not full model)
|
|
|
786 |
start = System.currentTimeMillis();
|
|
|
787 |
Map<Integer, Integer> allCollectionRankMap = new HashMap<>();
|
|
|
788 |
if (!allFofoIds.isEmpty()) {
|
|
|
789 |
try {
|
|
|
790 |
allCollectionRankMap = partnerCollectionService.getCollectionRankMap(new ArrayList<>(allFofoIds), startDate);
|
|
|
791 |
} catch (ProfitMandiBusinessException e) {
|
|
|
792 |
LOGGER.error("Error fetching collection rank map for all fofoIds", e);
|
|
|
793 |
}
|
|
|
794 |
}
|
|
|
795 |
LOGGER.info("RBM Call Target - CollectionRankMap fetch (OPTIMIZED): {}ms", System.currentTimeMillis() - start);
|
|
|
796 |
|
| 35669 |
ranu |
797 |
// Get MTD billing data for zero billing calculation and partner counts
|
| 35631 |
ranu |
798 |
start = System.currentTimeMillis();
|
|
|
799 |
List<RbmWeeklyBillingModel> mtdBillingData = getWeeklyBillingDataForMonth(firstOfMonth, endOfMonth);
|
|
|
800 |
Set<Integer> allMtdBilledFofoIds = mtdBillingData.stream()
|
|
|
801 |
.filter(RbmWeeklyBillingModel::isMtdBilled)
|
|
|
802 |
.map(RbmWeeklyBillingModel::getFofoId)
|
|
|
803 |
.collect(Collectors.toSet());
|
| 35669 |
ranu |
804 |
// Build partner count and fofoIds per RBM from mtdBillingData (same source as Today ARR page)
|
|
|
805 |
Map<Integer, Set<Integer>> mtdFofoIdsByAuthId = mtdBillingData.stream()
|
|
|
806 |
.filter(RbmWeeklyBillingModel::isTargetedPartner)
|
|
|
807 |
.collect(Collectors.groupingBy(RbmWeeklyBillingModel::getAuthId,
|
|
|
808 |
Collectors.mapping(RbmWeeklyBillingModel::getFofoId, Collectors.toSet())));
|
| 35631 |
ranu |
809 |
LOGGER.info("RBM Call Target - MTD Billing fetch: {}ms", System.currentTimeMillis() - start);
|
|
|
810 |
|
|
|
811 |
// Batch fetch today's remarks for all auth IDs (to calculate Value Achieved)
|
|
|
812 |
start = System.currentTimeMillis();
|
|
|
813 |
Map<Integer, List<PartnerCollectionRemark>> remarksByAuthId = partnerCollectionRemarkRepository
|
|
|
814 |
.selectAllByAuthIdsOnDate(rbmPositionsAuthIds, LocalDate.now()).stream()
|
|
|
815 |
.collect(Collectors.groupingBy(PartnerCollectionRemark::getAuthId));
|
|
|
816 |
LOGGER.info("RBM Call Target - Today Remarks fetch: {}ms", System.currentTimeMillis() - start);
|
|
|
817 |
|
|
|
818 |
// Batch fetch today's out-of-sequence logs for all RBMs
|
|
|
819 |
start = System.currentTimeMillis();
|
|
|
820 |
LocalDateTime todayStart = LocalDate.now().atStartOfDay();
|
|
|
821 |
LocalDateTime todayEnd = LocalDate.now().plusDays(1).atStartOfDay();
|
|
|
822 |
List<RbmCallSequenceLog> outOfSequenceLogs = rbmCallSequenceLogRepository.selectOutOfSequenceByDateRange(todayStart, todayEnd);
|
|
|
823 |
Map<Integer, Long> outOfSequenceCountByAuthId = outOfSequenceLogs.stream()
|
| 35654 |
ranu |
824 |
.collect(Collectors.groupingBy(RbmCallSequenceLog::getAuthId,
|
|
|
825 |
Collectors.mapping(RbmCallSequenceLog::getFofoId, Collectors.collectingAndThen(Collectors.toSet(), s -> (long) s.size()))));
|
| 35631 |
ranu |
826 |
LOGGER.info("RBM Call Target - Out of Sequence fetch: {}ms", System.currentTimeMillis() - start);
|
|
|
827 |
|
| 36284 |
ranu |
828 |
// BATCH FETCH: All call logs for all RBMs (L1 + L2 + L3) in a single query.
|
|
|
829 |
// Replaces the previous N+1 pattern where getCallStats() was called per RBM.
|
|
|
830 |
start = System.currentTimeMillis();
|
|
|
831 |
List<AgentCallLog> allCallLogs = agentCallLogRepository.findByAuthIdsAndDate(rbmPositionsAuthIds, queryDate);
|
|
|
832 |
Map<Long, List<AgentCallLog>> callLogsByAuthId = allCallLogs.stream()
|
|
|
833 |
.collect(Collectors.groupingBy(AgentCallLog::getAuthId));
|
|
|
834 |
LOGGER.info("RBM Call Target - Call logs batch fetch: {}ms ({} logs across {} RBMs)",
|
|
|
835 |
System.currentTimeMillis() - start, allCallLogs.size(), callLogsByAuthId.size());
|
|
|
836 |
|
|
|
837 |
// BATCH FETCH: Build a single mobile -> fofoId map from all unique customer numbers across all call logs.
|
|
|
838 |
// Replaces the previous N+1 pattern where findFofoIdByMobile() was called per call log entry.
|
|
|
839 |
start = System.currentTimeMillis();
|
|
|
840 |
Set<String> allNormalizedMobiles = new HashSet<>();
|
|
|
841 |
for (AgentCallLog callLog : allCallLogs) {
|
|
|
842 |
String customerNumber = callLog.getCustomerNumber();
|
|
|
843 |
if (customerNumber != null) {
|
|
|
844 |
String normalized = customerNumber.startsWith("+91") ? customerNumber.substring(3) : customerNumber;
|
|
|
845 |
allNormalizedMobiles.add(normalized);
|
|
|
846 |
}
|
|
|
847 |
}
|
|
|
848 |
Map<String, Integer> mobileToFofoIdMap = buildMobileToFofoIdMap(allNormalizedMobiles);
|
|
|
849 |
LOGGER.info("RBM Call Target - Mobile→FofoId batch fetch: {}ms ({} unique mobiles, {} mapped)",
|
|
|
850 |
System.currentTimeMillis() - start, allNormalizedMobiles.size(), mobileToFofoIdMap.size());
|
|
|
851 |
|
| 36225 |
ranu |
852 |
// Identify users who are both L1 and L2 — they will be shown only as L2
|
|
|
853 |
Set<Integer> l2AuthIdSet = new HashSet<>(l2AuthIds);
|
|
|
854 |
|
|
|
855 |
// Process L1 RBMs (skip users who are also L2 — their data will be merged into L2 model)
|
| 35631 |
ranu |
856 |
for (int rbmAuthId : l1AuthIds) {
|
| 36225 |
ranu |
857 |
if (l2AuthIdSet.contains(rbmAuthId)) {
|
|
|
858 |
continue; // Will be handled in L2 processing with merged L1 data
|
|
|
859 |
}
|
| 35631 |
ranu |
860 |
AuthUser authUser = authUserMap.get(rbmAuthId);
|
|
|
861 |
if (authUser == null || !storeGuyMap.containsKey(authUser.getEmailId())) {
|
|
|
862 |
continue;
|
|
|
863 |
}
|
|
|
864 |
|
|
|
865 |
List<Integer> fofoIdList = rbmToFofoIdsMap.getOrDefault(rbmAuthId, Collections.emptyList());
|
|
|
866 |
|
|
|
867 |
// Check if RBM is L1 (same logic as getSummaryModel)
|
|
|
868 |
List<Position> positions = positionsByAuthId.getOrDefault(authUser.getId(), Collections.emptyList());
|
|
|
869 |
boolean isRBMAndL1 = positions.stream()
|
|
|
870 |
.anyMatch(position ->
|
|
|
871 |
ProfitMandiConstants.TICKET_CATEGORY_RBM == position.getCategoryId()
|
|
|
872 |
&& EscalationType.L1.equals(position.getEscalationType()));
|
|
|
873 |
|
|
|
874 |
// Filter escalated partners for L1 RBMs (same logic as getSummaryModel)
|
|
|
875 |
List<Integer> fofoIds = fofoIdList;
|
|
|
876 |
if (isRBMAndL1) {
|
|
|
877 |
Map<Integer, PartnerCollectionRemark> partnerCollectionRemarks = new HashMap<>();
|
|
|
878 |
for (Integer fofoId : fofoIdList) {
|
|
|
879 |
if (allPartnerCollectionRemarks.containsKey(fofoId)) {
|
|
|
880 |
partnerCollectionRemarks.put(fofoId, allPartnerCollectionRemarks.get(fofoId));
|
|
|
881 |
}
|
|
|
882 |
}
|
|
|
883 |
fofoIds = partnerCollectionRemarks.entrySet().stream()
|
|
|
884 |
.filter(entry -> {
|
|
|
885 |
PartnerCollectionRemark pcrMap = entry.getValue();
|
|
|
886 |
return !(CollectionRemark.RBM_L2_ESCALATION.equals(pcrMap.getRemark())
|
|
|
887 |
|| CollectionRemark.SALES_ESCALATION.equals(pcrMap.getRemark()));
|
|
|
888 |
})
|
|
|
889 |
.map(Map.Entry::getKey)
|
|
|
890 |
.collect(Collectors.toList());
|
|
|
891 |
}
|
|
|
892 |
|
| 36181 |
ranu |
893 |
// Filter to only external, ACTIVE or REVIVAL stores (collection plan not required)
|
| 35631 |
ranu |
894 |
Map<Integer, Integer> finalAllCollectionRankMap = allCollectionRankMap;
|
|
|
895 |
Map<Integer, FofoStore> finalFofoStoresMap = fofoStoresMap;
|
|
|
896 |
List<Integer> validFofoIds = fofoIds.stream()
|
|
|
897 |
.filter(fofoId -> {
|
|
|
898 |
FofoStore store = finalFofoStoresMap.get(fofoId);
|
|
|
899 |
if (store == null || store.isInternal()) {
|
|
|
900 |
return false;
|
|
|
901 |
}
|
| 36181 |
ranu |
902 |
// Only include ACTIVE or REVIVAL partners (not Low Sale, not Disputed, not Billing Pending)
|
|
|
903 |
return ActivationType.ACTIVE.equals(store.getActivationType())
|
|
|
904 |
|| ActivationType.REVIVAL.equals(store.getActivationType());
|
| 35631 |
ranu |
905 |
})
|
|
|
906 |
.collect(Collectors.toList());
|
|
|
907 |
|
|
|
908 |
if (validFofoIds.isEmpty()) {
|
|
|
909 |
continue;
|
|
|
910 |
}
|
|
|
911 |
|
|
|
912 |
RbmCallTargetModel targetModel = new RbmCallTargetModel();
|
|
|
913 |
targetModel.setAuthId(rbmAuthId);
|
|
|
914 |
targetModel.setRbmName(authUser.getFullName());
|
| 35669 |
ranu |
915 |
// Use partner count from mtdBillingData (same source as Today ARR page)
|
|
|
916 |
Set<Integer> mtdFofoIds = mtdFofoIdsByAuthId.getOrDefault(rbmAuthId, Collections.emptySet());
|
|
|
917 |
targetModel.setPartnerCount(mtdFofoIds.size());
|
| 35631 |
ranu |
918 |
|
|
|
919 |
// Categorize each partner - each partner belongs to ONE category only
|
| 35665 |
ranu |
920 |
// Priority: PlanToday > CarryForward > ZeroBilling > Untouched > FuturePlan > Normal
|
| 36181 |
ranu |
921 |
// Revival is counted separately (just for display, doesn't affect categorization)
|
| 35631 |
ranu |
922 |
Set<Integer> planTodayPartners = new HashSet<>();
|
|
|
923 |
Set<Integer> carryForwardPartners = new HashSet<>();
|
|
|
924 |
Set<Integer> untouchedPartners = new HashSet<>();
|
|
|
925 |
Set<Integer> zeroBillingPartners = new HashSet<>();
|
|
|
926 |
Set<Integer> futurePlanPartners = new HashSet<>();
|
|
|
927 |
Set<Integer> normalPartners = new HashSet<>();
|
| 36181 |
ranu |
928 |
Set<Integer> revivalPartners = new HashSet<>();
|
| 35631 |
ranu |
929 |
|
|
|
930 |
for (Integer fofoId : validFofoIds) {
|
|
|
931 |
// Get collection plan rank (from optimized rank map)
|
|
|
932 |
int rank = allCollectionRankMap.getOrDefault(fofoId, 5); // default to Normal if no plan
|
|
|
933 |
|
|
|
934 |
// Check if partner has zero billing in MTD
|
|
|
935 |
boolean hasZeroBilling = !allMtdBilledFofoIds.contains(fofoId);
|
|
|
936 |
|
| 36181 |
ranu |
937 |
// Count REVIVAL partners separately (just for display, doesn't affect categorization)
|
|
|
938 |
FofoStore store = finalFofoStoresMap.get(fofoId);
|
|
|
939 |
if (store != null && ActivationType.REVIVAL.equals(store.getActivationType())) {
|
|
|
940 |
revivalPartners.add(fofoId);
|
|
|
941 |
}
|
|
|
942 |
|
| 35631 |
ranu |
943 |
// Assign to category based on priority
|
|
|
944 |
if (rank == 1) {
|
|
|
945 |
planTodayPartners.add(fofoId);
|
|
|
946 |
} else if (rank == 2) {
|
|
|
947 |
carryForwardPartners.add(fofoId);
|
| 35665 |
ranu |
948 |
} else if (hasZeroBilling) {
|
|
|
949 |
zeroBillingPartners.add(fofoId);
|
| 35631 |
ranu |
950 |
} else if (rank == 3) {
|
|
|
951 |
untouchedPartners.add(fofoId);
|
|
|
952 |
} else if (rank == 4) {
|
|
|
953 |
futurePlanPartners.add(fofoId);
|
|
|
954 |
} else {
|
|
|
955 |
normalPartners.add(fofoId);
|
|
|
956 |
}
|
|
|
957 |
}
|
|
|
958 |
|
|
|
959 |
// Set counts
|
|
|
960 |
targetModel.setCreditCollection(0); // Credit collection is handled in separate list
|
|
|
961 |
targetModel.setPlanToday(planTodayPartners.size());
|
|
|
962 |
targetModel.setCarryForward(carryForwardPartners.size());
|
|
|
963 |
targetModel.setUntouched(untouchedPartners.size());
|
|
|
964 |
targetModel.setZeroBilling(zeroBillingPartners.size());
|
|
|
965 |
targetModel.setFuturePlan(futurePlanPartners.size());
|
|
|
966 |
targetModel.setNormal(normalPartners.size());
|
| 36181 |
ranu |
967 |
targetModel.setRevival(revivalPartners.size());
|
| 35631 |
ranu |
968 |
|
|
|
969 |
// Today Target = PlanToday + CarryForward + ZeroBilling + Untouched
|
|
|
970 |
// These are mutually exclusive now, so we can sum them
|
|
|
971 |
long todayTarget = planTodayPartners.size() +
|
|
|
972 |
carryForwardPartners.size() + zeroBillingPartners.size() + untouchedPartners.size();
|
|
|
973 |
targetModel.setTodayTargetOfCall(todayTarget);
|
|
|
974 |
|
|
|
975 |
// Create set of partners in Today Target categories
|
|
|
976 |
Set<Integer> todayTargetPartners = new HashSet<>();
|
|
|
977 |
todayTargetPartners.addAll(planTodayPartners);
|
|
|
978 |
todayTargetPartners.addAll(carryForwardPartners);
|
|
|
979 |
todayTargetPartners.addAll(zeroBillingPartners);
|
|
|
980 |
todayTargetPartners.addAll(untouchedPartners);
|
|
|
981 |
|
| 36284 |
ranu |
982 |
// Value Achieved = All distinct partners called today (from pre-fetched call logs)
|
|
|
983 |
long[] callStats = getCallStatsFromLogs(callLogsByAuthId.get((long) rbmAuthId), mobileToFofoIdMap);
|
| 36276 |
ranu |
984 |
targetModel.setValueTargetAchieved(callStats[0]);
|
|
|
985 |
targetModel.setTotalRecordingCalls(callStats[1]);
|
|
|
986 |
targetModel.setUniqueRecordingCalls(callStats[2]);
|
| 35631 |
ranu |
987 |
|
| 35843 |
ranu |
988 |
// Keep todayRemarks for movedToFuture calculation
|
|
|
989 |
List<PartnerCollectionRemark> todayRemarks = remarksByAuthId.getOrDefault(rbmAuthId, Collections.emptyList());
|
|
|
990 |
|
| 35631 |
ranu |
991 |
// Moved to Future = Partners in Future Plan category who have a remark today
|
|
|
992 |
// These are partners who were contacted today but moved to a future date
|
|
|
993 |
Set<Integer> todayRemarkedFofoIds = todayRemarks.stream()
|
|
|
994 |
.map(PartnerCollectionRemark::getFofoId)
|
|
|
995 |
.collect(Collectors.toSet());
|
|
|
996 |
long movedToFuture = futurePlanPartners.stream()
|
|
|
997 |
.filter(todayRemarkedFofoIds::contains)
|
|
|
998 |
.count();
|
|
|
999 |
targetModel.setMovedToFuture(movedToFuture);
|
|
|
1000 |
|
|
|
1001 |
// Set out of sequence count for this RBM
|
|
|
1002 |
targetModel.setOutOfSequenceCount(outOfSequenceCountByAuthId.getOrDefault(rbmAuthId, 0L));
|
|
|
1003 |
|
|
|
1004 |
rbmCallTargetModels.add(targetModel);
|
|
|
1005 |
}
|
|
|
1006 |
|
|
|
1007 |
// Process L2 RBMs (escalated ticket logic with categorization)
|
| 36225 |
ranu |
1008 |
// For users who are both L1 and L2, merge their L1 calling target into L2 model
|
| 35631 |
ranu |
1009 |
for (int l2AuthId : l2AuthIds) {
|
|
|
1010 |
AuthUser authUser = authUserMap.get(l2AuthId);
|
|
|
1011 |
if (authUser == null) {
|
|
|
1012 |
continue;
|
|
|
1013 |
}
|
|
|
1014 |
|
|
|
1015 |
List<Integer> l2FofoIdList = l2AuthIdToFofoIds.getOrDefault(l2AuthId, Collections.emptyList());
|
|
|
1016 |
|
| 35816 |
ranu |
1017 |
// For L2, use unique fofoIds with RBM_L2_ESCALATION remark as target
|
| 35662 |
ranu |
1018 |
Set<Integer> l2TargetFofoIds = new HashSet<>(l2FofoIdList);
|
| 35631 |
ranu |
1019 |
|
|
|
1020 |
RbmCallTargetModel l2Model = new RbmCallTargetModel();
|
|
|
1021 |
l2Model.setAuthId(l2AuthId);
|
|
|
1022 |
l2Model.setRbmName(authUser.getFullName() + " (L2)");
|
|
|
1023 |
l2Model.setL2Position(true);
|
| 35816 |
ranu |
1024 |
l2Model.setL2CallingList(l2TargetFofoIds.size());
|
| 36228 |
ranu |
1025 |
// Partner count: if user is also L1, use L1 partner count (MTD targeted partners)
|
|
|
1026 |
if (l1AuthIds.contains(l2AuthId)) {
|
|
|
1027 |
Set<Integer> mtdFofoIds = mtdFofoIdsByAuthId.getOrDefault(l2AuthId, Collections.emptySet());
|
|
|
1028 |
l2Model.setPartnerCount(mtdFofoIds.size());
|
|
|
1029 |
} else {
|
|
|
1030 |
List<Integer> l2AssignedFofoIds = rbmToFofoIdsMap.getOrDefault(l2AuthId, Collections.emptyList());
|
|
|
1031 |
l2Model.setPartnerCount(l2AssignedFofoIds.size());
|
|
|
1032 |
}
|
| 35631 |
ranu |
1033 |
|
| 36229 |
ranu |
1034 |
// If user is also L1, calculate full L1 breakdown and merge into L2 model
|
| 36225 |
ranu |
1035 |
if (l1AuthIds.contains(l2AuthId) && storeGuyMap.containsKey(authUser.getEmailId())) {
|
| 36229 |
ranu |
1036 |
// Get only L1 RBM position partners (not L2 partners) from partner_position
|
| 36225 |
ranu |
1037 |
List<Position> positions = positionsByAuthId.getOrDefault(l2AuthId, Collections.emptyList());
|
| 36229 |
ranu |
1038 |
Set<Integer> l1RbmPositionIds = positions.stream()
|
|
|
1039 |
.filter(p -> ProfitMandiConstants.TICKET_CATEGORY_RBM == p.getCategoryId()
|
|
|
1040 |
&& EscalationType.L1.equals(p.getEscalationType()))
|
|
|
1041 |
.map(Position::getId)
|
|
|
1042 |
.collect(Collectors.toSet());
|
|
|
1043 |
// Fetch partner_position for only L1 RBM positions of this user
|
|
|
1044 |
List<Integer> fofoIdList = partnerPositionRepository
|
|
|
1045 |
.selectByPositionIds(new ArrayList<>(l1RbmPositionIds)).stream()
|
|
|
1046 |
.map(pp -> pp.getFofoId())
|
|
|
1047 |
.distinct()
|
|
|
1048 |
.collect(Collectors.toList());
|
|
|
1049 |
boolean isRBMAndL1 = !l1RbmPositionIds.isEmpty();
|
| 36225 |
ranu |
1050 |
List<Integer> l1FofoIds = new ArrayList<>(fofoIdList);
|
|
|
1051 |
if (isRBMAndL1) {
|
|
|
1052 |
Map<Integer, PartnerCollectionRemark> partnerCollectionRemarks = new HashMap<>();
|
|
|
1053 |
for (Integer fofoId : fofoIdList) {
|
|
|
1054 |
if (allPartnerCollectionRemarks.containsKey(fofoId)) {
|
|
|
1055 |
partnerCollectionRemarks.put(fofoId, allPartnerCollectionRemarks.get(fofoId));
|
|
|
1056 |
}
|
|
|
1057 |
}
|
|
|
1058 |
l1FofoIds = partnerCollectionRemarks.entrySet().stream()
|
|
|
1059 |
.filter(entry -> {
|
|
|
1060 |
PartnerCollectionRemark pcrMap = entry.getValue();
|
|
|
1061 |
return !(CollectionRemark.RBM_L2_ESCALATION.equals(pcrMap.getRemark())
|
|
|
1062 |
|| CollectionRemark.SALES_ESCALATION.equals(pcrMap.getRemark()));
|
|
|
1063 |
})
|
|
|
1064 |
.map(Map.Entry::getKey)
|
|
|
1065 |
.collect(Collectors.toList());
|
|
|
1066 |
}
|
|
|
1067 |
Map<Integer, FofoStore> finalFofoStoresMap2 = fofoStoresMap;
|
|
|
1068 |
List<Integer> validL1FofoIds = l1FofoIds.stream()
|
|
|
1069 |
.filter(fofoId -> {
|
|
|
1070 |
FofoStore store = finalFofoStoresMap2.get(fofoId);
|
|
|
1071 |
if (store == null || store.isInternal()) return false;
|
|
|
1072 |
return ActivationType.ACTIVE.equals(store.getActivationType())
|
|
|
1073 |
|| ActivationType.REVIVAL.equals(store.getActivationType());
|
|
|
1074 |
})
|
|
|
1075 |
.collect(Collectors.toList());
|
| 35631 |
ranu |
1076 |
|
| 36229 |
ranu |
1077 |
// Categorize L1 partners — same logic as L1 processing
|
|
|
1078 |
Set<Integer> planTodayPartners = new HashSet<>();
|
|
|
1079 |
Set<Integer> carryForwardPartners = new HashSet<>();
|
|
|
1080 |
Set<Integer> untouchedPartners = new HashSet<>();
|
|
|
1081 |
Set<Integer> zeroBillingPartners = new HashSet<>();
|
|
|
1082 |
Set<Integer> futurePlanPartners = new HashSet<>();
|
|
|
1083 |
Set<Integer> normalPartners = new HashSet<>();
|
|
|
1084 |
Set<Integer> revivalPartners = new HashSet<>();
|
|
|
1085 |
|
| 36225 |
ranu |
1086 |
for (Integer fofoId : validL1FofoIds) {
|
|
|
1087 |
int rank = allCollectionRankMap.getOrDefault(fofoId, 5);
|
|
|
1088 |
boolean hasZeroBilling = !allMtdBilledFofoIds.contains(fofoId);
|
| 36229 |
ranu |
1089 |
FofoStore store = finalFofoStoresMap2.get(fofoId);
|
|
|
1090 |
if (store != null && ActivationType.REVIVAL.equals(store.getActivationType())) {
|
|
|
1091 |
revivalPartners.add(fofoId);
|
| 36225 |
ranu |
1092 |
}
|
| 36229 |
ranu |
1093 |
if (rank == 1) {
|
|
|
1094 |
planTodayPartners.add(fofoId);
|
|
|
1095 |
} else if (rank == 2) {
|
|
|
1096 |
carryForwardPartners.add(fofoId);
|
|
|
1097 |
} else if (hasZeroBilling) {
|
|
|
1098 |
zeroBillingPartners.add(fofoId);
|
|
|
1099 |
} else if (rank == 3) {
|
|
|
1100 |
untouchedPartners.add(fofoId);
|
|
|
1101 |
} else if (rank == 4) {
|
|
|
1102 |
futurePlanPartners.add(fofoId);
|
|
|
1103 |
} else {
|
|
|
1104 |
normalPartners.add(fofoId);
|
|
|
1105 |
}
|
| 36225 |
ranu |
1106 |
}
|
| 36229 |
ranu |
1107 |
|
|
|
1108 |
// Set L1 breakdown fields on L2 model
|
|
|
1109 |
l2Model.setPlanToday(planTodayPartners.size());
|
|
|
1110 |
l2Model.setCarryForward(carryForwardPartners.size());
|
|
|
1111 |
l2Model.setZeroBilling(zeroBillingPartners.size());
|
|
|
1112 |
l2Model.setUntouched(untouchedPartners.size());
|
|
|
1113 |
l2Model.setFuturePlan(futurePlanPartners.size());
|
|
|
1114 |
l2Model.setNormal(normalPartners.size());
|
|
|
1115 |
l2Model.setRevival(revivalPartners.size());
|
|
|
1116 |
|
|
|
1117 |
long l1OwnTarget = planTodayPartners.size() + carryForwardPartners.size()
|
|
|
1118 |
+ zeroBillingPartners.size() + untouchedPartners.size();
|
|
|
1119 |
|
|
|
1120 |
// Today Target = own L1 target + L2 escalation
|
|
|
1121 |
l2Model.setTodayTargetOfCall(l2TargetFofoIds.size() + l1OwnTarget);
|
|
|
1122 |
|
|
|
1123 |
// Moved to Future from L1 partners
|
|
|
1124 |
List<PartnerCollectionRemark> todayRemarks = remarksByAuthId.getOrDefault(l2AuthId, Collections.emptyList());
|
|
|
1125 |
Set<Integer> todayRemarkedFofoIds = todayRemarks.stream()
|
|
|
1126 |
.map(PartnerCollectionRemark::getFofoId)
|
|
|
1127 |
.collect(Collectors.toSet());
|
|
|
1128 |
long movedToFuture = futurePlanPartners.stream()
|
|
|
1129 |
.filter(todayRemarkedFofoIds::contains)
|
|
|
1130 |
.count();
|
|
|
1131 |
l2Model.setMovedToFuture(movedToFuture);
|
|
|
1132 |
} else {
|
|
|
1133 |
// Pure L2 (not also L1) — target is only L2 escalation
|
|
|
1134 |
l2Model.setTodayTargetOfCall(l2TargetFofoIds.size());
|
| 36225 |
ranu |
1135 |
}
|
|
|
1136 |
|
| 36284 |
ranu |
1137 |
// Value Achieved = All distinct partners called today (from pre-fetched call logs)
|
|
|
1138 |
long[] l2CallStats = getCallStatsFromLogs(callLogsByAuthId.get((long) l2AuthId), mobileToFofoIdMap);
|
| 36276 |
ranu |
1139 |
l2Model.setValueTargetAchieved(l2CallStats[0]);
|
|
|
1140 |
l2Model.setTotalRecordingCalls(l2CallStats[1]);
|
|
|
1141 |
l2Model.setUniqueRecordingCalls(l2CallStats[2]);
|
| 35631 |
ranu |
1142 |
|
|
|
1143 |
l2Model.setOutOfSequenceCount(outOfSequenceCountByAuthId.getOrDefault(l2AuthId, 0L));
|
|
|
1144 |
rbmCallTargetModels.add(l2Model);
|
|
|
1145 |
}
|
|
|
1146 |
|
| 36210 |
ranu |
1147 |
// Process L3 RBMs (escalated ticket logic with categorization)
|
|
|
1148 |
for (int l3AuthId : l3AuthIds) {
|
|
|
1149 |
AuthUser authUser = authUserMap.get(l3AuthId);
|
|
|
1150 |
if (authUser == null) {
|
|
|
1151 |
continue;
|
|
|
1152 |
}
|
|
|
1153 |
|
|
|
1154 |
List<Integer> l3FofoIdList = l3AuthIdToFofoIds.getOrDefault(l3AuthId, Collections.emptyList());
|
|
|
1155 |
|
|
|
1156 |
// For L3, use unique fofoIds with RBM_L3_ESCALATION remark as target
|
|
|
1157 |
Set<Integer> l3TargetFofoIds = new HashSet<>(l3FofoIdList);
|
|
|
1158 |
|
|
|
1159 |
RbmCallTargetModel l3Model = new RbmCallTargetModel();
|
|
|
1160 |
l3Model.setAuthId(l3AuthId);
|
|
|
1161 |
l3Model.setRbmName(authUser.getFullName() + " (L3)");
|
|
|
1162 |
l3Model.setL3Position(true);
|
|
|
1163 |
l3Model.setL3CallingList(l3TargetFofoIds.size());
|
| 36359 |
ranu |
1164 |
// Partner count = total assigned partners (excluding internal)
|
|
|
1165 |
Map<Integer, FofoStore> finalFofoStoresMapL3 = fofoStoresMap;
|
| 36210 |
ranu |
1166 |
List<Integer> l3AssignedFofoIds = rbmToFofoIdsMap.getOrDefault(l3AuthId, Collections.emptyList());
|
| 36359 |
ranu |
1167 |
long l3ExternalPartnerCount = l3AssignedFofoIds.stream()
|
|
|
1168 |
.filter(fofoId -> {
|
|
|
1169 |
FofoStore store = finalFofoStoresMapL3.get(fofoId);
|
|
|
1170 |
return store != null && !store.isInternal();
|
|
|
1171 |
})
|
|
|
1172 |
.count();
|
|
|
1173 |
l3Model.setPartnerCount(l3ExternalPartnerCount);
|
| 36210 |
ranu |
1174 |
|
|
|
1175 |
// L3 Target = partners with RBM_L3_ESCALATION as latest remark
|
|
|
1176 |
l3Model.setTodayTargetOfCall(l3TargetFofoIds.size());
|
|
|
1177 |
|
| 36284 |
ranu |
1178 |
// Value Achieved = All distinct partners called today (from pre-fetched call logs)
|
|
|
1179 |
long[] l3CallStats = getCallStatsFromLogs(callLogsByAuthId.get((long) l3AuthId), mobileToFofoIdMap);
|
| 36276 |
ranu |
1180 |
l3Model.setValueTargetAchieved(l3CallStats[0]);
|
|
|
1181 |
l3Model.setTotalRecordingCalls(l3CallStats[1]);
|
|
|
1182 |
l3Model.setUniqueRecordingCalls(l3CallStats[2]);
|
| 36210 |
ranu |
1183 |
|
|
|
1184 |
l3Model.setOutOfSequenceCount(outOfSequenceCountByAuthId.getOrDefault(l3AuthId, 0L));
|
|
|
1185 |
rbmCallTargetModels.add(l3Model);
|
|
|
1186 |
}
|
|
|
1187 |
|
| 36225 |
ranu |
1188 |
// Group models by escalation level
|
| 36210 |
ranu |
1189 |
Map<Integer, RbmCallTargetModel> l3ModelsByAuthId = new HashMap<>();
|
| 35631 |
ranu |
1190 |
Map<Integer, RbmCallTargetModel> l2ModelsByAuthId = new HashMap<>();
|
|
|
1191 |
Map<Integer, RbmCallTargetModel> l1ModelsByAuthId = new HashMap<>();
|
|
|
1192 |
for (RbmCallTargetModel m : rbmCallTargetModels) {
|
| 36210 |
ranu |
1193 |
if (m.isL3Position()) {
|
|
|
1194 |
l3ModelsByAuthId.put(m.getAuthId(), m);
|
|
|
1195 |
} else if (m.isL2Position()) {
|
| 35631 |
ranu |
1196 |
l2ModelsByAuthId.put(m.getAuthId(), m);
|
|
|
1197 |
} else {
|
|
|
1198 |
l1ModelsByAuthId.put(m.getAuthId(), m);
|
|
|
1199 |
}
|
|
|
1200 |
}
|
|
|
1201 |
|
| 36225 |
ranu |
1202 |
// Build partner-based hierarchy using partner_position table
|
|
|
1203 |
// Map positionId -> Position for quick lookup
|
|
|
1204 |
Map<Integer, Position> positionByIdMap = allRbmPositions.stream()
|
|
|
1205 |
.collect(Collectors.toMap(Position::getId, p -> p, (a, b) -> a));
|
|
|
1206 |
|
|
|
1207 |
// Get all RBM position IDs and fetch their partner assignments
|
|
|
1208 |
List<Integer> allRbmPositionIds = allRbmPositions.stream()
|
|
|
1209 |
.map(Position::getId).collect(Collectors.toList());
|
|
|
1210 |
List<com.spice.profitmandi.dao.entity.cs.PartnerPosition> allPartnerPositions =
|
|
|
1211 |
partnerPositionRepository.selectByPositionIds(allRbmPositionIds);
|
|
|
1212 |
|
|
|
1213 |
// Build partnerId -> map of escalationType -> Set<authUserIds>
|
|
|
1214 |
// This tells us for each partner, who is their L1, L2, L3
|
|
|
1215 |
Map<Integer, Map<EscalationType, Set<Integer>>> partnerToAuthByLevel = new HashMap<>();
|
|
|
1216 |
for (com.spice.profitmandi.dao.entity.cs.PartnerPosition pp : allPartnerPositions) {
|
|
|
1217 |
Position pos = positionByIdMap.get(pp.getPositionId());
|
|
|
1218 |
if (pos != null && pos.getEscalationType() != null) {
|
|
|
1219 |
partnerToAuthByLevel
|
|
|
1220 |
.computeIfAbsent(pp.getFofoId(), k -> new HashMap<>())
|
|
|
1221 |
.computeIfAbsent(pos.getEscalationType(), k -> new HashSet<>())
|
|
|
1222 |
.add(pos.getAuthUserId());
|
|
|
1223 |
}
|
|
|
1224 |
}
|
|
|
1225 |
|
|
|
1226 |
// Build L2 -> L1 team map based on shared partners
|
|
|
1227 |
// If an L1 and L2 share partners (L1 at L1 level, L2 at L2 level), that L1 belongs under that L2
|
|
|
1228 |
Map<Integer, List<RbmCallTargetModel>> l2TeamMap = new LinkedHashMap<>();
|
|
|
1229 |
for (RbmCallTargetModel l2Model : l2ModelsByAuthId.values()) {
|
|
|
1230 |
l2TeamMap.put(l2Model.getAuthId(), new ArrayList<>());
|
|
|
1231 |
}
|
|
|
1232 |
|
|
|
1233 |
// Build L3 -> L2 team map based on shared partners
|
| 36210 |
ranu |
1234 |
Map<Integer, List<RbmCallTargetModel>> l3TeamMap = new LinkedHashMap<>();
|
|
|
1235 |
for (RbmCallTargetModel l3Model : l3ModelsByAuthId.values()) {
|
|
|
1236 |
l3TeamMap.put(l3Model.getAuthId(), new ArrayList<>());
|
|
|
1237 |
}
|
|
|
1238 |
|
| 36225 |
ranu |
1239 |
// For each L1, find which L2 shares the most partners -> that's their L2
|
|
|
1240 |
Set<Integer> addedL1AuthIds = new HashSet<>();
|
|
|
1241 |
for (RbmCallTargetModel l1Model : l1ModelsByAuthId.values()) {
|
|
|
1242 |
Map<Integer, Integer> l2SharedCount = new HashMap<>(); // l2AuthId -> shared partner count
|
|
|
1243 |
for (Map.Entry<Integer, Map<EscalationType, Set<Integer>>> entry : partnerToAuthByLevel.entrySet()) {
|
|
|
1244 |
Map<EscalationType, Set<Integer>> levelMap = entry.getValue();
|
|
|
1245 |
Set<Integer> l1IdsForPartner = levelMap.getOrDefault(EscalationType.L1, Collections.emptySet());
|
|
|
1246 |
Set<Integer> l2AuthIdsForPartner = levelMap.getOrDefault(EscalationType.L2, Collections.emptySet());
|
|
|
1247 |
if (l1IdsForPartner.contains(l1Model.getAuthId())) {
|
|
|
1248 |
for (int l2Id : l2AuthIdsForPartner) {
|
|
|
1249 |
if (l2ModelsByAuthId.containsKey(l2Id) && l2Id != l1Model.getAuthId()) {
|
|
|
1250 |
l2SharedCount.merge(l2Id, 1, Integer::sum);
|
|
|
1251 |
}
|
|
|
1252 |
}
|
|
|
1253 |
}
|
|
|
1254 |
}
|
|
|
1255 |
// Assign L1 to the L2 with most shared partners
|
|
|
1256 |
if (!l2SharedCount.isEmpty()) {
|
|
|
1257 |
int bestL2 = l2SharedCount.entrySet().stream()
|
|
|
1258 |
.max(Map.Entry.comparingByValue()).get().getKey();
|
|
|
1259 |
l2TeamMap.get(bestL2).add(l1Model);
|
|
|
1260 |
addedL1AuthIds.add(l1Model.getAuthId());
|
|
|
1261 |
}
|
|
|
1262 |
}
|
|
|
1263 |
|
|
|
1264 |
// For each L2, find which L3 shares the most partners -> that's their L3
|
| 36210 |
ranu |
1265 |
Set<Integer> addedL2AuthIds = new HashSet<>();
|
|
|
1266 |
for (RbmCallTargetModel l2Model : l2ModelsByAuthId.values()) {
|
| 36225 |
ranu |
1267 |
Map<Integer, Integer> l3SharedCount = new HashMap<>();
|
|
|
1268 |
for (Map.Entry<Integer, Map<EscalationType, Set<Integer>>> entry : partnerToAuthByLevel.entrySet()) {
|
|
|
1269 |
Map<EscalationType, Set<Integer>> levelMap = entry.getValue();
|
|
|
1270 |
Set<Integer> l2AuthIdsForPartner = levelMap.getOrDefault(EscalationType.L2, Collections.emptySet());
|
|
|
1271 |
Set<Integer> l3AuthIdsForPartner = levelMap.getOrDefault(EscalationType.L3, Collections.emptySet());
|
|
|
1272 |
if (l2AuthIdsForPartner.contains(l2Model.getAuthId())) {
|
|
|
1273 |
for (int l3Id : l3AuthIdsForPartner) {
|
|
|
1274 |
if (l3ModelsByAuthId.containsKey(l3Id)) {
|
|
|
1275 |
l3SharedCount.merge(l3Id, 1, Integer::sum);
|
|
|
1276 |
}
|
|
|
1277 |
}
|
|
|
1278 |
}
|
|
|
1279 |
}
|
|
|
1280 |
if (!l3SharedCount.isEmpty()) {
|
|
|
1281 |
int bestL3 = l3SharedCount.entrySet().stream()
|
|
|
1282 |
.max(Map.Entry.comparingByValue()).get().getKey();
|
|
|
1283 |
l3TeamMap.get(bestL3).add(l2Model);
|
| 36210 |
ranu |
1284 |
addedL2AuthIds.add(l2Model.getAuthId());
|
|
|
1285 |
}
|
|
|
1286 |
}
|
|
|
1287 |
|
| 36225 |
ranu |
1288 |
// For L1s not mapped to any L2, check if they map directly to an L3 via shared partners
|
|
|
1289 |
Map<Integer, List<RbmCallTargetModel>> l3DirectL1Map = new LinkedHashMap<>();
|
|
|
1290 |
for (RbmCallTargetModel l3Model : l3ModelsByAuthId.values()) {
|
|
|
1291 |
l3DirectL1Map.put(l3Model.getAuthId(), new ArrayList<>());
|
| 35631 |
ranu |
1292 |
}
|
|
|
1293 |
for (RbmCallTargetModel l1Model : l1ModelsByAuthId.values()) {
|
| 36225 |
ranu |
1294 |
if (addedL1AuthIds.contains(l1Model.getAuthId())) continue;
|
|
|
1295 |
Map<Integer, Integer> l3SharedCount = new HashMap<>();
|
|
|
1296 |
for (Map.Entry<Integer, Map<EscalationType, Set<Integer>>> entry : partnerToAuthByLevel.entrySet()) {
|
|
|
1297 |
Map<EscalationType, Set<Integer>> levelMap = entry.getValue();
|
|
|
1298 |
Set<Integer> l1IdsForPartner = levelMap.getOrDefault(EscalationType.L1, Collections.emptySet());
|
|
|
1299 |
Set<Integer> l3AuthIdsForPartner = levelMap.getOrDefault(EscalationType.L3, Collections.emptySet());
|
|
|
1300 |
if (l1IdsForPartner.contains(l1Model.getAuthId())) {
|
|
|
1301 |
for (int l3Id : l3AuthIdsForPartner) {
|
|
|
1302 |
if (l3ModelsByAuthId.containsKey(l3Id)) {
|
|
|
1303 |
l3SharedCount.merge(l3Id, 1, Integer::sum);
|
|
|
1304 |
}
|
|
|
1305 |
}
|
|
|
1306 |
}
|
|
|
1307 |
}
|
|
|
1308 |
if (!l3SharedCount.isEmpty()) {
|
|
|
1309 |
int bestL3 = l3SharedCount.entrySet().stream()
|
|
|
1310 |
.max(Map.Entry.comparingByValue()).get().getKey();
|
|
|
1311 |
l3DirectL1Map.get(bestL3).add(l1Model);
|
| 35631 |
ranu |
1312 |
addedL1AuthIds.add(l1Model.getAuthId());
|
|
|
1313 |
}
|
|
|
1314 |
}
|
|
|
1315 |
|
| 36225 |
ranu |
1316 |
// Build sorted result: L3 -> L2 -> L1 (with direct L1s under L3 if no L2)
|
| 35631 |
ranu |
1317 |
List<RbmCallTargetModel> sortedModels = new ArrayList<>();
|
|
|
1318 |
|
| 36210 |
ranu |
1319 |
List<RbmCallTargetModel> l3Sorted = new ArrayList<>(l3ModelsByAuthId.values());
|
|
|
1320 |
l3Sorted.sort(Comparator.comparing(RbmCallTargetModel::getRbmName));
|
| 35631 |
ranu |
1321 |
|
| 36210 |
ranu |
1322 |
for (RbmCallTargetModel l3Model : l3Sorted) {
|
|
|
1323 |
sortedModels.add(l3Model);
|
|
|
1324 |
List<RbmCallTargetModel> l2Team = l3TeamMap.getOrDefault(l3Model.getAuthId(), Collections.emptyList());
|
|
|
1325 |
l2Team.sort(Comparator.comparing(RbmCallTargetModel::getRbmName));
|
|
|
1326 |
for (RbmCallTargetModel l2Model : l2Team) {
|
|
|
1327 |
sortedModels.add(l2Model);
|
|
|
1328 |
List<RbmCallTargetModel> l1Team = l2TeamMap.getOrDefault(l2Model.getAuthId(), Collections.emptyList());
|
|
|
1329 |
l1Team.sort(Comparator.comparing(RbmCallTargetModel::getRbmName));
|
|
|
1330 |
sortedModels.addAll(l1Team);
|
|
|
1331 |
}
|
| 36225 |
ranu |
1332 |
// Add L1s that report directly to this L3 (no L2 in between)
|
|
|
1333 |
List<RbmCallTargetModel> directL1Team = l3DirectL1Map.getOrDefault(l3Model.getAuthId(), Collections.emptyList());
|
|
|
1334 |
directL1Team.sort(Comparator.comparing(RbmCallTargetModel::getRbmName));
|
|
|
1335 |
sortedModels.addAll(directL1Team);
|
| 36210 |
ranu |
1336 |
}
|
|
|
1337 |
|
| 36225 |
ranu |
1338 |
// Add L2s not mapped to any L3
|
| 36210 |
ranu |
1339 |
List<RbmCallTargetModel> unmappedL2 = new ArrayList<>();
|
|
|
1340 |
for (RbmCallTargetModel l2Model : l2ModelsByAuthId.values()) {
|
|
|
1341 |
if (!addedL2AuthIds.contains(l2Model.getAuthId())) {
|
|
|
1342 |
unmappedL2.add(l2Model);
|
|
|
1343 |
}
|
|
|
1344 |
}
|
|
|
1345 |
unmappedL2.sort(Comparator.comparing(RbmCallTargetModel::getRbmName));
|
|
|
1346 |
for (RbmCallTargetModel l2Model : unmappedL2) {
|
| 35631 |
ranu |
1347 |
sortedModels.add(l2Model);
|
|
|
1348 |
List<RbmCallTargetModel> team = l2TeamMap.getOrDefault(l2Model.getAuthId(), Collections.emptyList());
|
|
|
1349 |
team.sort(Comparator.comparing(RbmCallTargetModel::getRbmName));
|
|
|
1350 |
sortedModels.addAll(team);
|
|
|
1351 |
}
|
|
|
1352 |
|
| 36225 |
ranu |
1353 |
// Add any L1s not mapped to any L2 or L3
|
| 35631 |
ranu |
1354 |
List<RbmCallTargetModel> unmappedL1 = new ArrayList<>();
|
|
|
1355 |
for (RbmCallTargetModel m : l1ModelsByAuthId.values()) {
|
|
|
1356 |
if (!addedL1AuthIds.contains(m.getAuthId())) {
|
|
|
1357 |
unmappedL1.add(m);
|
|
|
1358 |
}
|
|
|
1359 |
}
|
|
|
1360 |
unmappedL1.sort(Comparator.comparing(RbmCallTargetModel::getRbmName));
|
|
|
1361 |
sortedModels.addAll(unmappedL1);
|
|
|
1362 |
|
|
|
1363 |
LOGGER.info("RBM Call Target - TOTAL TIME: {}ms, RBM count: {}", System.currentTimeMillis() - methodStart, sortedModels.size());
|
|
|
1364 |
return sortedModels;
|
|
|
1365 |
}
|
|
|
1366 |
|
|
|
1367 |
@Override
|
|
|
1368 |
public List<OutOfSequenceDetailModel> getOutOfSequenceDetails(int authId) {
|
|
|
1369 |
|
|
|
1370 |
LocalDate today = LocalDate.now();
|
|
|
1371 |
LocalDateTime start = today.atStartOfDay();
|
|
|
1372 |
LocalDateTime end = today.plusDays(1).atStartOfDay();
|
|
|
1373 |
|
|
|
1374 |
List<RbmCallSequenceLog> logs =
|
|
|
1375 |
rbmCallSequenceLogRepository.selectByAuthIdAndDateRange(authId, start, end);
|
|
|
1376 |
|
| 35654 |
ranu |
1377 |
Map<Integer, RbmCallSequenceLog> uniqueOosLogsByFofoId = new LinkedHashMap<>();
|
| 35631 |
ranu |
1378 |
|
|
|
1379 |
for (RbmCallSequenceLog log : logs) {
|
|
|
1380 |
if (log.isOutOfSequence()) {
|
| 35654 |
ranu |
1381 |
// Keep only the first occurrence per fofoId (latest entry since ordered by id DESC)
|
|
|
1382 |
uniqueOosLogsByFofoId.putIfAbsent(log.getFofoId(), log);
|
| 35631 |
ranu |
1383 |
}
|
|
|
1384 |
}
|
|
|
1385 |
|
| 35654 |
ranu |
1386 |
if (uniqueOosLogsByFofoId.isEmpty()) {
|
| 35631 |
ranu |
1387 |
return Collections.emptyList();
|
|
|
1388 |
}
|
|
|
1389 |
|
| 35654 |
ranu |
1390 |
Set<Integer> fofoIds = uniqueOosLogsByFofoId.keySet();
|
| 35631 |
ranu |
1391 |
Map<Integer, CustomRetailer> retailerMap = Collections.emptyMap();
|
|
|
1392 |
try {
|
|
|
1393 |
retailerMap = retailerService.getFofoRetailers(new ArrayList<>(fofoIds));
|
|
|
1394 |
} catch (ProfitMandiBusinessException e) {
|
|
|
1395 |
LOGGER.error("Error fetching fofo stores", e);
|
|
|
1396 |
}
|
|
|
1397 |
|
|
|
1398 |
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("hh:mm a");
|
|
|
1399 |
List<OutOfSequenceDetailModel> result = new ArrayList<>();
|
|
|
1400 |
|
| 35654 |
ranu |
1401 |
for (RbmCallSequenceLog log : uniqueOosLogsByFofoId.values()) {
|
| 35631 |
ranu |
1402 |
CustomRetailer retailer = retailerMap.get(log.getFofoId());
|
|
|
1403 |
String partyName = retailer != null
|
|
|
1404 |
? retailer.getBusinessName()
|
|
|
1405 |
: "Unknown (" + log.getFofoId() + ")";
|
|
|
1406 |
String code = retailer != null
|
|
|
1407 |
? retailer.getCode()
|
|
|
1408 |
: "-";
|
|
|
1409 |
|
|
|
1410 |
String time = log.getCreateTimestamp() != null
|
|
|
1411 |
? log.getCreateTimestamp().format(timeFormatter)
|
|
|
1412 |
: "-";
|
|
|
1413 |
|
|
|
1414 |
result.add(new OutOfSequenceDetailModel(partyName, code, time));
|
|
|
1415 |
}
|
|
|
1416 |
|
|
|
1417 |
return result;
|
|
|
1418 |
}
|
|
|
1419 |
|
| 35645 |
ranu |
1420 |
@Override
|
| 35672 |
ranu |
1421 |
public List<CalledPartnerDetailModel> getCalledPartnerDetails(int authId) throws ProfitMandiBusinessException {
|
| 35730 |
ranu |
1422 |
return getCalledPartnerDetails(authId, LocalDate.now());
|
|
|
1423 |
}
|
|
|
1424 |
|
|
|
1425 |
@Override
|
|
|
1426 |
public List<CalledPartnerDetailModel> getCalledPartnerDetails(int authId, LocalDate date) throws ProfitMandiBusinessException {
|
| 35759 |
ranu |
1427 |
// Get all call logs for this auth user on this date
|
| 35760 |
ranu |
1428 |
LOGGER.info("getCalledPartnerDetails: authId={}, date={}", authId, date);
|
| 35761 |
ranu |
1429 |
List<AgentCallLog> callLogs = agentCallLogRepository.findByAuthIdAndDate(authId, date);
|
| 35760 |
ranu |
1430 |
LOGGER.info("Found {} call logs for authId={} on date={}", callLogs.size(), authId, date);
|
| 35670 |
ranu |
1431 |
|
| 35759 |
ranu |
1432 |
if (callLogs.isEmpty()) {
|
| 35672 |
ranu |
1433 |
return Collections.emptyList();
|
|
|
1434 |
}
|
| 35670 |
ranu |
1435 |
|
| 35759 |
ranu |
1436 |
// Build a map of normalized customer number -> fofoId
|
|
|
1437 |
Map<String, Integer> customerToFofoIdMap = new HashMap<>();
|
|
|
1438 |
Set<String> normalizedNumbers = new HashSet<>();
|
| 35672 |
ranu |
1439 |
|
| 35763 |
ranu |
1440 |
for (AgentCallLog callLog : callLogs) {
|
| 35759 |
ranu |
1441 |
String customerNumber = callLog.getCustomerNumber();
|
|
|
1442 |
if (customerNumber != null) {
|
|
|
1443 |
String normalized = customerNumber.startsWith("+91") ? customerNumber.substring(3) : customerNumber;
|
|
|
1444 |
normalizedNumbers.add(normalized);
|
|
|
1445 |
}
|
| 35672 |
ranu |
1446 |
}
|
|
|
1447 |
|
| 35759 |
ranu |
1448 |
// For each normalized number, find fofoId from retailer_contact first, then address
|
|
|
1449 |
for (String mobile : normalizedNumbers) {
|
|
|
1450 |
Integer fofoId = findFofoIdByMobile(mobile);
|
|
|
1451 |
if (fofoId != null) {
|
|
|
1452 |
customerToFofoIdMap.put(mobile, fofoId);
|
|
|
1453 |
}
|
| 35670 |
ranu |
1454 |
}
|
|
|
1455 |
|
| 35759 |
ranu |
1456 |
// Get unique fofoIds for retailer lookup
|
|
|
1457 |
Set<Integer> fofoIds = new HashSet<>(customerToFofoIdMap.values());
|
|
|
1458 |
Map<Integer, CustomRetailer> retailerMap = Collections.emptyMap();
|
|
|
1459 |
if (!fofoIds.isEmpty()) {
|
|
|
1460 |
try {
|
|
|
1461 |
retailerMap = retailerService.getFofoRetailers(new ArrayList<>(fofoIds));
|
|
|
1462 |
} catch (ProfitMandiBusinessException e) {
|
|
|
1463 |
LOGGER.error("Error fetching fofo stores", e);
|
|
|
1464 |
}
|
| 35672 |
ranu |
1465 |
}
|
|
|
1466 |
|
| 35759 |
ranu |
1467 |
// Get today's remarks for these fofoIds
|
|
|
1468 |
Map<Integer, List<PartnerCollectionRemark>> fofoRemarkMap = new HashMap<>();
|
|
|
1469 |
if (!fofoIds.isEmpty()) {
|
|
|
1470 |
List<PartnerCollectionRemark> todayRemarks = partnerCollectionRemarkRepository
|
|
|
1471 |
.selectAllByFofoIdsOnDate(new ArrayList<>(fofoIds), date);
|
|
|
1472 |
for (PartnerCollectionRemark remark : todayRemarks) {
|
|
|
1473 |
fofoRemarkMap.computeIfAbsent(remark.getFofoId(), k -> new ArrayList<>()).add(remark);
|
|
|
1474 |
}
|
| 35672 |
ranu |
1475 |
}
|
|
|
1476 |
|
| 35759 |
ranu |
1477 |
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("hh:mm a");
|
|
|
1478 |
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy hh:mm a");
|
|
|
1479 |
List<CalledPartnerDetailModel> result = new ArrayList<>();
|
| 35672 |
ranu |
1480 |
|
| 35759 |
ranu |
1481 |
for (com.spice.profitmandi.dao.entity.cs.AgentCallLog callLog : callLogs) {
|
|
|
1482 |
String customerNumber = callLog.getCustomerNumber();
|
|
|
1483 |
if (customerNumber == null) {
|
|
|
1484 |
continue;
|
|
|
1485 |
}
|
| 35672 |
ranu |
1486 |
|
| 35759 |
ranu |
1487 |
String normalized = customerNumber.startsWith("+91") ? customerNumber.substring(3) : customerNumber;
|
|
|
1488 |
Integer fofoId = customerToFofoIdMap.get(normalized);
|
| 35672 |
ranu |
1489 |
|
| 35759 |
ranu |
1490 |
String partyName = "Unknown";
|
|
|
1491 |
String code = "-";
|
| 35672 |
ranu |
1492 |
|
| 35759 |
ranu |
1493 |
if (fofoId != null) {
|
|
|
1494 |
CustomRetailer retailer = retailerMap.get(fofoId);
|
|
|
1495 |
if (retailer != null) {
|
|
|
1496 |
partyName = retailer.getBusinessName();
|
|
|
1497 |
code = retailer.getCode();
|
|
|
1498 |
} else {
|
|
|
1499 |
partyName = "Unknown (" + fofoId + ")";
|
|
|
1500 |
}
|
|
|
1501 |
} else {
|
|
|
1502 |
partyName = "Unknown (" + normalized + ")";
|
|
|
1503 |
}
|
| 35672 |
ranu |
1504 |
|
| 35759 |
ranu |
1505 |
// Get remark if available
|
|
|
1506 |
String remarkValue = "-";
|
|
|
1507 |
String messageValue = "-";
|
|
|
1508 |
String remarkTime = "-";
|
| 35672 |
ranu |
1509 |
|
| 35759 |
ranu |
1510 |
if (fofoId != null && fofoRemarkMap.containsKey(fofoId)) {
|
|
|
1511 |
List<PartnerCollectionRemark> remarks = fofoRemarkMap.get(fofoId);
|
|
|
1512 |
if (!remarks.isEmpty()) {
|
|
|
1513 |
PartnerCollectionRemark remark = remarks.get(0);
|
|
|
1514 |
remarkValue = remark.getRemark() != null ? remark.getRemark().getValue() : "-";
|
|
|
1515 |
messageValue = remark.getMessage() != null ? remark.getMessage() : "-";
|
|
|
1516 |
remarkTime = remark.getCreateTimestamp() != null ? remark.getCreateTimestamp().format(timeFormatter) : "-";
|
|
|
1517 |
}
|
|
|
1518 |
}
|
| 35672 |
ranu |
1519 |
|
| 35759 |
ranu |
1520 |
// Build call log data
|
|
|
1521 |
String recordingUrl = callLog.getRecordingUrl();
|
|
|
1522 |
String callStatus = callLog.getCallStatus();
|
|
|
1523 |
String callDuration = callLog.getCallDuration();
|
|
|
1524 |
String callDateTime = null;
|
|
|
1525 |
if (callLog.getCallDate() != null && callLog.getCallTime() != null) {
|
|
|
1526 |
LocalDateTime callDateTimeObj = LocalDateTime.of(callLog.getCallDate(), callLog.getCallTime());
|
|
|
1527 |
callDateTime = callDateTimeObj.format(dateTimeFormatter);
|
| 35672 |
ranu |
1528 |
}
|
| 35759 |
ranu |
1529 |
|
|
|
1530 |
result.add(new CalledPartnerDetailModel(partyName, code, remarkValue, messageValue, remarkTime,
|
|
|
1531 |
recordingUrl, callStatus, callDuration, callDateTime));
|
| 35672 |
ranu |
1532 |
}
|
|
|
1533 |
|
| 35759 |
ranu |
1534 |
return result;
|
|
|
1535 |
}
|
| 35672 |
ranu |
1536 |
|
| 35759 |
ranu |
1537 |
private Integer findFofoIdByMobile(String mobile) {
|
|
|
1538 |
// First check retailer_contact
|
|
|
1539 |
List<RetailerContact> contacts = retailerContactRepository.selectByMobile(mobile);
|
|
|
1540 |
if (contacts != null && !contacts.isEmpty()) {
|
|
|
1541 |
return contacts.get(0).getFofoId();
|
|
|
1542 |
}
|
|
|
1543 |
|
|
|
1544 |
// Fallback to user.address
|
| 35762 |
ranu |
1545 |
List<Address> addresses = addressRepository.selectAllByPhoneNumber(mobile);
|
|
|
1546 |
if (addresses != null && !addresses.isEmpty()) {
|
|
|
1547 |
return addresses.get(0).getRetaierId();
|
| 35759 |
ranu |
1548 |
}
|
|
|
1549 |
|
|
|
1550 |
return null;
|
| 35672 |
ranu |
1551 |
}
|
|
|
1552 |
|
| 35757 |
ranu |
1553 |
private List<CalledPartnerDetailModel> buildCalledPartnerResult(List<PartnerCollectionRemark> allRemarks) {
|
|
|
1554 |
if (allRemarks.isEmpty()) {
|
| 35672 |
ranu |
1555 |
return Collections.emptyList();
|
|
|
1556 |
}
|
|
|
1557 |
|
| 35757 |
ranu |
1558 |
// Get unique fofoIds for retailer lookup
|
|
|
1559 |
Set<Integer> fofoIds = allRemarks.stream()
|
|
|
1560 |
.map(PartnerCollectionRemark::getFofoId)
|
|
|
1561 |
.collect(Collectors.toSet());
|
| 35670 |
ranu |
1562 |
Map<Integer, CustomRetailer> retailerMap = Collections.emptyMap();
|
|
|
1563 |
try {
|
|
|
1564 |
retailerMap = retailerService.getFofoRetailers(new ArrayList<>(fofoIds));
|
|
|
1565 |
} catch (ProfitMandiBusinessException e) {
|
|
|
1566 |
LOGGER.error("Error fetching fofo stores", e);
|
|
|
1567 |
}
|
|
|
1568 |
|
| 35702 |
ranu |
1569 |
// Fetch call logs for remarks that have agentCallLogId
|
| 35721 |
ranu |
1570 |
Map<Long, com.spice.profitmandi.dao.entity.cs.AgentCallLog> callLogMap = new HashMap<>();
|
|
|
1571 |
try {
|
| 35757 |
ranu |
1572 |
List<Long> callLogIds = allRemarks.stream()
|
| 35721 |
ranu |
1573 |
.filter(r -> r.getAgentCallLogId() > 0)
|
|
|
1574 |
.map(PartnerCollectionRemark::getAgentCallLogId)
|
|
|
1575 |
.collect(Collectors.toList());
|
| 35702 |
ranu |
1576 |
|
| 35721 |
ranu |
1577 |
if (!callLogIds.isEmpty()) {
|
| 35720 |
ranu |
1578 |
List<com.spice.profitmandi.dao.entity.cs.AgentCallLog> callLogs = agentCallLogRepository.findByIds(callLogIds);
|
| 35721 |
ranu |
1579 |
if (callLogs != null) {
|
|
|
1580 |
callLogMap = callLogs.stream()
|
|
|
1581 |
.collect(Collectors.toMap(com.spice.profitmandi.dao.entity.cs.AgentCallLog::getId, c -> c, (a, b) -> a));
|
|
|
1582 |
}
|
| 35720 |
ranu |
1583 |
}
|
| 35721 |
ranu |
1584 |
} catch (Exception e) {
|
|
|
1585 |
LOGGER.error("Error fetching call logs by ids", e);
|
| 35702 |
ranu |
1586 |
}
|
|
|
1587 |
|
| 35670 |
ranu |
1588 |
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("hh:mm a");
|
| 35702 |
ranu |
1589 |
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy hh:mm a");
|
| 35670 |
ranu |
1590 |
List<CalledPartnerDetailModel> result = new ArrayList<>();
|
|
|
1591 |
|
| 35757 |
ranu |
1592 |
for (PartnerCollectionRemark remark : allRemarks) {
|
| 35670 |
ranu |
1593 |
CustomRetailer retailer = retailerMap.get(remark.getFofoId());
|
|
|
1594 |
String partyName = retailer != null
|
|
|
1595 |
? retailer.getBusinessName()
|
|
|
1596 |
: "Unknown (" + remark.getFofoId() + ")";
|
|
|
1597 |
String code = retailer != null
|
|
|
1598 |
? retailer.getCode()
|
|
|
1599 |
: "-";
|
|
|
1600 |
|
|
|
1601 |
String remarkValue = remark.getRemark() != null
|
|
|
1602 |
? remark.getRemark().getValue()
|
|
|
1603 |
: "-";
|
|
|
1604 |
|
| 35677 |
ranu |
1605 |
String messageValue = remark.getMessage() != null
|
|
|
1606 |
? remark.getMessage()
|
|
|
1607 |
: "-";
|
|
|
1608 |
|
| 35670 |
ranu |
1609 |
String time = remark.getCreateTimestamp() != null
|
|
|
1610 |
? remark.getCreateTimestamp().format(timeFormatter)
|
|
|
1611 |
: "-";
|
|
|
1612 |
|
| 35702 |
ranu |
1613 |
// Get call log data if available
|
|
|
1614 |
String recordingUrl = null;
|
|
|
1615 |
String callStatus = null;
|
|
|
1616 |
String callDuration = null;
|
|
|
1617 |
String callDateTime = null;
|
|
|
1618 |
|
| 35721 |
ranu |
1619 |
try {
|
|
|
1620 |
if (remark.getAgentCallLogId() > 0 && callLogMap.containsKey(remark.getAgentCallLogId())) {
|
|
|
1621 |
com.spice.profitmandi.dao.entity.cs.AgentCallLog callLog = callLogMap.get(remark.getAgentCallLogId());
|
|
|
1622 |
recordingUrl = callLog.getRecordingUrl();
|
|
|
1623 |
callStatus = callLog.getCallStatus();
|
|
|
1624 |
callDuration = callLog.getCallDuration();
|
|
|
1625 |
if (callLog.getCallDate() != null && callLog.getCallTime() != null) {
|
|
|
1626 |
LocalDateTime callDateTimeObj = LocalDateTime.of(callLog.getCallDate(), callLog.getCallTime());
|
|
|
1627 |
callDateTime = callDateTimeObj.format(dateTimeFormatter);
|
|
|
1628 |
}
|
| 35702 |
ranu |
1629 |
}
|
| 35721 |
ranu |
1630 |
} catch (Exception e) {
|
|
|
1631 |
LOGGER.error("Error processing call log for remark id: {}", remark.getId(), e);
|
| 35702 |
ranu |
1632 |
}
|
|
|
1633 |
|
|
|
1634 |
result.add(new CalledPartnerDetailModel(partyName, code, remarkValue, messageValue, time,
|
|
|
1635 |
recordingUrl, callStatus, callDuration, callDateTime));
|
| 35670 |
ranu |
1636 |
}
|
|
|
1637 |
|
|
|
1638 |
return result;
|
|
|
1639 |
}
|
|
|
1640 |
|
|
|
1641 |
@Override
|
| 35645 |
ranu |
1642 |
public List<List<String>> getRbmCallTargetRawDataByAuthId(int authId) throws Exception {
|
|
|
1643 |
List<List<String>> rows = new ArrayList<>();
|
| 35631 |
ranu |
1644 |
|
| 35645 |
ranu |
1645 |
// Get auth user
|
|
|
1646 |
List<AuthUser> authUsers = authRepository.selectByIds(Collections.singletonList(authId));
|
|
|
1647 |
if (authUsers.isEmpty()) {
|
|
|
1648 |
return rows;
|
|
|
1649 |
}
|
|
|
1650 |
AuthUser authUser = authUsers.get(0);
|
|
|
1651 |
|
| 35757 |
ranu |
1652 |
// Get positions to determine if L2
|
| 35645 |
ranu |
1653 |
List<Position> positions = positionRepository.selectPositionByAuthIds(Collections.singletonList(authId));
|
|
|
1654 |
boolean isL2 = positions.stream()
|
|
|
1655 |
.anyMatch(p -> ProfitMandiConstants.TICKET_CATEGORY_RBM == p.getCategoryId()
|
|
|
1656 |
&& EscalationType.L2.equals(p.getEscalationType()));
|
|
|
1657 |
|
| 35757 |
ranu |
1658 |
LocalDateTime startDate = LocalDate.now().atStartOfDay();
|
|
|
1659 |
LocalDate firstOfMonth = LocalDate.now().withDayOfMonth(1);
|
|
|
1660 |
LocalDate endOfMonth = LocalDate.now().withDayOfMonth(LocalDate.now().lengthOfMonth()).plusDays(1);
|
| 35645 |
ranu |
1661 |
|
| 35757 |
ranu |
1662 |
// Get fofo IDs from mtdBillingData (same source as Partner Count in getRbmCallTargetModels)
|
|
|
1663 |
List<RbmWeeklyBillingModel> mtdBillingData = getWeeklyBillingDataForMonth(firstOfMonth, endOfMonth);
|
|
|
1664 |
|
|
|
1665 |
List<Integer> fofoIdList;
|
| 35645 |
ranu |
1666 |
if (isL2) {
|
| 35757 |
ranu |
1667 |
// L2: get fofo IDs from escalated tickets (same as getRbmCallTargetModels)
|
| 35645 |
ranu |
1668 |
List<Ticket> escalatedTickets = ticketRepository.selectOpenEscalatedTicketsByAuthIds(Collections.singletonList(authId));
|
|
|
1669 |
fofoIdList = escalatedTickets.stream()
|
|
|
1670 |
.filter(t -> t.getL2AuthUser() == authId
|
|
|
1671 |
|| t.getL3AuthUser() == authId
|
|
|
1672 |
|| t.getL4AuthUser() == authId
|
|
|
1673 |
|| t.getL5AuthUser() == authId)
|
|
|
1674 |
.map(Ticket::getFofoId)
|
|
|
1675 |
.distinct()
|
|
|
1676 |
.collect(Collectors.toList());
|
| 35757 |
ranu |
1677 |
} else {
|
|
|
1678 |
// L1: get fofo IDs from mtdBillingData with isTargetedPartner (same as Partner Count)
|
|
|
1679 |
fofoIdList = mtdBillingData.stream()
|
|
|
1680 |
.filter(RbmWeeklyBillingModel::isTargetedPartner)
|
|
|
1681 |
.filter(m -> m.getAuthId() == authId)
|
|
|
1682 |
.map(RbmWeeklyBillingModel::getFofoId)
|
|
|
1683 |
.distinct()
|
|
|
1684 |
.collect(Collectors.toList());
|
| 35645 |
ranu |
1685 |
}
|
|
|
1686 |
|
|
|
1687 |
if (fofoIdList.isEmpty()) {
|
|
|
1688 |
return rows;
|
|
|
1689 |
}
|
|
|
1690 |
|
| 35757 |
ranu |
1691 |
// MTD billed fofoIds for zero billing check
|
|
|
1692 |
Set<Integer> mtdBilledFofoIds = mtdBillingData.stream()
|
|
|
1693 |
.filter(RbmWeeklyBillingModel::isMtdBilled)
|
|
|
1694 |
.map(RbmWeeklyBillingModel::getFofoId)
|
|
|
1695 |
.collect(Collectors.toSet());
|
| 35645 |
ranu |
1696 |
|
| 35757 |
ranu |
1697 |
// Collection rank map for status calculation
|
| 35645 |
ranu |
1698 |
Map<Integer, Integer> collectionRankMap = new HashMap<>();
|
|
|
1699 |
try {
|
|
|
1700 |
collectionRankMap = partnerCollectionService.getCollectionRankMap(fofoIdList, startDate);
|
|
|
1701 |
} catch (ProfitMandiBusinessException e) {
|
|
|
1702 |
LOGGER.error("Error fetching collection rank map", e);
|
|
|
1703 |
}
|
|
|
1704 |
|
|
|
1705 |
// Resolve partner names/codes
|
|
|
1706 |
Map<Integer, CustomRetailer> retailerMap = Collections.emptyMap();
|
| 35757 |
ranu |
1707 |
if (!fofoIdList.isEmpty()) {
|
| 35645 |
ranu |
1708 |
try {
|
| 35757 |
ranu |
1709 |
retailerMap = retailerService.getFofoRetailers(fofoIdList);
|
| 35645 |
ranu |
1710 |
} catch (ProfitMandiBusinessException e) {
|
|
|
1711 |
LOGGER.error("Error fetching fofo retailers for raw data", e);
|
|
|
1712 |
}
|
|
|
1713 |
}
|
|
|
1714 |
|
|
|
1715 |
String rbmName = authUser.getFullName() + (isL2 ? " (L2)" : "");
|
|
|
1716 |
|
| 35757 |
ranu |
1717 |
// Build rows for ALL partners (same count as Partner Count)
|
|
|
1718 |
for (Integer fofoId : fofoIdList) {
|
|
|
1719 |
// Default to rank 5 (Normal) for partners without collection plan
|
| 35645 |
ranu |
1720 |
int rank = collectionRankMap.getOrDefault(fofoId, 5);
|
|
|
1721 |
boolean hasZeroBilling = !mtdBilledFofoIds.contains(fofoId);
|
|
|
1722 |
|
| 35757 |
ranu |
1723 |
// Status assignment with same priority as getRbmCallTargetModels
|
| 35645 |
ranu |
1724 |
String status;
|
|
|
1725 |
if (rank == 1) {
|
|
|
1726 |
status = "Plan Today";
|
|
|
1727 |
} else if (rank == 2) {
|
|
|
1728 |
status = "Carry Forward";
|
| 35757 |
ranu |
1729 |
} else if (hasZeroBilling) {
|
|
|
1730 |
status = "Zero Billing";
|
| 35645 |
ranu |
1731 |
} else if (rank == 3) {
|
|
|
1732 |
status = "Untouched";
|
|
|
1733 |
} else if (rank == 4) {
|
|
|
1734 |
status = "Future Plan";
|
|
|
1735 |
} else {
|
|
|
1736 |
status = "Normal";
|
|
|
1737 |
}
|
|
|
1738 |
|
|
|
1739 |
CustomRetailer retailer = retailerMap.get(fofoId);
|
|
|
1740 |
String partnerName = retailer != null ? retailer.getBusinessName() : "Unknown (" + fofoId + ")";
|
|
|
1741 |
String partnerCode = retailer != null ? retailer.getCode() : "-";
|
|
|
1742 |
|
|
|
1743 |
rows.add(Arrays.asList(partnerName, partnerCode, status, rbmName));
|
|
|
1744 |
}
|
|
|
1745 |
|
|
|
1746 |
return rows;
|
|
|
1747 |
}
|
|
|
1748 |
|
| 36596 |
ranu |
1749 |
@Override
|
|
|
1750 |
public List<List<String>> getAllRbmCallTargetRawData() throws Exception {
|
|
|
1751 |
List<List<String>> rows = new ArrayList<>();
|
|
|
1752 |
|
|
|
1753 |
// Get all L1 RBM positions
|
|
|
1754 |
List<Position> allRbmPositions = positionRepository
|
|
|
1755 |
.selectPositionByCategoryId(ProfitMandiConstants.TICKET_CATEGORY_RBM).stream()
|
|
|
1756 |
.filter(x -> EscalationType.L1.equals(x.getEscalationType()))
|
|
|
1757 |
.collect(Collectors.toList());
|
|
|
1758 |
|
|
|
1759 |
List<Integer> l1AuthIds = allRbmPositions.stream()
|
|
|
1760 |
.map(Position::getAuthUserId).distinct().collect(Collectors.toList());
|
|
|
1761 |
|
|
|
1762 |
if (l1AuthIds.isEmpty()) {
|
|
|
1763 |
return rows;
|
|
|
1764 |
}
|
|
|
1765 |
|
|
|
1766 |
// Get auth user map
|
|
|
1767 |
Map<Integer, AuthUser> authUserMap = authRepository.selectByIds(l1AuthIds).stream()
|
|
|
1768 |
.collect(Collectors.toMap(AuthUser::getId, au -> au));
|
|
|
1769 |
|
|
|
1770 |
// Get partner assignments
|
|
|
1771 |
Map<String, Set<Integer>> storeGuyMap = csService.getAuthUserPartnerIdMapping();
|
|
|
1772 |
|
|
|
1773 |
Map<Integer, List<Integer>> rbmToFofoIdsMap = new HashMap<>();
|
|
|
1774 |
Set<Integer> allFofoIds = new HashSet<>();
|
|
|
1775 |
for (int rbmAuthId : l1AuthIds) {
|
|
|
1776 |
AuthUser au = authUserMap.get(rbmAuthId);
|
|
|
1777 |
if (au != null && storeGuyMap.containsKey(au.getEmailId())) {
|
|
|
1778 |
List<Integer> fofoIds = new ArrayList<>(storeGuyMap.get(au.getEmailId()));
|
|
|
1779 |
allFofoIds.addAll(fofoIds);
|
|
|
1780 |
rbmToFofoIdsMap.put(rbmAuthId, fofoIds);
|
|
|
1781 |
}
|
|
|
1782 |
}
|
|
|
1783 |
|
|
|
1784 |
if (allFofoIds.isEmpty()) {
|
|
|
1785 |
return rows;
|
|
|
1786 |
}
|
|
|
1787 |
|
|
|
1788 |
// Get fofo stores for filtering and name resolution
|
|
|
1789 |
Map<Integer, FofoStore> fofoStoresMap = new HashMap<>();
|
|
|
1790 |
try {
|
|
|
1791 |
fofoStoresMap = fofoStoreRepository.selectByRetailerIds(new ArrayList<>(allFofoIds)).stream()
|
|
|
1792 |
.collect(Collectors.toMap(FofoStore::getId, x -> x, (a, b) -> a));
|
|
|
1793 |
} catch (ProfitMandiBusinessException e) {
|
|
|
1794 |
LOGGER.error("Error fetching fofo stores for all raw data", e);
|
|
|
1795 |
}
|
|
|
1796 |
|
|
|
1797 |
// Batch fetch collection rank map
|
|
|
1798 |
LocalDateTime startDate = LocalDate.now().atStartOfDay();
|
|
|
1799 |
Map<Integer, Integer> allCollectionRankMap = new HashMap<>();
|
|
|
1800 |
try {
|
|
|
1801 |
allCollectionRankMap = partnerCollectionService.getCollectionRankMap(new ArrayList<>(allFofoIds), startDate);
|
|
|
1802 |
} catch (ProfitMandiBusinessException e) {
|
|
|
1803 |
LOGGER.error("Error fetching collection rank map for all raw data", e);
|
|
|
1804 |
}
|
|
|
1805 |
|
|
|
1806 |
// MTD billing data
|
|
|
1807 |
LocalDate firstOfMonth = LocalDate.now().withDayOfMonth(1);
|
|
|
1808 |
LocalDate endOfMonth = LocalDate.now().withDayOfMonth(LocalDate.now().lengthOfMonth()).plusDays(1);
|
|
|
1809 |
List<RbmWeeklyBillingModel> mtdBillingData = getWeeklyBillingDataForMonth(firstOfMonth, endOfMonth);
|
|
|
1810 |
Set<Integer> allMtdBilledFofoIds = mtdBillingData.stream()
|
|
|
1811 |
.filter(RbmWeeklyBillingModel::isMtdBilled)
|
|
|
1812 |
.map(RbmWeeklyBillingModel::getFofoId)
|
|
|
1813 |
.collect(Collectors.toSet());
|
|
|
1814 |
|
|
|
1815 |
// Batch fetch partner collection remarks for escalation filtering
|
|
|
1816 |
Map<Integer, PartnerCollectionRemark> allPartnerCollectionRemarks = new HashMap<>();
|
|
|
1817 |
if (!allFofoIds.isEmpty()) {
|
|
|
1818 |
List<Integer> allRemarkIds = partnerCollectionRemarkRepository.selectMaxRemarkId(new ArrayList<>(allFofoIds));
|
|
|
1819 |
if (!allRemarkIds.isEmpty()) {
|
|
|
1820 |
allPartnerCollectionRemarks = partnerCollectionRemarkRepository.selectByIds(allRemarkIds).stream()
|
|
|
1821 |
.collect(Collectors.toMap(PartnerCollectionRemark::getFofoId, x -> x, (a, b) -> a));
|
|
|
1822 |
}
|
|
|
1823 |
}
|
|
|
1824 |
|
|
|
1825 |
// Resolve partner names/codes in batch
|
|
|
1826 |
Map<Integer, CustomRetailer> retailerMap = Collections.emptyMap();
|
|
|
1827 |
try {
|
|
|
1828 |
retailerMap = retailerService.getFofoRetailers(new ArrayList<>(allFofoIds));
|
|
|
1829 |
} catch (ProfitMandiBusinessException e) {
|
|
|
1830 |
LOGGER.error("Error fetching fofo retailers for all raw data", e);
|
|
|
1831 |
}
|
|
|
1832 |
|
|
|
1833 |
// Get positions for L1 check
|
|
|
1834 |
Map<Integer, List<Position>> positionsByAuthId = positionRepository.selectPositionByAuthIds(l1AuthIds).stream()
|
|
|
1835 |
.collect(Collectors.groupingBy(Position::getAuthUserId));
|
|
|
1836 |
|
| 36883 |
ranu |
1837 |
// Batch-fetch today's call logs for all L1 RBMs, and build a (authId, fofoId) -> latest AgentCallLog map
|
|
|
1838 |
// so each row can carry the latest call status for that RBM-partner pair.
|
|
|
1839 |
Map<Long, Map<Integer, AgentCallLog>> latestCallByAuthFofo = new HashMap<>();
|
|
|
1840 |
try {
|
|
|
1841 |
List<AgentCallLog> todayCallLogs = agentCallLogRepository.findByAuthIdsAndDate(l1AuthIds, LocalDate.now());
|
|
|
1842 |
Set<String> normalizedMobiles = new HashSet<>();
|
|
|
1843 |
for (AgentCallLog log : todayCallLogs) {
|
|
|
1844 |
if (log.getCustomerNumber() != null) {
|
|
|
1845 |
String n = log.getCustomerNumber();
|
|
|
1846 |
normalizedMobiles.add(n.startsWith("+91") ? n.substring(3) : n);
|
|
|
1847 |
}
|
|
|
1848 |
}
|
|
|
1849 |
Map<String, Integer> mobileToFofoIdMap = buildMobileToFofoIdMap(normalizedMobiles);
|
|
|
1850 |
for (AgentCallLog log : todayCallLogs) {
|
|
|
1851 |
if (log.getCustomerNumber() == null) continue;
|
|
|
1852 |
String n = log.getCustomerNumber();
|
|
|
1853 |
String normalized = n.startsWith("+91") ? n.substring(3) : n;
|
|
|
1854 |
Integer fofoId = mobileToFofoIdMap.get(normalized);
|
|
|
1855 |
if (fofoId == null) continue;
|
|
|
1856 |
Map<Integer, AgentCallLog> inner = latestCallByAuthFofo
|
|
|
1857 |
.computeIfAbsent(log.getAuthId(), k -> new HashMap<>());
|
|
|
1858 |
AgentCallLog existing = inner.get(fofoId);
|
|
|
1859 |
if (existing == null || (log.getId() != null && existing.getId() != null && log.getId() > existing.getId())) {
|
|
|
1860 |
inner.put(fofoId, log);
|
|
|
1861 |
}
|
|
|
1862 |
}
|
|
|
1863 |
} catch (Exception e) {
|
|
|
1864 |
LOGGER.error("Error building latest call status map for all raw data", e);
|
|
|
1865 |
}
|
|
|
1866 |
|
| 36596 |
ranu |
1867 |
// Track processed fofoIds to avoid duplicates (a party assigned to L1 RBM
|
|
|
1868 |
// should not appear again under another RBM who also has it via L2 position)
|
|
|
1869 |
Set<Integer> processedFofoIds = new HashSet<>();
|
|
|
1870 |
|
|
|
1871 |
// Process each L1 RBM
|
|
|
1872 |
for (int rbmAuthId : l1AuthIds) {
|
|
|
1873 |
AuthUser authUser = authUserMap.get(rbmAuthId);
|
|
|
1874 |
if (authUser == null || !storeGuyMap.containsKey(authUser.getEmailId())) {
|
|
|
1875 |
continue;
|
|
|
1876 |
}
|
|
|
1877 |
|
|
|
1878 |
List<Integer> fofoIdList = rbmToFofoIdsMap.getOrDefault(rbmAuthId, Collections.emptyList());
|
|
|
1879 |
|
|
|
1880 |
// Filter escalated partners for L1 RBMs
|
|
|
1881 |
List<Position> positions = positionsByAuthId.getOrDefault(rbmAuthId, Collections.emptyList());
|
|
|
1882 |
boolean isRBMAndL1 = positions.stream()
|
|
|
1883 |
.anyMatch(position ->
|
|
|
1884 |
ProfitMandiConstants.TICKET_CATEGORY_RBM == position.getCategoryId()
|
|
|
1885 |
&& EscalationType.L1.equals(position.getEscalationType()));
|
|
|
1886 |
|
|
|
1887 |
List<Integer> fofoIds = fofoIdList;
|
|
|
1888 |
if (isRBMAndL1) {
|
|
|
1889 |
Map<Integer, PartnerCollectionRemark> partnerRemarks = new HashMap<>();
|
|
|
1890 |
for (Integer fofoId : fofoIdList) {
|
|
|
1891 |
if (allPartnerCollectionRemarks.containsKey(fofoId)) {
|
|
|
1892 |
partnerRemarks.put(fofoId, allPartnerCollectionRemarks.get(fofoId));
|
|
|
1893 |
}
|
|
|
1894 |
}
|
|
|
1895 |
Map<Integer, PartnerCollectionRemark> finalPartnerRemarks = partnerRemarks;
|
|
|
1896 |
fofoIds = fofoIdList.stream()
|
|
|
1897 |
.filter(fofoId -> {
|
|
|
1898 |
if (!finalPartnerRemarks.containsKey(fofoId)) return true;
|
|
|
1899 |
PartnerCollectionRemark pcr = finalPartnerRemarks.get(fofoId);
|
|
|
1900 |
return !(CollectionRemark.RBM_L2_ESCALATION.equals(pcr.getRemark())
|
|
|
1901 |
|| CollectionRemark.SALES_ESCALATION.equals(pcr.getRemark()));
|
|
|
1902 |
})
|
|
|
1903 |
.collect(Collectors.toList());
|
|
|
1904 |
}
|
|
|
1905 |
|
|
|
1906 |
// Filter to only external, ACTIVE or REVIVAL stores
|
|
|
1907 |
Map<Integer, FofoStore> finalFofoStoresMap = fofoStoresMap;
|
|
|
1908 |
List<Integer> validFofoIds = fofoIds.stream()
|
|
|
1909 |
.filter(fofoId -> {
|
|
|
1910 |
FofoStore store = finalFofoStoresMap.get(fofoId);
|
|
|
1911 |
if (store == null || store.isInternal()) return false;
|
|
|
1912 |
return ActivationType.ACTIVE.equals(store.getActivationType())
|
|
|
1913 |
|| ActivationType.REVIVAL.equals(store.getActivationType());
|
|
|
1914 |
})
|
|
|
1915 |
.collect(Collectors.toList());
|
|
|
1916 |
|
|
|
1917 |
String rbmName = authUser.getFullName();
|
|
|
1918 |
|
|
|
1919 |
// Categorize each partner and add row (skip if already processed under another RBM)
|
|
|
1920 |
for (Integer fofoId : validFofoIds) {
|
|
|
1921 |
if (processedFofoIds.contains(fofoId)) {
|
|
|
1922 |
continue; // Already added under another L1 RBM
|
|
|
1923 |
}
|
|
|
1924 |
|
|
|
1925 |
int rank = allCollectionRankMap.getOrDefault(fofoId, 5);
|
|
|
1926 |
boolean hasZeroBilling = !allMtdBilledFofoIds.contains(fofoId);
|
|
|
1927 |
|
|
|
1928 |
String status;
|
|
|
1929 |
if (rank == 1) {
|
|
|
1930 |
status = "Plan Today";
|
|
|
1931 |
} else if (rank == 2) {
|
|
|
1932 |
status = "Carry Forward";
|
|
|
1933 |
} else if (hasZeroBilling) {
|
|
|
1934 |
status = "Zero Billing";
|
|
|
1935 |
} else if (rank == 3) {
|
|
|
1936 |
status = "Untouched";
|
|
|
1937 |
} else {
|
|
|
1938 |
continue; // Skip Future Plan and Normal — only include calling target parties
|
|
|
1939 |
}
|
|
|
1940 |
|
|
|
1941 |
processedFofoIds.add(fofoId);
|
|
|
1942 |
|
|
|
1943 |
CustomRetailer retailer = retailerMap.get(fofoId);
|
|
|
1944 |
String partnerName = retailer != null ? retailer.getBusinessName() : "Unknown (" + fofoId + ")";
|
|
|
1945 |
String partnerCode = retailer != null ? retailer.getCode() : "-";
|
|
|
1946 |
|
| 36883 |
ranu |
1947 |
String latestCallStatus = "Did Not Try";
|
|
|
1948 |
Map<Integer, AgentCallLog> rbmCalls = latestCallByAuthFofo.get((long) rbmAuthId);
|
|
|
1949 |
if (rbmCalls != null) {
|
|
|
1950 |
AgentCallLog latestLog = rbmCalls.get(fofoId);
|
|
|
1951 |
if (latestLog != null && latestLog.getCallStatus() != null && !latestLog.getCallStatus().isEmpty()) {
|
|
|
1952 |
latestCallStatus = latestLog.getCallStatus();
|
|
|
1953 |
}
|
|
|
1954 |
}
|
|
|
1955 |
|
|
|
1956 |
rows.add(Arrays.asList(partnerName, partnerCode, status, rbmName, latestCallStatus));
|
| 36596 |
ranu |
1957 |
}
|
|
|
1958 |
}
|
|
|
1959 |
|
|
|
1960 |
return rows;
|
|
|
1961 |
}
|
|
|
1962 |
|
| 35843 |
ranu |
1963 |
/**
|
|
|
1964 |
* Get count of distinct partners called today based on call logs.
|
|
|
1965 |
* Maps customerNumber from call log to fofoId using retailer_contact and address.
|
|
|
1966 |
* If same fofoId is called multiple times, counts only once.
|
|
|
1967 |
* Numbers without fofoId mapping are also counted (by distinct customer number).
|
|
|
1968 |
*
|
|
|
1969 |
* @param authId the RBM auth ID
|
|
|
1970 |
* @return count of distinct partners/numbers called today
|
|
|
1971 |
*/
|
|
|
1972 |
public long getCalledCountFromCallLogs(long authId) {
|
| 36234 |
ranu |
1973 |
return getCalledCountFromCallLogs(authId, LocalDate.now());
|
|
|
1974 |
}
|
| 35843 |
ranu |
1975 |
|
| 36234 |
ranu |
1976 |
public long getCalledCountFromCallLogs(long authId, LocalDate date) {
|
| 36276 |
ranu |
1977 |
return getCallStats(authId, date)[0];
|
|
|
1978 |
}
|
|
|
1979 |
|
|
|
1980 |
/**
|
| 36284 |
ranu |
1981 |
* Batch-builds a mobile (normalized, +91 stripped) -> fofoId mapping for all the given mobiles
|
|
|
1982 |
* in just two queries (retailer_contact, then address fallback for unmapped numbers).
|
|
|
1983 |
* Replaces the previous per-call-log findFofoIdByMobile() N+1 lookups.
|
|
|
1984 |
*/
|
|
|
1985 |
private Map<String, Integer> buildMobileToFofoIdMap(Set<String> normalizedMobiles) {
|
|
|
1986 |
Map<String, Integer> result = new HashMap<>();
|
|
|
1987 |
if (normalizedMobiles == null || normalizedMobiles.isEmpty()) {
|
|
|
1988 |
return result;
|
|
|
1989 |
}
|
|
|
1990 |
List<String> mobilesList = new ArrayList<>(normalizedMobiles);
|
|
|
1991 |
|
|
|
1992 |
// First pass: retailer_contact
|
|
|
1993 |
List<RetailerContact> contacts = retailerContactRepository.selectByMobiles(mobilesList);
|
|
|
1994 |
for (RetailerContact rc : contacts) {
|
|
|
1995 |
// Keep the first fofoId we see per mobile (matches old single-mobile behavior of get(0))
|
|
|
1996 |
result.putIfAbsent(rc.getMobile(), rc.getFofoId());
|
|
|
1997 |
}
|
|
|
1998 |
|
|
|
1999 |
// Second pass: address fallback for mobiles not yet mapped
|
|
|
2000 |
List<String> unmapped = mobilesList.stream()
|
|
|
2001 |
.filter(m -> !result.containsKey(m))
|
|
|
2002 |
.collect(Collectors.toList());
|
|
|
2003 |
if (!unmapped.isEmpty()) {
|
|
|
2004 |
List<Address> addresses = addressRepository.selectAllByPhoneNumbers(unmapped);
|
|
|
2005 |
for (Address addr : addresses) {
|
|
|
2006 |
result.putIfAbsent(addr.getPhoneNumber(), addr.getRetaierId());
|
|
|
2007 |
}
|
|
|
2008 |
}
|
|
|
2009 |
return result;
|
|
|
2010 |
}
|
|
|
2011 |
|
|
|
2012 |
/**
|
|
|
2013 |
* In-memory variant of getCallStats() that uses pre-fetched call logs and mobile→fofoId mapping.
|
|
|
2014 |
* Used by the batch-fetched RBM Call Target loop to avoid N+1 query patterns.
|
|
|
2015 |
*/
|
|
|
2016 |
private long[] getCallStatsFromLogs(List<AgentCallLog> callLogs, Map<String, Integer> mobileToFofoIdMap) {
|
|
|
2017 |
if (callLogs == null || callLogs.isEmpty()) {
|
|
|
2018 |
return new long[]{0, 0, 0};
|
|
|
2019 |
}
|
|
|
2020 |
|
|
|
2021 |
Set<Integer> calledFofoIds = new HashSet<>();
|
|
|
2022 |
Set<String> calledNumbersWithoutFofoId = new HashSet<>();
|
|
|
2023 |
long totalRecordingCalls = 0;
|
|
|
2024 |
Set<String> uniqueRecordingNumbers = new HashSet<>();
|
|
|
2025 |
|
|
|
2026 |
for (AgentCallLog callLog : callLogs) {
|
|
|
2027 |
String customerNumber = callLog.getCustomerNumber();
|
|
|
2028 |
if (customerNumber != null) {
|
|
|
2029 |
String normalized = customerNumber.startsWith("+91") ? customerNumber.substring(3) : customerNumber;
|
|
|
2030 |
Integer fofoId = mobileToFofoIdMap.get(normalized);
|
|
|
2031 |
if (fofoId != null) {
|
|
|
2032 |
calledFofoIds.add(fofoId);
|
|
|
2033 |
} else {
|
|
|
2034 |
calledNumbersWithoutFofoId.add(normalized);
|
|
|
2035 |
}
|
|
|
2036 |
|
|
|
2037 |
if (callLog.getRecordingUrl() != null && !callLog.getRecordingUrl().isEmpty()
|
|
|
2038 |
&& !"None".equalsIgnoreCase(callLog.getRecordingUrl())) {
|
|
|
2039 |
totalRecordingCalls++;
|
|
|
2040 |
uniqueRecordingNumbers.add(normalized);
|
|
|
2041 |
}
|
|
|
2042 |
}
|
|
|
2043 |
}
|
|
|
2044 |
|
|
|
2045 |
long calledCount = calledFofoIds.size() + calledNumbersWithoutFofoId.size();
|
|
|
2046 |
return new long[]{calledCount, totalRecordingCalls, uniqueRecordingNumbers.size()};
|
|
|
2047 |
}
|
|
|
2048 |
|
|
|
2049 |
/**
|
| 36276 |
ranu |
2050 |
* Returns call stats: [0] = called count, [1] = total recording calls, [2] = unique recording calls
|
|
|
2051 |
*/
|
|
|
2052 |
public long[] getCallStats(long authId, LocalDate date) {
|
| 36234 |
ranu |
2053 |
List<AgentCallLog> callLogs = agentCallLogRepository.findByAuthIdAndDate(authId, date);
|
|
|
2054 |
|
| 35843 |
ranu |
2055 |
if (callLogs == null || callLogs.isEmpty()) {
|
| 36276 |
ranu |
2056 |
return new long[]{0, 0, 0};
|
| 35843 |
ranu |
2057 |
}
|
|
|
2058 |
|
|
|
2059 |
Set<Integer> calledFofoIds = new HashSet<>();
|
|
|
2060 |
Set<String> calledNumbersWithoutFofoId = new HashSet<>();
|
| 36276 |
ranu |
2061 |
long totalRecordingCalls = 0;
|
|
|
2062 |
Set<String> uniqueRecordingNumbers = new HashSet<>();
|
| 35843 |
ranu |
2063 |
|
|
|
2064 |
for (AgentCallLog callLog : callLogs) {
|
|
|
2065 |
String customerNumber = callLog.getCustomerNumber();
|
|
|
2066 |
if (customerNumber != null) {
|
|
|
2067 |
// Normalize the phone number (remove +91 prefix if present)
|
|
|
2068 |
String normalized = customerNumber.startsWith("+91") ? customerNumber.substring(3) : customerNumber;
|
|
|
2069 |
|
|
|
2070 |
// Find fofoId from retailer_contact or address
|
|
|
2071 |
Integer fofoId = findFofoIdByMobile(normalized);
|
|
|
2072 |
if (fofoId != null) {
|
|
|
2073 |
calledFofoIds.add(fofoId);
|
|
|
2074 |
} else {
|
|
|
2075 |
// Number not found in retailer_contact or address, count by distinct number
|
|
|
2076 |
calledNumbersWithoutFofoId.add(normalized);
|
|
|
2077 |
}
|
| 36276 |
ranu |
2078 |
|
|
|
2079 |
// Count calls with recordings
|
|
|
2080 |
if (callLog.getRecordingUrl() != null && !callLog.getRecordingUrl().isEmpty()
|
|
|
2081 |
&& !"None".equalsIgnoreCase(callLog.getRecordingUrl())) {
|
|
|
2082 |
totalRecordingCalls++;
|
|
|
2083 |
uniqueRecordingNumbers.add(normalized);
|
|
|
2084 |
}
|
| 35843 |
ranu |
2085 |
}
|
|
|
2086 |
}
|
|
|
2087 |
|
|
|
2088 |
// Total called = distinct fofoIds + distinct numbers without fofoId mapping
|
| 36276 |
ranu |
2089 |
long calledCount = calledFofoIds.size() + calledNumbersWithoutFofoId.size();
|
|
|
2090 |
return new long[]{calledCount, totalRecordingCalls, uniqueRecordingNumbers.size()};
|
| 35843 |
ranu |
2091 |
}
|
|
|
2092 |
|
| 35852 |
ranu |
2093 |
@Override
|
|
|
2094 |
public List<List<String>> getAllCallDataByDate(LocalDate date) throws Exception {
|
|
|
2095 |
List<List<String>> rows = new ArrayList<>();
|
|
|
2096 |
|
|
|
2097 |
// Add header row
|
|
|
2098 |
rows.add(Arrays.asList("RBM Name", "Partner Name", "Code", "Remark", "Call Status", "Call Duration", "Call Date Time", "Recording URL"));
|
|
|
2099 |
|
|
|
2100 |
// Get all call logs for the date
|
|
|
2101 |
List<AgentCallLog> allCallLogs = agentCallLogRepository.findAllByDate(date);
|
|
|
2102 |
LOGGER.info("getAllCallDataByDate: Found {} call logs for date {}", allCallLogs.size(), date);
|
|
|
2103 |
|
|
|
2104 |
if (allCallLogs.isEmpty()) {
|
|
|
2105 |
return rows;
|
|
|
2106 |
}
|
|
|
2107 |
|
|
|
2108 |
// Get unique authIds from call logs
|
|
|
2109 |
Set<Long> authIds = allCallLogs.stream()
|
|
|
2110 |
.map(AgentCallLog::getAuthId)
|
|
|
2111 |
.collect(Collectors.toSet());
|
|
|
2112 |
|
|
|
2113 |
// Get auth users for RBM names
|
|
|
2114 |
List<Integer> authIdInts = authIds.stream().map(Long::intValue).collect(Collectors.toList());
|
|
|
2115 |
Map<Integer, AuthUser> authUserMap = authRepository.selectByIds(authIdInts).stream()
|
|
|
2116 |
.collect(Collectors.toMap(AuthUser::getId, au -> au, (a, b) -> a));
|
|
|
2117 |
|
|
|
2118 |
// Build a map of normalized customer number -> fofoId
|
|
|
2119 |
Map<String, Integer> customerToFofoIdMap = new HashMap<>();
|
|
|
2120 |
Set<String> normalizedNumbers = new HashSet<>();
|
|
|
2121 |
|
|
|
2122 |
for (AgentCallLog callLog : allCallLogs) {
|
|
|
2123 |
String customerNumber = callLog.getCustomerNumber();
|
|
|
2124 |
if (customerNumber != null) {
|
|
|
2125 |
String normalized = customerNumber.startsWith("+91") ? customerNumber.substring(3) : customerNumber;
|
|
|
2126 |
normalizedNumbers.add(normalized);
|
|
|
2127 |
}
|
|
|
2128 |
}
|
|
|
2129 |
|
|
|
2130 |
// For each normalized number, find fofoId
|
|
|
2131 |
for (String mobile : normalizedNumbers) {
|
|
|
2132 |
Integer fofoId = findFofoIdByMobile(mobile);
|
|
|
2133 |
if (fofoId != null) {
|
|
|
2134 |
customerToFofoIdMap.put(mobile, fofoId);
|
|
|
2135 |
}
|
|
|
2136 |
}
|
|
|
2137 |
|
|
|
2138 |
// Get unique fofoIds for retailer lookup
|
|
|
2139 |
Set<Integer> fofoIds = new HashSet<>(customerToFofoIdMap.values());
|
|
|
2140 |
Map<Integer, CustomRetailer> retailerMap = Collections.emptyMap();
|
|
|
2141 |
if (!fofoIds.isEmpty()) {
|
|
|
2142 |
try {
|
|
|
2143 |
retailerMap = retailerService.getFofoRetailers(new ArrayList<>(fofoIds));
|
|
|
2144 |
} catch (ProfitMandiBusinessException e) {
|
|
|
2145 |
LOGGER.error("Error fetching fofo stores", e);
|
|
|
2146 |
}
|
|
|
2147 |
}
|
|
|
2148 |
|
|
|
2149 |
// Get remarks for these fofoIds on this date
|
|
|
2150 |
Map<Integer, List<PartnerCollectionRemark>> fofoRemarkMap = new HashMap<>();
|
|
|
2151 |
if (!fofoIds.isEmpty()) {
|
|
|
2152 |
List<PartnerCollectionRemark> dateRemarks = partnerCollectionRemarkRepository
|
|
|
2153 |
.selectAllByFofoIdsOnDate(new ArrayList<>(fofoIds), date);
|
|
|
2154 |
for (PartnerCollectionRemark remark : dateRemarks) {
|
|
|
2155 |
fofoRemarkMap.computeIfAbsent(remark.getFofoId(), k -> new ArrayList<>()).add(remark);
|
|
|
2156 |
}
|
|
|
2157 |
}
|
|
|
2158 |
|
|
|
2159 |
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy hh:mm a");
|
|
|
2160 |
|
|
|
2161 |
// Build rows
|
|
|
2162 |
for (AgentCallLog callLog : allCallLogs) {
|
|
|
2163 |
String customerNumber = callLog.getCustomerNumber();
|
|
|
2164 |
if (customerNumber == null) {
|
|
|
2165 |
continue;
|
|
|
2166 |
}
|
|
|
2167 |
|
|
|
2168 |
// Get RBM Name
|
|
|
2169 |
AuthUser authUser = authUserMap.get((int) callLog.getAuthId());
|
|
|
2170 |
String rbmName = authUser != null ? authUser.getFullName() : "Unknown";
|
|
|
2171 |
|
|
|
2172 |
String normalized = customerNumber.startsWith("+91") ? customerNumber.substring(3) : customerNumber;
|
|
|
2173 |
Integer fofoId = customerToFofoIdMap.get(normalized);
|
|
|
2174 |
|
|
|
2175 |
String partyName = "Unknown";
|
|
|
2176 |
String code = "-";
|
|
|
2177 |
|
|
|
2178 |
if (fofoId != null) {
|
|
|
2179 |
CustomRetailer retailer = retailerMap.get(fofoId);
|
|
|
2180 |
if (retailer != null) {
|
|
|
2181 |
partyName = retailer.getBusinessName();
|
|
|
2182 |
code = retailer.getCode();
|
|
|
2183 |
} else {
|
|
|
2184 |
partyName = "Unknown (" + fofoId + ")";
|
|
|
2185 |
}
|
|
|
2186 |
} else {
|
|
|
2187 |
partyName = "Unknown (" + normalized + ")";
|
|
|
2188 |
}
|
|
|
2189 |
|
|
|
2190 |
// Get remark if available
|
|
|
2191 |
String remarkValue = "-";
|
|
|
2192 |
if (fofoId != null && fofoRemarkMap.containsKey(fofoId)) {
|
|
|
2193 |
List<PartnerCollectionRemark> remarks = fofoRemarkMap.get(fofoId);
|
|
|
2194 |
if (!remarks.isEmpty()) {
|
|
|
2195 |
PartnerCollectionRemark remark = remarks.get(0);
|
|
|
2196 |
remarkValue = remark.getRemark() != null ? remark.getRemark().getValue() : "-";
|
|
|
2197 |
if (remark.getMessage() != null && !remark.getMessage().isEmpty()) {
|
|
|
2198 |
remarkValue = remarkValue + " - " + remark.getMessage();
|
|
|
2199 |
}
|
|
|
2200 |
}
|
|
|
2201 |
}
|
|
|
2202 |
|
|
|
2203 |
// Call status from customerStatus field
|
|
|
2204 |
String callStatus = callLog.getCustomerStatus() != null ? callLog.getCustomerStatus() : "-";
|
|
|
2205 |
String callDuration = callLog.getCallDuration() != null ? callLog.getCallDuration() : "-";
|
|
|
2206 |
|
|
|
2207 |
String callDateTime = "-";
|
|
|
2208 |
if (callLog.getCallDate() != null && callLog.getCallTime() != null) {
|
|
|
2209 |
LocalDateTime callDateTimeObj = LocalDateTime.of(callLog.getCallDate(), callLog.getCallTime());
|
|
|
2210 |
callDateTime = callDateTimeObj.format(dateTimeFormatter);
|
|
|
2211 |
}
|
|
|
2212 |
|
|
|
2213 |
String recordingUrl = callLog.getRecordingUrl() != null ? callLog.getRecordingUrl() : "-";
|
|
|
2214 |
|
|
|
2215 |
rows.add(Arrays.asList(rbmName, partyName, code, remarkValue, callStatus, callDuration, callDateTime, recordingUrl));
|
|
|
2216 |
}
|
|
|
2217 |
|
|
|
2218 |
return rows;
|
|
|
2219 |
}
|
|
|
2220 |
|
| 33917 |
ranu |
2221 |
}
|