@happychef/algorithm 1.2.12 → 1.2.14

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.
Files changed (58) hide show
  1. package/.github/workflows/ci-cd.yml +234 -234
  2. package/BRANCH_PROTECTION_SETUP.md +167 -167
  3. package/CHANGELOG.md +8 -8
  4. package/README.md +144 -144
  5. package/RESERVERINGEN_GIDS.md +986 -986
  6. package/__tests__/filters.test.js +276 -276
  7. package/__tests__/isDateAvailable.test.js +175 -175
  8. package/__tests__/isTimeAvailable.test.js +168 -168
  9. package/__tests__/restaurantData.test.js +422 -422
  10. package/__tests__/tableHelpers.test.js +247 -247
  11. package/assignTables.js +443 -424
  12. package/changes/2025/December/PR2___change.md +14 -14
  13. package/changes/2025/December/PR3_add__change.md +20 -20
  14. package/changes/2025/December/PR4___.md +15 -15
  15. package/changes/2025/December/PR5___.md +15 -15
  16. package/changes/2025/December/PR6__del_.md +17 -17
  17. package/changes/2025/December/PR7_add__change.md +21 -21
  18. package/changes/2026/January/PR10_add__change.md +22 -0
  19. package/changes/2026/January/PR8_add__change.md +38 -38
  20. package/changes/2026/January/PR9_add__change.md +19 -19
  21. package/filters/maxArrivalsFilter.js +114 -114
  22. package/filters/maxGroupsFilter.js +221 -221
  23. package/filters/timeFilter.js +89 -89
  24. package/getAvailableTimeblocks.js +158 -158
  25. package/grouping.js +162 -162
  26. package/index.js +42 -42
  27. package/isDateAvailable.js +80 -80
  28. package/isDateAvailableWithTableCheck.js +172 -171
  29. package/isTimeAvailable.js +25 -25
  30. package/jest.config.js +23 -23
  31. package/package.json +27 -27
  32. package/processing/dailyGuestCounts.js +73 -73
  33. package/processing/mealTypeCount.js +133 -133
  34. package/processing/timeblocksAvailable.js +182 -167
  35. package/reservation_data/counter.js +74 -64
  36. package/restaurant_data/exceptions.js +149 -149
  37. package/restaurant_data/openinghours.js +123 -123
  38. package/simulateTableAssignment.js +726 -709
  39. package/tableHelpers.js +178 -178
  40. package/tables/time/parseTime.js +19 -19
  41. package/tables/time/shifts.js +7 -7
  42. package/tables/utils/calculateDistance.js +13 -13
  43. package/tables/utils/isTableFreeForAllSlots.js +14 -14
  44. package/tables/utils/isTemporaryTableValid.js +39 -39
  45. package/test/test_counter.js +194 -194
  46. package/test/test_dailyCount.js +81 -81
  47. package/test/test_datesAvailable.js +106 -106
  48. package/test/test_exceptions.js +172 -172
  49. package/test/test_isDateAvailable.js +330 -330
  50. package/test/test_mealTypeCount.js +54 -54
  51. package/test/test_timesAvailable.js +88 -88
  52. package/test-detailed-filter.js +100 -100
  53. package/test-lunch-debug.js +110 -110
  54. package/test-max-arrivals-filter.js +79 -79
  55. package/test-meal-stop-fix.js +147 -147
  56. package/test-meal-stop-simple.js +93 -93
  57. package/test-timezone-debug.js +47 -47
  58. package/test.js +336 -336
