From 69ec9e62a6ab68032ae1ee30608dcc6c5b29811f Mon Sep 17 00:00:00 2001 From: Astral04 Date: Thu, 6 Aug 2026 11:01:44 +0000 Subject: [PATCH] Require bookings to be at least 5 days ahead Guests could previously book for the same day or tomorrow. The earliest selectable date is now today + 5 days, configured in one place via the BOOKING_MIN_LEAD_DAYS constant. - constants.php: new BOOKING_MIN_LEAD_DAYS define (5) - Service_model::getAvailableTimes(): optional $minLeadDays param, returns no slots for dates closer than that; defaults to 0 so existing callers are unaffected - Pages::ajax(): guest actions (getAvailableTimes, isTimeAvailable) pass the constant. The admin action getAvailableTimeOptions deliberately does not, so staff can still enter phone bookings for tomorrow. - Pages::booking_process(): rejects an early booking_date POST and redirects back to /booking, guarding against a stale page or a crafted request - booking-form.php: datepicker minDate/defaultDate and the hidden booking_date default all derive from the constant Deployed and verified on test, dev and prod. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01MyYsTAAA1kJLMLCResmgTE --- application/config/constants.php | 12 ++++++++++++ application/controllers/Pages.php | 11 +++++++++-- application/models/Service_model.php | 8 +++++++- application/views/pages/includes/booking-form.php | 5 +++-- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/application/config/constants.php b/application/config/constants.php index 9b667b0..12b372d 100644 --- a/application/config/constants.php +++ b/application/config/constants.php @@ -83,3 +83,15 @@ defined('EXIT_USER_INPUT') OR define('EXIT_USER_INPUT', 7); // invalid user defined('EXIT_DATABASE') OR define('EXIT_DATABASE', 8); // database error defined('EXIT__AUTO_MIN') OR define('EXIT__AUTO_MIN', 9); // lowest automatically-assigned error code defined('EXIT__AUTO_MAX') OR define('EXIT__AUTO_MAX', 125); // highest automatically-assigned error code + +/* +|-------------------------------------------------------------------------- +| Booking lead time +|-------------------------------------------------------------------------- +| +| Minimum number of days ahead a guest can book a job. 5 means the earliest +| selectable date is today + 5 days. Applies to the public booking form only +| - the admin portal can still book any date. +| +*/ +defined('BOOKING_MIN_LEAD_DAYS') OR define('BOOKING_MIN_LEAD_DAYS', 5); diff --git a/application/controllers/Pages.php b/application/controllers/Pages.php index 85ef264..51a153d 100644 --- a/application/controllers/Pages.php +++ b/application/controllers/Pages.php @@ -197,7 +197,7 @@ class Pages extends CI_Controller { } if(isset($_POST['action']) && $_POST['action'] == 'isTimeAvailable' && isset($_POST['selectedDate'])){ - $results = $this->Service_model->getAvailableTimes($_POST['group_id'], $_POST['selectedDate'], $_POST['servicelength']); + $results = $this->Service_model->getAvailableTimes($_POST['group_id'], $_POST['selectedDate'], $_POST['servicelength'], BOOKING_MIN_LEAD_DAYS); $timeIsAvailable = 0; if(is_array($results)){ @@ -215,7 +215,7 @@ class Pages extends CI_Controller { } if(isset($_POST['action']) && $_POST['action'] == 'getAvailableTimes' && isset($_POST['selectedDate'])){ - $results = $this->Service_model->getAvailableTimes($_POST['group_id'], $_POST['selectedDate'], $_POST['servicelength'].':00'); + $results = $this->Service_model->getAvailableTimes($_POST['group_id'], $_POST['selectedDate'], $_POST['servicelength'].':00', BOOKING_MIN_LEAD_DAYS); $rowIndex = 1; if(!empty($results)){ @@ -515,6 +515,13 @@ class Pages extends CI_Controller { if(isset($_POST['sendBooking'])){ + //guest bookings must be at least BOOKING_MIN_LEAD_DAYS days ahead + $earliestBookingDate = date('Y-m-d', strtotime('+'.BOOKING_MIN_LEAD_DAYS.' days')); + if(!isset($_POST['booking_date']) || $_POST['booking_date'] < $earliestBookingDate){ + header('Location:'.SITEURL.'booking'); + exit; + } + //calculate finish time $serviceStartTime = date("H:i:s", strtotime($_POST['booking_start_time'])); $serviceLengthTime = date("H:i:s", strtotime($_POST['servicelength'])); diff --git a/application/models/Service_model.php b/application/models/Service_model.php index 1340915..4a5b99f 100644 --- a/application/models/Service_model.php +++ b/application/models/Service_model.php @@ -342,7 +342,7 @@ class Service_model extends CI_Model { } } - public function getAvailableTimes($group_id, $selectedDate, $servicelength){ + public function getAvailableTimes($group_id, $selectedDate, $servicelength, $minLeadDays = 0){ $this->load->database(); $serviceLengthDateTime = new DateTime($selectedDate.' '.$servicelength); $service_length_time = strtotime($servicelength); @@ -366,6 +366,12 @@ class Service_model extends CI_Model { $selectedDay=date_create($selectedDate); $dateDiff=date_diff($today,$selectedDay); + //minimum booking lead time - no times offered before today + $minLeadDays days. + //$minLeadDays = 0 means no restriction (admin portal). + if($minLeadDays > 0 && intval($dateDiff->format('%R%a')) < $minLeadDays){ + return array(); + } + $tmpDateStart = date_create(date('2024-02-29')); $tmpDateEnd = date_create(date('2024-03-07')); diff --git a/application/views/pages/includes/booking-form.php b/application/views/pages/includes/booking-form.php index da5c12f..74d9e54 100644 --- a/application/views/pages/includes/booking-form.php +++ b/application/views/pages/includes/booking-form.php @@ -787,7 +787,7 @@
- +
@@ -1122,7 +1122,8 @@ $("#datepicker").datepicker({ firstDay: 1, - defaultDate: new Date(), + minDate: , + defaultDate: +, dateFormat: 'yy-mm-dd', onSelect: function(dateText) { $('#booking_date').val(this.value);