Subversion Repositories SmartDukaan

Rev

Rev 35759 | Rev 35761 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
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;
10
import com.spice.profitmandi.dao.entity.cs.Position;
11
import com.spice.profitmandi.dao.entity.cs.Ticket;
12
import com.spice.profitmandi.dao.entity.fofo.FofoStore;
34397 ranu 13
import com.spice.profitmandi.dao.entity.fofo.MonthlyTarget;
35759 ranu 14
import com.spice.profitmandi.dao.entity.fofo.RetailerContact;
33985 ranu 15
import com.spice.profitmandi.dao.entity.inventory.RbmAchievements;
33926 ranu 16
import com.spice.profitmandi.dao.entity.inventory.RbmTargets;
35759 ranu 17
import com.spice.profitmandi.dao.entity.user.Address;
35631 ranu 18
import com.spice.profitmandi.dao.enumuration.auth.CollectionRemark;
19
import com.spice.profitmandi.dao.enumuration.cs.EscalationType;
33917 ranu 20
import com.spice.profitmandi.dao.model.*;
35631 ranu 21
import com.spice.profitmandi.dao.repository.auth.AuthRepository;
22
import com.spice.profitmandi.dao.repository.auth.PartnerCollectionRemarkRepository;
23
import com.spice.profitmandi.dao.repository.auth.RbmCallSequenceLogRepository;
33985 ranu 24
import com.spice.profitmandi.dao.repository.catalog.RbmAchievementsRepository;
33926 ranu 25
import com.spice.profitmandi.dao.repository.catalog.RbmTargetsRepository;
35631 ranu 26
import com.spice.profitmandi.dao.repository.cs.CsService;
27
import com.spice.profitmandi.dao.repository.cs.PositionRepository;
28
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
35759 ranu 29
import com.spice.profitmandi.dao.repository.dtr.RetailerContactRepository;
34397 ranu 30
import com.spice.profitmandi.dao.repository.fofo.MonthlyTargetRepository;
34880 ranu 31
import com.spice.profitmandi.dao.repository.logistics.PublicHolidaysRepository;
35631 ranu 32
import com.spice.profitmandi.dao.repository.transaction.LoanRepository;
34397 ranu 33
import com.spice.profitmandi.dao.repository.transaction.OrderRepository;
35759 ranu 34
import com.spice.profitmandi.dao.repository.user.AddressRepository;
35631 ranu 35
import com.spice.profitmandi.service.user.RetailerService;
33917 ranu 36
import org.apache.logging.log4j.LogManager;
37
import org.apache.logging.log4j.Logger;
38
import org.hibernate.Session;
39
import org.hibernate.SessionFactory;
40
import org.hibernate.query.NativeQuery;
41
import org.springframework.beans.factory.annotation.Autowired;
42
import org.springframework.stereotype.Component;
43
 
44
import javax.persistence.TypedQuery;
34880 ranu 45
import java.time.*;
35631 ranu 46
import java.time.format.DateTimeFormatter;
34880 ranu 47
import java.time.temporal.ChronoUnit;
35631 ranu 48
import java.util.*;
33997 ranu 49
import java.util.stream.Collectors;
33917 ranu 50
 
