Subversion Repositories SmartDukaan

Rev

Rev 36821 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 36821 Rev 36840
Line 2476... Line 2476...
2476
				otherBeat = ub;
2476
				otherBeat = ub;
2477
				break;
2477
				break;
2478
			}
2478
			}
2479
		}
2479
		}
2480
 
2480
 
-
 
2481
		// Multi-day beats can't be drag-swapped — moving one of their day_numbers
-
 
2482
		// in isolation would leave the other days behind and break the
-
 
2483
		// Day 1 → Day 2 → … chronological contiguity of the plan. Block both
-
 
2484
		// sides of the swap, point the BM at the Reschedule flow which moves
-
 
2485
		// every day together.
-
 
2486
		if (beat.getTotalDays() > 1) {
-
 
2487
			return responseSender.badRequest(
-
 
2488
					"\"" + (beat.getName() != null ? beat.getName() : "Beat #" + beat.getId())
-
 
2489
							+ "\" is a multi-day beat (" + beat.getTotalDays()
-
 
2490
							+ " days). Drag-swap is only allowed for single-day beats. Use Reschedule to move the whole plan together.");
-
 
2491
		}
-
 
2492
		if (otherBeat != null && otherBeat.getTotalDays() > 1) {
-
 
2493
			return responseSender.badRequest(
-
 
2494
					"Target date already has \"" + (otherBeat.getName() != null ? otherBeat.getName() : "Beat #" + otherBeat.getId())
-
 
2495
							+ "\", a multi-day beat (" + otherBeat.getTotalDays()
-
 
2496
							+ " days). Drag-swap is only allowed when both beats are single-day. Use Reschedule on one of them first.");
-
 
2497
		}
-
 
2498
 
2481
		// Move the dragged beat onto the target date.
2499
		// Move the dragged beat onto the target date. Per-row invariant:
-
 
2500
		// each schedule row's end_date == its own start_date (single-day shape).
-
 
2501
		// We touch ONLY the two rows being swapped — other schedule rows for the
-
 
2502
		// same beat (e.g. older dates) are left exactly as they were.
2482
		match.setStartDate(to);
2503
		match.setStartDate(to);
2483
		// If another beat occupied the target, slide it onto the source date (swap).
2504
		match.setEndDate(to);
2484
		if (otherSchedule != null) {
2505
		if (otherSchedule != null) {
2485
			otherSchedule.setStartDate(from);
2506
			otherSchedule.setStartDate(from);
2486
		}
-
 
2487
 
-
 
2488
		// Recompute endDate as the max across each affected beat's schedules so
-
 
2489
		// the [startDate, endDate] envelope stays consistent.
-
 
2490
		recomputeEndDate(schedules);
-
 
2491
		if (otherSchedules != null) {
2507
			otherSchedule.setEndDate(from);
2492
			recomputeEndDate(otherSchedules);
-
 
2493
		}
2508
		}
2494
 
2509
 
2495
		Map<String, Object> response = new HashMap<>();
2510
		Map<String, Object> response = new HashMap<>();
2496
		response.put("status", true);
2511
		response.put("status", true);
2497
		response.put("message", otherBeat != null
2512
		response.put("message", otherBeat != null
Line 2599... Line 2614...
2599
		response.put("status", true);
2614
		response.put("status", true);
2600
		response.put("message", "Unscheduled from " + date);
2615
		response.put("message", "Unscheduled from " + date);
2601
		return responseSender.ok(response);
2616
		return responseSender.ok(response);
2602
	}
2617
	}
2603
 
2618
 
2604
	private void recomputeEndDate(List<BeatSchedule> schedules) {
-
 
2605
		LocalDate newEnd = schedules.stream()
-
 
2606
				.map(BeatSchedule::getStartDate)
-
 
2607
				.filter(d -> d != null && d.getYear() != 9999)
-
 
2608
				.max(LocalDate::compareTo).orElse(null);
-
 
2609
		if (newEnd == null) return;
-
 
2610
		for (BeatSchedule s : schedules) {
-
 
2611
			if (s.getStartDate() != null && s.getStartDate().getYear() != 9999) {
-
 
2612
				s.setEndDate(newEnd);
-
 
2613
			}
-
 
2614
		}
-
 
2615
	}
-
 
2616
 
-
 
2617
	/**
2619
	/**
2618
	 * Per-user one-beat-per-day guard. Walks every active beat the sales user
2620
	 * Per-user one-beat-per-day guard. Walks every active beat the sales user
2619
	 * already has and looks for a schedule row on any of the candidate dates.
2621
	 * already has and looks for a schedule row on any of the candidate dates.
2620
	 * Returns null if the candidate dates are clear, otherwise a {date,beatName}
2622
	 * Returns null if the candidate dates are clear, otherwise a {date,beatName}
2621
	 * map describing the first collision so the caller can surface a clean error.
2623
	 * map describing the first collision so the caller can surface a clean error.