Subversion Repositories SmartDukaan

Rev

Rev 36723 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 36723 Rev 36771
Line 188... Line 188...
188
 
188
 
189
    @Autowired
189
    @Autowired
190
    LeadDetailRepository leadDetailRepository;
190
    LeadDetailRepository leadDetailRepository;
191
 
191
 
192
    @Autowired
192
    @Autowired
-
 
193
    private com.spice.profitmandi.dao.repository.dtr.BeatRepository beatRepository;
-
 
194
 
-
 
195
    @Autowired
-
 
196
    private com.spice.profitmandi.dao.repository.dtr.BeatScheduleRepository beatScheduleRepository;
-
 
197
 
-
 
198
    @Autowired
-
 
199
    private com.spice.profitmandi.dao.repository.dtr.BeatRouteRepository beatRouteRepository;
-
 
200
 
-
 
201
    @Autowired
-
 
202
    private com.spice.profitmandi.dao.repository.dtr.LeadRouteRepository leadRouteRepository;
-
 
203
 
-
 
204
    @Autowired
-
 
205
    private com.spice.profitmandi.dao.repository.dtr.LeadLiveLocationRepository leadLiveLocationRepository;
-
 
206
 
-
 
207
    @Autowired
193
    PurchaseRepository purchaseRepository;
208
    PurchaseRepository purchaseRepository;
194
 
209
 
195
    @Autowired
210
    @Autowired
196
    private LoanRepository loanRepository;
211
    private LoanRepository loanRepository;
197
 
212
 
198
    @Autowired
213
    @Autowired
199
    private RecordingService recordingService;
214
    private RecordingService recordingService;
200
 
215
 
-
 
216
    // Field-staff creates a lead from the planner — they're physically at the lead's
-
 
217
    // location, so we mark the geo APPROVED immediately (no link-and-approve cycle).
-
 
