Subversion Repositories SmartDukaan

Rev

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

Rev 36840 Rev 36962
Line 318... Line 318...
318
		List<Map<String, Object>> selected = (List<Map<String, Object>>) body.get("parties");
318
		List<Map<String, Object>> selected = (List<Map<String, Object>>) body.get("parties");
319
		if (authUserId == null || planDate == null || selected == null || selected.isEmpty()) {
319
		if (authUserId == null || planDate == null || selected == null || selected.isEmpty()) {
320
			return responseSender.badRequest("authUserId, planDate and parties are required");
320
			return responseSender.badRequest("authUserId, planDate and parties are required");
321
		}
321
		}
322
 
322
 
-
 
323
		// Defence-in-depth: Assign Visit is L2-and-above only (mirrors the hidden UI).
-
 
324
		if (!canEditBeat(currentUser(request))) {
-
 
325
			return responseSender.badRequest("Assigning a visit is restricted to L2 and above.");
-
 
326
		}
-
 
327
 
323
		AuthUser au = authRepository.selectById(authUserId);
328
		AuthUser au = authRepository.selectById(authUserId);
324
		if (au == null) return responseSender.badRequest("Auth user not found");
329
		if (au == null) return responseSender.badRequest("Auth user not found");
325
 
330
 
326
		// Map auth → dtr.users.id (this is the userId the v2 endpoint expects)
331
		// Map auth → dtr.users.id (this is the userId the v2 endpoint expects)
327
		com.spice.profitmandi.dao.entity.dtr.User dtrUser;
332
		com.spice.profitmandi.dao.entity.dtr.User dtrUser;
Line 826... Line 831...
826
	}
831
	}
827
 
832
 
828
	@GetMapping(value = "/beatPlanWindow")
833
	@GetMapping(value = "/beatPlanWindow")
829
	public String beatPlanWindow(HttpServletRequest request, Model model) throws ProfitMandiBusinessException {
834
	public String beatPlanWindow(HttpServletRequest request, Model model) throws ProfitMandiBusinessException {
830
		model.addAttribute("escalationTypes", visibleLevelsFor(request));
835
		model.addAttribute("escalationTypes", visibleLevelsFor(request));
-
 
836
		model.addAttribute("canScheduleToday", canScheduleToday(currentUser(request)));
831
		return "beat-plan-window";
837
		return "beat-plan-window";
832
	}
838
	}
833
 
839
 
834
	// Helpers for XLSX bulk upload
840
	// Helpers for XLSX bulk upload
835
	private static String readCell(org.apache.poi.ss.usermodel.Cell cell) {
841
	private static String readCell(org.apache.poi.ss.usermodel.Cell cell) {
Line 1482... Line 1488...
1482
	@GetMapping(value = "/beatPlan/dayView")
1488
	@GetMapping(value = "/beatPlan/dayView")
1483
	public String beatPlanDayView(HttpServletRequest request, Model model) throws ProfitMandiBusinessException {
1489
	public String beatPlanDayView(HttpServletRequest request, Model model) throws ProfitMandiBusinessException {
1484
		model.addAttribute("escalationTypes", visibleLevelsFor(request));
1490
		model.addAttribute("escalationTypes", visibleLevelsFor(request));
1485
		// Matches /beatPlan/getAuthUsers and the Beat Report — default Sales category.
1491
		// Matches /beatPlan/getAuthUsers and the Beat Report — default Sales category.
1486
		model.addAttribute("categoryId", com.spice.profitmandi.common.model.ProfitMandiConstants.TICKET_CATEGORY_SALES);
1492
		model.addAttribute("categoryId", com.spice.profitmandi.common.model.ProfitMandiConstants.TICKET_CATEGORY_SALES);
-
 
1493
		model.addAttribute("canEditBeat", canEditBeat(currentUser(request)));
1487
		return "beat-plan-day-view";
1494
		return "beat-plan-day-view";
1488
	}
1495
	}
1489
 
1496
 
1490
	// Returns visits for a beat.
1497
	// Returns visits for a beat.
1491
	// - Partner stops (beat_route) belong to the beat template — always returned.
1498
	// - Partner stops (beat_route) belong to the beat template — always returned.
Line 1728... Line 1735...
1728
			if (mine.isGreaterThanEqualTo(e) && !e.equals(mine)) below.add(e);
1735
			if (mine.isGreaterThanEqualTo(e) && !e.equals(mine)) below.add(e);
1729
		}
1736
		}
