@happychef/algorithm 1.0.3 → 1.1.0
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/RESERVERINGEN_GIDS.md +986 -0
- package/getAvailableTimeblocks.js +7 -6
- package/index.js +7 -27
- package/isDateAvailable.js +5 -4
- package/isDateAvailableWithTableCheck.js +5 -3
- package/isTimeAvailable.js +3 -2
- package/package.json +1 -1
- package/processing/timeblocksAvailable.js +3 -3
- package/tables/assignment/assignTablesForGivenTime.js +0 -79
- package/tables/assignment/filterTimeblocksByTableAvailability.js +0 -48
- package/tables/availability/findMultiTableCombination.js +0 -100
- package/tables/availability/getAvailableTablesForTime.js +0 -106
- package/tables/availability/isTimeAvailableSync.js +0 -128
- package/tables/data/extractTableNumbers.js +0 -17
- package/tables/data/getActualTableAssignment.js +0 -16
- package/tables/data/getAllTables.js +0 -84
- package/tables/main.js +0 -33
- package/tables/time/computeRequiredSlots.js +0 -27
- package/tables/time/getMealTypeByTime.js +0 -26
- package/tables/utils/safeParseInt.js +0 -29
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
const safeParseInt = require('../utils/safeParseInt');
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Extracts actual table numbers from a reservation's tables array.
|
|
5
|
-
* Handles MongoDB $numberInt format.
|
|
6
|
-
*/
|
|
7
|
-
function extractTableNumbers(tablesArray) {
|
|
8
|
-
if (!Array.isArray(tablesArray)) {
|
|
9
|
-
return [];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return tablesArray
|
|
13
|
-
.map(table => safeParseInt(table, null))
|
|
14
|
-
.filter(tableNum => tableNum !== null);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
module.exports = extractTableNumbers;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
const extractTableNumbers = require('./extractTableNumbers');
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Gets actual table assignments from reservation data if available.
|
|
5
|
-
* @param {Object} reservation - The reservation object
|
|
6
|
-
* @returns {Array} Array of table numbers that are actually assigned, or empty array if no data
|
|
7
|
-
*/
|
|
8
|
-
function getActualTableAssignment(reservation) {
|
|
9
|
-
if (reservation.tables && Array.isArray(reservation.tables)) {
|
|
10
|
-
const tableNumbers = extractTableNumbers(reservation.tables);
|
|
11
|
-
return tableNumbers;
|
|
12
|
-
}
|
|
13
|
-
return [];
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
module.exports = getActualTableAssignment;
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Extracts and processes table data from the restaurantData object.
|
|
3
|
-
* Includes temporary table properties, zitplaats filtering, and sorts tables.
|
|
4
|
-
* @param {Object} restaurantData - The main restaurant data object.
|
|
5
|
-
* @param {string} selectedZitplaats - Optional zitplaats value to filter tables by.
|
|
6
|
-
* @returns {Array} An array of processed table objects.
|
|
7
|
-
*/
|
|
8
|
-
function getAllTables(restaurantData, selectedZitplaats = null) {
|
|
9
|
-
let allTables = [];
|
|
10
|
-
if (restaurantData?.floors && Array.isArray(restaurantData.floors)) {
|
|
11
|
-
restaurantData.floors.forEach(floor => {
|
|
12
|
-
if (floor?.tables && Array.isArray(floor.tables)) {
|
|
13
|
-
floor.tables.forEach(tbl => {
|
|
14
|
-
// Ensure table number, capacities, priority exist before parsing
|
|
15
|
-
const tableNumberRaw = tbl.tableNumber?.$numberInt ?? tbl.tableNumber;
|
|
16
|
-
const minCapacityRaw = tbl.minCapacity?.$numberInt ?? tbl.minCapacity;
|
|
17
|
-
const maxCapacityRaw = tbl.maxCapacity?.$numberInt ?? tbl.maxCapacity;
|
|
18
|
-
const priorityRaw = tbl.priority?.$numberInt ?? tbl.priority;
|
|
19
|
-
const xRaw = tbl.x?.$numberInt ?? tbl.x;
|
|
20
|
-
const yRaw = tbl.y?.$numberInt ?? tbl.y;
|
|
21
|
-
|
|
22
|
-
// Skip tables that don't match the selected zitplaats (if one is selected)
|
|
23
|
-
if (selectedZitplaats && selectedZitplaats.trim() !== '' && tbl.zitplaats !== selectedZitplaats) {
|
|
24
|
-
return; // Skip this table
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (tbl.objectType === "Tafel" &&
|
|
28
|
-
tableNumberRaw !== undefined &&
|
|
29
|
-
minCapacityRaw !== undefined &&
|
|
30
|
-
maxCapacityRaw !== undefined &&
|
|
31
|
-
priorityRaw !== undefined &&
|
|
32
|
-
xRaw !== undefined &&
|
|
33
|
-
yRaw !== undefined)
|
|
34
|
-
{
|
|
35
|
-
allTables.push({
|
|
36
|
-
tableId: tbl.id,
|
|
37
|
-
tableNumber: parseInt(tableNumberRaw, 10),
|
|
38
|
-
minCapacity: parseInt(minCapacityRaw, 10),
|
|
39
|
-
maxCapacity: parseInt(maxCapacityRaw, 10),
|
|
40
|
-
priority: parseInt(priorityRaw, 10),
|
|
41
|
-
x: parseInt(xRaw, 10),
|
|
42
|
-
y: parseInt(yRaw, 10),
|
|
43
|
-
isTemporary: tbl.isTemporary === true, // Ensure boolean
|
|
44
|
-
startDate: tbl.startDate || null, // Expects 'YYYY-MM-DD'
|
|
45
|
-
endDate: tbl.endDate || null, // Expects 'YYYY-MM-DD'
|
|
46
|
-
application: tbl.application || null, // Expects 'breakfast', 'lunch', or 'dinner'
|
|
47
|
-
zitplaats: tbl.zitplaats || null // Add zitplaats to the table object
|
|
48
|
-
});
|
|
49
|
-
} else if (tbl.objectType === "Tafel") {
|
|
50
|
-
console.warn(`Skipping table due to missing essential properties: ${JSON.stringify(tbl)}`);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
} else {
|
|
56
|
-
console.warn("Restaurant data is missing 'floors' array.");
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Sort tables
|
|
60
|
-
allTables.sort((a, b) => {
|
|
61
|
-
if (a.maxCapacity !== b.maxCapacity) {
|
|
62
|
-
return a.maxCapacity - b.maxCapacity;
|
|
63
|
-
}
|
|
64
|
-
if (a.priority !== b.priority) {
|
|
65
|
-
// Assuming lower priority number means higher priority
|
|
66
|
-
return a.priority - b.priority;
|
|
67
|
-
}
|
|
68
|
-
return a.minCapacity - b.minCapacity;
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
// Filter out tables where parsing failed (resulted in NaN)
|
|
72
|
-
allTables = allTables.filter(t =>
|
|
73
|
-
!isNaN(t.tableNumber) &&
|
|
74
|
-
!isNaN(t.minCapacity) &&
|
|
75
|
-
!isNaN(t.maxCapacity) &&
|
|
76
|
-
!isNaN(t.priority) &&
|
|
77
|
-
!isNaN(t.x) &&
|
|
78
|
-
!isNaN(t.y)
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
return allTables;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
module.exports = getAllTables;
|
package/tables/main.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
// Central public API for all table logic (replaces simulateTableAssignment.js)
|
|
2
|
-
|
|
3
|
-
// Import primitives directly from their files to avoid circular deps.
|
|
4
|
-
const isTimeAvailableSync = require('./availability/isTimeAvailableSync');
|
|
5
|
-
const getAvailableTablesForTime = require('./availability/getAvailableTablesForTime');
|
|
6
|
-
const filterTimeblocksByTableAvailability = require('./assignment/filterTimeblocksByTableAvailability');
|
|
7
|
-
|
|
8
|
-
// Keep backward compatibility: expose getAvailableTimeblocksWithTableCheck
|
|
9
|
-
// as an alias of filterTimeblocksByTableAvailability so existing imports continue to work.
|
|
10
|
-
const getAvailableTimeblocksWithTableCheck = (
|
|
11
|
-
restaurantData,
|
|
12
|
-
date,
|
|
13
|
-
timeblocks,
|
|
14
|
-
guests,
|
|
15
|
-
reservations,
|
|
16
|
-
selectedZitplaats = null
|
|
17
|
-
) =>
|
|
18
|
-
filterTimeblocksByTableAvailability(
|
|
19
|
-
restaurantData,
|
|
20
|
-
date,
|
|
21
|
-
timeblocks,
|
|
22
|
-
guests,
|
|
23
|
-
reservations,
|
|
24
|
-
selectedZitplaats
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
module.exports = {
|
|
28
|
-
isTimeAvailableSync,
|
|
29
|
-
filterTimeblocksByTableAvailability,
|
|
30
|
-
getAvailableTimeblocksWithTableCheck,
|
|
31
|
-
getAvailableTablesForTime,
|
|
32
|
-
// assignTablesForGivenTime
|
|
33
|
-
};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Converts a reservation's start time and duration into discrete time slots (in minutes from midnight).
|
|
3
|
-
*/
|
|
4
|
-
function computeRequiredSlots(timeString, durationMinutes, intervalMinutes) {
|
|
5
|
-
const timePattern = /^([01]\d|2[0-3]):([0-5]\d)$/;
|
|
6
|
-
if (!timeString || !timePattern.test(timeString)) {
|
|
7
|
-
return [];
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const [hour, minute] = timeString.split(":").map(Number);
|
|
11
|
-
const startMinutes = hour * 60 + minute;
|
|
12
|
-
|
|
13
|
-
if (intervalMinutes <= 0) {
|
|
14
|
-
return [startMinutes];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const slotCount = Math.ceil(durationMinutes / intervalMinutes);
|
|
18
|
-
|
|
19
|
-
const slots = [];
|
|
20
|
-
for (let i = 0; i < slotCount; i++) {
|
|
21
|
-
slots.push(startMinutes + i * intervalMinutes);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return slots;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
module.exports = computeRequiredSlots;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
const parseTime = require('./parseTime');
|
|
2
|
-
const { shifts } = require('./shifts');
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Determines the meal type ('breakfast', 'lunch', 'dinner') for a given time string ("HH:MM").
|
|
6
|
-
* Returns null if the time doesn't fall into a defined shift.
|
|
7
|
-
*/
|
|
8
|
-
function getMealTypeByTime(timeStr) {
|
|
9
|
-
const time = parseTime(timeStr);
|
|
10
|
-
if (isNaN(time)) return null;
|
|
11
|
-
|
|
12
|
-
for (const [mealType, shift] of Object.entries(shifts)) {
|
|
13
|
-
const start = parseTime(shift.start);
|
|
14
|
-
const end = parseTime(shift.end);
|
|
15
|
-
// Handle potential errors from parseTime if shift definitions are invalid
|
|
16
|
-
if (isNaN(start) || isNaN(end)) continue;
|
|
17
|
-
|
|
18
|
-
// Check if time falls within the shift range [start, end)
|
|
19
|
-
if (time >= start && time < end) {
|
|
20
|
-
return mealType;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return null; // Return null if no matching shift is found
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
module.exports = getMealTypeByTime;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Robust helper for parsing numeric values from various formats.
|
|
3
|
-
* Handles MongoDB $numberInt format and regular values.
|
|
4
|
-
*/
|
|
5
|
-
function safeParseInt(val, defaultValue) {
|
|
6
|
-
if (val === undefined || val === null) return defaultValue;
|
|
7
|
-
|
|
8
|
-
if (typeof val === 'object' && val !== null && '$numberInt' in val) {
|
|
9
|
-
try {
|
|
10
|
-
const parsed = parseInt(val.$numberInt, 10);
|
|
11
|
-
if (!isNaN(parsed)) return parsed;
|
|
12
|
-
} catch (e) {}
|
|
13
|
-
return defaultValue;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (typeof val === 'number' && !isNaN(val)) {
|
|
17
|
-
return val;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (typeof val === 'string') {
|
|
21
|
-
try {
|
|
22
|
-
const parsed = parseInt(val, 10);
|
|
23
|
-
if (!isNaN(parsed)) return parsed;
|
|
24
|
-
} catch (e) {}
|
|
25
|
-
}
|
|
26
|
-
return defaultValue;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
module.exports = safeParseInt;
|