@happychef/algorithm 1.2.5 → 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -49,16 +49,16 @@ function getMealType(time) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
|
-
* Count
|
|
52
|
+
* Count guests arriving at exact time
|
|
53
53
|
* @param {Array} reservations - Reservation list
|
|
54
54
|
* @param {string} date - Date (YYYY-MM-DD)
|
|
55
55
|
* @param {string} time - Time (HH:MM)
|
|
56
|
-
* @returns {number} -
|
|
56
|
+
* @returns {number} - Guest count
|
|
57
57
|
*/
|
|
58
58
|
function countArrivalsAtTime(reservations, date, time) {
|
|
59
59
|
return reservations
|
|
60
60
|
.filter(r => r.date === date && r.time === time)
|
|
61
|
-
.
|
|
61
|
+
.reduce((sum, r) => sum + (parseInt(r.guests, 10) || 0), 0);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/**
|
|
@@ -92,18 +92,17 @@ function getMealType(time) {
|
|
|
92
92
|
|
|
93
93
|
// Get max arrivals value for this specific time
|
|
94
94
|
const maxArrivals = extractNumber(maxArrivalsConfig[time]);
|
|
95
|
-
if (maxArrivals === null
|
|
96
|
-
// Keep the timeblock if no specific max arrivals for this time
|
|
95
|
+
if (maxArrivals === null) {
|
|
96
|
+
// Keep the timeblock if no specific max arrivals for this time
|
|
97
97
|
filteredBlocks[time] = timeData;
|
|
98
98
|
continue;
|
|
99
99
|
}
|
|
100
|
-
|
|
100
|
+
|
|
101
101
|
// Count current arrivals at this exact time
|
|
102
102
|
const currentArrivals = countArrivalsAtTime(reservations, date, time);
|
|
103
|
-
|
|
103
|
+
|
|
104
104
|
// Only include timeblock if adding these guests doesn't exceed max arrivals
|
|
105
|
-
|
|
106
|
-
if (currentArrivals + 1 <= maxArrivals) {
|
|
105
|
+
if (currentArrivals + guests <= maxArrivals) {
|
|
107
106
|
filteredBlocks[time] = timeData;
|
|
108
107
|
}
|
|
109
108
|
}
|
|
@@ -166,11 +166,10 @@ function getMealType(time) {
|
|
|
166
166
|
// Extract the maximum number of groups allowed for this threshold
|
|
167
167
|
const maxAllowedCount = extractNumber(maxGroupSettings[limitSizeStr]);
|
|
168
168
|
logDebug(` Max groups allowed for >=${limitSize} is: ${maxAllowedCount} (raw setting: ${JSON.stringify(maxGroupSettings[limitSizeStr])})`);
|
|
169
|
-
|
|
170
|
-
// If the setting for this limit size is invalid (null
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
logDebug(` Skipping check: Invalid or non-positive max count (${maxAllowedCount}) - treating as unlimited for size ${limitSize}.`);
|
|
169
|
+
|
|
170
|
+
// If the setting for this limit size is invalid (null or negative), treat it as 'no limit'
|
|
171
|
+
if (maxAllowedCount === null || maxAllowedCount < 0) {
|
|
172
|
+
logDebug(` Skipping check: Invalid or non-positive max count defined for size ${limitSize}.`);
|
|
174
173
|
continue; // Skip to the next limitSize
|
|
175
174
|
}
|
|
176
175
|
|
|
@@ -1,27 +1,22 @@
|
|
|
1
1
|
// getAvailableTimeblocks.js
|
|
2
2
|
|
|
3
3
|
const { timeblocksAvailable } = require('./processing/timeblocksAvailable');
|
|
4
|
-
const {
|
|
5
|
-
const { filterTimeblocksByMaxGroups } = require('./filters/maxGroupsFilter');
|
|
4
|
+
const { parseTime, getMealTypeByTime } = require('./tableHelpers');
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* Parses a time string in "HH:MM" format into a Date object on a specific date.
|
|
9
8
|
* @param {string} dateStr - The date string in "YYYY-MM-DD" format.
|
|
10
9
|
* @param {string} timeStr - Time string in "HH:MM" format.
|
|
11
|
-
* @param {string} timeZone - The IANA time zone identifier.
|
|
12
|
-
* @returns {Date} Date object representing the time on the specified date
|
|
10
|
+
* @param {string} timeZone - The IANA time zone identifier (not used, kept for compatibility).
|
|
11
|
+
* @returns {Date} Date object representing the time on the specified date.
|
|
13
12
|
*/
|
|
14
13
|
function parseDateTimeInTimeZone(dateStr, timeStr, timeZone) {
|
|
15
14
|
const [year, month, day] = dateStr.split('-').map(Number);
|
|
16
15
|
const [hours, minutes] = timeStr.split(':').map(Number);
|
|
17
16
|
|
|
18
|
-
// Create a date object
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const dateInTimeZone = new Date(
|
|
22
|
-
date.toLocaleString('en-US', { timeZone: timeZone })
|
|
23
|
-
);
|
|
24
|
-
return dateInTimeZone;
|
|
17
|
+
// Create a simple date object for the given date and time
|
|
18
|
+
// This represents the local time on that date
|
|
19
|
+
return new Date(year, month - 1, day, hours, minutes);
|
|
25
20
|
}
|
|
26
21
|
|
|
27
22
|
/**
|
|
@@ -59,23 +54,19 @@ function getAvailableTimeblocks(data, dateStr, reservations, guests, blockedSlot
|
|
|
59
54
|
// Time zone for CEST/CET (Europe/Amsterdam)
|
|
60
55
|
const timeZone = 'Europe/Amsterdam';
|
|
61
56
|
|
|
62
|
-
// Current date/time in
|
|
57
|
+
// Current date/time in local timezone (system time)
|
|
58
|
+
// Note: We assume the server is running in the correct timezone
|
|
63
59
|
const now = new Date();
|
|
64
|
-
const currentTimeInTimeZone =
|
|
65
|
-
now.toLocaleString('en-US', { timeZone: timeZone })
|
|
66
|
-
);
|
|
60
|
+
const currentTimeInTimeZone = now;
|
|
67
61
|
|
|
68
62
|
// Calculate the maximum allowed date
|
|
69
63
|
const maxAllowedDate = new Date(currentTimeInTimeZone.getTime());
|
|
70
64
|
maxAllowedDate.setDate(maxAllowedDate.getDate() + dagenInToekomst);
|
|
71
65
|
maxAllowedDate.setHours(23, 59, 59, 999);
|
|
72
66
|
|
|
73
|
-
// Parse the target date
|
|
67
|
+
// Parse the target date (just the date part, no time)
|
|
74
68
|
const [year, month, day] = dateStr.split('-').map(Number);
|
|
75
|
-
const
|
|
76
|
-
const targetDateInTimeZone = new Date(
|
|
77
|
-
targetDate.toLocaleString('en-US', { timeZone: timeZone })
|
|
78
|
-
);
|
|
69
|
+
const targetDateInTimeZone = new Date(year, month - 1, day);
|
|
79
70
|
|
|
80
71
|
// Check if targetDateInTimeZone is within dagenInToekomst (skip for admin)
|
|
81
72
|
if (!isAdmin && targetDateInTimeZone > maxAllowedDate) {
|
|
@@ -88,7 +79,7 @@ function getAvailableTimeblocks(data, dateStr, reservations, guests, blockedSlot
|
|
|
88
79
|
currentTimeInTimeZone.toDateString() === targetDateInTimeZone.toDateString();
|
|
89
80
|
|
|
90
81
|
// Get available time blocks or shifts
|
|
91
|
-
|
|
82
|
+
const availableTimeblocks = timeblocksAvailable(data, dateStr, reservations, guests, blockedSlots, giftcard, isAdmin);
|
|
92
83
|
|
|
93
84
|
// If the date is today and uurOpVoorhand is greater than zero, prune time blocks (skip for admin)
|
|
94
85
|
if (!isAdmin && isToday && uurOpVoorhand >= 0) {
|
|
@@ -106,14 +97,44 @@ function getAvailableTimeblocks(data, dateStr, reservations, guests, blockedSlot
|
|
|
106
97
|
}
|
|
107
98
|
}
|
|
108
99
|
|
|
109
|
-
// Apply
|
|
100
|
+
// Apply last booking time filter (lunchStop, dinerStop, ontbijtStop) - skip for admin
|
|
110
101
|
if (!isAdmin) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
102
|
+
const settings = data?.['general-settings'] || {};
|
|
103
|
+
const breakfastStop = settings.ontbijtStop || null;
|
|
104
|
+
const lunchStop = settings.lunchStop || null;
|
|
105
|
+
const dinnerStop = settings.dinerStop || null;
|
|
106
|
+
|
|
107
|
+
// Only apply if at least one stop time is configured
|
|
108
|
+
if (breakfastStop || lunchStop || dinnerStop) {
|
|
109
|
+
for (const time in availableTimeblocks) {
|
|
110
|
+
const mealType = getMealTypeByTime(time);
|
|
111
|
+
const timeMinutes = parseTime(time);
|
|
112
|
+
let shouldRemove = false;
|
|
113
|
+
|
|
114
|
+
// Check if this time is AT OR AFTER the stop time for its meal type
|
|
115
|
+
// Using ">=" so that lunchStop="14:00" blocks 14:00 and later times
|
|
116
|
+
if (mealType === 'breakfast' && breakfastStop) {
|
|
117
|
+
const stopMinutes = parseTime(breakfastStop);
|
|
118
|
+
if (timeMinutes >= stopMinutes) {
|
|
119
|
+
shouldRemove = true;
|
|
120
|
+
}
|
|
121
|
+
} else if (mealType === 'lunch' && lunchStop) {
|
|
122
|
+
const stopMinutes = parseTime(lunchStop);
|
|
123
|
+
if (timeMinutes >= stopMinutes) {
|
|
124
|
+
shouldRemove = true;
|
|
125
|
+
}
|
|
126
|
+
} else if (mealType === 'dinner' && dinnerStop) {
|
|
127
|
+
const stopMinutes = parseTime(dinnerStop);
|
|
128
|
+
if (timeMinutes >= stopMinutes) {
|
|
129
|
+
shouldRemove = true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (shouldRemove) {
|
|
134
|
+
delete availableTimeblocks[time];
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
117
138
|
}
|
|
118
139
|
|
|
119
140
|
return availableTimeblocks;
|