@happychef/algorithm 1.2.29 → 1.2.30

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 CHANGED
@@ -236,9 +236,11 @@ async function assignTablesIfPossible({
236
236
  }
237
237
  }
238
238
 
239
- // 2) Get floors data directly from the restaurant document
240
- let floorsData = restaurantSettings.floors;
241
- if (!floorsData || !Array.isArray(floorsData) || floorsData.length === 0) {
239
+ // 2) Get floors data directly from the restaurant document (include manualFloors)
240
+ const regularFloors = Array.isArray(restaurantSettings.floors) ? restaurantSettings.floors : [];
241
+ const manualFloors = Array.isArray(restaurantSettings.manualFloors) ? restaurantSettings.manualFloors : [];
242
+ let floorsData = [...regularFloors, ...manualFloors];
243
+ if (floorsData.length === 0) {
242
244
  if (enforceTableAvailability) {
243
245
  throw new Error('No floors data found in restaurant document.');
244
246
  } else {
@@ -257,21 +259,31 @@ async function assignTablesIfPossible({
257
259
  }
258
260
  }
259
261
 
260
- // 3) Helper to collect tables from floors
262
+ // 3) Helper to safely parse int from MongoDB $numberInt or plain value
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
261
271
  function collectTablesFromFloors(floors) {
262
272
  const tables = [];
263
273
  floors.forEach(floor => {
264
274
  if (floor.tables && Array.isArray(floor.tables)) {
265
275
  floor.tables.forEach(tbl => {
266
276
  if (tbl.objectType === "Tafel") {
277
+ const tableNumber = safeInt(tbl.tableNumber, null);
278
+ if (tableNumber == null) return; // skip tables without a number
267
279
  tables.push({
268
280
  tableId: tbl.id,
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),
281
+ tableNumber,
282
+ minCapacity: safeInt(tbl.minCapacity, 1),
283
+ maxCapacity: safeInt(tbl.maxCapacity, 99),
284
+ priority: safeInt(tbl.priority, 99),
285
+ x: safeInt(tbl.x, 0),
286
+ y: safeInt(tbl.y, 0),
275
287
  isTemporary: tbl.isTemporary === true,
276
288
  startDate: tbl.startDate || null,
277
289
  endDate: tbl.endDate || null,
package/bundle_entry.js CHANGED
@@ -96,5 +96,5 @@ globalThis.HappyAlgorithm = {
96
96
  },
97
97
 
98
98
  // Version info
99
- VERSION: '1.2.28'
99
+ VERSION: '1.2.29'
100
100
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happychef/algorithm",
3
- "version": "1.2.29",
3
+ "version": "1.2.30",
4
4
  "description": "Restaurant and reservation algorithm utilities",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/tableHelpers.js CHANGED
@@ -72,63 +72,71 @@ 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
+
75
89
  function getAllTables(restaurantData, selectedZitplaats) {
76
90
  let allTables = [];
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
- }
91
+ // Combine regular floors and manualFloors
92
+ const regularFloors = Array.isArray(restaurantData?.floors) ? restaurantData.floors : [];
93
+ const manualFloors = Array.isArray(restaurantData?.manualFloors) ? restaurantData.manualFloors : [];
94
+ let allFloors = [...regularFloors, ...manualFloors];
95
+
96
+ if (allFloors.length === 0) {
97
+ console.warn("Restaurant data is missing 'floors' array.");
98
+ return allTables;
99
+ }
100
+
101
+ // If a zitplaats is specified and has a floor link, only use that floor
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}'`);
88
110
  }
89
111
  }
112
+ }
90
113
 
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)}`);
114
+ floorsToUse.forEach(floor => {
115
+ if (floor?.tables && Array.isArray(floor.tables)) {
116
+ floor.tables.forEach(tbl => {
117
+ if (tbl.objectType === "Tafel") {
118
+ const tableNumber = safeInt(tbl.tableNumber, NaN);
119
+ if (isNaN(tableNumber)) {
120
+ console.warn(`Skipping table without valid tableNumber: ${JSON.stringify(tbl)}`);
121
+ return;
125
122
  }
126
- });
127
- }
128
- });
129
- } else {
130
- console.warn("Restaurant data is missing 'floors' array.");
131
- }
123
+ allTables.push({
124
+ tableId: tbl.id,
125
+ tableNumber,
126
+ minCapacity: safeInt(tbl.minCapacity, 1),
127
+ maxCapacity: safeInt(tbl.maxCapacity, 99),
128
+ priority: safeInt(tbl.priority, 99),
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
+ });
132
140
 
133
141
  // Sort tables
134
142
  allTables.sort((a, b) => {
@@ -136,22 +144,11 @@ function getAllTables(restaurantData, selectedZitplaats) {
136
144
  return a.maxCapacity - b.maxCapacity;
137
145
  }
138
146
  if (a.priority !== b.priority) {
139
- // Assuming lower priority number means higher priority
140
147
  return a.priority - b.priority;
141
148
  }
142
149
  return a.minCapacity - b.minCapacity;
143
150
  });
144
151
 
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
-
155
152
  return allTables;
156
153
  }
157
154