@happychef/algorithm 1.2.11 → 1.2.12

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 (57) 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 +424 -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/PR8_add__change.md +39 -0
  19. package/changes/2026/January/PR9_add__change.md +20 -0
  20. package/filters/maxArrivalsFilter.js +114 -114
  21. package/filters/maxGroupsFilter.js +221 -221
  22. package/filters/timeFilter.js +89 -89
  23. package/getAvailableTimeblocks.js +158 -158
  24. package/grouping.js +162 -162
  25. package/index.js +42 -42
  26. package/isDateAvailable.js +80 -80
  27. package/isDateAvailableWithTableCheck.js +171 -171
  28. package/isTimeAvailable.js +25 -25
  29. package/jest.config.js +23 -23
  30. package/package.json +27 -27
  31. package/processing/dailyGuestCounts.js +73 -73
  32. package/processing/mealTypeCount.js +133 -133
  33. package/processing/timeblocksAvailable.js +167 -167
  34. package/reservation_data/counter.js +64 -64
  35. package/restaurant_data/exceptions.js +149 -149
  36. package/restaurant_data/openinghours.js +123 -123
  37. package/simulateTableAssignment.js +709 -699
  38. package/tableHelpers.js +178 -178
  39. package/tables/time/parseTime.js +19 -19
  40. package/tables/time/shifts.js +7 -7
  41. package/tables/utils/calculateDistance.js +13 -13
  42. package/tables/utils/isTableFreeForAllSlots.js +14 -14
  43. package/tables/utils/isTemporaryTableValid.js +39 -39
  44. package/test/test_counter.js +194 -194
  45. package/test/test_dailyCount.js +81 -81
  46. package/test/test_datesAvailable.js +106 -106
  47. package/test/test_exceptions.js +172 -172
  48. package/test/test_isDateAvailable.js +330 -330
  49. package/test/test_mealTypeCount.js +54 -54
  50. package/test/test_timesAvailable.js +88 -88
  51. package/test-detailed-filter.js +100 -100
  52. package/test-lunch-debug.js +110 -110
  53. package/test-max-arrivals-filter.js +79 -79
  54. package/test-meal-stop-fix.js +147 -147
  55. package/test-meal-stop-simple.js +93 -93
  56. package/test-timezone-debug.js +47 -47
  57. 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 ===');