Subversion Repositories SmartDukaan

Rev

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

Rev 37120 Rev 37175
Line 9... Line 9...
9
import com.spice.profitmandi.dao.entity.auth.AuthUser;
9
import com.spice.profitmandi.dao.entity.auth.AuthUser;
10
import com.spice.profitmandi.dao.entity.fofo.FofoStore;
10
import com.spice.profitmandi.dao.entity.fofo.FofoStore;
11
import com.spice.profitmandi.dao.entity.logistics.PublicHolidays;
11
import com.spice.profitmandi.dao.entity.logistics.PublicHolidays;
12
import com.spice.profitmandi.dao.entity.user.*;
12
import com.spice.profitmandi.dao.entity.user.*;
13
import com.spice.profitmandi.dao.enumuration.cs.EscalationType;
13
import com.spice.profitmandi.dao.enumuration.cs.EscalationType;
-
 
14
import com.spice.profitmandi.dao.enumuration.dtr.AgendaSource;
-
 
15
import com.spice.profitmandi.dao.enumuration.dtr.AgendaType;
14
import com.spice.profitmandi.dao.repository.auth.AuthRepository;
16
import com.spice.profitmandi.dao.repository.auth.AuthRepository;
15
import com.spice.profitmandi.dao.repository.cs.CsService;
17
import com.spice.profitmandi.dao.repository.cs.CsService;
16
import com.spice.profitmandi.dao.repository.dtr.*;
18
import com.spice.profitmandi.dao.repository.dtr.*;
17
import com.spice.profitmandi.dao.repository.logistics.PublicHolidaysRepository;
19
import com.spice.profitmandi.dao.repository.logistics.PublicHolidaysRepository;
18
import com.spice.profitmandi.service.user.RetailerService;
20
import com.spice.profitmandi.service.user.RetailerService;
Line 85... Line 87...
85
	private ResponseSender responseSender;
87
	private ResponseSender responseSender;
86
	@Autowired
88
	@Autowired
87
	private FofoStoreRepository fofoStoreRepository;
89
	private FofoStoreRepository fofoStoreRepository;
88
	@Autowired
90
	@Autowired
89
	private com.spice.profitmandi.dao.repository.logistics.CompanyOfficeRepository companyOfficeRepository;
91
	private com.spice.profitmandi.dao.repository.logistics.CompanyOfficeRepository companyOfficeRepository;
-
 
92
	@Autowired
-
 
93
	private AgendaInstanceRepository agendaInstanceRepository;
-
 
94
	@Autowired
-
 
95
	private com.spice.profitmandi.service.AgendaInstanceService agendaInstanceService;
90
 
96
 
91
	@GetMapping(value = "/beatPlan")
97
	@GetMapping(value = "/beatPlan")
92
	public String beatPlan(HttpServletRequest request, Model model) throws ProfitMandiBusinessException {
98
	public String beatPlan(HttpServletRequest request, Model model) throws ProfitMandiBusinessException {
93
		model.addAttribute("escalationTypes", visibleLevelsFor(request));
99
		model.addAttribute("escalationTypes", visibleLevelsFor(request));
94
		return "beat-plan";
100
		return "beat-plan";
Line 349... Line 355...
349
				if (ai != bi) return ai ? -1 : 1;
355
				if (ai != bi) return ai ? -1 : 1;
350
				return String.valueOf(a.get("code")).compareToIgnoreCase(String.valueOf(b.get("code")));
356
				return String.valueOf(a.get("code")).compareToIgnoreCase(String.valueOf(b.get("code")));
351
			});
357
			});
352
		}
358
		}
353
 
359
 
-
 
360
		// Open agenda instances (AUTO + MANUAL) per party — the modal pre-selects
-
 
361
		// these; AUTO ones are badged and close only when their metric normalizes.
-
 
362
		List<Integer> partyIds = new ArrayList<>();
-
 
363
		for (Map<String, Object> p : parties) partyIds.add((Integer) p.get("fofoStoreId"));
-
 
364
		Map<Integer, List<Map<String, Object>>> openAgendasByFofo = new HashMap<>();
-
 
365
		for (AgendaInstance ai : agendaInstanceRepository.selectOpenByFofoIds(partyIds)) {
-
 
366
			Map<String, Object> m = new HashMap<>();
-
 
367
			m.put("id", ai.getId());
-
 
368
			m.put("agendaType", ai.getAgendaType());
-
 
369
			m.put("label", labelFor(ai.getAgendaType()));
-
 
370
			m.put("source", ai.getSource());
-
 
371
			m.put("openedOn", ai.getOpenedOn() != null ? ai.getOpenedOn().toLocalDate().toString() : null);
-
 
372
			openAgendasByFofo.computeIfAbsent(ai.getFofoId(), k -> new ArrayList<>()).add(m);
-
 
373
		}
-
 
374
		for (Map<String, Object> p : parties) {
-
 
375
			p.put("openAgendas", openAgendasByFofo.getOrDefault((Integer) p.get("fofoStoreId"), new ArrayList<>()));
-
 
376
		}
-
 
377
 
354
		Map<String, Object> result = new HashMap<>();
378
		Map<String, Object> result = new HashMap<>();
355
		result.put("dtrUserId", dtrUserId);