218
    @RequestMapping(value = "/lead-geo/self-approve", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
-
 
219
    @ApiImplicitParams({
-
 
220
            @ApiImplicitParam(name = "Auth-Token", value = "Auth-Token", required = true, dataType = "string", paramType = "header")})
-
 
221
    public ResponseEntity<?> selfApproveLeadGeo(javax.servlet.http.HttpServletRequest request,
-
 
222
                                                @RequestBody Map<String, Object> req) throws Exception {
-
 
223
        Integer leadId = req.get("leadId") instanceof Number ? ((Number) req.get("leadId")).intValue() : null;
-
 
224
        if (leadId == null || leadId <= 0) return responseSender.badRequest("leadId required");
-
 
225
        Object latObj = req.get("latitude"), lngObj = req.get("longitude");
-
 
226
        if (!(latObj instanceof Number) || !(lngObj instanceof Number)) return responseSender.badRequest("latitude/longitude required");
-
 
227
        double latitude = ((Number) latObj).doubleValue();
-
 
228
        double longitude = ((Number) lngObj).doubleValue();
-
 
229
        Lead lead = leadRepository.selectById(leadId);
-
 
230
        if (lead == null) return responseSender.badRequest("Lead not found");
-
 
231
        // Resolve approver from session, fall back to request body.
-
 
232
        int approverAuthId = 0;
-
 
233
        com.spice.profitmandi.common.model.UserInfo userInfo =
-
 
234
                (com.spice.profitmandi.common.model.UserInfo) request.getAttribute("userInfo");
-
 
235
        if (userInfo != null && userInfo.getEmail() != null) {
-
 
236
            AuthUser sessionAuth = authRepository.selectByGmailId(userInfo.getEmail());
-
 
237
            if (sessionAuth != null) approverAuthId = sessionAuth.getId();
-
 
238
        }
-
 
239
        if (approverAuthId == 0 && req.get("authUserId") instanceof Number) {
-
 
240
            approverAuthId = ((Number) req.get("authUserId")).intValue();
-
 
241
        }
-
 
242
 
-
 
243
        int imageDocumentId = 0;
-
 
244
        if (req.get("imageDocumentId") instanceof Number) {
-
 
245
            imageDocumentId = ((Number) req.get("imageDocumentId")).intValue();
-
 
246
        }
-
 
247
 
-
 
248
        LocalDateTime now = LocalDateTime.now();
-
 
249
        com.spice.profitmandi.dao.entity.user.LeadLiveLocation existing = leadLiveLocationRepository.selectByLeadId(leadId);
-
 
250
        if (existing != null) {
-
 
251
            existing.setLatitude(latitude);
-
 
252
            existing.setLongitude(longitude);
-
 
253
            existing.setStatus(com.spice.profitmandi.dao.enumuration.dtr.GeoLocationStatus.APPROVED);
-
 
254
            existing.setReviewedBy(approverAuthId);
-
 
255
            existing.setReviewedTimestamp(now);
-
 
256
            existing.setSubmissionCount(existing.getSubmissionCount() + 1);
-
 
257
            existing.setMobileNumber(lead.getLeadMobile());
-
 
258
            if (imageDocumentId > 0) existing.setImageDocumentId(imageDocumentId);
-
 
259
            existing.setUpdatedTimestamp(now);
-
 
260
            existing.setRemark("Self-approved by field creator");
-
 
261
        } else {
-
 
262
            com.spice.profitmandi.dao.entity.user.LeadLiveLocation loc = new com.spice.profitmandi.dao.entity.user.LeadLiveLocation();
-
 
263
            loc.setLeadId(leadId);
-
 
264
            loc.setLatitude(latitude);
-
 
265
            loc.setLongitude(longitude);
-
 
266
            loc.setMobileNumber(lead.getLeadMobile());
-
 
267
            loc.setImageDocumentId(imageDocumentId);
-
 
268
            loc.setStatus(com.spice.profitmandi.dao.enumuration.dtr.GeoLocationStatus.APPROVED);
-
 
269
            loc.setReviewedBy(approverAuthId);
-
 
270
            loc.setReviewedTimestamp(now);
-
 
271
            loc.setSubmissionCount(1);
-
 
272
            loc.setRemark("Self-approved by field creator");
-
 
273
            loc.setCreatedTimestamp(now);
-
 
274
            loc.setUpdatedTimestamp(now);
-
 
275
            leadLiveLocationRepository.persist(loc);
-
 
276
        }
-
 
277
 
-
 
278
        LeadActivity activity = new LeadActivity();
-
 
279
        activity.setLeadId(leadId);
-
 
280
        activity.setRemark("Geolocation self-approved by field creator");
-
 
281
        activity.setAuthId(approverAuthId);
-
 
282
        activity.setCreatedTimestamp(now);
-
 
283
        leadActivityRepository.persist(activity);
-
 
284
 
-
 
285
        Map<String, Object> result = new HashMap<>();
-
 
286
        result.put("status", "approved");
-
 
287
        result.put("leadId", leadId);
-
 
288
        return responseSender.ok(result);
-
 
289
    }
-
 
290
 
-
 
291
    // Returns the field-staff person's upcoming beat-day chips (today + next N days) so
-
 
292
    // the partner app can present "Schedule on today vs future" right after a self-create.
-
 
293
    // The auth user is resolved from the session — matches the existing
-
 
294
    // BeatTrackingController.listBeats pattern (the client `userId` is unreliable).
-
 
295
    public ResponseEntity<?> upcomingBeatsForUser(javax.servlet.http.HttpServletRequest request, int days) throws Exception {
-
 
296
        com.spice.profitmandi.common.model.UserInfo userInfo =
-
 
297
                (com.spice.profitmandi.common.model.UserInfo) request.getAttribute("userInfo");
-
 
298
        if (userInfo == null || userInfo.getEmail() == null) {
-
 
299
            return responseSender.badRequest("Auth session not found");
-
 
300
        }
-
 
301
        AuthUser authUser = authRepository.selectByGmailId(userInfo.getEmail());
-
 
302
        if (authUser == null) return responseSender.badRequest("Auth user not found");
-
 
303
        int authUserId = authUser.getId();
-
 
304
        LOGGER.info("upcomingBeatsForUser resolved authUserId={} from session email={}", authUserId, userInfo.getEmail());
-
 
305
        LocalDate today = LocalDate.now();
-
 
306
        LocalDate end = today.plusDays(days);
-
 
307
        List<com.spice.profitmandi.dao.entity.user.Beat> beats = beatRepository.selectActiveByAuthUserId(authUserId);
-
 
308
        List<Map<String, Object>> out = new ArrayList<>();
-
 
309
        for (com.spice.profitmandi.dao.entity.user.Beat b : beats) {
-
 
310
            List<com.spice.profitmandi.dao.entity.user.BeatSchedule> schedules =
-
 
311
                    beatScheduleRepository.selectByBeatIdAndDateRange(b.getId(), today, end);
-
 
312
            for (com.spice.profitmandi.dao.entity.user.BeatSchedule s : schedules) {
-
 
313
                if (s.getStartDate() == null || s.getStartDate().getYear() == 9999) continue;
-
 
314
                Map<String, Object> row = new HashMap<>();
-
 
315
                row.put("beatId", b.getId());
-
 
316
                row.put("beatName", b.getName());
-
 
317
                row.put("beatColor", b.getBeatColor());
-
 
318
                row.put("scheduleDate", s.getStartDate().toString());
-
 
319
                row.put("dayNumber", s.getDayNumber());
-
 
320
                row.put("isToday", today.equals(s.getStartDate()));
-
 
321
                out.add(row);
-
 
322
            }
-
 
323
        }
-
 
324
        out.sort(Comparator.comparing(r -> (String) r.get("scheduleDate")));
-
 
325
        return responseSender.ok(out);
-
 
326
    }
-
 
327
 
-
 
328
    // Attaches a (just-created, self-approved) lead to a sales user's beat on a given
-
 
329
    // date. Inserts a LeadRoute row with status=APPROVED; idempotent on re-call.
-
 
330
    // The auth user is resolved from the session token, not the request body.
-
 
331
    public ResponseEntity<?> scheduleLeadOnBeat(javax.servlet.http.HttpServletRequest request,
-
 
332
                                                Map<String, Object> req) throws Exception {
-
 
333
        com.spice.profitmandi.common.model.UserInfo userInfo =
-
 
334
                (com.spice.profitmandi.common.model.UserInfo) request.getAttribute("userInfo");
-
 
335
        if (userInfo == null || userInfo.getEmail() == null) {
-
 
336
            return responseSender.badRequest("Auth session not found");
-
 
337
        }
-
 
338
        AuthUser sessionAuth = authRepository.selectByGmailId(userInfo.getEmail());
-
 
339
        if (sessionAuth == null) return responseSender.badRequest("Auth user not found");
-
 
340
        int authUserId = sessionAuth.getId();
-
 
341
 
-
 
342
        Integer leadId = req.get("leadId") instanceof Number ? ((Number) req.get("leadId")).intValue() : null;
-
 
343
        Integer beatId = req.get("beatId") instanceof Number ? ((Number) req.get("beatId")).intValue() : null;
-
 
344
        Object dateObj = req.get("scheduleDate");
-
 
345
        if (leadId == null || beatId == null || dateObj == null) {
-
 
346
            return responseSender.badRequest("leadId, beatId and scheduleDate are required");
-
 
347
        }
-
 
348
        LocalDate scheduleDate;
-
 
349
        try {
-
 
350
            scheduleDate = LocalDate.parse(dateObj.toString());
-
 
351
        } catch (Exception e) {
-
 
352
            return responseSender.badRequest("scheduleDate must be yyyy-MM-dd");
-
 
353
        }
-
 
354
 
-
 
355
        Lead lead = leadRepository.selectById(leadId);
-
 
356
        if (lead == null) return responseSender.badRequest("Lead not found");
-
 
357
 
-
 
358
        // Beat must actually run on the chosen date — same guard as the panel-side flow.
-
 
359
        List<com.spice.profitmandi.dao.entity.user.BeatSchedule> match =
-
 
360
                beatScheduleRepository.selectByBeatIdAndDateRange(beatId, scheduleDate, scheduleDate);
-
 
361
        if (match.isEmpty()) return responseSender.badRequest("Beat is not scheduled on " + scheduleDate);
-
 
362
 
-
 
363
        // Idempotency: skip if the same lead is already pinned to this beat-day.
-
 
364
        boolean exists = leadRouteRepository.selectByBeatId(beatId).stream()
-
 
365
                .anyMatch(lr -> lr.getLeadId() == leadId
-
 
366
                        && scheduleDate.equals(lr.getScheduleDate())
-
 
367
                        && !"CANCELLED".equals(lr.getStatus()));
-
 
368
        if (exists) {
-
 
369
            return responseSender.ok(Collections.singletonMap("status", "already_scheduled"));
-
 
370
        }
-
 
371
 
-
 
372
        // Append at the end of the day's existing stops.
-
 
373
        int seq = beatRouteRepository.selectByBeatId(beatId).size() + 1;
-
 
374
 
-
 
375
        com.spice.profitmandi.dao.entity.user.LeadRoute lr = new com.spice.profitmandi.dao.entity.user.LeadRoute();
-
 
376
        lr.setBeatId(beatId);
-
 
377
        lr.setLeadId(leadId);
-
 
378
        lr.setScheduleDate(scheduleDate);
-
 
379
        lr.setSequenceOrder(seq);
-
 
380
        lr.setStatus("APPROVED");
-
 
381
        lr.setRequestedBy(authUserId);
-
 
382
        lr.setApprovedBy(authUserId);
-
 
383
        LocalDateTime now = LocalDateTime.now();
-
 
384
        lr.setApprovedTimestamp(now);
-
 
385
        lr.setCreatedTimestamp(now);
-
 
386
        lr.setUpdatedTimestamp(now);
-
 
387
        leadRouteRepository.persist(lr);
-
 
388
 
-
 
389
        Map<String, Object> result = new HashMap<>();
-
 
390
        result.put("status", "scheduled");
-
 
391
        result.put("scheduleDate", scheduleDate.toString());
-
 
392
        return responseSender.ok(result);
-
 
393
    }
-
 
394
 
201
    @RequestMapping(value = "/lead", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
395
    @RequestMapping(value = "/lead", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
202
    @ApiImplicitParams({
396
    @ApiImplicitParams({
203
            @ApiImplicitParam(name = "Auth-Token", value = "Auth-Token", required = true, dataType = "string", paramType = "header")})
397
            @ApiImplicitParam(name = "Auth-Token", value = "Auth-Token", required = true, dataType = "string", paramType = "header")})
204
 
398
 
205
    public ResponseEntity<?> LeadUser(@RequestBody CreateRefferalRequest createRefferalRequest) throws Exception {
399
    public ResponseEntity<?> LeadUser(@RequestBody CreateRefferalRequest createRefferalRequest) throws Exception {
Line 263... Line 457...
263
            lead.setClosureTimestamp(null);
457
            lead.setClosureTimestamp(null);
264
        }
458
        }
265
        leadActivity.setCreatedTimestamp(LocalDateTime.now());
459
        leadActivity.setCreatedTimestamp(LocalDateTime.now());
266
        leadActivityRepository.persist(leadActivity);
460
        leadActivityRepository.persist(leadActivity);
267
 
461
 
-
 
462
        // Return the new lead's id alongside the legacy `success: true` flag so callers
-
 
463
        // that need to chain follow-up actions (e.g., the partner app's self-create →
-
 
464
        // self-approve geo → schedule on beat flow) can do so without an extra lookup.
-
 
465
        Map<String, Object> body = new HashMap<>();
-
 
466
        body.put("success", true);
-
 
467
        body.put("leadId", lead.getId());
268
        return responseSender.ok(true);
468
        return responseSender.ok(body);
269
    }
469
    }
270
 
470
 
271
    @RequestMapping(value = "/lead-description", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
471
    @RequestMapping(value = "/lead-description", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
272
    @ApiImplicitParams({
472
    @ApiImplicitParams({
273
            @ApiImplicitParam(name = "Auth-Token", value = "Auth-Token", required = true, dataType = "string", paramType = "header")})
473
            @ApiImplicitParam(name = "Auth-Token", value = "Auth-Token", required = true, dataType = "string", paramType = "header")})