1730
		return below;
1737
		return below;
1731
	}
1738
	}
1732
 
1739
 
1733
	private List<EscalationType> visibleLevelsFor(HttpServletRequest request) throws ProfitMandiBusinessException {
1740
	private AuthUser currentUser(HttpServletRequest request) throws ProfitMandiBusinessException {
1734
		LoginDetails ld = cookiesProcessor.getCookiesObject(request);
1741
		LoginDetails ld = cookiesProcessor.getCookiesObject(request);
1735
		AuthUser me = (ld != null) ? authRepository.selectByEmailOrMobile(ld.getEmailId()) : null;
1742
		return (ld != null) ? authRepository.selectByEmailOrMobile(ld.getEmailId()) : null;
-
 
1743
	}
-
 
1744
 
-
 
1745
	private List<EscalationType> visibleLevelsFor(HttpServletRequest request) throws ProfitMandiBusinessException {
-
 
1746
		AuthUser me = currentUser(request);
1736
		return me == null ? java.util.Collections.emptyList() : getVisibleEscalationLevels(me);
1747
		return me == null ? java.util.Collections.emptyList() : getVisibleEscalationLevels(me);
1737
	}
1748
	}
1738
 
1749
 
-
 
1750
	// Same-day scheduling is restricted to L4+ operators (or super-admin). Everyone
-
 
1751
	// else can only schedule beats for future dates.
-
 
1752
	private boolean canScheduleToday(AuthUser me) {
-
 
1753
		if (me == null) return false;
-
 
1754
		if (isSuperAdmin(me)) return true;
-
 
1755
		EscalationType lvl = getHighestEscalation(me.getId());
-
 
1756
		return lvl != null && lvl.isGreaterThanEqualTo(EscalationType.L4);
-
 
1757
	}
-
 
1758
 
-
 
1759
	// Editing a beat / assigning a visit from the day-view is restricted to L2 and
-
 
1760
	// above (or super-admin). L1 executives can view but not edit.
-
 
1761
	private boolean canEditBeat(AuthUser me) {
-
 
1762
		if (me == null) return false;
-
 
1763
		if (isSuperAdmin(me)) return true;
-
 
1764
		EscalationType lvl = getHighestEscalation(me.getId());
-
 
1765
		return lvl != null && lvl.isGreaterThanEqualTo(EscalationType.L2);
-
 
1766
	}
-
 
1767
 
1739
	// Shared permission check for base-location admin actions: Sales L3+ OR super-admin.
1768
	// Shared permission check for base-location admin actions: Sales L3+ OR super-admin.
1740
	private boolean isBaseLocationManager(AuthUser me) {
1769
	private boolean isBaseLocationManager(AuthUser me) {
1741
		if (isSuperAdmin(me)) return true;
1770
		if (isSuperAdmin(me)) return true;
1742
		return csService.getAuthUserIds(
1771
		return csService.getAuthUserIds(
1743
						com.spice.profitmandi.common.model.ProfitMandiConstants.TICKET_CATEGORY_SALES,
1772
						com.spice.profitmandi.common.model.ProfitMandiConstants.TICKET_CATEGORY_SALES,
Line 2676... Line 2705...
2676
			try {
2705
			try {
2677
				requested.add(LocalDate.parse(s));
2706
				requested.add(LocalDate.parse(s));
2678
			} catch (Exception ignored) {
2707
			} catch (Exception ignored) {
2679
			}
2708
			}
2680
		}
2709
		}
-
 
2710
		// Same-day scheduling is restricted to L4+ operators.
-
 
2711
		if (requested.contains(LocalDate.now()) && !canScheduleToday(currentUser(request))) {
-
 
2712
			return responseSender.badRequest("Scheduling a beat for today is restricted to L4 and above.");
-
 
2713
		}
2681
		Map<String, Object> conflict = findScheduleConflict(beat.getAuthUserId(), requested, beatId);
2714
		Map<String, Object> conflict = findScheduleConflict(beat.getAuthUserId(), requested, beatId);
2682
		if (conflict != null) return responseSender.badRequest(scheduleConflictMessage(conflict));
2715
		if (conflict != null) return responseSender.badRequest(scheduleConflictMessage(conflict));
2683
 
2716
 
2684
		// Delete old schedules and create new
2717
		// Delete old schedules and create new
2685
		beatScheduleRepository.deleteByBeatId(beatId);
2718
		beatScheduleRepository.deleteByBeatId(beatId);