@happychef/algorithm 1.2.5 → 1.2.7
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.
- package/filters/maxArrivalsFilter.js +8 -9
- package/filters/maxGroupsFilter.js +4 -5
- package/getAvailableTimeblocks.js +51 -29
- package/package.json +1 -1
- package/test-detailed-filter.js +100 -0
- package/test-lunch-debug.js +110 -0
- package/test-max-arrivals-filter.js +79 -0
- package/test-timezone-debug.js +47 -0
|
@@ -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,45 @@ function getAvailableTimeblocks(data, dateStr, reservations, guests, blockedSlot
|
|
|
106
97
|
}
|
|
107
98
|
}
|
|
108
99
|
|
|
109
|
-
// Apply
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
100
|
+
// Apply last booking time filter (lunchStop, dinerStop, ontbijtStop) - skip for admin
|
|
101
|
+
// IMPORTANT: This filter should only apply to TODAY, just like uurOpVoorhand
|
|
102
|
+
if (!isAdmin && isToday) {
|
|
103
|
+
const settings = data?.['general-settings'] || {};
|
|
104
|
+
const breakfastStop = settings.ontbijtStop || null;
|
|
105
|
+
const lunchStop = settings.lunchStop || null;
|
|
106
|
+
const dinnerStop = settings.dinerStop || null;
|
|
107
|
+
|
|
108
|
+
// Only apply if at least one stop time is configured
|
|
109
|
+
if (breakfastStop || lunchStop || dinnerStop) {
|
|
110
|
+
for (const time in availableTimeblocks) {
|
|
111
|
+
const mealType = getMealTypeByTime(time);
|
|
112
|
+
const timeMinutes = parseTime(time);
|
|
113
|
+
let shouldRemove = false;
|
|
114
|
+
|
|
115
|
+
// Check if this time is AT OR AFTER the stop time for its meal type
|
|
116
|
+
// Using ">=" so that lunchStop="14:00" blocks 14:00 and later times
|
|
117
|
+
if (mealType === 'breakfast' && breakfastStop) {
|
|
118
|
+
const stopMinutes = parseTime(breakfastStop);
|
|
119
|
+
if (timeMinutes >= stopMinutes) {
|
|
120
|
+
shouldRemove = true;
|
|
121
|
+
}
|
|
122
|
+
} else if (mealType === 'lunch' && lunchStop) {
|
|
123
|
+
const stopMinutes = parseTime(lunchStop);
|
|
124
|
+
if (timeMinutes >= stopMinutes) {
|
|
125
|
+
shouldRemove = true;
|
|
126
|
+
}
|
|
127
|
+
} else if (mealType === 'dinner' && dinnerStop) {
|
|
128
|
+
const stopMinutes = parseTime(dinnerStop);
|
|
129
|
+
if (timeMinutes >= stopMinutes) {
|
|
130
|
+
shouldRemove = true;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (shouldRemove) {
|
|
135
|
+
delete availableTimeblocks[time];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
117
139
|
}
|
|
118
140
|
|
|
119
141
|
return availableTimeblocks;
|
package/package.json
CHANGED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// Detailed filter test - simulating getAvailableTimeblocks logic
|
|
2
|
+
const { timeblocksAvailable } = require('./processing/timeblocksAvailable');
|
|
3
|
+
const { getMealTypeByTime, parseTime } = require('./tableHelpers');
|
|
4
|
+
|
|
5
|
+
const restaurantData = {
|
|
6
|
+
"_id": "demo",
|
|
7
|
+
"openinghours-lunch": {
|
|
8
|
+
"schemeSettings": {
|
|
9
|
+
"Monday": {
|
|
10
|
+
"enabled": true,
|
|
11
|
+
"startTime": "14:15",
|
|
12
|
+
"endTime": "15:00",
|
|
13
|
+
"maxCapacityEnabled": true,
|
|
14
|
+
"maxCapacity": "10"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"general-settings": {
|
|
19
|
+
"zitplaatsen": 13,
|
|
20
|
+
"uurOpVoorhand": 0,
|
|
21
|
+
"dagenInToekomst": 365,
|
|
22
|
+
"intervalReservatie": 30,
|
|
23
|
+
"duurReservatie": 60,
|
|
24
|
+
"ontbijtStop": "",
|
|
25
|
+
"lunchStop": "",
|
|
26
|
+
"dinerStop": ""
|
|
27
|
+
},
|
|
28
|
+
"max-arrivals-lunch": {
|
|
29
|
+
"14:15": 10,
|
|
30
|
+
"14:30": 10,
|
|
31
|
+
"14:45": 10
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const testDate = "2025-12-08";
|
|
36
|
+
const guests = 2;
|
|
37
|
+
const reservations = [];
|
|
38
|
+
const uurOpVoorhand = 0;
|
|
39
|
+
const isAdmin = false;
|
|
40
|
+
|
|
41
|
+
console.log('=== DETAILED FILTER TEST ===\n');
|
|
42
|
+
|
|
43
|
+
// Get timeblocks
|
|
44
|
+
const availableTimeblocks = timeblocksAvailable(restaurantData, testDate, reservations, guests, [], null, isAdmin);
|
|
45
|
+
console.log('Initial timeblocks:', Object.keys(availableTimeblocks));
|
|
46
|
+
|
|
47
|
+
// Simulate the time filtering logic
|
|
48
|
+
const now = new Date();
|
|
49
|
+
const [year, month, day] = testDate.split('-').map(Number);
|
|
50
|
+
const targetDateInTimeZone = new Date(year, month - 1, day);
|
|
51
|
+
const isToday = now.toDateString() === targetDateInTimeZone.toDateString();
|
|
52
|
+
|
|
53
|
+
console.log('\nTime filter check:');
|
|
54
|
+
console.log('Is today:', isToday);
|
|
55
|
+
console.log('uurOpVoorhand:', uurOpVoorhand);
|
|
56
|
+
console.log('Current time:', now.toString());
|
|
57
|
+
|
|
58
|
+
if (isToday && uurOpVoorhand >= 0) {
|
|
59
|
+
const cutoffTime = new Date(now.getTime());
|
|
60
|
+
cutoffTime.setHours(cutoffTime.getHours() + uurOpVoorhand);
|
|
61
|
+
console.log('Cutoff time:', cutoffTime.toString());
|
|
62
|
+
|
|
63
|
+
for (const key of Object.keys(availableTimeblocks)) {
|
|
64
|
+
const timeStr = key;
|
|
65
|
+
const [hours, minutes] = timeStr.split(':').map(Number);
|
|
66
|
+
const timeBlockDateTime = new Date(year, month - 1, day, hours, minutes);
|
|
67
|
+
|
|
68
|
+
console.log(`\n Checking ${timeStr}:`);
|
|
69
|
+
console.log(` timeBlockDateTime: ${timeBlockDateTime.toString()}`);
|
|
70
|
+
console.log(` cutoffTime: ${cutoffTime.toString()}`);
|
|
71
|
+
console.log(` timeBlockDateTime < cutoffTime: ${timeBlockDateTime < cutoffTime}`);
|
|
72
|
+
console.log(` Would be deleted: ${timeBlockDateTime < cutoffTime ? 'YES' : 'NO'}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Check lunchStop filter
|
|
77
|
+
console.log('\n\nLunch Stop filter check:');
|
|
78
|
+
const settings = restaurantData['general-settings'];
|
|
79
|
+
const lunchStop = settings.lunchStop || null;
|
|
80
|
+
console.log('lunchStop value:', JSON.stringify(lunchStop));
|
|
81
|
+
console.log('lunchStop truthy:', !!lunchStop);
|
|
82
|
+
|
|
83
|
+
if (lunchStop) {
|
|
84
|
+
console.log('LunchStop is set, would apply filter');
|
|
85
|
+
for (const time in availableTimeblocks) {
|
|
86
|
+
const mealType = getMealTypeByTime(time);
|
|
87
|
+
console.log(` ${time}: mealType=${mealType}`);
|
|
88
|
+
|
|
89
|
+
if (mealType === 'lunch') {
|
|
90
|
+
const timeMinutes = parseTime(time);
|
|
91
|
+
const stopMinutes = parseTime(lunchStop);
|
|
92
|
+
console.log(` timeMinutes=${timeMinutes}, stopMinutes=${stopMinutes}`);
|
|
93
|
+
console.log(` Would remove: ${timeMinutes >= stopMinutes ? 'YES' : 'NO'}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
console.log('LunchStop is NOT set, no filter applied');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.log('\n=== END TEST ===');
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// Test script to debug why Monday lunch isn't showing
|
|
2
|
+
const { getAvailableTimeblocks } = require('./getAvailableTimeblocks');
|
|
3
|
+
const { timeblocksAvailable } = require('./processing/timeblocksAvailable');
|
|
4
|
+
const { getDailyGuestCounts } = require('./processing/dailyGuestCounts');
|
|
5
|
+
|
|
6
|
+
// Your restaurant data
|
|
7
|
+
const restaurantData = {
|
|
8
|
+
"_id": "demo",
|
|
9
|
+
"openinghours-lunch": {
|
|
10
|
+
"schemeSettings": {
|
|
11
|
+
"Monday": {
|
|
12
|
+
"enabled": true,
|
|
13
|
+
"startTime": "14:15",
|
|
14
|
+
"endTime": "15:00",
|
|
15
|
+
"maxCapacityEnabled": true,
|
|
16
|
+
"maxCapacity": "10",
|
|
17
|
+
"shiftsEnabled": false,
|
|
18
|
+
"shifts": [],
|
|
19
|
+
"giftcardsEnabled": false,
|
|
20
|
+
"giftcards": [],
|
|
21
|
+
"giftcardTakeawayEnabled": false,
|
|
22
|
+
"giftcardTakeawayStart": "",
|
|
23
|
+
"giftcardTakeawayEnd": ""
|
|
24
|
+
},
|
|
25
|
+
"Wednesday": {
|
|
26
|
+
"enabled": true,
|
|
27
|
+
"startTime": "13:45",
|
|
28
|
+
"endTime": "14:45",
|
|
29
|
+
"maxCapacityEnabled": false,
|
|
30
|
+
"maxCapacity": "",
|
|
31
|
+
"shiftsEnabled": false,
|
|
32
|
+
"shifts": [],
|
|
33
|
+
"giftcardsEnabled": false,
|
|
34
|
+
"giftcards": [],
|
|
35
|
+
"giftcardTakeawayEnabled": true,
|
|
36
|
+
"giftcardTakeawayStart": "11:00",
|
|
37
|
+
"giftcardTakeawayEnd": "16:00"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"general-settings": {
|
|
42
|
+
"zitplaatsen": 13,
|
|
43
|
+
"uurOpVoorhand": 0,
|
|
44
|
+
"dagenInToekomst": 365,
|
|
45
|
+
"minGasten": 1,
|
|
46
|
+
"maxGasten": 10,
|
|
47
|
+
"intervalReservatie": 30,
|
|
48
|
+
"duurReservatie": 60,
|
|
49
|
+
"ontbijtStop": "",
|
|
50
|
+
"lunchStop": "",
|
|
51
|
+
"dinerStop": ""
|
|
52
|
+
},
|
|
53
|
+
"max-arrivals-lunch": {
|
|
54
|
+
"12:00": 6,
|
|
55
|
+
"12:15": 1,
|
|
56
|
+
"12:30": 6,
|
|
57
|
+
"12:45": 4,
|
|
58
|
+
"13:00": 10,
|
|
59
|
+
"14:15": 10,
|
|
60
|
+
"14:30": 10,
|
|
61
|
+
"14:45": 10,
|
|
62
|
+
"storedNumber": 30
|
|
63
|
+
},
|
|
64
|
+
"exceptions": [],
|
|
65
|
+
"blocked-slots": []
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Test for Monday December 8, 2025
|
|
69
|
+
const testDate = "2025-12-08"; // Monday
|
|
70
|
+
const guests = 2;
|
|
71
|
+
const reservations = [];
|
|
72
|
+
|
|
73
|
+
console.log('=== LUNCH AVAILABILITY DEBUG ===\n');
|
|
74
|
+
console.log('Date:', testDate, '(Monday)');
|
|
75
|
+
console.log('Guests:', guests);
|
|
76
|
+
console.log('Current time:', new Date().toISOString());
|
|
77
|
+
console.log('\n--- Restaurant Settings ---');
|
|
78
|
+
console.log('Lunch Opening Hours (Monday):', restaurantData['openinghours-lunch'].schemeSettings.Monday);
|
|
79
|
+
console.log('General Settings:', restaurantData['general-settings']);
|
|
80
|
+
console.log('Max Arrivals Lunch:', restaurantData['max-arrivals-lunch']);
|
|
81
|
+
|
|
82
|
+
console.log('\n--- Step 1: getDailyGuestCounts ---');
|
|
83
|
+
const { guestCounts, shiftsInfo } = getDailyGuestCounts(restaurantData, testDate, reservations);
|
|
84
|
+
console.log('Guest Counts:', guestCounts);
|
|
85
|
+
console.log('Shifts Info:', shiftsInfo);
|
|
86
|
+
|
|
87
|
+
console.log('\n--- Step 2: timeblocksAvailable ---');
|
|
88
|
+
const timeblocks = timeblocksAvailable(restaurantData, testDate, reservations, guests, [], null, false);
|
|
89
|
+
console.log('Available Timeblocks:', timeblocks);
|
|
90
|
+
|
|
91
|
+
console.log('\n--- Step 3: getAvailableTimeblocks (with filters) ---');
|
|
92
|
+
const finalTimeblocks = getAvailableTimeblocks(restaurantData, testDate, reservations, guests, [], null, false);
|
|
93
|
+
console.log('Final Available Timeblocks:', finalTimeblocks);
|
|
94
|
+
|
|
95
|
+
console.log('\n--- Step 4: Test with Admin Flag ---');
|
|
96
|
+
const adminTimeblocks = getAvailableTimeblocks(restaurantData, testDate, reservations, guests, [], null, true);
|
|
97
|
+
console.log('Admin Timeblocks (no time restrictions):', adminTimeblocks);
|
|
98
|
+
|
|
99
|
+
// Check if lunch times exist
|
|
100
|
+
const lunchTimes = ['14:15', '14:30', '14:45'];
|
|
101
|
+
console.log('\n--- Lunch Time Analysis ---');
|
|
102
|
+
lunchTimes.forEach(time => {
|
|
103
|
+
console.log(`${time}:`);
|
|
104
|
+
console.log(` - In guestCounts: ${guestCounts.hasOwnProperty(time) ? 'YES (capacity: ' + guestCounts[time] + ')' : 'NO'}`);
|
|
105
|
+
console.log(` - In timeblocks: ${timeblocks.hasOwnProperty(time) ? 'YES' : 'NO'}`);
|
|
106
|
+
console.log(` - In final: ${finalTimeblocks.hasOwnProperty(time) ? 'YES' : 'NO'}`);
|
|
107
|
+
console.log(` - In admin: ${adminTimeblocks.hasOwnProperty(time) ? 'YES' : 'NO'}`);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
console.log('\n=== END DEBUG ===');
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Test the max arrivals filter specifically
|
|
2
|
+
const { filterTimeblocksByMaxArrivals } = require('./filters/maxArrivalsFilter');
|
|
3
|
+
const { getAvailableTimeblocks } = require('./getAvailableTimeblocks');
|
|
4
|
+
|
|
5
|
+
const restaurantData = {
|
|
6
|
+
"_id": "demo",
|
|
7
|
+
"openinghours-lunch": {
|
|
8
|
+
"schemeSettings": {
|
|
9
|
+
"Monday": {
|
|
10
|
+
"enabled": true,
|
|
11
|
+
"startTime": "14:15",
|
|
12
|
+
"endTime": "15:00",
|
|
13
|
+
"maxCapacityEnabled": true,
|
|
14
|
+
"maxCapacity": "10"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"general-settings": {
|
|
19
|
+
"zitplaatsen": 13,
|
|
20
|
+
"uurOpVoorhand": 0,
|
|
21
|
+
"dagenInToekomst": 365,
|
|
22
|
+
"intervalReservatie": 30,
|
|
23
|
+
"duurReservatie": 60,
|
|
24
|
+
"ontbijtStop": "",
|
|
25
|
+
"lunchStop": "",
|
|
26
|
+
"dinerStop": ""
|
|
27
|
+
},
|
|
28
|
+
"max-arrivals-lunch": {
|
|
29
|
+
"12:00": 6,
|
|
30
|
+
"12:15": 1,
|
|
31
|
+
"12:30": 6,
|
|
32
|
+
"12:45": 4,
|
|
33
|
+
"13:00": 10,
|
|
34
|
+
"14:15": 10,
|
|
35
|
+
"14:30": 10,
|
|
36
|
+
"14:45": 10,
|
|
37
|
+
"storedNumber": 30
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const testDate = "2025-12-08";
|
|
42
|
+
const guests = 2;
|
|
43
|
+
const reservations = [];
|
|
44
|
+
|
|
45
|
+
console.log('=== MAX ARRIVALS FILTER TEST ===\n');
|
|
46
|
+
|
|
47
|
+
// Get initial timeblocks from algorithm
|
|
48
|
+
const timeblocks = getAvailableTimeblocks(restaurantData, testDate, reservations, guests, [], null, true);
|
|
49
|
+
console.log('Timeblocks from algorithm (admin mode):', Object.keys(timeblocks));
|
|
50
|
+
|
|
51
|
+
// Apply max arrivals filter
|
|
52
|
+
const filtered = filterTimeblocksByMaxArrivals(restaurantData, testDate, timeblocks, reservations, guests);
|
|
53
|
+
console.log('\nAfter max arrivals filter:', Object.keys(filtered));
|
|
54
|
+
|
|
55
|
+
// Debug each time slot
|
|
56
|
+
console.log('\n--- Detailed Analysis ---');
|
|
57
|
+
for (const time of Object.keys(timeblocks)) {
|
|
58
|
+
const maxArrivalsConfig = restaurantData['max-arrivals-lunch'];
|
|
59
|
+
const maxArrivals = maxArrivalsConfig ? maxArrivalsConfig[time] : null;
|
|
60
|
+
|
|
61
|
+
const currentArrivals = reservations
|
|
62
|
+
.filter(r => r.date === testDate && r.time === time)
|
|
63
|
+
.reduce((sum, r) => sum + (parseInt(r.guests, 10) || 0), 0);
|
|
64
|
+
|
|
65
|
+
const isInFiltered = filtered.hasOwnProperty(time);
|
|
66
|
+
|
|
67
|
+
console.log(`\n${time}:`);
|
|
68
|
+
console.log(` Max arrivals setting: ${maxArrivals || 'NOT SET'}`);
|
|
69
|
+
console.log(` Current arrivals: ${currentArrivals}`);
|
|
70
|
+
console.log(` New reservation: ${guests} guests`);
|
|
71
|
+
console.log(` Total after adding: ${currentArrivals + guests}`);
|
|
72
|
+
console.log(` Passes filter: ${isInFiltered ? 'YES' : 'NO'}`);
|
|
73
|
+
|
|
74
|
+
if (maxArrivals !== null && maxArrivals !== undefined) {
|
|
75
|
+
console.log(` Logic: ${currentArrivals} + ${guests} = ${currentArrivals + guests} ${currentArrivals + guests <= maxArrivals ? '<=' : '>'} ${maxArrivals}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
console.log('\n=== END TEST ===');
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Test timezone handling
|
|
2
|
+
const moment = require('moment-timezone');
|
|
3
|
+
|
|
4
|
+
const testDate = "2025-12-08";
|
|
5
|
+
const testTime = "14:15";
|
|
6
|
+
|
|
7
|
+
console.log('=== TIMEZONE DEBUG ===\n');
|
|
8
|
+
|
|
9
|
+
// What the algorithm does
|
|
10
|
+
const now = new Date();
|
|
11
|
+
console.log('System now:', now);
|
|
12
|
+
console.log('System now ISO:', now.toISOString());
|
|
13
|
+
console.log('System now local string:', now.toString());
|
|
14
|
+
|
|
15
|
+
// Parse the time as the algorithm does (line 68-69 in getAvailableTimeblocks.js)
|
|
16
|
+
const [year, month, day] = testDate.split('-').map(Number);
|
|
17
|
+
const targetDateInTimeZone = new Date(year, month - 1, day);
|
|
18
|
+
console.log('\nTarget date:', targetDateInTimeZone);
|
|
19
|
+
console.log('Target date string:', targetDateInTimeZone.toString());
|
|
20
|
+
|
|
21
|
+
const isToday = now.toDateString() === targetDateInTimeZone.toDateString();
|
|
22
|
+
console.log('\nIs today?:', isToday);
|
|
23
|
+
|
|
24
|
+
// With uurOpVoorhand = 0
|
|
25
|
+
const uurOpVoorhand = 0;
|
|
26
|
+
const cutoffTime = new Date(now.getTime());
|
|
27
|
+
cutoffTime.setHours(cutoffTime.getHours() + uurOpVoorhand);
|
|
28
|
+
console.log('\nCutoff time (now + 0 hours):', cutoffTime);
|
|
29
|
+
console.log('Cutoff time string:', cutoffTime.toString());
|
|
30
|
+
|
|
31
|
+
// Parse the test time
|
|
32
|
+
const [hours, minutes] = testTime.split(':').map(Number);
|
|
33
|
+
const timeBlockDateTime = new Date(year, month - 1, day, hours, minutes);
|
|
34
|
+
console.log('\nTime block (14:15):', timeBlockDateTime);
|
|
35
|
+
console.log('Time block string:', timeBlockDateTime.toString());
|
|
36
|
+
|
|
37
|
+
console.log('\nComparison:');
|
|
38
|
+
console.log('timeBlockDateTime < cutoffTime:', timeBlockDateTime < cutoffTime);
|
|
39
|
+
console.log('Should be filtered out?:', timeBlockDateTime < cutoffTime ? 'YES' : 'NO');
|
|
40
|
+
|
|
41
|
+
// Check with Europe/Brussels timezone
|
|
42
|
+
console.log('\n=== Using moment-timezone ===');
|
|
43
|
+
const nowBrussels = moment.tz('Europe/Brussels');
|
|
44
|
+
console.log('Now in Brussels:', nowBrussels.format('YYYY-MM-DD HH:mm:ss Z'));
|
|
45
|
+
const targetTimeBrussels = moment.tz(`${testDate} ${testTime}`, 'YYYY-MM-DD HH:mm', 'Europe/Brussels');
|
|
46
|
+
console.log('Target time in Brussels:', targetTimeBrussels.format('YYYY-MM-DD HH:mm:ss Z'));
|
|
47
|
+
console.log('Is target time in past?:', targetTimeBrussels.isBefore(nowBrussels));
|