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