@happychef/algorithm 1.2.32 → 1.3.2
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/.github/workflows/ci-cd.yml +80 -80
- package/CHANGELOG.md +8 -8
- package/RESERVERINGEN_GIDS.md +986 -986
- package/assignTables.js +444 -444
- package/changes/2025/December/PR2___change.md +14 -14
- package/changes/2025/December/PR3_add__change.md +20 -20
- package/changes/2025/December/PR4___.md +15 -15
- package/changes/2025/December/PR5___.md +15 -15
- package/changes/2025/December/PR6__del_.md +17 -17
- package/changes/2025/December/PR7_add__change.md +21 -21
- package/changes/2026/February/PR15_add__change.md +21 -21
- package/changes/2026/February/PR16_add_getDateClosingReasons.md +31 -0
- package/changes/2026/January/PR10_add__change.md +21 -21
- package/changes/2026/January/PR11_add__change.md +19 -19
- package/changes/2026/January/PR12_add__.md +21 -21
- package/changes/2026/January/PR13_add__change.md +20 -20
- package/changes/2026/January/PR14_add__change.md +19 -19
- package/changes/2026/January/PR8_add__change.md +38 -38
- package/changes/2026/January/PR9_add__change.md +19 -19
- package/filters/maxArrivalsFilter.js +114 -114
- package/filters/maxGroupsFilter.js +221 -221
- package/filters/timeFilter.js +89 -89
- package/getAvailableTimeblocks.js +158 -158
- package/getDateClosingReasons.js +193 -0
- package/grouping.js +162 -162
- package/index.js +43 -42
- package/isDateAvailable.js +80 -80
- package/isDateAvailableWithTableCheck.js +172 -172
- package/isTimeAvailable.js +26 -26
- package/package.json +27 -27
- package/processing/dailyGuestCounts.js +73 -73
- package/processing/mealTypeCount.js +133 -133
- package/processing/timeblocksAvailable.js +182 -182
- package/reservation_data/counter.js +74 -74
- package/restaurant_data/exceptions.js +150 -150
- package/restaurant_data/openinghours.js +142 -156
- package/simulateTableAssignment.js +726 -726
- package/tableHelpers.js +209 -209
- package/tables/time/parseTime.js +19 -19
- package/tables/time/shifts.js +7 -7
- package/tables/utils/calculateDistance.js +13 -13
- package/tables/utils/isTableFreeForAllSlots.js +14 -14
- package/tables/utils/isTemporaryTableValid.js +39 -39
- package/test/test_counter.js +194 -194
- package/test/test_dailyCount.js +81 -81
- package/test/test_datesAvailable.js +106 -106
- package/test/test_exceptions.js +172 -172
- package/test/test_isDateAvailable.js +330 -330
- package/test/test_mealTypeCount.js +54 -54
- package/test/test_timesAvailable.js +88 -88
- package/test-meal-stop-fix.js +147 -147
- package/test-meal-stop-simple.js +93 -93
- package/test.js +336 -336
- package/bundle_entry.js +0 -100
- package/moment-timezone-shim.js +0 -179
- package/nul +0 -0
|
@@ -1,115 +1,115 @@
|
|
|
1
|
-
// file: /src/Pages/NewReservation/StepOne/algorithm/maxArrivalsFilter.js
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Simple max arrivals filter for time slots
|
|
5
|
-
*
|
|
6
|
-
* Only considers exact arrivals at each time slot without factoring duration
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Get meal type based on time
|
|
11
|
-
* @param {string} time - Time string (HH:MM)
|
|
12
|
-
* @returns {string|null} - Meal type or null
|
|
13
|
-
*/
|
|
14
|
-
function getMealType(time) {
|
|
15
|
-
const hour = parseInt(time.split(':')[0], 10);
|
|
16
|
-
|
|
17
|
-
if (hour >= 4 && hour < 11) return 'breakfast';
|
|
18
|
-
if (hour >= 11 && hour < 16) return 'lunch';
|
|
19
|
-
if (hour >= 16 && hour < 23) return 'dinner';
|
|
20
|
-
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Extract number value from various data formats
|
|
26
|
-
* @param {*} value - Value from data object
|
|
27
|
-
* @returns {number|null} - Number or null
|
|
28
|
-
*/
|
|
29
|
-
function extractNumber(value) {
|
|
30
|
-
if (!value) return null;
|
|
31
|
-
|
|
32
|
-
// Handle MongoDB NumberInt format
|
|
33
|
-
if (value.$numberInt) {
|
|
34
|
-
return parseInt(value.$numberInt, 10);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Handle regular number
|
|
38
|
-
if (typeof value === 'number') {
|
|
39
|
-
return value;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Handle string number
|
|
43
|
-
if (typeof value === 'string') {
|
|
44
|
-
const parsed = parseInt(value, 10);
|
|
45
|
-
return isNaN(parsed) ? null : parsed;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Count guests arriving at exact time
|
|
53
|
-
* @param {Array} reservations - Reservation list
|
|
54
|
-
* @param {string} date - Date (YYYY-MM-DD)
|
|
55
|
-
* @param {string} time - Time (HH:MM)
|
|
56
|
-
* @returns {number} - Guest count
|
|
57
|
-
*/
|
|
58
|
-
function countArrivalsAtTime(reservations, date, time) {
|
|
59
|
-
return reservations
|
|
60
|
-
.filter(r => r.date === date && r.time === time)
|
|
61
|
-
.reduce((sum, r) => sum + (parseInt(r.guests, 10) || 0), 0);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Filter timeblocks based on max arrivals settings
|
|
66
|
-
* @param {Object} restaurantData - Restaurant data
|
|
67
|
-
* @param {string} date - Date string
|
|
68
|
-
* @param {Object} timeblocks - Available timeblocks
|
|
69
|
-
* @param {Array} reservations - Existing reservations
|
|
70
|
-
* @param {number} guests - New reservation guest count
|
|
71
|
-
* @returns {Object} - Filtered timeblocks
|
|
72
|
-
*/
|
|
73
|
-
function filterTimeblocksByMaxArrivals(restaurantData, date, timeblocks, reservations, guests) {
|
|
74
|
-
const filteredBlocks = {};
|
|
75
|
-
|
|
76
|
-
for (const [time, timeData] of Object.entries(timeblocks)) {
|
|
77
|
-
// Get meal type for this time
|
|
78
|
-
const mealType = getMealType(time);
|
|
79
|
-
if (!mealType) {
|
|
80
|
-
// Keep the timeblock if we can't determine its meal type
|
|
81
|
-
filteredBlocks[time] = timeData;
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Get max arrivals config for this meal type
|
|
86
|
-
const maxArrivalsConfig = restaurantData[`max-arrivals-${mealType}`];
|
|
87
|
-
if (!maxArrivalsConfig) {
|
|
88
|
-
// Keep the timeblock if no max arrivals config for this meal type
|
|
89
|
-
filteredBlocks[time] = timeData;
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Get max arrivals value for this specific time
|
|
94
|
-
const maxArrivals = extractNumber(maxArrivalsConfig[time]);
|
|
95
|
-
if (maxArrivals === null) {
|
|
96
|
-
// Keep the timeblock if no specific max arrivals for this time
|
|
97
|
-
filteredBlocks[time] = timeData;
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Count current arrivals at this exact time
|
|
102
|
-
const currentArrivals = countArrivalsAtTime(reservations, date, time);
|
|
103
|
-
|
|
104
|
-
// Only include timeblock if adding these guests doesn't exceed max arrivals
|
|
105
|
-
if (currentArrivals + guests <= maxArrivals) {
|
|
106
|
-
filteredBlocks[time] = timeData;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return filteredBlocks;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
module.exports = {
|
|
114
|
-
filterTimeblocksByMaxArrivals
|
|
1
|
+
// file: /src/Pages/NewReservation/StepOne/algorithm/maxArrivalsFilter.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Simple max arrivals filter for time slots
|
|
5
|
+
*
|
|
6
|
+
* Only considers exact arrivals at each time slot without factoring duration
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Get meal type based on time
|
|
11
|
+
* @param {string} time - Time string (HH:MM)
|
|
12
|
+
* @returns {string|null} - Meal type or null
|
|
13
|
+
*/
|
|
14
|
+
function getMealType(time) {
|
|
15
|
+
const hour = parseInt(time.split(':')[0], 10);
|
|
16
|
+
|
|
17
|
+
if (hour >= 4 && hour < 11) return 'breakfast';
|
|
18
|
+
if (hour >= 11 && hour < 16) return 'lunch';
|
|
19
|
+
if (hour >= 16 && hour < 23) return 'dinner';
|
|
20
|
+
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Extract number value from various data formats
|
|
26
|
+
* @param {*} value - Value from data object
|
|
27
|
+
* @returns {number|null} - Number or null
|
|
28
|
+
*/
|
|
29
|
+
function extractNumber(value) {
|
|
30
|
+
if (!value) return null;
|
|
31
|
+
|
|
32
|
+
// Handle MongoDB NumberInt format
|
|
33
|
+
if (value.$numberInt) {
|
|
34
|
+
return parseInt(value.$numberInt, 10);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Handle regular number
|
|
38
|
+
if (typeof value === 'number') {
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Handle string number
|
|
43
|
+
if (typeof value === 'string') {
|
|
44
|
+
const parsed = parseInt(value, 10);
|
|
45
|
+
return isNaN(parsed) ? null : parsed;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Count guests arriving at exact time
|
|
53
|
+
* @param {Array} reservations - Reservation list
|
|
54
|
+
* @param {string} date - Date (YYYY-MM-DD)
|
|
55
|
+
* @param {string} time - Time (HH:MM)
|
|
56
|
+
* @returns {number} - Guest count
|
|
57
|
+
*/
|
|
58
|
+
function countArrivalsAtTime(reservations, date, time) {
|
|
59
|
+
return reservations
|
|
60
|
+
.filter(r => r.date === date && r.time === time)
|
|
61
|
+
.reduce((sum, r) => sum + (parseInt(r.guests, 10) || 0), 0);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Filter timeblocks based on max arrivals settings
|
|
66
|
+
* @param {Object} restaurantData - Restaurant data
|
|
67
|
+
* @param {string} date - Date string
|
|
68
|
+
* @param {Object} timeblocks - Available timeblocks
|
|
69
|
+
* @param {Array} reservations - Existing reservations
|
|
70
|
+
* @param {number} guests - New reservation guest count
|
|
71
|
+
* @returns {Object} - Filtered timeblocks
|
|
72
|
+
*/
|
|
73
|
+
function filterTimeblocksByMaxArrivals(restaurantData, date, timeblocks, reservations, guests) {
|
|
74
|
+
const filteredBlocks = {};
|
|
75
|
+
|
|
76
|
+
for (const [time, timeData] of Object.entries(timeblocks)) {
|
|
77
|
+
// Get meal type for this time
|
|
78
|
+
const mealType = getMealType(time);
|
|
79
|
+
if (!mealType) {
|
|
80
|
+
// Keep the timeblock if we can't determine its meal type
|
|
81
|
+
filteredBlocks[time] = timeData;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Get max arrivals config for this meal type
|
|
86
|
+
const maxArrivalsConfig = restaurantData[`max-arrivals-${mealType}`];
|
|
87
|
+
if (!maxArrivalsConfig) {
|
|
88
|
+
// Keep the timeblock if no max arrivals config for this meal type
|
|
89
|
+
filteredBlocks[time] = timeData;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Get max arrivals value for this specific time
|
|
94
|
+
const maxArrivals = extractNumber(maxArrivalsConfig[time]);
|
|
95
|
+
if (maxArrivals === null) {
|
|
96
|
+
// Keep the timeblock if no specific max arrivals for this time
|
|
97
|
+
filteredBlocks[time] = timeData;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Count current arrivals at this exact time
|
|
102
|
+
const currentArrivals = countArrivalsAtTime(reservations, date, time);
|
|
103
|
+
|
|
104
|
+
// Only include timeblock if adding these guests doesn't exceed max arrivals
|
|
105
|
+
if (currentArrivals + guests <= maxArrivals) {
|
|
106
|
+
filteredBlocks[time] = timeData;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return filteredBlocks;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = {
|
|
114
|
+
filterTimeblocksByMaxArrivals
|
|
115
115
|
};
|