Apply the worker capability filter to the manage-booking flow

The per-worker service allow-list was only enforced on the new-booking form.
On the guest manage-booking page a worker could still be offered for services
they do not perform:

- manage_booking() branched on $firstService, which was never assigned - the
  resolve loop above it used $resolvedService - so the guarded branch was dead
  and the worker list fell through to getActiveWorkers(), filtered by vertical
  only. Assigning it activates both the category filter and the capability
  check, and with it the $isOtherCategory checkbox disabling in the view.
- The page's own getAvailableWorkersByServiceCategorySlug() never sent
  service_ids, so re-picking services asked for a category-only worker list.
  It now mirrors the booking form, including the empty-result message.
- setWorker() clears any time already chosen: changing worker or services left
  a stale selection with the submit button still enabled.

manage_booking_process() did re-check capability server-side, but every
rejection there answered with raw JSON, which this non-AJAX form renders as an
unstyled blob in the guest's browser. All eight rejections, plus the
cancellation cutoff, now go through _booking_error(), which takes an optional
back URL so the guest returns to their own manage page rather than an empty
booking form. Adds the cutoff_passed message in all three languages and makes
the error title and button label reflect which flow failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYGSbK1erKv7VG1pvdPEjG
This commit is contained in:
Ubuntu
2026-08-24 17:06:08 +00:00
co-authored by Claude Opus 5
parent 13e1b1a672
commit ce7400578a
5 changed files with 103 additions and 34 deletions
+28 -2
View File
@@ -30,6 +30,7 @@
'back' => 'Tilbake',
'send' => 'Bekreft endring',
'no_times' => 'Ingen ledige tider denne dagen!',
'no_workers' => 'Ingen medarbeidere utfører alle de valgte tjenestene.',
'expired_msg' => 'Denne bestillingen er allerede passert og kan ikke endres.',
'cutoff_msg' => 'Bestillingen er innen 24 timer og kan ikke endres eller avbestilles.',
),
@@ -53,6 +54,7 @@
'back' => 'Vissza',
'send' => 'Módosítás megerősítése',
'no_times' => 'Ezen a napon nincs szabad időpont!',
'no_workers' => 'Egyik kolléga sem végzi el az összes kiválasztott szolgáltatást.',
'expired_msg' => 'Ez a foglalás már elmúlt, nem módosítható.',
'cutoff_msg' => 'A foglalás 24 órán belül van, nem módosítható vagy törölhető.',
),
@@ -76,6 +78,7 @@
'back' => 'Back',
'send' => 'Confirm changes',
'no_times' => 'There is no available time on this day!',
'no_workers' => 'No staff member performs all of the selected services.',
'expired_msg' => 'This booking has already passed and cannot be modified.',
'cutoff_msg' => 'Your booking is within 24 hours and can no longer be changed or cancelled.',
),
@@ -246,6 +249,7 @@
onsubmit="return confirm('<?php echo addslashes($l['cancel_confirm']); ?>');">
<input type="hidden" name="token" value="<?php echo htmlspecialchars($token); ?>">
<input type="hidden" name="lang" value="<?php echo htmlspecialchars($lang); ?>">
<input type="hidden" name="subpage" value="<?php echo htmlspecialchars($subpage); ?>">
<button type="submit" class="manage-cancel-btn"><?php echo $l['cancel_btn']; ?></button>
</form>
</div>
@@ -445,6 +449,7 @@
<script>
var noTimesMsg = '<?php echo addslashes($l['no_times']); ?>';
var noWorkersMsg = '<?php echo addslashes($l['no_workers']); ?>';
$(document).ready(function(){
recalcServices();
@@ -543,16 +548,30 @@
}
function getAvailableWorkersByServiceCategorySlug(categorySlug){
// Same rule as the new-booking form: only workers who can perform EVERY
// ticked service may be offered. The checkbox id IS the service_id.
var selectedServiceIds = $('.service:checked').map(function(){
return this.id;
}).get();
$.ajax({
url: '<?php echo base_url(); ?>ajax',
type: 'POST',
data: { action: 'getAvailableWorkersByServiceCategory', serv_cat_slug: categorySlug },
data: {
action: 'getAvailableWorkersByServiceCategory',
serv_cat_slug: categorySlug,
service_ids: selectedServiceIds
},
dataType: 'json',
}).done(function(result){
$('#workerTable').html(result.workerListShow);
if(result.workers && result.workers.length > 0){
$('#workerTable').html(result.workerListShow);
setWorker(result.workers[0].worker_id);
}
else{
$('#workerTable').html('<div class="noWorkerMessage">' + noWorkersMsg + '</div>');
setWorker('');
}
});
}
@@ -645,6 +664,13 @@
function setWorker(worker_id){
$('#worker_id').val(worker_id);
$('.serviceBookingWorkerContainer').hide().html('');
// The worker (or the service set that produced this list) has changed, so
// a time picked for the previous one is stale. Clearing it also disables
// the submit button via the #booking_time change handler.
$('#booking_time').val('').trigger('change');
$('#serviceBookingTime').html('').hide();
$('.availableBookingTime').removeClass('selectedTime');
}
</script>