51
@Component
52
public class RbmTargetServiceImpl implements RbmTargetService {
53
    private static final Logger LOGGER = LogManager.getLogger(RbmTargetServiceImpl.class);
54
 
55
    @Autowired
56
    SessionFactory sessionFactory;
57
 
33926 ranu 58
    @Autowired
59
    RbmTargetsRepository rbmTargetsRepository;
33917 ranu 60
 
33985 ranu 61
    @Autowired
62
    RbmAchievementsRepository rbmAchievementsRepository;
63
 
34397 ranu 64
    @Autowired
65
    MonthlyTargetRepository monthlyTargetRepository;
66
 
34880 ranu 67
    @Autowired
68
    PublicHolidaysRepository publicHolidaysRepository;
69
 
35631 ranu 70
    @Autowired
71
    RetailerService retailerService;
72
 
33917 ranu 73
    @Override
74
    public List<WarehouseRbmTargetModel> getWarehouseWiseRbmMonthlyTarget() {
75
        Session session = sessionFactory.getCurrentSession();
76
        final TypedQuery<WarehouseRbmTargetModel> typedQuerySimilar = session.createNamedQuery("RbmTarget.getWarehouseWiseMonthlyTarget", WarehouseRbmTargetModel.class);
77
 
78
        return typedQuerySimilar.getResultList();
79
 
80
    }
81
 
82
    @Override
83
    public List<MTDAchievedTargetModel> getDateWiseAchievedTargetOfRbm(LocalDate startDate, LocalDate endDate) {
84
        Session session = sessionFactory.getCurrentSession();
85
        final TypedQuery<MTDAchievedTargetModel> typedQuerySimilar = session.createNamedQuery("RbmTarget.getRbmAchievedMonthlyTarget", MTDAchievedTargetModel.class);
86
        typedQuerySimilar.setParameter("startDate", startDate);
87
        typedQuerySimilar.setParameter("endDate", endDate);
88
        return typedQuerySimilar.getResultList();
89
 
90
    }
91
 
92
    @Override
34055 ranu 93
    public List<TodayAchievedMovementModel> getMovementWiseAchievementByDate(LocalDate startDate, LocalDate endDate) {
33917 ranu 94
        LOGGER.info("start date {}, end date {}", startDate, endDate);
95
        Session session = sessionFactory.getCurrentSession();
34055 ranu 96
        final TypedQuery<TodayAchievedMovementModel> typedQuerySimilar = session.createNamedQuery("RBMTarget.TodayAchivementByMovement", TodayAchievedMovementModel.class);
33917 ranu 97
        typedQuerySimilar.setParameter("startDate", startDate);
98
        typedQuerySimilar.setParameter("endDate", endDate);
99
        return typedQuerySimilar.getResultList();
100
 
101
    }
102
 
103
    @Override
104
    public List<WarehouseMobileStockByMovementModel> getWarehouseMobileStockByMovement() {
105
        Session session = sessionFactory.getCurrentSession();
106
        final TypedQuery<WarehouseMobileStockByMovementModel> typedQuerySimilar = session.createNamedQuery("WarehouseStock.MovementWiseMobileStock", WarehouseMobileStockByMovementModel.class);
107
 
108
        return typedQuerySimilar.getResultList();
109
 
110
    }
111
 
33991 ranu 112
    @Override
113
    public List<SoldCatalogsReportModel> getCatalogSoldReport(LocalDate startDate, LocalDate endDate) {
114
        Session session = sessionFactory.getCurrentSession();
115
        final TypedQuery<SoldCatalogsReportModel> typedQuerySimilar = session.createNamedQuery("CatalogsReport.SoldCatalogsReport", SoldCatalogsReportModel.class);
116
        typedQuerySimilar.setParameter("startDate", startDate);
117
        typedQuerySimilar.setParameter("endDate", endDate);
118
        return typedQuerySimilar.getResultList();
33917 ranu 119
 
33991 ranu 120
    }
121
 
122
 
33917 ranu 123
    public int getWorkingDaysCount(LocalDate startDate) {
124
        Session session = sessionFactory.getCurrentSession();
125
 
126
        // Convert the LocalDate to a format MySQL can interpret
127
        String startDateString = startDate.toString();
128
 
129
        final NativeQuery<?> nativeQuery = session.createNativeQuery(
130
                "SELECT (DATEDIFF(LAST_DAY(:startDate), :startDate) + 1) " +
131
                        " - (FLOOR((DATEDIFF(LAST_DAY(:startDate), :startDate) + (WEEKDAY(:startDate) + 1)) / 7)) " +
132
                        " - (SELECT COUNT(*) " +
133
                        " FROM logistics.publicholidays " +
134
                        " WHERE date BETWEEN :startDate AND LAST_DAY(:startDate) " +
135
                        " AND WEEKDAY(date) != 6) AS working_days"
136
        );
137
 
138
        // Set the start date parameter for each placeholder
139
        nativeQuery.setParameter("startDate", startDateString);
140
 
141
        Object result = nativeQuery.getSingleResult();
142
        return result != null ? ((Number) result).intValue() : 0;
143
    }
144
 
145
 
35044 ranu 146
 
33917 ranu 147
    @Override
148
    public List<RbmArrViewModel> getRbmTodayArr() throws Exception {
149
        LocalDate todayDate = LocalDate.now();
150
        return getRbmTodayArr(todayDate);
151
    }
152
 
153
    @Override
33997 ranu 154
    public List<RbmTargetAndAchievementsModel> getRbmTargetsAndAchievemnts(LocalDate startDate, LocalDate endDate) {
155
 
34002 ranu 156
        List<RbmTargetsModel> rbmTargetsList = rbmTargetsRepository.selectTargetsModelListByDates(startDate.atStartOfDay(), endDate.atTime(LocalTime.MAX));
33997 ranu 157
 
158
        LOGGER.info("rbmTargetsList {}", rbmTargetsList);
159
        // Group Targtes by RBM and Warehouse
34002 ranu 160
        Map<String, RbmTargetsModel> targetsMap = rbmTargetsList.stream()
33997 ranu 161
                .collect(Collectors.toMap(
162
                        a -> a.getRbmAuthId() + "-" + a.getWarehouseId(),
163
                        a -> a,
164
                        (a1, a2) -> mergeTargets(a1, a2) // Handle duplicates by merging
165
                ));
166
 
167
 
34002 ranu 168
        List<RbmAchievementsModel> rbmAchievements = rbmAchievementsRepository.selectAchievementsModelListByDates(startDate.atStartOfDay(), endDate.atTime(LocalTime.MAX));
33997 ranu 169
        LOGGER.info("rbmTargetsList {}", rbmAchievements);
170
        // Group achievements by RBM and Warehouse
34002 ranu 171
        Map<String, RbmAchievementsModel> achievementMap = rbmAchievements.stream()
33997 ranu 172
                .collect(Collectors.toMap(
173
                        a -> a.getRbmAuthId() + "-" + a.getWarehouseId(),
174
                        a -> a,
175
                        (a1, a2) -> mergeAchievements(a1, a2) // Handle duplicates by merging
176
                ));
177
 
178
        return targetsMap.keySet().stream()
179
                .map(key -> {
180
                    String[] parts = key.split("-");
181
                    int rbmAuthId = Integer.parseInt(parts[0]);
182
                    int warehouseId = Integer.parseInt(parts[1]);
183
 
34002 ranu 184
                    RbmTargetsModel target = targetsMap.get(key);
185
                    RbmAchievementsModel achievement = achievementMap.getOrDefault(key, new RbmAchievementsModel());
33997 ranu 186
 
187
                    RbmTargetAndAchievementsModel model = new RbmTargetAndAchievementsModel();
188
                    model.setAuthId(rbmAuthId);
189
                    model.setRbmName(target.getRbmName());
190
                    model.setWarehouseName(ProfitMandiConstants.WAREHOUSE_MAP.getOrDefault(warehouseId, "Unknown"));
191
 
192
                    // Set target values
34006 ranu 193
                    model.setHidTarget((long) target.getHidTarget());
34098 ranu 194
                    model.setRunningTarget((long) target.getRunningTarget());
34006 ranu 195
                    model.setFastMovingTarget((long) target.getFastMovingTarget());
196
                    model.setSlowMovingTarget((long) target.getSlowMovingTarget());
197
                    model.setOtherMovingTarget((long) target.getOtherTarget());
33997 ranu 198
 
199
                    // Set achievement values
34006 ranu 200
                    model.setAchievedHid((long) achievement.getAchievedHidTarget());
34098 ranu 201
                    model.setAchievedRunning((long) achievement.getAchievedRunningTarget());
34006 ranu 202
                    model.setAchievedFastMoving((long) achievement.getAchievedFastMovingTarget());
203
                    model.setAchievedSlowMoving((long) achievement.getAchievedSlowMovingTarget());
204
                    model.setAchievedOtherMoving((long) achievement.getAchievedOtherTarget());
33997 ranu 205
 
206
                    model.setTotalTarget(
34006 ranu 207
                            (long) target.getHidTarget() +
34098 ranu 208
                                    (long) target.getRunningTarget() +
34006 ranu 209
                                    (long) target.getFastMovingTarget() +
210
                                    (long) target.getSlowMovingTarget() +
211
                                    (long) target.getOtherTarget()
33997 ranu 212
                    );
213
                    model.setTotalAchievemnt(
34006 ranu 214
                            (long) achievement.getAchievedHidTarget() +
34098 ranu 215
                                    (long) achievement.getAchievedRunningTarget() +
34006 ranu 216
                                    (long) achievement.getAchievedFastMovingTarget() +
217
                                    (long) achievement.getAchievedSlowMovingTarget() +
218
                                    (long) achievement.getAchievedOtherTarget()
33997 ranu 219
                    );
220
 
221
                    return model;
222
                })
223
                .collect(Collectors.toList());
224
 
225
    }
226
 
34002 ranu 227
    private RbmTargetsModel mergeTargets(RbmTargetsModel a1, RbmTargetsModel a2) {
33997 ranu 228
 
229
        // Merge logic for achievements (aggregate the target and achieved values)
34006 ranu 230
        a1.setHidTarget((a1.getHidTarget()) +
231
                (a2.getHidTarget()));
33997 ranu 232
 
34006 ranu 233
        a1.setFastMovingTarget((a1.getFastMovingTarget()) +
234
                (a2.getFastMovingTarget()));
33997 ranu 235
 
34006 ranu 236
        a1.setSlowMovingTarget((a1.getSlowMovingTarget()) +
237
                (a2.getSlowMovingTarget()));
33997 ranu 238
 
34098 ranu 239
        a1.setRunningTarget((a1.getRunningTarget()) +
240
                (a2.getRunningTarget()));
33997 ranu 241
 
34006 ranu 242
        a1.setOtherTarget((a1.getOtherTarget()) +
243
                (a2.getOtherTarget()));
33997 ranu 244
        return a1;
245
    }
246
 
34002 ranu 247
    private RbmAchievementsModel mergeAchievements(RbmAchievementsModel a1, RbmAchievementsModel a2) {
33997 ranu 248
        // Merge logic for achievements (aggregate the target and achieved values)
34006 ranu 249
        a1.setAchievedHidTarget((a1.getAchievedHidTarget()) +
250
                (a2.getAchievedHidTarget()));
33997 ranu 251
 
34098 ranu 252
        a1.setAchievedRunningTarget((a1.getAchievedRunningTarget()) +
253
                (a2.getAchievedRunningTarget()));
33997 ranu 254
 
34006 ranu 255
        a1.setAchievedFastMovingTarget((a1.getAchievedFastMovingTarget()) +
256
                (a2.getAchievedFastMovingTarget()));
33997 ranu 257
 
34006 ranu 258
        a1.setAchievedSlowMovingTarget((a1.getAchievedSlowMovingTarget()) +
259
                (a2.getAchievedSlowMovingTarget()));
33997 ranu 260
 
34006 ranu 261
        a1.setAchievedOtherTarget((a1.getAchievedOtherTarget()) +
262
                (a2.getAchievedOtherTarget()));
33997 ranu 263
 
264
        return a1;
265
    }
34002 ranu 266
 
33997 ranu 267
    @Override
33917 ranu 268
    public List<RbmArrViewModel> getRbmTodayArr(LocalDate todayDate) throws Exception {
269
 
270
        LocalDate startDateOfMonthDay1 = LocalDate.now().withDayOfMonth(1);
271
 
34289 ranu 272
        List<WarehouseRbmTargetModel> warehouseRbmTargetModelList = this.getWarehouseWiseRbmMonthlyTarget();
273
        List<WarehouseRbmTargetModel> warehouseRbmTargetModels = warehouseRbmTargetModelList.stream().filter(x -> x.getMonthlyTarget() > 0).collect(Collectors.toList());
274
        LOGGER.info("warehouseRbmTargetModels {}", warehouseRbmTargetModels);
275
        List<TodayAchievedMovementModel> todayAchievedMovementModels = getMovementWiseAchievementByDate(todayDate, todayDate.plusDays(1));
33917 ranu 276
 
277
        List<MTDAchievedTargetModel> mtdAchievedTargetModels = getDateWiseAchievedTargetOfRbm(startDateOfMonthDay1, todayDate);
278
 
35044 ranu 279
        int remainingWorkingDaysCount = (int) getRemainingDaysInMonth(todayDate);
33917 ranu 280
 
33926 ranu 281
        List<RbmTargets> todayRbmTargetsList = rbmTargetsRepository.selectTargetsByDates(todayDate.atStartOfDay(), todayDate.atTime(LocalTime.MAX));
33917 ranu 282
 
33926 ranu 283
        LOGGER.info("todayRbmTargetsList {}", todayRbmTargetsList);
33917 ranu 284
 
285
        List<RbmArrViewModel> rbmArrViewModels = new ArrayList<>();
286
 
34028 ranu 287
        if (!todayRbmTargetsList.isEmpty()) {
33917 ranu 288
 
35454 amit 289
            // OPTIMIZED: Pre-build maps for O(1) lookup instead of O(n) filter in each iteration
290
            // Map key: "authId-warehouseId"
291
            Map<String, Double> mtdAchievedMap = mtdAchievedTargetModels.stream()
292
                    .collect(Collectors.groupingBy(
293
                            x -> x.getAuthId() + "-" + x.getWarehouseId(),
294
                            Collectors.summingDouble(MTDAchievedTargetModel::getAcheivedMonthlyTarget)
295
                    ));
296
 
297
            Map<String, TodayAchievedMovementModel> todayAchievedMap = todayAchievedMovementModels.stream()
298
                    .collect(Collectors.toMap(
299
                            x -> x.getAuthId() + "-" + x.getWarehouseId(),
300
                            x -> x,
301
                            (a, b) -> a
302
                    ));
303
 
304
            Map<String, RbmTargets> todayRbmTargetsMap = todayRbmTargetsList.stream()
305
                    .collect(Collectors.toMap(
306
                            x -> x.getRbmAuthId() + "-" + x.getWarehouseId(),
307
                            x -> x,
308
                            (a, b) -> a
309
                    ));
310
 
34028 ranu 311
            for (WarehouseRbmTargetModel rbmTarget : warehouseRbmTargetModels) {
33917 ranu 312
 
35454 amit 313
                String lookupKey = rbmTarget.getAuthId() + "-" + rbmTarget.getWarehouseId();
314
 
34028 ranu 315
                float monthlyTarget = rbmTarget.getMonthlyTarget();
35454 amit 316
                float achievedSoFar = mtdAchievedMap.getOrDefault(lookupKey, 0.0).floatValue();
33917 ranu 317
 
34028 ranu 318
                float remainingTarget = monthlyTarget - achievedSoFar;
33953 ranu 319
 
34028 ranu 320
                float todayTarget = (remainingWorkingDaysCount > 0 && remainingTarget > 0) ? remainingTarget / remainingWorkingDaysCount : 0;
321
 
33926 ranu 322
                String warehouseName = ProfitMandiConstants.WAREHOUSE_MAP.getOrDefault(rbmTarget.getWarehouseId(), "Unknown");
33917 ranu 323
 
34288 ranu 324
                LOGGER.info("rbmTarget ==== {}", rbmTarget);
34281 ranu 325
 
35454 amit 326
                TodayAchievedMovementModel todayAchievedMovementModel = todayAchievedMap.get(lookupKey);
34283 ranu 327
 
35454 amit 328
                RbmTargets todayRbmTargets = todayRbmTargetsMap.get(lookupKey);
34285 ranu 329
 
35454 amit 330
                if (todayRbmTargets != null) {
34034 ranu 331
                    LOGGER.info("todayRbmTargets {}", todayRbmTargets);
332
                    RbmArrViewModel viewModel = new RbmArrViewModel();
33917 ranu 333
 
34034 ranu 334
                    viewModel.setAuthId(rbmTarget.getAuthId());
335
                    viewModel.setRbmName(rbmTarget.getRbmName());
336
                    viewModel.setWarehouseName(warehouseName);
337
                    viewModel.setTodayTarget(Math.round(todayTarget));
338
                    viewModel.setMonthlyTarget(Math.round(monthlyTarget));
339
                    viewModel.setMtdAchievedTarget(Math.round(achievedSoFar));
33926 ranu 340
 
34034 ranu 341
                    viewModel.setTodayHidTarget(Math.round((todayRbmTargets.getHidTarget())));
342
                    viewModel.setTodayFastMovingTarget(Math.round(todayRbmTargets.getFastMovingTarget()));
34098 ranu 343
                    viewModel.setTodaySlowMovingTarget(Math.round(todayRbmTargets.getSlowMovingtarget()));
344
                    viewModel.setTodayRunningTarget(Math.round(todayRbmTargets.getRunningtarget()));
34034 ranu 345
                    viewModel.setTodayOtherMovingTarget(Math.round(todayRbmTargets.getOtherTarget()));
33926 ranu 346
 
34283 ranu 347
                    if (todayAchievedMovementModel != null) {
348
                        viewModel.setTodayAchievedHidTarget(Math.round(todayAchievedMovementModel.getHidBilled()));
349
                        viewModel.setTodayAchievedFastMovingTarget(Math.round(todayAchievedMovementModel.getFastMovingBilled()));
350
                        viewModel.setTodayAchievedSlowMovingTarget(Math.round(todayAchievedMovementModel.getSlowMovinBilled()));
351
                        viewModel.setTodayAchievedRunningTarget(Math.round(todayAchievedMovementModel.getRunningBilled()));
352
                        viewModel.setTodayAchievedOtherMovingTarget(Math.round(todayAchievedMovementModel.getOtherBilled()));
353
                        viewModel.setTotalAchievedTarget(Math.round(todayAchievedMovementModel.getHidBilled() + todayAchievedMovementModel.getFastMovingBilled() + todayAchievedMovementModel.getSlowMovinBilled() + todayAchievedMovementModel.getRunningBilled() + todayAchievedMovementModel.getOtherBilled()));
354
                    } else {
355
                        viewModel.setTodayAchievedHidTarget(0);
356
                        viewModel.setTodayAchievedFastMovingTarget(0);
357
                        viewModel.setTodayAchievedSlowMovingTarget(0);
358
                        viewModel.setTodayAchievedRunningTarget(0);
359
                        viewModel.setTodayAchievedOtherMovingTarget(0);
360
                        viewModel.setTotalAchievedTarget(0);
361
                    }
34034 ranu 362
                    rbmArrViewModels.add(viewModel);
363
                } else {
364
                    LOGGER.info("No matching RbmTargets found for AuthId: {} and rbmname {} and WarehouseId: {}", rbmTarget.getAuthId(), rbmTarget.getRbmName(), rbmTarget.getWarehouseId());
365
                }
33917 ranu 366
 
34034 ranu 367
 
368
 
34028 ranu 369
            }
33917 ranu 370
        }
371
 
372
        LOGGER.info("rbmArrViewModels {}", rbmArrViewModels);
373
        return rbmArrViewModels;
374
    }
375
 
33926 ranu 376
    @Override
377
    public void setMovementWiseRbmTargets() {
378
        LocalDate todayDate = LocalDate.now();
33917 ranu 379
 
33926 ranu 380
        LocalDate startDateOfMonthDay1 = LocalDate.now().withDayOfMonth(1);
381
 
382
        List<WarehouseRbmTargetModel> warehouseRbmTargetModels = this.getWarehouseWiseRbmMonthlyTarget();
383
 
384
        List<MTDAchievedTargetModel> mtdAchievedTargetModels = getDateWiseAchievedTargetOfRbm(startDateOfMonthDay1, todayDate);
385
 
386
 
35044 ranu 387
        int remainingWorkingDaysCount = (int) getRemainingDaysInMonth(todayDate);
33926 ranu 388
 
389
        List<WarehouseMobileStockByMovementModel> warehouseMobileStockByMovementModels = getWarehouseMobileStockByMovement();
390
 
35454 amit 391
        // OPTIMIZED: Pre-build maps for O(1) lookup instead of O(n) filter in each iteration
392
        Map<String, Double> mtdAchievedMap = mtdAchievedTargetModels.stream()
393
                .collect(Collectors.groupingBy(
394
                        x -> x.getAuthId() + "-" + x.getWarehouseId(),
395
                        Collectors.summingDouble(MTDAchievedTargetModel::getAcheivedMonthlyTarget)
396
                ));
397
 
398
        Map<Integer, WarehouseMobileStockByMovementModel> warehouseStockMap = warehouseMobileStockByMovementModels.stream()
399
                .collect(Collectors.toMap(
400
                        WarehouseMobileStockByMovementModel::getWarehouseId,
401
                        x -> x,
402
                        (a, b) -> a
403
                ));
404
 
33926 ranu 405
        for (WarehouseRbmTargetModel rbmTarget : warehouseRbmTargetModels) {
406
 
35454 amit 407
            String lookupKey = rbmTarget.getAuthId() + "-" + rbmTarget.getWarehouseId();
408
 
33926 ranu 409
            float monthlyTarget = rbmTarget.getMonthlyTarget();
35454 amit 410
            float achievedSoFar = mtdAchievedMap.getOrDefault(lookupKey, 0.0).floatValue();
33926 ranu 411
 
412
 
413
            float remainingTarget = monthlyTarget - achievedSoFar;
33953 ranu 414
            LOGGER.info("remainingTarget {}", remainingTarget);
33926 ranu 415
 
33953 ranu 416
            float todayTarget = (remainingWorkingDaysCount > 0 && remainingTarget > 0) ? remainingTarget / remainingWorkingDaysCount : 0;
417
            LOGGER.info("todayTarget {}", todayTarget);
418
 
33926 ranu 419
            // Get the warehouse stock data
35454 amit 420
            WarehouseMobileStockByMovementModel warehouseMobileStockByMovementModel = warehouseStockMap.get(rbmTarget.getWarehouseId());
33926 ranu 421
 
422
 
423
            if (warehouseMobileStockByMovementModel != null) {
424
 
425
                // Total stock value for this warehouse
426
                float totalStockValue = warehouseMobileStockByMovementModel.getTotalAvailabilityPrice();
427
 
428
                // Calculate target allocation based on stock value proportion
429
                float hidTarget = (warehouseMobileStockByMovementModel.getTotalHidCatalogPrice() / totalStockValue) * todayTarget;
430
                float fastMovingTarget = (warehouseMobileStockByMovementModel.getTotalFastMovingCatalogPrice() / totalStockValue) * todayTarget;
431
                float slowMovingTarget = (warehouseMobileStockByMovementModel.getTotalSlowMovingCatalogPrice() / totalStockValue) * todayTarget;
34098 ranu 432
                float runningTarget = (warehouseMobileStockByMovementModel.getTotalRunningCatalogPrice() / totalStockValue) * todayTarget;
33926 ranu 433
                float otherTarget = (warehouseMobileStockByMovementModel.getTotalOtherCategoryCatalogPrice() / totalStockValue) * todayTarget;
434
 
435
                RbmTargets rbmTargets = new RbmTargets();
436
                rbmTargets.setWarehouseId(rbmTarget.getWarehouseId());
437
                rbmTargets.setRbmAuthId(rbmTarget.getAuthId());
438
                rbmTargets.setRbmName(rbmTarget.getRbmName());
34098 ranu 439
                rbmTargets.setRunningtarget(runningTarget);
33926 ranu 440
                rbmTargets.setHidTarget(hidTarget);
441
                rbmTargets.setFastMovingTarget(fastMovingTarget);
34098 ranu 442
                rbmTargets.setSlowMovingtarget(slowMovingTarget);
33926 ranu 443
                rbmTargets.setOtherTarget(otherTarget);
444
                rbmTargets.setCreateTimestamp(LocalDateTime.now());
445
 
446
                rbmTargetsRepository.persist(rbmTargets);
447
 
448
            }
449
        }
450
 
451
    }
452
 
453
 
33985 ranu 454
    @Override
455
    public void setMovementWiseRbmAchievement() {
456
        LocalDate todayDate = LocalDate.now();
457
 
34055 ranu 458
        List<TodayAchievedMovementModel> todayAchievedMovementModels = getMovementWiseAchievementByDate(todayDate, todayDate.plusDays(1));
33985 ranu 459
 
460
 
461
        for (TodayAchievedMovementModel achievement : todayAchievedMovementModels) {
462
 
463
            RbmAchievements rbmAchievements = new RbmAchievements();
464
 
465
            rbmAchievements.setRbmAuthId(achievement.getAuthId());
466
            rbmAchievements.setRbmName(achievement.getRbmName());
467
            rbmAchievements.setWarehouseId(achievement.getWarehouseId());
468
            rbmAchievements.setAchievedHidTarget(achievement.getHidBilled());
469
            rbmAchievements.setAchievedFastMovingTarget(achievement.getFastMovingBilled());
34098 ranu 470
            rbmAchievements.setAchievedSlowMovingTarget(achievement.getSlowMovinBilled());
471
            rbmAchievements.setAchievedRunningTarget(achievement.getRunningBilled());
34012 ranu 472
            rbmAchievements.setAchievedOtherTarget(achievement.getOtherBilled());
33985 ranu 473
            rbmAchievements.setCreateTimestamp(LocalDateTime.now());
474
 
475
            rbmAchievementsRepository.persist(rbmAchievements);
476
 
477
        }
478
 
479
    }
480
 
34055 ranu 481
    @Override
482
    public List<Sold15daysOldAgingModel> getAgingSale(LocalDate startDate, LocalDate endDate) {
483
        Session session = sessionFactory.getCurrentSession();
484
        final TypedQuery<Sold15daysOldAgingModel> typedQuerySimilar = session.createNamedQuery("Aging.SoldAgingModel", Sold15daysOldAgingModel.class);
34056 ranu 485
        typedQuerySimilar.setParameter("startDate", startDate);
486
        typedQuerySimilar.setParameter("endDate", endDate);
34055 ranu 487
        return typedQuerySimilar.getResultList();
33985 ranu 488
 
34055 ranu 489
    }
490
 
34103 ranu 491
    @Override
492
    public List<RbmBilledFofoIdsModel> getDateWiseBilledFofoIdByRbm(LocalDate startDate, LocalDate endDate) {
493
        Session session = sessionFactory.getCurrentSession();
494
        final TypedQuery<RbmBilledFofoIdsModel> typedQuerySimilar = session.createNamedQuery("RBM.RbmBilledFofoId", RbmBilledFofoIdsModel.class);
495
        typedQuerySimilar.setParameter("startDate", startDate);
496
        typedQuerySimilar.setParameter("endDate", endDate);
497
        return typedQuerySimilar.getResultList();
35453 amit 498
    }
34103 ranu 499
 
35453 amit 500
    @Override
501
    public List<RbmWeeklyBillingModel> getWeeklyBillingDataForMonth(LocalDate monthStart, LocalDate monthEnd) {
502
        Session session = sessionFactory.getCurrentSession();
503
        final TypedQuery<RbmWeeklyBillingModel> typedQuery = session.createNamedQuery("RBM.WeeklyBilling", RbmWeeklyBillingModel.class);
504
        typedQuery.setParameter("startDate", monthStart);
505
        typedQuery.setParameter("endDate", monthEnd);
506
        return typedQuery.getResultList();
34103 ranu 507
    }
508
 
34055 ranu 509
    public List<Our15DaysOldAgingStock> our15DaysAgingStock() {
510
        Session session = sessionFactory.getCurrentSession();
511
        final TypedQuery<Our15DaysOldAgingStock> typedQuerySimilar = session.createNamedQuery("Aging.15DaysOurStock", Our15DaysOldAgingStock.class);
512
        return typedQuerySimilar.getResultList();
513
 
514
    }
515
 
34397 ranu 516
    @Autowired
517
    OrderRepository orderRepository;
34055 ranu 518
 
34397 ranu 519
    @Override
34641 ranu 520
    public double calculateFofoIdTodayTarget(int fofoId, double secondryMtd,LocalDate date) {
34397 ranu 521
 
522
        MonthlyTarget monthlyTarget = monthlyTargetRepository.selectByDateAndFofoId(YearMonth.now(), fofoId);
34404 ranu 523
        if (monthlyTarget == null) {
524
            // Log or handle as needed
525
            return 0; // or -1 or some fallback
526
        }
34397 ranu 527
 
528
        double remainingTarget = monthlyTarget.getPurchaseTarget() - secondryMtd;
34880 ranu 529
//        double remainingWorkingDays = getWorkingDaysCount(date);
530
        double remainingWorkingDays = (double) getRemainingDaysInMonth(date);
34397 ranu 531
 
532
 
34716 ranu 533
 
34397 ranu 534
        if (remainingWorkingDays == 0) return remainingTarget; // Last day
34716 ranu 535
        LOGGER.info("remainingWorkingDays {}", remainingWorkingDays);
536
        LOGGER.info("remainingTarget {}", remainingTarget);
34397 ranu 537
 
538
        return (int) Math.ceil(remainingTarget / remainingWorkingDays);
539
    }
540
 
34880 ranu 541
    @Override
542
    public long getRemainingDaysInMonth(LocalDate date) {
543
        LocalDate lastDayOfMonth = YearMonth.from(date).atEndOfMonth();
34397 ranu 544
 
34880 ranu 545
        long totalDays = ChronoUnit.DAYS.between(date, lastDayOfMonth) + 1;
34397 ranu 546
 
34880 ranu 547
        // Count Sundays manually
548
        long sundayCount = 0;
549
        LocalDate current = date;
550
        while (!current.isAfter(lastDayOfMonth)) {
551
            if (current.getDayOfWeek() == DayOfWeek.SUNDAY) {
552
                sundayCount++;
553
            }
554
            current = current.plusDays(1);
555
        }
556
 
557
        // Public holidays in the range
558
        long publicHolidays = publicHolidaysRepository
559
                .selectAllBetweenDates(date, lastDayOfMonth)
560
                .size();
561
 
562
        long remainingDays = totalDays - sundayCount - publicHolidays;
563
 
564
        LOGGER.info("remainingDays {}", remainingDays);
565
        LOGGER.info("totalDays {}", totalDays);
566
        LOGGER.info("sundays {}", sundayCount);
567
        LOGGER.info("publicHolidays {}", publicHolidays);
568
 
569
        return remainingDays;
570
    }
571
 
35631 ranu 572
    @Autowired
573
    PositionRepository positionRepository;
34880 ranu 574
 
35631 ranu 575
    @Autowired
576
    CsService csService;
34880 ranu 577
 
35631 ranu 578
    @Autowired
579
    FofoStoreRepository fofoStoreRepository;
580
 
581
    @Autowired
582
    AuthRepository authRepository;
583
 
584
    @Autowired
585
    LoanRepository loanRepository;
586
 
587
    @Autowired
588
    PartnerCollectionService partnerCollectionService;
589
 
590
    @Autowired
591
    PartnerCollectionRemarkRepository partnerCollectionRemarkRepository;
592
 
593
    @Autowired
594
    RbmCallSequenceLogRepository rbmCallSequenceLogRepository;
595
 
596
    @Autowired
597
    com.spice.profitmandi.dao.repository.cs.TicketRepository ticketRepository;
598
 
35702 ranu 599
    @Autowired
600
    com.spice.profitmandi.dao.repository.cs.AgentCallLogRepository agentCallLogRepository;
601
 
35759 ranu 602
    @Autowired
603
    RetailerContactRepository retailerContactRepository;
604
 
605
    @Autowired
606
    AddressRepository addressRepository;
607
 
35631 ranu 608
    @Override
609
    public List<RbmCallTargetModel> getRbmCallTargetModels() throws Exception {
610
        long methodStart = System.currentTimeMillis();
611
        List<RbmCallTargetModel> rbmCallTargetModels = new ArrayList<>();
612
 
613
        // Get all RBM positions (L1 and L2)
614
        long start = System.currentTimeMillis();
615
        List<Position> allRbmPositions = positionRepository
616
                .selectPositionByCategoryId(ProfitMandiConstants.TICKET_CATEGORY_RBM).stream()
617
                .filter(x -> Arrays.asList(EscalationType.L1, EscalationType.L2).contains(x.getEscalationType()))
618
                .collect(Collectors.toList());
619
 
620
        // Separate L1 and L2 auth IDs
621
        List<Integer> l1AuthIds = allRbmPositions.stream()
622
                .filter(p -> EscalationType.L1.equals(p.getEscalationType()))
623
                .map(Position::getAuthUserId).distinct().collect(Collectors.toList());
624
        List<Integer> l2AuthIds = allRbmPositions.stream()
625
                .filter(p -> EscalationType.L2.equals(p.getEscalationType()))
626
                .map(Position::getAuthUserId).distinct().collect(Collectors.toList());
627
 
628
        // Union of all auth IDs for batch fetching
629
        List<Integer> rbmPositionsAuthIds = allRbmPositions.stream()
630
                .map(Position::getAuthUserId).distinct().collect(Collectors.toList());
631
        LOGGER.info("RBM Call Target - RBM positions fetch: {}ms, L1: {}, L2: {}", System.currentTimeMillis() - start, l1AuthIds.size(), l2AuthIds.size());
632
 
633
        start = System.currentTimeMillis();
634
        Map<String, Set<Integer>> storeGuyMap = csService.getAuthUserPartnerIdMapping();
635
        LOGGER.info("RBM Call Target - StoreGuyMap fetch: {}ms", System.currentTimeMillis() - start);
636
 
637
        LocalDateTime startDate = LocalDate.now().atStartOfDay();
638
        LocalDate firstOfMonth = LocalDate.now().withDayOfMonth(1);
639
        LocalDate endOfMonth = LocalDate.now().withDayOfMonth(LocalDate.now().lengthOfMonth()).plusDays(1);
640
 
641
        // Get auth user map
642
        start = System.currentTimeMillis();
643
        Map<Integer, AuthUser> authUserMap = authRepository.selectByIds(rbmPositionsAuthIds).stream()
644
                .collect(Collectors.toMap(AuthUser::getId, au -> au));
645
        LOGGER.info("RBM Call Target - AuthUser fetch: {}ms", System.currentTimeMillis() - start);
646
 
647
        // Batch fetch positions by auth IDs (to check if RBM is L1)
648
        start = System.currentTimeMillis();
649
        Map<Integer, List<Position>> positionsByAuthId = positionRepository.selectPositionByAuthIds(rbmPositionsAuthIds).stream()
650
                .collect(Collectors.groupingBy(Position::getAuthUserId));
651
        LOGGER.info("RBM Call Target - Positions by AuthId fetch: {}ms", System.currentTimeMillis() - start);
652
 
653
        // Get all fofo IDs for all RBMs
654
        Set<Integer> allFofoIds = new HashSet<>();
655
        Map<Integer, List<Integer>> rbmToFofoIdsMap = new HashMap<>();
656
        for (int rbmAuthId : rbmPositionsAuthIds) {
657
            AuthUser au = authUserMap.get(rbmAuthId);
658
            if (au != null && storeGuyMap.containsKey(au.getEmailId())) {
659
                List<Integer> fofoIds = new ArrayList<>(storeGuyMap.get(au.getEmailId()));
660
                allFofoIds.addAll(fofoIds);
661
                rbmToFofoIdsMap.put(rbmAuthId, fofoIds);
662
            }
663
        }
664
        // Fetch escalated tickets for L2 early so their fofoIds are included in batch fetches
665
        List<Ticket> escalatedTickets = Collections.emptyList();
666
        Map<Integer, List<Integer>> l2AuthIdToFofoIds = new HashMap<>();
667
        if (!l2AuthIds.isEmpty()) {
668
            start = System.currentTimeMillis();
669
            escalatedTickets = ticketRepository.selectOpenEscalatedTicketsByAuthIds(l2AuthIds);
670
            LOGGER.info("RBM Call Target - Escalated tickets fetch: {}ms, count: {}", System.currentTimeMillis() - start, escalatedTickets.size());
671
 
672
            for (int l2AuthId : l2AuthIds) {
673
                List<Integer> l2FofoIds = escalatedTickets.stream()
674
                        .filter(t -> t.getL2AuthUser() == l2AuthId
675
                                || t.getL3AuthUser() == l2AuthId
676
                                || t.getL4AuthUser() == l2AuthId
677
                                || t.getL5AuthUser() == l2AuthId)
678
                        .map(Ticket::getFofoId)
679
                        .distinct()
680
                        .collect(Collectors.toList());
681
                l2AuthIdToFofoIds.put(l2AuthId, l2FofoIds);
682
                allFofoIds.addAll(l2FofoIds);
683
            }
684
        }
685
        LOGGER.info("RBM Call Target - Total fofo IDs to process: {}", allFofoIds.size());
686
 
687
        // Get only needed fofo stores (OPTIMIZED - was fetching ALL stores before)
688
        start = System.currentTimeMillis();
689
        Map<Integer, FofoStore> fofoStoresMap = new HashMap<>();
690
        if (!allFofoIds.isEmpty()) {
691
            try {
692
                fofoStoresMap = fofoStoreRepository.selectByRetailerIds(new ArrayList<>(allFofoIds)).stream()
693
                        .collect(Collectors.toMap(FofoStore::getId, x -> x, (a, b) -> a));
694
            } catch (ProfitMandiBusinessException e) {
695
                LOGGER.error("Error fetching fofo stores", e);
696
            }
697
        }
698
        LOGGER.info("RBM Call Target - FofoStores fetch (only needed): {}ms, count: {}", System.currentTimeMillis() - start, fofoStoresMap.size());
699
 
700
        // Batch fetch max remark ids for all fofoIds (for escalation filtering)
701
        start = System.currentTimeMillis();
702
        Map<Integer, PartnerCollectionRemark> allPartnerCollectionRemarks = new HashMap<>();
703
        if (!allFofoIds.isEmpty()) {
704
            List<Integer> allRemarkIds = partnerCollectionRemarkRepository.selectMaxRemarkId(new ArrayList<>(allFofoIds));
705
            if (!allRemarkIds.isEmpty()) {
706
                allPartnerCollectionRemarks = partnerCollectionRemarkRepository.selectByIds(allRemarkIds).stream()
707
                        .collect(Collectors.toMap(PartnerCollectionRemark::getFofoId, x -> x, (a, b) -> a));
708
            }
709
        }
710
        LOGGER.info("RBM Call Target - PartnerCollectionRemarks fetch: {}ms", System.currentTimeMillis() - start);
711
 
712
        // Batch fetch collection RANK map for all fofoIds (OPTIMIZED - only fetches rank, not full model)
713
        start = System.currentTimeMillis();
714
        Map<Integer, Integer> allCollectionRankMap = new HashMap<>();
715
        if (!allFofoIds.isEmpty()) {
716
            try {
717
                allCollectionRankMap = partnerCollectionService.getCollectionRankMap(new ArrayList<>(allFofoIds), startDate);
718
            } catch (ProfitMandiBusinessException e) {
719
                LOGGER.error("Error fetching collection rank map for all fofoIds", e);
720
            }
721
        }
722
        LOGGER.info("RBM Call Target - CollectionRankMap fetch (OPTIMIZED): {}ms", System.currentTimeMillis() - start);
723
 
35669 ranu 724
        // Get MTD billing data for zero billing calculation and partner counts
35631 ranu 725
        start = System.currentTimeMillis();
726
        List<RbmWeeklyBillingModel> mtdBillingData = getWeeklyBillingDataForMonth(firstOfMonth, endOfMonth);
727
        Set<Integer> allMtdBilledFofoIds = mtdBillingData.stream()
728
                .filter(RbmWeeklyBillingModel::isMtdBilled)
729
                .map(RbmWeeklyBillingModel::getFofoId)
730
                .collect(Collectors.toSet());
35669 ranu 731
        // Build partner count and fofoIds per RBM from mtdBillingData (same source as Today ARR page)
732
        Map<Integer, Set<Integer>> mtdFofoIdsByAuthId = mtdBillingData.stream()
733
                .filter(RbmWeeklyBillingModel::isTargetedPartner)
734
                .collect(Collectors.groupingBy(RbmWeeklyBillingModel::getAuthId,
735
                        Collectors.mapping(RbmWeeklyBillingModel::getFofoId, Collectors.toSet())));
35631 ranu 736
        LOGGER.info("RBM Call Target - MTD Billing fetch: {}ms", System.currentTimeMillis() - start);
737
 
738
        // Batch fetch today's remarks for all auth IDs (to calculate Value Achieved)
739
        start = System.currentTimeMillis();
740
        Map<Integer, List<PartnerCollectionRemark>> remarksByAuthId = partnerCollectionRemarkRepository
741
                .selectAllByAuthIdsOnDate(rbmPositionsAuthIds, LocalDate.now()).stream()
742
                .collect(Collectors.groupingBy(PartnerCollectionRemark::getAuthId));
743
        LOGGER.info("RBM Call Target - Today Remarks fetch: {}ms", System.currentTimeMillis() - start);
744
 
745
        // Batch fetch today's out-of-sequence logs for all RBMs
746
        start = System.currentTimeMillis();
747
        LocalDateTime todayStart = LocalDate.now().atStartOfDay();
748
        LocalDateTime todayEnd = LocalDate.now().plusDays(1).atStartOfDay();
749
        List<RbmCallSequenceLog> outOfSequenceLogs = rbmCallSequenceLogRepository.selectOutOfSequenceByDateRange(todayStart, todayEnd);
750
        Map<Integer, Long> outOfSequenceCountByAuthId = outOfSequenceLogs.stream()
35654 ranu 751
                .collect(Collectors.groupingBy(RbmCallSequenceLog::getAuthId,
752
                        Collectors.mapping(RbmCallSequenceLog::getFofoId, Collectors.collectingAndThen(Collectors.toSet(), s -> (long) s.size()))));
35631 ranu 753
        LOGGER.info("RBM Call Target - Out of Sequence fetch: {}ms", System.currentTimeMillis() - start);
754
 
755
        // Process L1 RBMs (existing logic)
756
        for (int rbmAuthId : l1AuthIds) {
757
            AuthUser authUser = authUserMap.get(rbmAuthId);
758
            if (authUser == null || !storeGuyMap.containsKey(authUser.getEmailId())) {
759
                continue;
760
            }
761
 
762
            List<Integer> fofoIdList = rbmToFofoIdsMap.getOrDefault(rbmAuthId, Collections.emptyList());
763
 
764
            // Check if RBM is L1 (same logic as getSummaryModel)
765
            List<Position> positions = positionsByAuthId.getOrDefault(authUser.getId(), Collections.emptyList());
766
            boolean isRBMAndL1 = positions.stream()
767
                    .anyMatch(position ->
768
                            ProfitMandiConstants.TICKET_CATEGORY_RBM == position.getCategoryId()
769
                                    && EscalationType.L1.equals(position.getEscalationType()));
770
 
771
            // Filter escalated partners for L1 RBMs (same logic as getSummaryModel)
772
            List<Integer> fofoIds = fofoIdList;
773
            if (isRBMAndL1) {
774
                Map<Integer, PartnerCollectionRemark> partnerCollectionRemarks = new HashMap<>();
775
                for (Integer fofoId : fofoIdList) {
776
                    if (allPartnerCollectionRemarks.containsKey(fofoId)) {
777
                        partnerCollectionRemarks.put(fofoId, allPartnerCollectionRemarks.get(fofoId));
778
                    }
779
                }
780
                fofoIds = partnerCollectionRemarks.entrySet().stream()
781
                        .filter(entry -> {
782
                            PartnerCollectionRemark pcrMap = entry.getValue();
783
                            return !(CollectionRemark.RBM_L2_ESCALATION.equals(pcrMap.getRemark())
784
                                    || CollectionRemark.SALES_ESCALATION.equals(pcrMap.getRemark()));
785
                        })
786
                        .map(Map.Entry::getKey)
787
                        .collect(Collectors.toList());
788
            }
789
 
35669 ranu 790
            // Filter to only external, ACTIVE stores (collection plan not required)
35631 ranu 791
            Map<Integer, Integer> finalAllCollectionRankMap = allCollectionRankMap;
792
            Map<Integer, FofoStore> finalFofoStoresMap = fofoStoresMap;
793
            List<Integer> validFofoIds = fofoIds.stream()
794
                    .filter(fofoId -> {
795
                        FofoStore store = finalFofoStoresMap.get(fofoId);
796
                        if (store == null || store.isInternal()) {
797
                            return false;
798
                        }
799
                        // Only include ACTIVE partners (not Low Sale, not Disputed, not Billing Pending)
35669 ranu 800
                        return ActivationType.ACTIVE.equals(store.getActivationType());
35631 ranu 801
                    })
802
                    .collect(Collectors.toList());
803
 
804
            if (validFofoIds.isEmpty()) {
805
                continue;
806
            }
807
 
808
            RbmCallTargetModel targetModel = new RbmCallTargetModel();
809
            targetModel.setAuthId(rbmAuthId);
810
            targetModel.setRbmName(authUser.getFullName());
35669 ranu 811
            // Use partner count from mtdBillingData (same source as Today ARR page)
812
            Set<Integer> mtdFofoIds = mtdFofoIdsByAuthId.getOrDefault(rbmAuthId, Collections.emptySet());
813
            targetModel.setPartnerCount(mtdFofoIds.size());
35631 ranu 814
 
815
            // Categorize each partner - each partner belongs to ONE category only
35665 ranu 816
            // Priority: PlanToday > CarryForward > ZeroBilling > Untouched > FuturePlan > Normal
35631 ranu 817
            Set<Integer> planTodayPartners = new HashSet<>();
818
            Set<Integer> carryForwardPartners = new HashSet<>();
819
            Set<Integer> untouchedPartners = new HashSet<>();
820
            Set<Integer> zeroBillingPartners = new HashSet<>();
821
            Set<Integer> futurePlanPartners = new HashSet<>();
822
            Set<Integer> normalPartners = new HashSet<>();
823
 
824
            for (Integer fofoId : validFofoIds) {
825
                // Get collection plan rank (from optimized rank map)
826
                int rank = allCollectionRankMap.getOrDefault(fofoId, 5); // default to Normal if no plan
827
 
828
                // Check if partner has zero billing in MTD
829
                boolean hasZeroBilling = !allMtdBilledFofoIds.contains(fofoId);
830
 
831
                // Assign to category based on priority
832
                if (rank == 1) {
833
                    planTodayPartners.add(fofoId);
834
                } else if (rank == 2) {
835
                    carryForwardPartners.add(fofoId);
35665 ranu 836
                } else if (hasZeroBilling) {
837
                    zeroBillingPartners.add(fofoId);
35631 ranu 838
                } else if (rank == 3) {
839
                    untouchedPartners.add(fofoId);
840
                } else if (rank == 4) {
841
                    futurePlanPartners.add(fofoId);
842
                } else {
843
                    normalPartners.add(fofoId);
844
                }
845
            }
846
 
847
            // Set counts
848
            targetModel.setCreditCollection(0); // Credit collection is handled in separate list
849
            targetModel.setPlanToday(planTodayPartners.size());
850
            targetModel.setCarryForward(carryForwardPartners.size());
851
            targetModel.setUntouched(untouchedPartners.size());
852
            targetModel.setZeroBilling(zeroBillingPartners.size());
853
            targetModel.setFuturePlan(futurePlanPartners.size());
854
            targetModel.setNormal(normalPartners.size());
855
 
856
            // Today Target = PlanToday + CarryForward + ZeroBilling + Untouched
857
            // These are mutually exclusive now, so we can sum them
858
            long todayTarget = planTodayPartners.size() +
859
                    carryForwardPartners.size() + zeroBillingPartners.size() + untouchedPartners.size();
860
            targetModel.setTodayTargetOfCall(todayTarget);
861
 
862
            // Create set of partners in Today Target categories
863
            Set<Integer> todayTargetPartners = new HashSet<>();
864
            todayTargetPartners.addAll(planTodayPartners);
865
            todayTargetPartners.addAll(carryForwardPartners);
866
            todayTargetPartners.addAll(zeroBillingPartners);
867
            todayTargetPartners.addAll(untouchedPartners);
868
 
869
            // Value Achieved = Partners from Today Target that have been contacted today (have remark today)
870
            List<PartnerCollectionRemark> todayRemarks = remarksByAuthId.getOrDefault(rbmAuthId, Collections.emptyList());
871
            long valueAchieved = todayRemarks.stream()
872
                    .map(PartnerCollectionRemark::getFofoId)
873
                    .filter(todayTargetPartners::contains)
874
                    .distinct()
875
                    .count();
876
            targetModel.setValueTargetAchieved(valueAchieved);
877
 
878
            // Moved to Future = Partners in Future Plan category who have a remark today
879
            // These are partners who were contacted today but moved to a future date
880
            Set<Integer> todayRemarkedFofoIds = todayRemarks.stream()
881
                    .map(PartnerCollectionRemark::getFofoId)
882
                    .collect(Collectors.toSet());
883
            long movedToFuture = futurePlanPartners.stream()
884
                    .filter(todayRemarkedFofoIds::contains)
885
                    .count();
886
            targetModel.setMovedToFuture(movedToFuture);
887
 
888
            // Set out of sequence count for this RBM
889
            targetModel.setOutOfSequenceCount(outOfSequenceCountByAuthId.getOrDefault(rbmAuthId, 0L));
890
 
891
            rbmCallTargetModels.add(targetModel);
892
        }
893
 
894
        // Process L2 RBMs (escalated ticket logic with categorization)
895
        for (int l2AuthId : l2AuthIds) {
896
            AuthUser authUser = authUserMap.get(l2AuthId);
897
            if (authUser == null) {
898
                continue;
899
            }
900
 
901
            List<Integer> l2FofoIdList = l2AuthIdToFofoIds.getOrDefault(l2AuthId, Collections.emptyList());
902
 
35662 ranu 903
            // For L2, use all escalated ticket fofoIds as target (no collection plan filter)
904
            Set<Integer> l2TargetFofoIds = new HashSet<>(l2FofoIdList);
35631 ranu 905
 
906
            RbmCallTargetModel l2Model = new RbmCallTargetModel();
907
            l2Model.setAuthId(l2AuthId);
908
            l2Model.setRbmName(authUser.getFullName() + " (L2)");
909
            l2Model.setL2Position(true);
910
            l2Model.setL2CallingList(l2FofoIdList.size());
911
            // Partner count = total assigned partners (same as L1 source)
912
            List<Integer> l2AssignedFofoIds = rbmToFofoIdsMap.getOrDefault(l2AuthId, Collections.emptyList());
913
            l2Model.setPartnerCount(l2AssignedFofoIds.size());
914
 
35662 ranu 915
            // L2 Target = all escalated ticket fofoIds
916
            l2Model.setTodayTargetOfCall(l2TargetFofoIds.size());
35631 ranu 917
 
35662 ranu 918
            // Value Achieved = distinct fofoIds from today's remarks that are in escalated tickets
919
            List<PartnerCollectionRemark> l2TodayRemarks = remarksByAuthId.getOrDefault(l2AuthId, Collections.emptyList());
920
            long l2ValueAchieved = l2TodayRemarks.stream()
921
                    .map(PartnerCollectionRemark::getFofoId)
922
                    .filter(l2TargetFofoIds::contains)
923
                    .distinct()
924
                    .count();
925
            l2Model.setValueTargetAchieved(l2ValueAchieved);
35631 ranu 926
 
927
            l2Model.setOutOfSequenceCount(outOfSequenceCountByAuthId.getOrDefault(l2AuthId, 0L));
928
            rbmCallTargetModels.add(l2Model);
929
        }
930
 
931
        // Group L1 under their L2 manager using authUser.managerId
932
        Map<Integer, RbmCallTargetModel> l2ModelsByAuthId = new HashMap<>();
933
        Map<Integer, RbmCallTargetModel> l1ModelsByAuthId = new HashMap<>();
934
        for (RbmCallTargetModel m : rbmCallTargetModels) {
935
            if (m.isL2Position()) {
936
                l2ModelsByAuthId.put(m.getAuthId(), m);
937
            } else {
938
                l1ModelsByAuthId.put(m.getAuthId(), m);
939
            }
940
        }
941
 
942
        // Build L2 -> L1 team map using managerId from AuthUser
943
        Map<Integer, List<RbmCallTargetModel>> l2TeamMap = new LinkedHashMap<>();
944
        for (RbmCallTargetModel l2Model : l2ModelsByAuthId.values()) {
945
            l2TeamMap.put(l2Model.getAuthId(), new ArrayList<>());
946
        }
947
 
948
        Set<Integer> addedL1AuthIds = new HashSet<>();
949
        for (RbmCallTargetModel l1Model : l1ModelsByAuthId.values()) {
950
            AuthUser l1User = authUserMap.get(l1Model.getAuthId());
951
            if (l1User != null && l2TeamMap.containsKey(l1User.getManagerId())) {
952
                l2TeamMap.get(l1User.getManagerId()).add(l1Model);
953
                addedL1AuthIds.add(l1Model.getAuthId());
954
            }
955
        }
956
 
957
        // Build sorted result: L2 row, then its L1 team (sorted by name)
958
        List<RbmCallTargetModel> sortedModels = new ArrayList<>();
959
 
960
        List<RbmCallTargetModel> l2Sorted = new ArrayList<>(l2ModelsByAuthId.values());
961
        l2Sorted.sort(Comparator.comparing(RbmCallTargetModel::getRbmName));
962
 
963
        for (RbmCallTargetModel l2Model : l2Sorted) {
964
            sortedModels.add(l2Model);
965
            List<RbmCallTargetModel> team = l2TeamMap.getOrDefault(l2Model.getAuthId(), Collections.emptyList());
966
            team.sort(Comparator.comparing(RbmCallTargetModel::getRbmName));
967
            sortedModels.addAll(team);
968
        }
969
 
970
        // Add any L1 RBMs not mapped to any L2 (sorted by name)
971
        List<RbmCallTargetModel> unmappedL1 = new ArrayList<>();
972
        for (RbmCallTargetModel m : l1ModelsByAuthId.values()) {
973
            if (!addedL1AuthIds.contains(m.getAuthId())) {
974
                unmappedL1.add(m);
975
            }
976
        }
977
        unmappedL1.sort(Comparator.comparing(RbmCallTargetModel::getRbmName));
978
        sortedModels.addAll(unmappedL1);
979
 
980
        LOGGER.info("RBM Call Target - TOTAL TIME: {}ms, RBM count: {}", System.currentTimeMillis() - methodStart, sortedModels.size());
981
        return sortedModels;
982
    }
983
 
984
    @Override
985
    public List<OutOfSequenceDetailModel> getOutOfSequenceDetails(int authId) {
986
 
987
        LocalDate today = LocalDate.now();
988
        LocalDateTime start = today.atStartOfDay();
989
        LocalDateTime end = today.plusDays(1).atStartOfDay();
990
 
991
        List<RbmCallSequenceLog> logs =
992
                rbmCallSequenceLogRepository.selectByAuthIdAndDateRange(authId, start, end);
993
 
35654 ranu 994
        Map<Integer, RbmCallSequenceLog> uniqueOosLogsByFofoId = new LinkedHashMap<>();
35631 ranu 995
 
996
        for (RbmCallSequenceLog log : logs) {
997
            if (log.isOutOfSequence()) {
35654 ranu 998
                // Keep only the first occurrence per fofoId (latest entry since ordered by id DESC)
999
                uniqueOosLogsByFofoId.putIfAbsent(log.getFofoId(), log);
35631 ranu 1000
            }
1001
        }
1002
 
35654 ranu 1003
        if (uniqueOosLogsByFofoId.isEmpty()) {
35631 ranu 1004
            return Collections.emptyList();
1005
        }
1006
 
35654 ranu 1007
        Set<Integer> fofoIds = uniqueOosLogsByFofoId.keySet();
35631 ranu 1008
        Map<Integer, CustomRetailer> retailerMap = Collections.emptyMap();
1009
        try {
1010
            retailerMap = retailerService.getFofoRetailers(new ArrayList<>(fofoIds));
1011
        } catch (ProfitMandiBusinessException e) {
1012
            LOGGER.error("Error fetching fofo stores", e);
1013
        }
1014
 
1015
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("hh:mm a");
1016
        List<OutOfSequenceDetailModel> result = new ArrayList<>();
1017
 
35654 ranu 1018
        for (RbmCallSequenceLog log : uniqueOosLogsByFofoId.values()) {
35631 ranu 1019
            CustomRetailer retailer = retailerMap.get(log.getFofoId());
1020
            String partyName = retailer != null
1021
                    ? retailer.getBusinessName()
1022
                    : "Unknown (" + log.getFofoId() + ")";
1023
            String code = retailer != null
1024
                    ? retailer.getCode()
1025
                    : "-";
1026
 
1027
            String time = log.getCreateTimestamp() != null
1028
                    ? log.getCreateTimestamp().format(timeFormatter)
1029
                    : "-";
1030
 
1031
            result.add(new OutOfSequenceDetailModel(partyName, code, time));
1032
        }
1033
 
1034
        return result;
1035
    }
1036
 
35645 ranu 1037
    @Override
35672 ranu 1038
    public List<CalledPartnerDetailModel> getCalledPartnerDetails(int authId) throws ProfitMandiBusinessException {
35730 ranu 1039
        return getCalledPartnerDetails(authId, LocalDate.now());
1040
    }
1041
 
1042
    @Override
1043
    public List<CalledPartnerDetailModel> getCalledPartnerDetails(int authId, LocalDate date) throws ProfitMandiBusinessException {
35759 ranu 1044
        // Get all call logs for this auth user on this date
35760 ranu 1045
        LOGGER.info("getCalledPartnerDetails: authId={}, date={}", authId, date);
35759 ranu 1046
        List<com.spice.profitmandi.dao.entity.cs.AgentCallLog> callLogs = agentCallLogRepository.findByAuthIdAndDate(authId, date);
35760 ranu 1047
        LOGGER.info("Found {} call logs for authId={} on date={}", callLogs.size(), authId, date);
35670 ranu 1048
 
35759 ranu 1049
        if (callLogs.isEmpty()) {
35672 ranu 1050
            return Collections.emptyList();
1051
        }
35670 ranu 1052
 
35759 ranu 1053
        // Build a map of normalized customer number -> fofoId
1054
        Map<String, Integer> customerToFofoIdMap = new HashMap<>();
1055
        Set<String> normalizedNumbers = new HashSet<>();
35672 ranu 1056
 
35759 ranu 1057
        for (com.spice.profitmandi.dao.entity.cs.AgentCallLog callLog : callLogs) {
1058
            String customerNumber = callLog.getCustomerNumber();
1059
            if (customerNumber != null) {
1060
                String normalized = customerNumber.startsWith("+91") ? customerNumber.substring(3) : customerNumber;
1061
                normalizedNumbers.add(normalized);
1062
            }
35672 ranu 1063
        }
1064
 
35759 ranu 1065
        // For each normalized number, find fofoId from retailer_contact first, then address
1066
        for (String mobile : normalizedNumbers) {
1067
            Integer fofoId = findFofoIdByMobile(mobile);
1068
            if (fofoId != null) {
1069
                customerToFofoIdMap.put(mobile, fofoId);
1070
            }
35670 ranu 1071
        }
1072
 
35759 ranu 1073
        // Get unique fofoIds for retailer lookup
1074
        Set<Integer> fofoIds = new HashSet<>(customerToFofoIdMap.values());
1075
        Map<Integer, CustomRetailer> retailerMap = Collections.emptyMap();
1076
        if (!fofoIds.isEmpty()) {
1077
            try {
1078
                retailerMap = retailerService.getFofoRetailers(new ArrayList<>(fofoIds));
1079
            } catch (ProfitMandiBusinessException e) {
1080
                LOGGER.error("Error fetching fofo stores", e);
1081
            }
35672 ranu 1082
        }
1083
 
35759 ranu 1084
        // Get today's remarks for these fofoIds
1085
        Map<Integer, List<PartnerCollectionRemark>> fofoRemarkMap = new HashMap<>();
1086
        if (!fofoIds.isEmpty()) {
1087
            List<PartnerCollectionRemark> todayRemarks = partnerCollectionRemarkRepository
1088
                    .selectAllByFofoIdsOnDate(new ArrayList<>(fofoIds), date);
1089
            for (PartnerCollectionRemark remark : todayRemarks) {
1090
                fofoRemarkMap.computeIfAbsent(remark.getFofoId(), k -> new ArrayList<>()).add(remark);
1091
            }
35672 ranu 1092
        }
1093
 
35759 ranu 1094
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("hh:mm a");
1095
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy hh:mm a");
1096
        List<CalledPartnerDetailModel> result = new ArrayList<>();
35672 ranu 1097
 
35759 ranu 1098
        for (com.spice.profitmandi.dao.entity.cs.AgentCallLog callLog : callLogs) {
1099
            String customerNumber = callLog.getCustomerNumber();
1100
            if (customerNumber == null) {
1101
                continue;
1102
            }
35672 ranu 1103
 
35759 ranu 1104
            String normalized = customerNumber.startsWith("+91") ? customerNumber.substring(3) : customerNumber;
1105
            Integer fofoId = customerToFofoIdMap.get(normalized);
35672 ranu 1106
 
35759 ranu 1107
            String partyName = "Unknown";
1108
            String code = "-";
35672 ranu 1109
 
35759 ranu 1110
            if (fofoId != null) {
1111
                CustomRetailer retailer = retailerMap.get(fofoId);
1112
                if (retailer != null) {
1113
                    partyName = retailer.getBusinessName();
1114
                    code = retailer.getCode();
1115
                } else {
1116
                    partyName = "Unknown (" + fofoId + ")";
1117
                }
1118
            } else {
1119
                partyName = "Unknown (" + normalized + ")";
1120
            }
35672 ranu 1121
 
35759 ranu 1122
            // Get remark if available
1123
            String remarkValue = "-";
1124
            String messageValue = "-";
1125
            String remarkTime = "-";
35672 ranu 1126
 
35759 ranu 1127
            if (fofoId != null && fofoRemarkMap.containsKey(fofoId)) {
1128
                List<PartnerCollectionRemark> remarks = fofoRemarkMap.get(fofoId);
1129
                if (!remarks.isEmpty()) {
1130
                    PartnerCollectionRemark remark = remarks.get(0);
1131
                    remarkValue = remark.getRemark() != null ? remark.getRemark().getValue() : "-";
1132
                    messageValue = remark.getMessage() != null ? remark.getMessage() : "-";
1133
                    remarkTime = remark.getCreateTimestamp() != null ? remark.getCreateTimestamp().format(timeFormatter) : "-";
1134
                }
1135
            }
35672 ranu 1136
 
35759 ranu 1137
            // Build call log data
1138
            String recordingUrl = callLog.getRecordingUrl();
1139
            String callStatus = callLog.getCallStatus();
1140
            String callDuration = callLog.getCallDuration();
1141
            String callDateTime = null;
1142
            if (callLog.getCallDate() != null && callLog.getCallTime() != null) {
1143
                LocalDateTime callDateTimeObj = LocalDateTime.of(callLog.getCallDate(), callLog.getCallTime());
1144
                callDateTime = callDateTimeObj.format(dateTimeFormatter);
35672 ranu 1145
            }
35759 ranu 1146
 
1147
            result.add(new CalledPartnerDetailModel(partyName, code, remarkValue, messageValue, remarkTime,
1148
                    recordingUrl, callStatus, callDuration, callDateTime));
35672 ranu 1149
        }
1150
 
35759 ranu 1151
        return result;
1152
    }
35672 ranu 1153
 
35759 ranu 1154
    private Integer findFofoIdByMobile(String mobile) {
1155
        // First check retailer_contact
1156
        List<RetailerContact> contacts = retailerContactRepository.selectByMobile(mobile);
1157
        if (contacts != null && !contacts.isEmpty()) {
1158
            return contacts.get(0).getFofoId();
1159
        }
1160
 
1161
        // Fallback to user.address
1162
        Address address = addressRepository.selectByPhoneNumber(mobile);
1163
        if (address != null) {
1164
            return address.getRetaierId();
1165
        }
1166
 
1167
        return null;
35672 ranu 1168
    }
1169
 
35757 ranu 1170
    private List<CalledPartnerDetailModel> buildCalledPartnerResult(List<PartnerCollectionRemark> allRemarks) {
1171
        if (allRemarks.isEmpty()) {
35672 ranu 1172
            return Collections.emptyList();
1173
        }
1174
 
35757 ranu 1175
        // Get unique fofoIds for retailer lookup
1176
        Set<Integer> fofoIds = allRemarks.stream()
1177
                .map(PartnerCollectionRemark::getFofoId)
1178
                .collect(Collectors.toSet());
35670 ranu 1179
        Map<Integer, CustomRetailer> retailerMap = Collections.emptyMap();
1180
        try {
1181
            retailerMap = retailerService.getFofoRetailers(new ArrayList<>(fofoIds));
1182
        } catch (ProfitMandiBusinessException e) {
1183
            LOGGER.error("Error fetching fofo stores", e);
1184
        }
1185
 
35702 ranu 1186
        // Fetch call logs for remarks that have agentCallLogId
35721 ranu 1187
        Map<Long, com.spice.profitmandi.dao.entity.cs.AgentCallLog> callLogMap = new HashMap<>();
1188
        try {
35757 ranu 1189
            List<Long> callLogIds = allRemarks.stream()
35721 ranu 1190
                    .filter(r -> r.getAgentCallLogId() > 0)
1191
                    .map(PartnerCollectionRemark::getAgentCallLogId)
1192
                    .collect(Collectors.toList());
35702 ranu 1193
 
35721 ranu 1194
            if (!callLogIds.isEmpty()) {
35720 ranu 1195
                List<com.spice.profitmandi.dao.entity.cs.AgentCallLog> callLogs = agentCallLogRepository.findByIds(callLogIds);
35721 ranu 1196
                if (callLogs != null) {
1197
                    callLogMap = callLogs.stream()
1198
                            .collect(Collectors.toMap(com.spice.profitmandi.dao.entity.cs.AgentCallLog::getId, c -> c, (a, b) -> a));
1199
                }
35720 ranu 1200
            }
35721 ranu 1201
        } catch (Exception e) {
1202
            LOGGER.error("Error fetching call logs by ids", e);
35702 ranu 1203
        }
1204
 
35670 ranu 1205
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("hh:mm a");
35702 ranu 1206
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy hh:mm a");
35670 ranu 1207
        List<CalledPartnerDetailModel> result = new ArrayList<>();
1208
 
35757 ranu 1209
        for (PartnerCollectionRemark remark : allRemarks) {
35670 ranu 1210
            CustomRetailer retailer = retailerMap.get(remark.getFofoId());
1211
            String partyName = retailer != null
1212
                    ? retailer.getBusinessName()
1213
                    : "Unknown (" + remark.getFofoId() + ")";
1214
            String code = retailer != null
1215
                    ? retailer.getCode()
1216
                    : "-";
1217
 
1218
            String remarkValue = remark.getRemark() != null
1219
                    ? remark.getRemark().getValue()
1220
                    : "-";
1221
 
35677 ranu 1222
            String messageValue = remark.getMessage() != null
1223
                    ? remark.getMessage()
1224
                    : "-";
1225
 
35670 ranu 1226
            String time = remark.getCreateTimestamp() != null
1227
                    ? remark.getCreateTimestamp().format(timeFormatter)
1228
                    : "-";
1229
 
35702 ranu 1230
            // Get call log data if available
1231
            String recordingUrl = null;
1232
            String callStatus = null;
1233
            String callDuration = null;
1234
            String callDateTime = null;
1235
 
35721 ranu 1236
            try {
1237
                if (remark.getAgentCallLogId() > 0 && callLogMap.containsKey(remark.getAgentCallLogId())) {
1238
                    com.spice.profitmandi.dao.entity.cs.AgentCallLog callLog = callLogMap.get(remark.getAgentCallLogId());
1239
                    recordingUrl = callLog.getRecordingUrl();
1240
                    callStatus = callLog.getCallStatus();
1241
                    callDuration = callLog.getCallDuration();
1242
                    if (callLog.getCallDate() != null && callLog.getCallTime() != null) {
1243
                        LocalDateTime callDateTimeObj = LocalDateTime.of(callLog.getCallDate(), callLog.getCallTime());
1244
                        callDateTime = callDateTimeObj.format(dateTimeFormatter);
1245
                    }
35702 ranu 1246
                }
35721 ranu 1247
            } catch (Exception e) {
1248
                LOGGER.error("Error processing call log for remark id: {}", remark.getId(), e);
35702 ranu 1249
            }
1250
 
1251
            result.add(new CalledPartnerDetailModel(partyName, code, remarkValue, messageValue, time,
1252
                    recordingUrl, callStatus, callDuration, callDateTime));
35670 ranu 1253
        }
1254
 
1255
        return result;
1256
    }
1257
 
1258
    @Override
35645 ranu 1259
    public List<List<String>> getRbmCallTargetRawDataByAuthId(int authId) throws Exception {
1260
        List<List<String>> rows = new ArrayList<>();
35631 ranu 1261
 
35645 ranu 1262
        // Get auth user
1263
        List<AuthUser> authUsers = authRepository.selectByIds(Collections.singletonList(authId));
1264
        if (authUsers.isEmpty()) {
1265
            return rows;
1266
        }
1267
        AuthUser authUser = authUsers.get(0);
1268
 
35757 ranu 1269
        // Get positions to determine if L2
35645 ranu 1270
        List<Position> positions = positionRepository.selectPositionByAuthIds(Collections.singletonList(authId));
1271
        boolean isL2 = positions.stream()
1272
                .anyMatch(p -> ProfitMandiConstants.TICKET_CATEGORY_RBM == p.getCategoryId()
1273
                        && EscalationType.L2.equals(p.getEscalationType()));
1274
 
35757 ranu 1275
        LocalDateTime startDate = LocalDate.now().atStartOfDay();
1276
        LocalDate firstOfMonth = LocalDate.now().withDayOfMonth(1);
1277
        LocalDate endOfMonth = LocalDate.now().withDayOfMonth(LocalDate.now().lengthOfMonth()).plusDays(1);
35645 ranu 1278
 
35757 ranu 1279
        // Get fofo IDs from mtdBillingData (same source as Partner Count in getRbmCallTargetModels)
1280
        List<RbmWeeklyBillingModel> mtdBillingData = getWeeklyBillingDataForMonth(firstOfMonth, endOfMonth);
1281
 
1282
        List<Integer> fofoIdList;
35645 ranu 1283
        if (isL2) {
35757 ranu 1284
            // L2: get fofo IDs from escalated tickets (same as getRbmCallTargetModels)
35645 ranu 1285
            List<Ticket> escalatedTickets = ticketRepository.selectOpenEscalatedTicketsByAuthIds(Collections.singletonList(authId));
1286
            fofoIdList = escalatedTickets.stream()
1287
                    .filter(t -> t.getL2AuthUser() == authId
1288
                            || t.getL3AuthUser() == authId
1289
                            || t.getL4AuthUser() == authId
1290
                            || t.getL5AuthUser() == authId)
1291
                    .map(Ticket::getFofoId)
1292
                    .distinct()
1293
                    .collect(Collectors.toList());
35757 ranu 1294
        } else {
1295
            // L1: get fofo IDs from mtdBillingData with isTargetedPartner (same as Partner Count)
1296
            fofoIdList = mtdBillingData.stream()
1297
                    .filter(RbmWeeklyBillingModel::isTargetedPartner)
1298
                    .filter(m -> m.getAuthId() == authId)
1299
                    .map(RbmWeeklyBillingModel::getFofoId)
1300
                    .distinct()
1301
                    .collect(Collectors.toList());
35645 ranu 1302
        }
1303
 
1304
        if (fofoIdList.isEmpty()) {
1305
            return rows;
1306
        }
1307
 
35757 ranu 1308
        // MTD billed fofoIds for zero billing check
1309
        Set<Integer> mtdBilledFofoIds = mtdBillingData.stream()
1310
                .filter(RbmWeeklyBillingModel::isMtdBilled)
1311
                .map(RbmWeeklyBillingModel::getFofoId)
1312
                .collect(Collectors.toSet());
35645 ranu 1313
 
35757 ranu 1314
        // Collection rank map for status calculation
35645 ranu 1315
        Map<Integer, Integer> collectionRankMap = new HashMap<>();
1316
        try {
1317
            collectionRankMap = partnerCollectionService.getCollectionRankMap(fofoIdList, startDate);
1318
        } catch (ProfitMandiBusinessException e) {
1319
            LOGGER.error("Error fetching collection rank map", e);
1320
        }
1321
 
1322
        // Resolve partner names/codes
1323
        Map<Integer, CustomRetailer> retailerMap = Collections.emptyMap();
35757 ranu 1324
        if (!fofoIdList.isEmpty()) {
35645 ranu 1325
            try {
35757 ranu 1326
                retailerMap = retailerService.getFofoRetailers(fofoIdList);
35645 ranu 1327
            } catch (ProfitMandiBusinessException e) {
1328
                LOGGER.error("Error fetching fofo retailers for raw data", e);
1329
            }
1330
        }
1331
 
1332
        String rbmName = authUser.getFullName() + (isL2 ? " (L2)" : "");
1333
 
35757 ranu 1334
        // Build rows for ALL partners (same count as Partner Count)
1335
        for (Integer fofoId : fofoIdList) {
1336
            // Default to rank 5 (Normal) for partners without collection plan
35645 ranu 1337
            int rank = collectionRankMap.getOrDefault(fofoId, 5);
1338
            boolean hasZeroBilling = !mtdBilledFofoIds.contains(fofoId);
1339
 
35757 ranu 1340
            // Status assignment with same priority as getRbmCallTargetModels
35645 ranu 1341
            String status;
1342
            if (rank == 1) {
1343
                status = "Plan Today";
1344
            } else if (rank == 2) {
1345
                status = "Carry Forward";
35757 ranu 1346
            } else if (hasZeroBilling) {
1347
                status = "Zero Billing";
35645 ranu 1348
            } else if (rank == 3) {
1349
                status = "Untouched";
1350
            } else if (rank == 4) {
1351
                status = "Future Plan";
1352
            } else {
1353
                status = "Normal";
1354
            }
1355
 
1356
            CustomRetailer retailer = retailerMap.get(fofoId);
1357
            String partnerName = retailer != null ? retailer.getBusinessName() : "Unknown (" + fofoId + ")";
1358
            String partnerCode = retailer != null ? retailer.getCode() : "-";
1359
 
1360
            rows.add(Arrays.asList(partnerName, partnerCode, status, rbmName));
1361
        }
1362
 
1363
        return rows;
1364
    }
1365
 
33917 ranu 1366
}