@@ -1,54 +1,54 @@
1
- // mealReservationTests.js
2
-
3
- const { getGuestCountsForMeal } = require('../processing/mealTypeCount');
4
-
5
- // Sample data including shifts
6
- const data = {
7
- "_id": "demo",
8
- "openinghours-breakfast": {
9
- "schemeSettings": {
10
- "Monday": {
11
- "enabled": true,
12
- "startTime": "07:00",
13
- "endTime": "09:30",
14
- "maxCapacityEnabled": true,
15
- "maxCapacity": "12",
16
- "shiftsEnabled": true,
17
- "shifts": [
18
- {
19
- "name": "Shift 1",
20
- "time": "08:00"
21
- },
22
- {
23
- "name": "Shift 2",
24
- "time": "09:00"
25
- }
26
- ]
27
- }
28
- },
29
- "storedNumber": {
30
- "$numberInt": "0"
31
- }
32
- },
33
- // Other meal data...
34
- };
35
-
36
- // Sample reservations
37
- const reservations = [
38
- { guests: "5", time: "08:00", date: "2024-12-02" },
39
- { guests: "3", time: "09:00", date: "2024-12-02" },
40
- { guests: "2", time: "07:00", date: "2024-12-02" },
41
- { guests: "4", time: "07:30", date: "2024-12-02" },
42
- { guests: "6", time: "08:00", date: "2024-12-02" }, // Reservation on a different date
43
- ];
44
-
45
- console.log('--- Meal Reservation Guest Counts Tests ---');
46
-
47
- // Test 1: Breakfast on January 12th (Monday) with shifts
48
- const dateStr = '2024-12-02';
49
- const mealType = 'breakfast';
50
-
51
- const guestCounts = getGuestCountsForMeal(data, dateStr, mealType, reservations);
52
-
53
- console.log('Test 1 - Guest Counts for Breakfast on January 12th with Shifts:');
54
- console.log(guestCounts);
1
+ // mealReservationTests.js
2
+
3
+ const { getGuestCountsForMeal } = require('../processing/mealTypeCount');
4
+
5
+ // Sample data including shifts
6
+ const data = {
7
+ "_id": "demo",
8
+ "openinghours-breakfast": {
9
+ "schemeSettings": {
10
+ "Monday": {
11
+ "enabled": true,
12
+ "startTime": "07:00",
13
+ "endTime": "09:30",
14
+ "maxCapacityEnabled": true,
15
+ "maxCapacity": "12",
16
+ "shiftsEnabled": true,
17
+ "shifts": [
18
+ {
19
+ "name": "Shift 1",
20
+ "time": "08:00"
21
+ },
22
+ {
23
+ "name": "Shift 2",
24
+ "time": "09:00"
25
+ }
26
+ ]
27
+ }
28
+ },
29
+ "storedNumber": {
30
+ "$numberInt": "0"
31
+ }
32
+ },
33
+ // Other meal data...
34
+ };
35
+
36
+ // Sample reservations
37
+ const reservations = [
38
+ { guests: "5", time: "08:00", date: "2024-12-02" },
39
+ { guests: "3", time: "09:00", date: "2024-12-02" },
40
+ { guests: "2", time: "07:00", date: "2024-12-02" },
41
+ { guests: "4", time: "07:30", date: "2024-12-02" },
42
+ { guests: "6", time: "08:00", date: "2024-12-02" }, // Reservation on a different date
43
+ ];
44
+
45
+ console.log('--- Meal Reservation Guest Counts Tests ---');
46
+
47
+ // Test 1: Breakfast on January 12th (Monday) with shifts
48
+ const dateStr = '2024-12-02';
49
+ const mealType = 'breakfast';
50
+
51
+ const guestCounts = getGuestCountsForMeal(data, dateStr, mealType, reservations);
52
+
53
+ console.log('Test 1 - Guest Counts for Breakfast on January 12th with Shifts:');
54
+ console.log(guestCounts);
@@ -1,88 +1,88 @@
1
- // timeblocksAvailableTests.js
2
-
3
- const { timeblocksAvailable } = require('../processing/timeblocksAvailable');
4
-
5
- // Sample data (same as previous examples)
6
- const data = {
7
- "_id": "demo",
8
- "general-settings": {
9
- "zitplaatsen": "5",
10
- "duurReservatie": "120", // Reservation duration of 120 minutes
11
- "intervalReservatie": "30" // Time increment of 30 minutes
12
- },
13
- "openinghours-breakfast": {
14
- "schemeSettings": {
15
- "Monday": {
16
- "enabled": false,
17
- "startTime": "07:00",
18
- "endTime": "11:00",
19
- "maxCapacityEnabled": false,
20
- "maxCapacity": "0",
21
- "shiftsEnabled": false,
22
- "shifts": []
23
- }
24
- },
25
- "storedNumber": {
26
- "$numberInt": "0"
27
- }
28
- },
29
- "openinghours-lunch": {
30
- "schemeSettings": {
31
- "Monday": {
32
- "enabled": false,
33
- "startTime": "13:00",
34
- "endTime": "16:00",
35
- "maxCapacityEnabled": true,
36
- "maxCapacity": "20",
37
- "shiftsEnabled": false,
38
- "shifts": []
39
- }
40
- },
41
- "storedNumber": {
42
- "$numberInt": "0"
43
- }
44
- },
45
- "openinghours-dinner": {
46
- "schemeSettings": {
47
- "Monday": {
48
- "enabled": true,
49
- "startTime": "16:00",
50
- "endTime": "23:00",
51
- "maxCapacityEnabled": true,
52
- "maxCapacity": "5",
53
- "shiftsEnabled": true,
54
- "shifts": [
55
- {
56
- "name": "Shift 1",
57
- "time": "18:00"
58
- },
59
- {
60
- "name": "Shift 2",
61
- "time": "20:00"
62
- }
63
- ]
64
- }
65
- },
66
- "storedNumber": {
67
- "$numberInt": "0"
68
- }
69
- },
70
- "exceptions": []
71
- };
72
-
73
- // Sample reservations
74
- const reservations = [
75
- // Dinner reservations
76
- { guests: "5", time: "18:00", date: "2024-12-02" }, // Shift 1 is fully booked
77
- { guests: "2", time: "20:00", date: "2024-12-02" }, // Shift 2 has available seats
78
- ];
79
-
80
- console.log('--- Time Blocks Availability Tests ---');
81
-
82
- const guests = 3;
83
- const dateStr = '2024-12-02';
84
-
85
- const availableTimeblocks = timeblocksAvailable(data, dateStr, reservations, guests);
86
-
87
- console.log(`Available time blocks for ${guests} guests on ${dateStr}:`);
88
- console.log(availableTimeblocks);
1
+ // timeblocksAvailableTests.js
2
+
3
+ const { timeblocksAvailable } = require('../processing/timeblocksAvailable');
4
+
5
+ // Sample data (same as previous examples)
6
+ const data = {
7
+ "_id": "demo",
8
+ "general-settings": {
9
+ "zitplaatsen": "5",
10
+ "duurReservatie": "120", // Reservation duration of 120 minutes
11
+ "intervalReservatie": "30" // Time increment of 30 minutes
12
+ },
13
+ "openinghours-breakfast": {
14
+ "schemeSettings": {
15
+ "Monday": {
16
+ "enabled": false,
17
+ "startTime": "07:00",
18
+ "endTime": "11:00",
19
+ "maxCapacityEnabled": false,
20
+ "maxCapacity": "0",
21
+ "shiftsEnabled": false,
22
+ "shifts": []
23
+ }
24
+ },
25
+ "storedNumber": {
26
+ "$numberInt": "0"
27
+ }
28
+ },
29
+ "openinghours-lunch": {
30
+ "schemeSettings": {
31
+ "Monday": {
32
+ "enabled": false,
33
+ "startTime": "13:00",
34
+ "endTime": "16:00",
35
+ "maxCapacityEnabled": true,
36
+ "maxCapacity": "20",
37
+ "shiftsEnabled": false,
38
+ "shifts": []
39
+ }
40
+ },
41
+ "storedNumber": {
42
+ "$numberInt": "0"
43
+ }
44
+ },
45
+ "openinghours-dinner": {
46
+ "schemeSettings": {
47
+ "Monday": {
48
+ "enabled": true,
49
+ "startTime": "16:00",
50
+ "endTime": "23:00",
51
+ "maxCapacityEnabled": true,
52
+ "maxCapacity": "5",
53
+ "shiftsEnabled": true,
54
+ "shifts": [
55
+ {
56
+ "name": "Shift 1",
57
+ "time": "18:00"
58
+ },
59
+ {
60
+ "name": "Shift 2",
61
+ "time": "20:00"
62
+ }
63
+ ]
64
+ }
65
+ },
66
+ "storedNumber": {
67
+ "$numberInt": "0"
68
+ }
69
+ },
70
+ "exceptions": []
71
+ };
72
+
73
+ // Sample reservations
74
+ const reservations = [
75
+ // Dinner reservations
76
+ { guests: "5", time: "18:00", date: "2024-12-02" }, // Shift 1 is fully booked
77
+ { guests: "2", time: "20:00", date: "2024-12-02" }, // Shift 2 has available seats
78
+ ];
79
+
80
+ console.log('--- Time Blocks Availability Tests ---');
81
+
82
+ const guests = 3;
83
+ const dateStr = '2024-12-02';
84
+
85
+ const availableTimeblocks = timeblocksAvailable(data, dateStr, reservations, guests);
86
+
87
+ console.log(`Available time blocks for ${guests} guests on ${dateStr}:`);
88
+ console.log(availableTimeblocks);
@@ -1,100 +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 ===');
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 ===');