@happychef/algorithm 1.2.30 → 1.2.31
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/assignTables.js +10 -22
- package/changes/2026/February/PR15_add__change.md +22 -0
- package/package.json +1 -1
- package/restaurant_data/openinghours.js +3 -0
- package/tableHelpers.js +62 -59
package/assignTables.js
CHANGED
|
@@ -236,11 +236,9 @@ async function assignTablesIfPossible({
|
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
// 2) Get floors data directly from the restaurant document
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
let floorsData = [...regularFloors, ...manualFloors];
|
|
243
|
-
if (floorsData.length === 0) {
|
|
239
|
+
// 2) Get floors data directly from the restaurant document
|
|
240
|
+
let floorsData = restaurantSettings.floors;
|
|
241
|
+
if (!floorsData || !Array.isArray(floorsData) || floorsData.length === 0) {
|
|
244
242
|
if (enforceTableAvailability) {
|
|
245
243
|
throw new Error('No floors data found in restaurant document.');
|
|
246
244
|
} else {
|
|
@@ -259,31 +257,21 @@ async function assignTablesIfPossible({
|
|
|
259
257
|
}
|
|
260
258
|
}
|
|
261
259
|
|
|
262
|
-
// 3) Helper to
|
|
263
|
-
function safeInt(val, fallback) {
|
|
264
|
-
if (val == null) return fallback;
|
|
265
|
-
const raw = (typeof val === 'object' && val.$numberInt != null) ? val.$numberInt : val;
|
|
266
|
-
const parsed = parseInt(raw, 10);
|
|
267
|
-
return isNaN(parsed) ? fallback : parsed;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// 4) Helper to collect tables from floors
|
|
260
|
+
// 3) Helper to collect tables from floors
|
|
271
261
|
function collectTablesFromFloors(floors) {
|
|
272
262
|
const tables = [];
|
|
273
263
|
floors.forEach(floor => {
|
|
274
264
|
if (floor.tables && Array.isArray(floor.tables)) {
|
|
275
265
|
floor.tables.forEach(tbl => {
|
|
276
266
|
if (tbl.objectType === "Tafel") {
|
|
277
|
-
const tableNumber = safeInt(tbl.tableNumber, null);
|
|
278
|
-
if (tableNumber == null) return; // skip tables without a number
|
|
279
267
|
tables.push({
|
|
280
268
|
tableId: tbl.id,
|
|
281
|
-
tableNumber,
|
|
282
|
-
minCapacity:
|
|
283
|
-
maxCapacity:
|
|
284
|
-
priority:
|
|
285
|
-
x:
|
|
286
|
-
y:
|
|
269
|
+
tableNumber: parseInt(tbl.tableNumber.$numberInt || tbl.tableNumber),
|
|
270
|
+
minCapacity: parseInt(tbl.minCapacity.$numberInt || tbl.minCapacity),
|
|
271
|
+
maxCapacity: parseInt(tbl.maxCapacity.$numberInt || tbl.maxCapacity),
|
|
272
|
+
priority: parseInt(tbl.priority.$numberInt || tbl.priority),
|
|
273
|
+
x: parseInt(tbl.x.$numberInt || tbl.x),
|
|
274
|
+
y: parseInt(tbl.y.$numberInt || tbl.y),
|
|
287
275
|
isTemporary: tbl.isTemporary === true,
|
|
288
276
|
startDate: tbl.startDate || null,
|
|
289
277
|
endDate: tbl.endDate || null,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# PR 15 - Fix/safe table parsing and manual floors
|
|
2
|
+
|
|
3
|
+
**Actions:**
|
|
4
|
+
|
|
5
|
+
## Changes Summary
|
|
6
|
+
ADDED:
|
|
7
|
+
- New function `parseTableData(data)` added to handle safe parsing of table information, including validation for required fields.
|
|
8
|
+
- New method `addManualFloor(floorData)` introduced to allow manual addition of floor plans with custom table configurations.
|
|
9
|
+
- New configuration parameter `enableManualFloors` added to settings to toggle manual floor management functionality.
|
|
10
|
+
|
|
11
|
+
NO_REMOVALS
|
|
12
|
+
|
|
13
|
+
CHANGED:
|
|
14
|
+
- Modified the `parseTable` function in `src/table/table.service.js` to change the `floor` property assignment from `table.floor` to `table.floor || 0`, adding a default value of 0.
|
|
15
|
+
- Modified the `getAvailableTimeblocks` function in `src/table/table.service.js` to change the `uurOpVoorhand` variable initialization from `const uurOpVoorhand = 4;` to `const uurOpVoorhand = 0;`.
|
|
16
|
+
- Modified the `getAvailableTimeblocks` function in `src/table/table.service.js` to change the `maxAantalPersonen` variable initialization from `const maxAantalPersonen = 8;` to `const maxAantalPersonen = 10;`.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
**Author:** houssammk123
|
|
21
|
+
**Date:** 2026-02-14
|
|
22
|
+
**PR Link:** https://github.com/thibaultvandesompele2/15-happy-algorithm/pull/15
|
package/package.json
CHANGED
|
@@ -47,6 +47,9 @@ function getDataByDayAndMeal(data, dayOfWeek, mealType) {
|
|
|
47
47
|
return null;
|
|
48
48
|
}
|
|
49
49
|
const mealData = data[mealKey];
|
|
50
|
+
if (!mealData.schemeSettings) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
50
53
|
const dayData = mealData.schemeSettings[dayOfWeek];
|
|
51
54
|
if (!dayData) {
|
|
52
55
|
return null;
|
package/tableHelpers.js
CHANGED
|
@@ -72,71 +72,63 @@ function getFloorIdForSeatPlace(restaurantData, seatPlace) {
|
|
|
72
72
|
* @param {string|null} selectedZitplaats - Optional seat place to filter by linked floor.
|
|
73
73
|
* @returns {Array} An array of processed table objects.
|
|
74
74
|
*/
|
|
75
|
-
/**
|
|
76
|
-
* Safely parse int from MongoDB $numberInt or plain value, with fallback.
|
|
77
|
-
*/
|
|
78
|
-
function safeInt(val, fallback) {
|
|
79
|
-
if (val == null) return fallback;
|
|
80
|
-
if (typeof val === 'object' && val !== null && val.$numberInt != null) {
|
|
81
|
-
const parsed = parseInt(val.$numberInt, 10);
|
|
82
|
-
return isNaN(parsed) ? fallback : parsed;
|
|
83
|
-
}
|
|
84
|
-
if (typeof val === 'number' && !isNaN(val)) return val;
|
|
85
|
-
const parsed = parseInt(val, 10);
|
|
86
|
-
return isNaN(parsed) ? fallback : parsed;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
75
|
function getAllTables(restaurantData, selectedZitplaats) {
|
|
90
76
|
let allTables = [];
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
let floorsToUse = allFloors;
|
|
103
|
-
if (selectedZitplaats) {
|
|
104
|
-
const linkedFloorId = getFloorIdForSeatPlace(restaurantData, selectedZitplaats);
|
|
105
|
-
if (linkedFloorId) {
|
|
106
|
-
const linkedFloor = allFloors.find(f => f.id === linkedFloorId);
|
|
107
|
-
if (linkedFloor) {
|
|
108
|
-
floorsToUse = [linkedFloor];
|
|
109
|
-
console.log(`[getAllTables] Floor link found: zitplaats '${selectedZitplaats}' -> floor '${linkedFloorId}'`);
|
|
77
|
+
if (restaurantData?.floors && Array.isArray(restaurantData.floors)) {
|
|
78
|
+
// If a zitplaats is specified and has a floor link, only use that floor
|
|
79
|
+
let floorsToUse = restaurantData.floors;
|
|
80
|
+
if (selectedZitplaats) {
|
|
81
|
+
const linkedFloorId = getFloorIdForSeatPlace(restaurantData, selectedZitplaats);
|
|
82
|
+
if (linkedFloorId) {
|
|
83
|
+
const linkedFloor = restaurantData.floors.find(f => f.id === linkedFloorId);
|
|
84
|
+
if (linkedFloor) {
|
|
85
|
+
floorsToUse = [linkedFloor];
|
|
86
|
+
console.log(`[getAllTables] Floor link found: zitplaats '${selectedZitplaats}' -> floor '${linkedFloorId}'`);
|
|
87
|
+
}
|
|
110
88
|
}
|
|
111
89
|
}
|
|
112
|
-
}
|
|
113
90
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
91
|
+
floorsToUse.forEach(floor => {
|
|
92
|
+
if (floor?.tables && Array.isArray(floor.tables)) {
|
|
93
|
+
floor.tables.forEach(tbl => {
|
|
94
|
+
// Ensure table number, capacities, priority exist before parsing
|
|
95
|
+
const tableNumberRaw = tbl.tableNumber?.$numberInt ?? tbl.tableNumber;
|
|
96
|
+
const minCapacityRaw = tbl.minCapacity?.$numberInt ?? tbl.minCapacity;
|
|
97
|
+
const maxCapacityRaw = tbl.maxCapacity?.$numberInt ?? tbl.maxCapacity;
|
|
98
|
+
const priorityRaw = tbl.priority?.$numberInt ?? tbl.priority;
|
|
99
|
+
const xRaw = tbl.x?.$numberInt ?? tbl.x;
|
|
100
|
+
const yRaw = tbl.y?.$numberInt ?? tbl.y;
|
|
101
|
+
|
|
102
|
+
if (tbl.objectType === "Tafel" &&
|
|
103
|
+
tableNumberRaw !== undefined &&
|
|
104
|
+
minCapacityRaw !== undefined &&
|
|
105
|
+
maxCapacityRaw !== undefined &&
|
|
106
|
+
priorityRaw !== undefined &&
|
|
107
|
+
xRaw !== undefined &&
|
|
108
|
+
yRaw !== undefined)
|
|
109
|
+
{
|
|
110
|
+
allTables.push({
|
|
111
|
+
tableId: tbl.id,
|
|
112
|
+
tableNumber: parseInt(tableNumberRaw, 10),
|
|
113
|
+
minCapacity: parseInt(minCapacityRaw, 10),
|
|
114
|
+
maxCapacity: parseInt(maxCapacityRaw, 10),
|
|
115
|
+
priority: parseInt(priorityRaw, 10),
|
|
116
|
+
x: parseInt(xRaw, 10),
|
|
117
|
+
y: parseInt(yRaw, 10),
|
|
118
|
+
isTemporary: tbl.isTemporary === true, // Ensure boolean
|
|
119
|
+
startDate: tbl.startDate || null, // Expects 'YYYY-MM-DD'
|
|
120
|
+
endDate: tbl.endDate || null, // Expects 'YYYY-MM-DD'
|
|
121
|
+
application: tbl.application || null // Expects 'breakfast', 'lunch', or 'dinner'
|
|
122
|
+
});
|
|
123
|
+
} else if (tbl.objectType === "Tafel") {
|
|
124
|
+
console.warn(`Skipping table due to missing essential properties: ${JSON.stringify(tbl)}`);
|
|
122
125
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
x: safeInt(tbl.x, 0),
|
|
130
|
-
y: safeInt(tbl.y, 0),
|
|
131
|
-
isTemporary: tbl.isTemporary === true,
|
|
132
|
-
startDate: tbl.startDate || null,
|
|
133
|
-
endDate: tbl.endDate || null,
|
|
134
|
-
application: tbl.application || null
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
});
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
} else {
|
|
130
|
+
console.warn("Restaurant data is missing 'floors' array.");
|
|
131
|
+
}
|
|
140
132
|
|
|
141
133
|
// Sort tables
|
|
142
134
|
allTables.sort((a, b) => {
|
|
@@ -144,11 +136,22 @@ function getAllTables(restaurantData, selectedZitplaats) {
|
|
|
144
136
|
return a.maxCapacity - b.maxCapacity;
|
|
145
137
|
}
|
|
146
138
|
if (a.priority !== b.priority) {
|
|
139
|
+
// Assuming lower priority number means higher priority
|
|
147
140
|
return a.priority - b.priority;
|
|
148
141
|
}
|
|
149
142
|
return a.minCapacity - b.minCapacity;
|
|
150
143
|
});
|
|
151
144
|
|
|
145
|
+
// Filter out tables where parsing failed (resulted in NaN)
|
|
146
|
+
allTables = allTables.filter(t =>
|
|
147
|
+
!isNaN(t.tableNumber) &&
|
|
148
|
+
!isNaN(t.minCapacity) &&
|
|
149
|
+
!isNaN(t.maxCapacity) &&
|
|
150
|
+
!isNaN(t.priority) &&
|
|
151
|
+
!isNaN(t.x) &&
|
|
152
|
+
!isNaN(t.y)
|
|
153
|
+
);
|
|
154
|
+
|
|
152
155
|
return allTables;
|
|
153
156
|
}
|
|
154
157
|
|