379
		result.put("dtrUserId", dtrUserId);
356
		result.put("authUserId", authUserId);
380
		result.put("authUserId", authUserId);
357
		result.put("userName", au.getFirstName() + " " + au.getLastName());
381
		result.put("userName", au.getFirstName() + " " + au.getLastName());
358
		result.put("parties", parties);
382
		result.put("parties", parties);
359
		result.put("agendaOptions", com.spice.profitmandi.dao.enumuration.dtr.VisitAgenda.labels());
383
		result.put("agendaOptions", com.spice.profitmandi.dao.enumuration.dtr.VisitAgenda.labels());
360
		return responseSender.ok(result);
384
		return responseSender.ok(result);
361
	}
385
	}
362
 
386
 
-
 
387
	// agenda_type holds the enum NAME (e.g. LOW_SALES); tolerate unknown values.
-
 
388
	private String labelFor(String agendaTypeName) {
-
 
389
		try {
-
 
390
			return AgendaType.valueOf(agendaTypeName).getLabel();
-
 
391
		} catch (Exception e) {
-
 
392
			return agendaTypeName;
-
 
393
		}
-
 
394
	}
-
 
395
 
363
	// Submit assignment — accepts a JSON body, builds the v2 payload, posts it
396
	// Submit assignment — accepts a JSON body, builds the v2 payload, posts it
364
	@PostMapping(value = "/beatPlan/assignVisit/submit")
397
	@PostMapping(value = "/beatPlan/assignVisit/submit")
365
	public ResponseEntity<?> assignVisitSubmit(
398
	public ResponseEntity<?> assignVisitSubmit(
366
			HttpServletRequest request,
399
			HttpServletRequest request,
367
			@org.springframework.web.bind.annotation.RequestBody Map<String, Object> body) throws Exception {
400
			@org.springframework.web.bind.annotation.RequestBody Map<String, Object> body) throws Exception {
Line 372... Line 405...
372
		if (authUserId == null || planDate == null || selected == null || selected.isEmpty()) {
405
		if (authUserId == null || planDate == null || selected == null || selected.isEmpty()) {
373
			return responseSender.badRequest("authUserId, planDate and parties are required");
406
			return responseSender.badRequest("authUserId, planDate and parties are required");
374
		}
407
		}
375
 
408
 
376
		// Defence-in-depth: Assign Visit is L2-and-above only (mirrors the hidden UI).
409
		// Defence-in-depth: Assign Visit is L2-and-above only (mirrors the hidden UI).
-
 
410
		AuthUser operator = currentUser(request);
377
		if (!canEditBeat(currentUser(request))) {
411
		if (!canEditBeat(operator)) {
378
			return responseSender.badRequest("Assigning a visit is restricted to L2 and above.");
412
			return responseSender.badRequest("Assigning a visit is restricted to L2 and above.");
379
		}
413
		}
-
 
414
		Integer operatorAuthId = operator != null ? operator.getId() : null;
380
 
415
 
381
		AuthUser au = authRepository.selectById(authUserId);
416
		AuthUser au = authRepository.selectById(authUserId);
382
		if (au == null) return responseSender.badRequest("Auth user not found");
417
		if (au == null) return responseSender.badRequest("Auth user not found");
383
 
418
 
384
		// Map auth → dtr.users.id (this is the userId the v2 endpoint expects)
419
		// Map auth → dtr.users.id (this is the userId the v2 endpoint expects)
Line 448... Line 483...
448
				if (single != null && !single.trim().isEmpty()) agendas.add(single.trim());
483
				if (single != null && !single.trim().isEmpty()) agendas.add(single.trim());
449
			}
484
			}
450
			if (agendas.isEmpty()) agendas.add("Visit");
485
			if (agendas.isEmpty()) agendas.add("Visit");
451
			String agendaJoined = String.join(", ", agendas);
486
			String agendaJoined = String.join(", ", agendas);
452
 
487
 
-
 
488
			// Lifecycle: any picked agenda without an open instance becomes a
-
 
489
			// MANUAL instance. open() no-ops when one is already OPEN (AUTO or
-
 
490
			// MANUAL), so pre-existing auto agendas are left untouched.
-
 
491
			for (String label : agendas) {
-
 
492
				AgendaType type = AgendaType.fromLabel(label);
-
 
493
				if (type == null) continue; // "Visit" default — not lifecycle-tracked
-
 
494
				agendaInstanceService.open(fofoStoreId, type.name(), AgendaSource.MANUAL, operatorAuthId, null);
-
 
495
			}
-
 
496
 
453
			String visitLocation = (lat != null && lng != null && !lat.isEmpty() && !lng.isEmpty())
497
			String visitLocation = (lat != null && lng != null && !lat.isEmpty() && !lng.isEmpty())
454
					? (lat + "," + lng) : "0.0000,0.0000";
498
					? (lat + "," + lng) : "0.0000,0.0000";
455
 
499
 
456
			String displayName = (outletName != null && !outletName.isEmpty()) ? outletName : ("Store #" + fofoStoreId);
500
			String displayName = (outletName != null && !outletName.isEmpty()) ? outletName : ("Store #" + fofoStoreId);
457
			String newTaskName = agendaJoined + " | " + displayName;
501
			String newTaskName = agendaJoined + " | " + displayName;