order3000 0.8.2 → 0.10.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/dist/client.cjs +174 -0
- package/dist/client.d.cts +258 -76
- package/dist/client.d.mts +258 -76
- package/dist/client.mjs +174 -1
- package/package.json +2 -2
package/dist/client.cjs
CHANGED
|
@@ -126,6 +126,49 @@ class BaseResource {
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
class BasketsResource extends BaseResource {
|
|
130
|
+
constructor(tokenManager, baseUrl) {
|
|
131
|
+
super(tokenManager, baseUrl, "/baskets");
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get the current basket for a session
|
|
135
|
+
* @param sessionId - The session identifier (from cookie)
|
|
136
|
+
* @returns The basket with all items, or null if no basket exists
|
|
137
|
+
*/
|
|
138
|
+
async get(sessionId) {
|
|
139
|
+
return this.request(
|
|
140
|
+
"GET",
|
|
141
|
+
`?sessionId=${encodeURIComponent(sessionId)}`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Add an item to the basket
|
|
146
|
+
* Creates basket and guest customer if they don't exist
|
|
147
|
+
* @param request - The add to basket request
|
|
148
|
+
* @returns The response with basket item ID and item count
|
|
149
|
+
*/
|
|
150
|
+
async add(request) {
|
|
151
|
+
return this.request("POST", "/items", request);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Remove an item from the basket.
|
|
155
|
+
*
|
|
156
|
+
* Since each basket item represents a single physical product,
|
|
157
|
+
* removing it removes the entire item. There is no partial removal.
|
|
158
|
+
*
|
|
159
|
+
* @param sessionId - The session identifier
|
|
160
|
+
* @param basketItemId - The basket item ID to remove
|
|
161
|
+
* @returns The response with item count
|
|
162
|
+
*/
|
|
163
|
+
async remove(sessionId, basketItemId) {
|
|
164
|
+
const params = new URLSearchParams({ sessionId });
|
|
165
|
+
return this.request(
|
|
166
|
+
"DELETE",
|
|
167
|
+
`/items/${basketItemId}?${params.toString()}`
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
129
172
|
class EventsResource extends BaseResource {
|
|
130
173
|
constructor(tokenManager, baseUrl) {
|
|
131
174
|
super(tokenManager, baseUrl, "/events");
|
|
@@ -172,6 +215,20 @@ class EventsResource extends BaseResource {
|
|
|
172
215
|
async get(eventId) {
|
|
173
216
|
return this.request("GET", `/${eventId}`);
|
|
174
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Get an event by accessor (slug)
|
|
220
|
+
* @param accessor - The event accessor (e.g., 'lunch-menu')
|
|
221
|
+
* @param options - Optional expand options
|
|
222
|
+
* @returns The event with optional schedule, timeSlots, menus, and posters
|
|
223
|
+
*/
|
|
224
|
+
async getByAccessor(accessor, options) {
|
|
225
|
+
const queryString = this.buildQueryString(options);
|
|
226
|
+
return this.request("GET", `/${accessor}${queryString}`);
|
|
227
|
+
}
|
|
228
|
+
buildQueryString(options) {
|
|
229
|
+
if (!options?.expand?.length) return "";
|
|
230
|
+
return `?expand=${options.expand.join(",")}`;
|
|
231
|
+
}
|
|
175
232
|
}
|
|
176
233
|
|
|
177
234
|
class MenusResource extends BaseResource {
|
|
@@ -443,11 +500,126 @@ class RealtimeManager {
|
|
|
443
500
|
}
|
|
444
501
|
}
|
|
445
502
|
|
|
503
|
+
const ALL_DAYS = [
|
|
504
|
+
"monday",
|
|
505
|
+
"tuesday",
|
|
506
|
+
"wednesday",
|
|
507
|
+
"thursday",
|
|
508
|
+
"friday",
|
|
509
|
+
"saturday",
|
|
510
|
+
"sunday"
|
|
511
|
+
];
|
|
512
|
+
const RRULE_DAY_MAP = {
|
|
513
|
+
MO: "monday",
|
|
514
|
+
TU: "tuesday",
|
|
515
|
+
WE: "wednesday",
|
|
516
|
+
TH: "thursday",
|
|
517
|
+
FR: "friday",
|
|
518
|
+
SA: "saturday",
|
|
519
|
+
SU: "sunday"
|
|
520
|
+
};
|
|
521
|
+
function parseDaysFromRRule(rrule) {
|
|
522
|
+
if (!rrule) {
|
|
523
|
+
return [];
|
|
524
|
+
}
|
|
525
|
+
const byDayMatch = rrule.match(/BYDAY=([^;]+)/);
|
|
526
|
+
if (!byDayMatch) {
|
|
527
|
+
return [];
|
|
528
|
+
}
|
|
529
|
+
const rruleDays = byDayMatch[1].split(",");
|
|
530
|
+
const days = [];
|
|
531
|
+
for (const rruleDay of rruleDays) {
|
|
532
|
+
const day = RRULE_DAY_MAP[rruleDay.trim()];
|
|
533
|
+
if (day) {
|
|
534
|
+
days.push(day);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
return ALL_DAYS.filter((day) => days.includes(day));
|
|
538
|
+
}
|
|
539
|
+
function addMinutesToTime(time, minutes) {
|
|
540
|
+
const parts = time.split(":");
|
|
541
|
+
const hours = parseInt(parts[0], 10);
|
|
542
|
+
const mins = parseInt(parts[1], 10);
|
|
543
|
+
const totalMinutes = hours * 60 + mins + minutes;
|
|
544
|
+
const newHours = Math.floor(totalMinutes / 60) % 24;
|
|
545
|
+
const newMins = totalMinutes % 60;
|
|
546
|
+
return `${newHours.toString().padStart(2, "0")}:${newMins.toString().padStart(2, "0")}`;
|
|
547
|
+
}
|
|
548
|
+
function formatTime(time) {
|
|
549
|
+
const parts = time.split(":");
|
|
550
|
+
if (parts.length >= 2) {
|
|
551
|
+
return `${parts[0]}:${parts[1]}`;
|
|
552
|
+
}
|
|
553
|
+
return time;
|
|
554
|
+
}
|
|
555
|
+
function getScheduleInfo(schedule) {
|
|
556
|
+
const defaultData = {
|
|
557
|
+
timeRange: null,
|
|
558
|
+
activeDays: []
|
|
559
|
+
};
|
|
560
|
+
if (!schedule?.scheduleTimeSlots?.length) {
|
|
561
|
+
return defaultData;
|
|
562
|
+
}
|
|
563
|
+
const timeSlots = schedule.scheduleTimeSlots;
|
|
564
|
+
const rrule = schedule.rrule;
|
|
565
|
+
const intervalMinutes = schedule.intervalMinutes ?? 30;
|
|
566
|
+
const activeDaysSet = /* @__PURE__ */ new Set();
|
|
567
|
+
let hasNullDayOfWeek = false;
|
|
568
|
+
const startTimes = [];
|
|
569
|
+
let latestEndTime = null;
|
|
570
|
+
for (const slot of timeSlots) {
|
|
571
|
+
if (slot.dayOfWeek) {
|
|
572
|
+
activeDaysSet.add(slot.dayOfWeek);
|
|
573
|
+
} else {
|
|
574
|
+
hasNullDayOfWeek = true;
|
|
575
|
+
}
|
|
576
|
+
if (slot.timeSlot.startTime) {
|
|
577
|
+
startTimes.push(slot.timeSlot.startTime);
|
|
578
|
+
}
|
|
579
|
+
if (slot.timeSlot.endTime) {
|
|
580
|
+
if (!latestEndTime || slot.timeSlot.endTime > latestEndTime) {
|
|
581
|
+
latestEndTime = slot.timeSlot.endTime;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
let activeDays;
|
|
586
|
+
if (hasNullDayOfWeek) {
|
|
587
|
+
const rruleDays = parseDaysFromRRule(rrule);
|
|
588
|
+
if (rruleDays.length > 0) {
|
|
589
|
+
activeDays = rruleDays;
|
|
590
|
+
} else {
|
|
591
|
+
activeDays = ALL_DAYS.filter((day) => activeDaysSet.has(day));
|
|
592
|
+
}
|
|
593
|
+
} else {
|
|
594
|
+
activeDays = ALL_DAYS.filter((day) => activeDaysSet.has(day));
|
|
595
|
+
}
|
|
596
|
+
let timeRange = null;
|
|
597
|
+
if (startTimes.length > 0) {
|
|
598
|
+
startTimes.sort();
|
|
599
|
+
const earliestStart = startTimes[0];
|
|
600
|
+
const latestStart = startTimes[startTimes.length - 1];
|
|
601
|
+
let endTime;
|
|
602
|
+
if (latestEndTime) {
|
|
603
|
+
endTime = latestEndTime;
|
|
604
|
+
} else {
|
|
605
|
+
endTime = addMinutesToTime(latestStart, intervalMinutes);
|
|
606
|
+
}
|
|
607
|
+
const startFormatted = formatTime(earliestStart);
|
|
608
|
+
const endFormatted = formatTime(endTime);
|
|
609
|
+
timeRange = `${startFormatted}-${endFormatted}`;
|
|
610
|
+
}
|
|
611
|
+
return {
|
|
612
|
+
timeRange,
|
|
613
|
+
activeDays
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
|
|
446
617
|
var __defProp = Object.defineProperty;
|
|
447
618
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
448
619
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
449
620
|
class Order3000Client {
|
|
450
621
|
constructor(config) {
|
|
622
|
+
__publicField(this, "baskets");
|
|
451
623
|
__publicField(this, "events");
|
|
452
624
|
__publicField(this, "menus");
|
|
453
625
|
__publicField(this, "orders");
|
|
@@ -463,6 +635,7 @@ class Order3000Client {
|
|
|
463
635
|
tokenUrl,
|
|
464
636
|
config.venueId
|
|
465
637
|
);
|
|
638
|
+
this.baskets = new BasketsResource(this.tokenManager, this.baseUrl);
|
|
466
639
|
this.events = new EventsResource(this.tokenManager, this.baseUrl);
|
|
467
640
|
this.menus = new MenusResource(this.tokenManager, this.baseUrl);
|
|
468
641
|
this.orders = new OrdersResource(this.tokenManager, this.baseUrl);
|
|
@@ -475,3 +648,4 @@ class Order3000Client {
|
|
|
475
648
|
}
|
|
476
649
|
|
|
477
650
|
exports.Order3000Client = Order3000Client;
|
|
651
|
+
exports.getScheduleInfo = getScheduleInfo;
|
package/dist/client.d.cts
CHANGED
|
@@ -22,11 +22,84 @@ declare abstract class BaseResource {
|
|
|
22
22
|
protected readonly baseUrl: string;
|
|
23
23
|
protected readonly resourcePath: string;
|
|
24
24
|
constructor(tokenManager: TokenManager, baseUrl: string, resourcePath: string);
|
|
25
|
-
protected request<T>(method: 'GET' | 'POST', path: string, data?:
|
|
25
|
+
protected request<T>(method: 'GET' | 'POST' | 'DELETE', path: string, data?: unknown): Promise<T>;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
interface components {
|
|
29
29
|
schemas: {
|
|
30
|
+
/**
|
|
31
|
+
* CreateEventRequest
|
|
32
|
+
* @description Request payload for creating a new event
|
|
33
|
+
*/
|
|
34
|
+
CreateEventRequest: {
|
|
35
|
+
accessor?: string | null;
|
|
36
|
+
name: (string | number | boolean | (null)) | {
|
|
37
|
+
[key: string]: unknown;
|
|
38
|
+
} | unknown[];
|
|
39
|
+
description?: ((string | number | boolean | (null)) | {
|
|
40
|
+
[key: string]: unknown;
|
|
41
|
+
} | unknown[]) | null;
|
|
42
|
+
scheduleId?: string | null;
|
|
43
|
+
maxBookings?: number | null;
|
|
44
|
+
maxGuests?: number | null;
|
|
45
|
+
minPartySize?: number | null;
|
|
46
|
+
maxPartySize?: number | null;
|
|
47
|
+
isPublic?: boolean;
|
|
48
|
+
isRecurring?: boolean;
|
|
49
|
+
acceptsReservations?: boolean;
|
|
50
|
+
bookingOpensAtDays?: number | null;
|
|
51
|
+
bookingClosesAtHours?: number | null;
|
|
52
|
+
isActive?: boolean;
|
|
53
|
+
isFeatured?: boolean;
|
|
54
|
+
priority?: number;
|
|
55
|
+
schedule?: {
|
|
56
|
+
rrule?: string | null;
|
|
57
|
+
timezone?: string | null;
|
|
58
|
+
validFrom?: string | null;
|
|
59
|
+
validTo?: string | null;
|
|
60
|
+
timeRanges: {
|
|
61
|
+
startTime: string;
|
|
62
|
+
endTime: string;
|
|
63
|
+
lastSeatingTime?: string | null;
|
|
64
|
+
}[];
|
|
65
|
+
/** @enum {string|null} */
|
|
66
|
+
slotMode?: "interval" | "duration" | null;
|
|
67
|
+
intervalMinutes?: number | null;
|
|
68
|
+
durationMinutes?: number | null;
|
|
69
|
+
} | null;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* CreateEventResponse
|
|
73
|
+
* @description Successfully created event
|
|
74
|
+
*/
|
|
75
|
+
CreateEventResponse: {
|
|
76
|
+
id: string;
|
|
77
|
+
venueId: string;
|
|
78
|
+
accessor: string | null;
|
|
79
|
+
name: (string | number | boolean | (null)) | {
|
|
80
|
+
[key: string]: unknown;
|
|
81
|
+
} | unknown[];
|
|
82
|
+
description: ((string | number | boolean | (null)) | {
|
|
83
|
+
[key: string]: unknown;
|
|
84
|
+
} | unknown[]) | null;
|
|
85
|
+
scheduleId: string | null;
|
|
86
|
+
maxBookings: number | null;
|
|
87
|
+
maxGuests: number | null;
|
|
88
|
+
minPartySize: number | null;
|
|
89
|
+
maxPartySize: number | null;
|
|
90
|
+
isPublic: boolean;
|
|
91
|
+
isRecurring: boolean;
|
|
92
|
+
acceptsReservations: boolean;
|
|
93
|
+
bookingOpensAtDays: number | null;
|
|
94
|
+
bookingClosesAtHours: number | null;
|
|
95
|
+
isActive: boolean;
|
|
96
|
+
isFeatured: boolean;
|
|
97
|
+
priority: number;
|
|
98
|
+
createdBy: string | null;
|
|
99
|
+
updatedBy: string | null;
|
|
100
|
+
createdAt: unknown;
|
|
101
|
+
updatedAt: unknown;
|
|
102
|
+
};
|
|
30
103
|
/**
|
|
31
104
|
* PlaceOrderRequest
|
|
32
105
|
* @description Place a new order for a specific venue
|
|
@@ -205,79 +278,6 @@ interface components {
|
|
|
205
278
|
/** @description Last update timestamp */
|
|
206
279
|
updatedAt: unknown;
|
|
207
280
|
};
|
|
208
|
-
/**
|
|
209
|
-
* CreateEventRequest
|
|
210
|
-
* @description Request payload for creating a new event
|
|
211
|
-
*/
|
|
212
|
-
CreateEventRequest: {
|
|
213
|
-
accessor?: string | null;
|
|
214
|
-
name: (string | number | boolean | (null)) | {
|
|
215
|
-
[key: string]: unknown;
|
|
216
|
-
} | unknown[];
|
|
217
|
-
description?: ((string | number | boolean | (null)) | {
|
|
218
|
-
[key: string]: unknown;
|
|
219
|
-
} | unknown[]) | null;
|
|
220
|
-
scheduleId?: string | null;
|
|
221
|
-
maxBookings?: number | null;
|
|
222
|
-
maxGuests?: number | null;
|
|
223
|
-
minPartySize?: number | null;
|
|
224
|
-
maxPartySize?: number | null;
|
|
225
|
-
isPublic?: boolean;
|
|
226
|
-
isRecurring?: boolean;
|
|
227
|
-
acceptsReservations?: boolean;
|
|
228
|
-
bookingOpensAtDays?: number | null;
|
|
229
|
-
bookingClosesAtHours?: number | null;
|
|
230
|
-
isActive?: boolean;
|
|
231
|
-
isFeatured?: boolean;
|
|
232
|
-
priority?: number;
|
|
233
|
-
schedule?: {
|
|
234
|
-
rrule?: string | null;
|
|
235
|
-
timezone?: string | null;
|
|
236
|
-
validFrom?: string | null;
|
|
237
|
-
validTo?: string | null;
|
|
238
|
-
timeRanges: {
|
|
239
|
-
startTime: string;
|
|
240
|
-
endTime: string;
|
|
241
|
-
lastSeatingTime?: string | null;
|
|
242
|
-
}[];
|
|
243
|
-
/** @enum {string|null} */
|
|
244
|
-
slotMode?: "interval" | "duration" | null;
|
|
245
|
-
intervalMinutes?: number | null;
|
|
246
|
-
durationMinutes?: number | null;
|
|
247
|
-
} | null;
|
|
248
|
-
};
|
|
249
|
-
/**
|
|
250
|
-
* CreateEventResponse
|
|
251
|
-
* @description Successfully created event
|
|
252
|
-
*/
|
|
253
|
-
CreateEventResponse: {
|
|
254
|
-
id: string;
|
|
255
|
-
venueId: string;
|
|
256
|
-
accessor: string | null;
|
|
257
|
-
name: (string | number | boolean | (null)) | {
|
|
258
|
-
[key: string]: unknown;
|
|
259
|
-
} | unknown[];
|
|
260
|
-
description: ((string | number | boolean | (null)) | {
|
|
261
|
-
[key: string]: unknown;
|
|
262
|
-
} | unknown[]) | null;
|
|
263
|
-
scheduleId: string | null;
|
|
264
|
-
maxBookings: number | null;
|
|
265
|
-
maxGuests: number | null;
|
|
266
|
-
minPartySize: number | null;
|
|
267
|
-
maxPartySize: number | null;
|
|
268
|
-
isPublic: boolean;
|
|
269
|
-
isRecurring: boolean;
|
|
270
|
-
acceptsReservations: boolean;
|
|
271
|
-
bookingOpensAtDays: number | null;
|
|
272
|
-
bookingClosesAtHours: number | null;
|
|
273
|
-
isActive: boolean;
|
|
274
|
-
isFeatured: boolean;
|
|
275
|
-
priority: number;
|
|
276
|
-
createdBy: string | null;
|
|
277
|
-
updatedBy: string | null;
|
|
278
|
-
createdAt: unknown;
|
|
279
|
-
updatedAt: unknown;
|
|
280
|
-
};
|
|
281
281
|
};
|
|
282
282
|
responses: never;
|
|
283
283
|
parameters: never;
|
|
@@ -293,11 +293,12 @@ type PlaceOrderRequest = schemas['PlaceOrderRequest'];
|
|
|
293
293
|
type PlaceOrderResponse = schemas['PlaceOrderResponse'];
|
|
294
294
|
type MakeReservationRequest = schemas['MakeReservationRequest'];
|
|
295
295
|
type MakeReservationResponse = schemas['MakeReservationResponse'];
|
|
296
|
+
type DayOfWeek = 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday' | 'sunday';
|
|
296
297
|
interface TimeSlot {
|
|
297
298
|
id: string;
|
|
298
299
|
startTime: string;
|
|
299
300
|
endTime: string | null;
|
|
300
|
-
dayOfWeek?:
|
|
301
|
+
dayOfWeek?: DayOfWeek | null;
|
|
301
302
|
isSchedulable: boolean | null;
|
|
302
303
|
}
|
|
303
304
|
interface ScheduleOverride {
|
|
@@ -476,6 +477,158 @@ interface GetMenuOptions {
|
|
|
476
477
|
/** Expand related resources (items, assets) */
|
|
477
478
|
expand?: ('items' | 'assets')[];
|
|
478
479
|
}
|
|
480
|
+
interface ScheduleTimeSlot {
|
|
481
|
+
dayOfWeek: DayOfWeek | null;
|
|
482
|
+
timeSlot: {
|
|
483
|
+
id: string;
|
|
484
|
+
startTime: string;
|
|
485
|
+
endTime: string | null;
|
|
486
|
+
isActive: boolean | null;
|
|
487
|
+
isSchedulable: boolean | null;
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
interface ScheduleWithTimeSlots extends Schedule {
|
|
491
|
+
scheduleTimeSlots?: ScheduleTimeSlot[];
|
|
492
|
+
}
|
|
493
|
+
interface EventMenu {
|
|
494
|
+
id: string;
|
|
495
|
+
accessor: string;
|
|
496
|
+
name: Record<string, string>;
|
|
497
|
+
category: string;
|
|
498
|
+
}
|
|
499
|
+
interface EventByAccessor {
|
|
500
|
+
id: string;
|
|
501
|
+
venueId: string;
|
|
502
|
+
accessor: string | null;
|
|
503
|
+
name: Record<string, string>;
|
|
504
|
+
description: Record<string, string> | null;
|
|
505
|
+
scheduleId: string | null;
|
|
506
|
+
maxBookings: number | null;
|
|
507
|
+
maxGuests: number | null;
|
|
508
|
+
minPartySize: number | null;
|
|
509
|
+
maxPartySize: number | null;
|
|
510
|
+
isPublic: boolean;
|
|
511
|
+
isRecurring: boolean;
|
|
512
|
+
acceptsReservations: boolean;
|
|
513
|
+
bookingOpensAtDays: number | null;
|
|
514
|
+
bookingClosesAtHours: number | null;
|
|
515
|
+
isActive: boolean;
|
|
516
|
+
isFeatured: boolean;
|
|
517
|
+
priority: number;
|
|
518
|
+
createdAt: string | null;
|
|
519
|
+
updatedAt: string | null;
|
|
520
|
+
schedule?: ScheduleWithTimeSlots;
|
|
521
|
+
menus?: EventMenu[];
|
|
522
|
+
posters?: EventPoster[];
|
|
523
|
+
}
|
|
524
|
+
interface GetEventOptions {
|
|
525
|
+
/** Expand related resources (schedule, timeSlots, menus, posters) */
|
|
526
|
+
expand?: ('schedule' | 'timeSlots' | 'menus' | 'posters')[];
|
|
527
|
+
}
|
|
528
|
+
type BasketStatus = 'active' | 'abandoned' | 'converted';
|
|
529
|
+
type Currency = 'EUR' | 'CHF';
|
|
530
|
+
/**
|
|
531
|
+
* Unit of measurement for portion tracking.
|
|
532
|
+
*/
|
|
533
|
+
type Unit = 'grams' | 'kilograms' | 'liters' | 'milliliters' | 'pieces';
|
|
534
|
+
/**
|
|
535
|
+
* Reference to a menu item within a basket item.
|
|
536
|
+
*
|
|
537
|
+
* Each menu item can have its own portion size (quantity + unit),
|
|
538
|
+
* allowing for precise tracking like "100g rice, 80g curry".
|
|
539
|
+
*/
|
|
540
|
+
interface BasketItemMenuItemRef {
|
|
541
|
+
menuItemId: string;
|
|
542
|
+
role: string | null;
|
|
543
|
+
quantity: number;
|
|
544
|
+
unit: Unit;
|
|
545
|
+
}
|
|
546
|
+
interface BasketItemMetadata {
|
|
547
|
+
type?: 'tiffinbox' | 'bowl' | 'sushi';
|
|
548
|
+
mode?: 2 | 3;
|
|
549
|
+
upsell?: {
|
|
550
|
+
tinOption: string;
|
|
551
|
+
rollOption: string;
|
|
552
|
+
};
|
|
553
|
+
price?: number;
|
|
554
|
+
[key: string]: unknown;
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* A basket item represents a single physical product in the basket.
|
|
558
|
+
*
|
|
559
|
+
* Each basket item can contain multiple menu items (e.g., a TiffinBox
|
|
560
|
+
* with rice, curry, and sides). The itemCount in the response is the
|
|
561
|
+
* COUNT of basket items, not a sum of quantities.
|
|
562
|
+
*/
|
|
563
|
+
interface BasketItem {
|
|
564
|
+
id: string;
|
|
565
|
+
metadata: BasketItemMetadata | null;
|
|
566
|
+
menuItems: BasketItemMenuItemRef[];
|
|
567
|
+
}
|
|
568
|
+
interface Basket {
|
|
569
|
+
id: string;
|
|
570
|
+
sessionId: string;
|
|
571
|
+
status: BasketStatus;
|
|
572
|
+
currency: Currency;
|
|
573
|
+
items: BasketItem[];
|
|
574
|
+
itemCount: number;
|
|
575
|
+
expiresAt: string;
|
|
576
|
+
createdAt: string | null;
|
|
577
|
+
updatedAt: string | null;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Request to add an item to the basket.
|
|
581
|
+
*
|
|
582
|
+
* Menu items can optionally include portion information (quantity/unit).
|
|
583
|
+
* If not provided, defaults to the menu item's configured portion size.
|
|
584
|
+
*/
|
|
585
|
+
interface AddToBasketRequest {
|
|
586
|
+
sessionId: string;
|
|
587
|
+
menuItems: Array<{
|
|
588
|
+
menuItemId: string;
|
|
589
|
+
role?: string;
|
|
590
|
+
quantity?: number;
|
|
591
|
+
unit?: Unit;
|
|
592
|
+
}>;
|
|
593
|
+
metadata?: BasketItemMetadata;
|
|
594
|
+
}
|
|
595
|
+
interface AddToBasketResponse {
|
|
596
|
+
basketItemId: string;
|
|
597
|
+
itemCount: number;
|
|
598
|
+
}
|
|
599
|
+
interface RemoveFromBasketResponse {
|
|
600
|
+
success: boolean;
|
|
601
|
+
basketItemId: string;
|
|
602
|
+
itemCount: number;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
declare class BasketsResource extends BaseResource {
|
|
606
|
+
constructor(tokenManager: TokenManager, baseUrl: string);
|
|
607
|
+
/**
|
|
608
|
+
* Get the current basket for a session
|
|
609
|
+
* @param sessionId - The session identifier (from cookie)
|
|
610
|
+
* @returns The basket with all items, or null if no basket exists
|
|
611
|
+
*/
|
|
612
|
+
get(sessionId: string): Promise<Basket | null>;
|
|
613
|
+
/**
|
|
614
|
+
* Add an item to the basket
|
|
615
|
+
* Creates basket and guest customer if they don't exist
|
|
616
|
+
* @param request - The add to basket request
|
|
617
|
+
* @returns The response with basket item ID and item count
|
|
618
|
+
*/
|
|
619
|
+
add(request: AddToBasketRequest): Promise<AddToBasketResponse>;
|
|
620
|
+
/**
|
|
621
|
+
* Remove an item from the basket.
|
|
622
|
+
*
|
|
623
|
+
* Since each basket item represents a single physical product,
|
|
624
|
+
* removing it removes the entire item. There is no partial removal.
|
|
625
|
+
*
|
|
626
|
+
* @param sessionId - The session identifier
|
|
627
|
+
* @param basketItemId - The basket item ID to remove
|
|
628
|
+
* @returns The response with item count
|
|
629
|
+
*/
|
|
630
|
+
remove(sessionId: string, basketItemId: string): Promise<RemoveFromBasketResponse>;
|
|
631
|
+
}
|
|
479
632
|
|
|
480
633
|
declare class EventsResource extends BaseResource {
|
|
481
634
|
constructor(tokenManager: TokenManager, baseUrl: string);
|
|
@@ -497,6 +650,14 @@ declare class EventsResource extends BaseResource {
|
|
|
497
650
|
* @returns The event details
|
|
498
651
|
*/
|
|
499
652
|
get(eventId: string): Promise<Event>;
|
|
653
|
+
/**
|
|
654
|
+
* Get an event by accessor (slug)
|
|
655
|
+
* @param accessor - The event accessor (e.g., 'lunch-menu')
|
|
656
|
+
* @param options - Optional expand options
|
|
657
|
+
* @returns The event with optional schedule, timeSlots, menus, and posters
|
|
658
|
+
*/
|
|
659
|
+
getByAccessor(accessor: string, options?: GetEventOptions): Promise<EventByAccessor>;
|
|
660
|
+
private buildQueryString;
|
|
500
661
|
}
|
|
501
662
|
|
|
502
663
|
declare class MenusResource extends BaseResource {
|
|
@@ -661,6 +822,26 @@ declare class RealtimeManager {
|
|
|
661
822
|
disconnectAll(): Promise<void>;
|
|
662
823
|
}
|
|
663
824
|
|
|
825
|
+
interface ScheduleInfo {
|
|
826
|
+
/** Time range string, e.g. "11:30-15:00" */
|
|
827
|
+
timeRange: string | null;
|
|
828
|
+
/** Active days in week order */
|
|
829
|
+
activeDays: DayOfWeek[];
|
|
830
|
+
}
|
|
831
|
+
interface ScheduleInput {
|
|
832
|
+
rrule?: string | null;
|
|
833
|
+
intervalMinutes?: number | null;
|
|
834
|
+
scheduleTimeSlots?: ScheduleTimeSlot[];
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Extract schedule information from a schedule object.
|
|
838
|
+
* Returns time range and active days for display purposes.
|
|
839
|
+
*
|
|
840
|
+
* @param schedule - Schedule object with rrule, intervalMinutes, and scheduleTimeSlots
|
|
841
|
+
* @returns ScheduleInfo with timeRange and activeDays
|
|
842
|
+
*/
|
|
843
|
+
declare function getScheduleInfo(schedule: ScheduleInput | null | undefined): ScheduleInfo;
|
|
844
|
+
|
|
664
845
|
interface Order3000ClientConfig {
|
|
665
846
|
clientId: string;
|
|
666
847
|
clientSecret: string;
|
|
@@ -677,6 +858,7 @@ interface Order3000ClientConfig {
|
|
|
677
858
|
tokenUrl?: string;
|
|
678
859
|
}
|
|
679
860
|
declare class Order3000Client {
|
|
861
|
+
baskets: BasketsResource;
|
|
680
862
|
events: EventsResource;
|
|
681
863
|
menus: MenusResource;
|
|
682
864
|
orders: OrdersResource;
|
|
@@ -687,4 +869,4 @@ declare class Order3000Client {
|
|
|
687
869
|
constructor(config: Order3000ClientConfig);
|
|
688
870
|
}
|
|
689
871
|
|
|
690
|
-
export { type CropArea, type Event, type EventPoster, type EventRow, type GetMenuOptions, type ListEventsOptions, type ListEventsResponse, type Menu, type MenuAsset, type MenuBeverage, type MenuDish, type MenuItem, type MenuItemRow, type MenuItemType, Order3000Client, type Order3000ClientConfig, type Promotion, type RealtimeConfig, type RealtimeEvent, type RealtimeSubscription, type Schedule, type ScheduleOverride, type ScheduleOverrideRow, type ScheduleRow, type SubscriptionOptions, type TimeSlot };
|
|
872
|
+
export { type AddToBasketRequest, type AddToBasketResponse, type Basket, type BasketItem, type BasketItemMenuItemRef, type BasketItemMetadata, type BasketStatus, type CropArea, type Currency, type DayOfWeek, type Event, type EventByAccessor, type EventMenu, type EventPoster, type EventRow, type GetEventOptions, type GetMenuOptions, type ListEventsOptions, type ListEventsResponse, type Menu, type MenuAsset, type MenuBeverage, type MenuDish, type MenuItem, type MenuItemRow, type MenuItemType, Order3000Client, type Order3000ClientConfig, type Promotion, type RealtimeConfig, type RealtimeEvent, type RealtimeSubscription, type RemoveFromBasketResponse, type Schedule, type ScheduleInfo, type ScheduleOverride, type ScheduleOverrideRow, type ScheduleRow, type ScheduleTimeSlot, type ScheduleWithTimeSlots, type SubscriptionOptions, type TimeSlot, type Unit, getScheduleInfo };
|
package/dist/client.d.mts
CHANGED
|
@@ -22,11 +22,84 @@ declare abstract class BaseResource {
|
|
|
22
22
|
protected readonly baseUrl: string;
|
|
23
23
|
protected readonly resourcePath: string;
|
|
24
24
|
constructor(tokenManager: TokenManager, baseUrl: string, resourcePath: string);
|
|
25
|
-
protected request<T>(method: 'GET' | 'POST', path: string, data?:
|
|
25
|
+
protected request<T>(method: 'GET' | 'POST' | 'DELETE', path: string, data?: unknown): Promise<T>;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
interface components {
|
|
29
29
|
schemas: {
|
|
30
|
+
/**
|
|
31
|
+
* CreateEventRequest
|
|
32
|
+
* @description Request payload for creating a new event
|
|
33
|
+
*/
|
|
34
|
+
CreateEventRequest: {
|
|
35
|
+
accessor?: string | null;
|
|
36
|
+
name: (string | number | boolean | (null)) | {
|
|
37
|
+
[key: string]: unknown;
|
|
38
|
+
} | unknown[];
|
|
39
|
+
description?: ((string | number | boolean | (null)) | {
|
|
40
|
+
[key: string]: unknown;
|
|
41
|
+
} | unknown[]) | null;
|
|
42
|
+
scheduleId?: string | null;
|
|
43
|
+
maxBookings?: number | null;
|
|
44
|
+
maxGuests?: number | null;
|
|
45
|
+
minPartySize?: number | null;
|
|
46
|
+
maxPartySize?: number | null;
|
|
47
|
+
isPublic?: boolean;
|
|
48
|
+
isRecurring?: boolean;
|
|
49
|
+
acceptsReservations?: boolean;
|
|
50
|
+
bookingOpensAtDays?: number | null;
|
|
51
|
+
bookingClosesAtHours?: number | null;
|
|
52
|
+
isActive?: boolean;
|
|
53
|
+
isFeatured?: boolean;
|
|
54
|
+
priority?: number;
|
|
55
|
+
schedule?: {
|
|
56
|
+
rrule?: string | null;
|
|
57
|
+
timezone?: string | null;
|
|
58
|
+
validFrom?: string | null;
|
|
59
|
+
validTo?: string | null;
|
|
60
|
+
timeRanges: {
|
|
61
|
+
startTime: string;
|
|
62
|
+
endTime: string;
|
|
63
|
+
lastSeatingTime?: string | null;
|
|
64
|
+
}[];
|
|
65
|
+
/** @enum {string|null} */
|
|
66
|
+
slotMode?: "interval" | "duration" | null;
|
|
67
|
+
intervalMinutes?: number | null;
|
|
68
|
+
durationMinutes?: number | null;
|
|
69
|
+
} | null;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* CreateEventResponse
|
|
73
|
+
* @description Successfully created event
|
|
74
|
+
*/
|
|
75
|
+
CreateEventResponse: {
|
|
76
|
+
id: string;
|
|
77
|
+
venueId: string;
|
|
78
|
+
accessor: string | null;
|
|
79
|
+
name: (string | number | boolean | (null)) | {
|
|
80
|
+
[key: string]: unknown;
|
|
81
|
+
} | unknown[];
|
|
82
|
+
description: ((string | number | boolean | (null)) | {
|
|
83
|
+
[key: string]: unknown;
|
|
84
|
+
} | unknown[]) | null;
|
|
85
|
+
scheduleId: string | null;
|
|
86
|
+
maxBookings: number | null;
|
|
87
|
+
maxGuests: number | null;
|
|
88
|
+
minPartySize: number | null;
|
|
89
|
+
maxPartySize: number | null;
|
|
90
|
+
isPublic: boolean;
|
|
91
|
+
isRecurring: boolean;
|
|
92
|
+
acceptsReservations: boolean;
|
|
93
|
+
bookingOpensAtDays: number | null;
|
|
94
|
+
bookingClosesAtHours: number | null;
|
|
95
|
+
isActive: boolean;
|
|
96
|
+
isFeatured: boolean;
|
|
97
|
+
priority: number;
|
|
98
|
+
createdBy: string | null;
|
|
99
|
+
updatedBy: string | null;
|
|
100
|
+
createdAt: unknown;
|
|
101
|
+
updatedAt: unknown;
|
|
102
|
+
};
|
|
30
103
|
/**
|
|
31
104
|
* PlaceOrderRequest
|
|
32
105
|
* @description Place a new order for a specific venue
|
|
@@ -205,79 +278,6 @@ interface components {
|
|
|
205
278
|
/** @description Last update timestamp */
|
|
206
279
|
updatedAt: unknown;
|
|
207
280
|
};
|
|
208
|
-
/**
|
|
209
|
-
* CreateEventRequest
|
|
210
|
-
* @description Request payload for creating a new event
|
|
211
|
-
*/
|
|
212
|
-
CreateEventRequest: {
|
|
213
|
-
accessor?: string | null;
|
|
214
|
-
name: (string | number | boolean | (null)) | {
|
|
215
|
-
[key: string]: unknown;
|
|
216
|
-
} | unknown[];
|
|
217
|
-
description?: ((string | number | boolean | (null)) | {
|
|
218
|
-
[key: string]: unknown;
|
|
219
|
-
} | unknown[]) | null;
|
|
220
|
-
scheduleId?: string | null;
|
|
221
|
-
maxBookings?: number | null;
|
|
222
|
-
maxGuests?: number | null;
|
|
223
|
-
minPartySize?: number | null;
|
|
224
|
-
maxPartySize?: number | null;
|
|
225
|
-
isPublic?: boolean;
|
|
226
|
-
isRecurring?: boolean;
|
|
227
|
-
acceptsReservations?: boolean;
|
|
228
|
-
bookingOpensAtDays?: number | null;
|
|
229
|
-
bookingClosesAtHours?: number | null;
|
|
230
|
-
isActive?: boolean;
|
|
231
|
-
isFeatured?: boolean;
|
|
232
|
-
priority?: number;
|
|
233
|
-
schedule?: {
|
|
234
|
-
rrule?: string | null;
|
|
235
|
-
timezone?: string | null;
|
|
236
|
-
validFrom?: string | null;
|
|
237
|
-
validTo?: string | null;
|
|
238
|
-
timeRanges: {
|
|
239
|
-
startTime: string;
|
|
240
|
-
endTime: string;
|
|
241
|
-
lastSeatingTime?: string | null;
|
|
242
|
-
}[];
|
|
243
|
-
/** @enum {string|null} */
|
|
244
|
-
slotMode?: "interval" | "duration" | null;
|
|
245
|
-
intervalMinutes?: number | null;
|
|
246
|
-
durationMinutes?: number | null;
|
|
247
|
-
} | null;
|
|
248
|
-
};
|
|
249
|
-
/**
|
|
250
|
-
* CreateEventResponse
|
|
251
|
-
* @description Successfully created event
|
|
252
|
-
*/
|
|
253
|
-
CreateEventResponse: {
|
|
254
|
-
id: string;
|
|
255
|
-
venueId: string;
|
|
256
|
-
accessor: string | null;
|
|
257
|
-
name: (string | number | boolean | (null)) | {
|
|
258
|
-
[key: string]: unknown;
|
|
259
|
-
} | unknown[];
|
|
260
|
-
description: ((string | number | boolean | (null)) | {
|
|
261
|
-
[key: string]: unknown;
|
|
262
|
-
} | unknown[]) | null;
|
|
263
|
-
scheduleId: string | null;
|
|
264
|
-
maxBookings: number | null;
|
|
265
|
-
maxGuests: number | null;
|
|
266
|
-
minPartySize: number | null;
|
|
267
|
-
maxPartySize: number | null;
|
|
268
|
-
isPublic: boolean;
|
|
269
|
-
isRecurring: boolean;
|
|
270
|
-
acceptsReservations: boolean;
|
|
271
|
-
bookingOpensAtDays: number | null;
|
|
272
|
-
bookingClosesAtHours: number | null;
|
|
273
|
-
isActive: boolean;
|
|
274
|
-
isFeatured: boolean;
|
|
275
|
-
priority: number;
|
|
276
|
-
createdBy: string | null;
|
|
277
|
-
updatedBy: string | null;
|
|
278
|
-
createdAt: unknown;
|
|
279
|
-
updatedAt: unknown;
|
|
280
|
-
};
|
|
281
281
|
};
|
|
282
282
|
responses: never;
|
|
283
283
|
parameters: never;
|
|
@@ -293,11 +293,12 @@ type PlaceOrderRequest = schemas['PlaceOrderRequest'];
|
|
|
293
293
|
type PlaceOrderResponse = schemas['PlaceOrderResponse'];
|
|
294
294
|
type MakeReservationRequest = schemas['MakeReservationRequest'];
|
|
295
295
|
type MakeReservationResponse = schemas['MakeReservationResponse'];
|
|
296
|
+
type DayOfWeek = 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday' | 'sunday';
|
|
296
297
|
interface TimeSlot {
|
|
297
298
|
id: string;
|
|
298
299
|
startTime: string;
|
|
299
300
|
endTime: string | null;
|
|
300
|
-
dayOfWeek?:
|
|
301
|
+
dayOfWeek?: DayOfWeek | null;
|
|
301
302
|
isSchedulable: boolean | null;
|
|
302
303
|
}
|
|
303
304
|
interface ScheduleOverride {
|
|
@@ -476,6 +477,158 @@ interface GetMenuOptions {
|
|
|
476
477
|
/** Expand related resources (items, assets) */
|
|
477
478
|
expand?: ('items' | 'assets')[];
|
|
478
479
|
}
|
|
480
|
+
interface ScheduleTimeSlot {
|
|
481
|
+
dayOfWeek: DayOfWeek | null;
|
|
482
|
+
timeSlot: {
|
|
483
|
+
id: string;
|
|
484
|
+
startTime: string;
|
|
485
|
+
endTime: string | null;
|
|
486
|
+
isActive: boolean | null;
|
|
487
|
+
isSchedulable: boolean | null;
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
interface ScheduleWithTimeSlots extends Schedule {
|
|
491
|
+
scheduleTimeSlots?: ScheduleTimeSlot[];
|
|
492
|
+
}
|
|
493
|
+
interface EventMenu {
|
|
494
|
+
id: string;
|
|
495
|
+
accessor: string;
|
|
496
|
+
name: Record<string, string>;
|
|
497
|
+
category: string;
|
|
498
|
+
}
|
|
499
|
+
interface EventByAccessor {
|
|
500
|
+
id: string;
|
|
501
|
+
venueId: string;
|
|
502
|
+
accessor: string | null;
|
|
503
|
+
name: Record<string, string>;
|
|
504
|
+
description: Record<string, string> | null;
|
|
505
|
+
scheduleId: string | null;
|
|
506
|
+
maxBookings: number | null;
|
|
507
|
+
maxGuests: number | null;
|
|
508
|
+
minPartySize: number | null;
|
|
509
|
+
maxPartySize: number | null;
|
|
510
|
+
isPublic: boolean;
|
|
511
|
+
isRecurring: boolean;
|
|
512
|
+
acceptsReservations: boolean;
|
|
513
|
+
bookingOpensAtDays: number | null;
|
|
514
|
+
bookingClosesAtHours: number | null;
|
|
515
|
+
isActive: boolean;
|
|
516
|
+
isFeatured: boolean;
|
|
517
|
+
priority: number;
|
|
518
|
+
createdAt: string | null;
|
|
519
|
+
updatedAt: string | null;
|
|
520
|
+
schedule?: ScheduleWithTimeSlots;
|
|
521
|
+
menus?: EventMenu[];
|
|
522
|
+
posters?: EventPoster[];
|
|
523
|
+
}
|
|
524
|
+
interface GetEventOptions {
|
|
525
|
+
/** Expand related resources (schedule, timeSlots, menus, posters) */
|
|
526
|
+
expand?: ('schedule' | 'timeSlots' | 'menus' | 'posters')[];
|
|
527
|
+
}
|
|
528
|
+
type BasketStatus = 'active' | 'abandoned' | 'converted';
|
|
529
|
+
type Currency = 'EUR' | 'CHF';
|
|
530
|
+
/**
|
|
531
|
+
* Unit of measurement for portion tracking.
|
|
532
|
+
*/
|
|
533
|
+
type Unit = 'grams' | 'kilograms' | 'liters' | 'milliliters' | 'pieces';
|
|
534
|
+
/**
|
|
535
|
+
* Reference to a menu item within a basket item.
|
|
536
|
+
*
|
|
537
|
+
* Each menu item can have its own portion size (quantity + unit),
|
|
538
|
+
* allowing for precise tracking like "100g rice, 80g curry".
|
|
539
|
+
*/
|
|
540
|
+
interface BasketItemMenuItemRef {
|
|
541
|
+
menuItemId: string;
|
|
542
|
+
role: string | null;
|
|
543
|
+
quantity: number;
|
|
544
|
+
unit: Unit;
|
|
545
|
+
}
|
|
546
|
+
interface BasketItemMetadata {
|
|
547
|
+
type?: 'tiffinbox' | 'bowl' | 'sushi';
|
|
548
|
+
mode?: 2 | 3;
|
|
549
|
+
upsell?: {
|
|
550
|
+
tinOption: string;
|
|
551
|
+
rollOption: string;
|
|
552
|
+
};
|
|
553
|
+
price?: number;
|
|
554
|
+
[key: string]: unknown;
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* A basket item represents a single physical product in the basket.
|
|
558
|
+
*
|
|
559
|
+
* Each basket item can contain multiple menu items (e.g., a TiffinBox
|
|
560
|
+
* with rice, curry, and sides). The itemCount in the response is the
|
|
561
|
+
* COUNT of basket items, not a sum of quantities.
|
|
562
|
+
*/
|
|
563
|
+
interface BasketItem {
|
|
564
|
+
id: string;
|
|
565
|
+
metadata: BasketItemMetadata | null;
|
|
566
|
+
menuItems: BasketItemMenuItemRef[];
|
|
567
|
+
}
|
|
568
|
+
interface Basket {
|
|
569
|
+
id: string;
|
|
570
|
+
sessionId: string;
|
|
571
|
+
status: BasketStatus;
|
|
572
|
+
currency: Currency;
|
|
573
|
+
items: BasketItem[];
|
|
574
|
+
itemCount: number;
|
|
575
|
+
expiresAt: string;
|
|
576
|
+
createdAt: string | null;
|
|
577
|
+
updatedAt: string | null;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Request to add an item to the basket.
|
|
581
|
+
*
|
|
582
|
+
* Menu items can optionally include portion information (quantity/unit).
|
|
583
|
+
* If not provided, defaults to the menu item's configured portion size.
|
|
584
|
+
*/
|
|
585
|
+
interface AddToBasketRequest {
|
|
586
|
+
sessionId: string;
|
|
587
|
+
menuItems: Array<{
|
|
588
|
+
menuItemId: string;
|
|
589
|
+
role?: string;
|
|
590
|
+
quantity?: number;
|
|
591
|
+
unit?: Unit;
|
|
592
|
+
}>;
|
|
593
|
+
metadata?: BasketItemMetadata;
|
|
594
|
+
}
|
|
595
|
+
interface AddToBasketResponse {
|
|
596
|
+
basketItemId: string;
|
|
597
|
+
itemCount: number;
|
|
598
|
+
}
|
|
599
|
+
interface RemoveFromBasketResponse {
|
|
600
|
+
success: boolean;
|
|
601
|
+
basketItemId: string;
|
|
602
|
+
itemCount: number;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
declare class BasketsResource extends BaseResource {
|
|
606
|
+
constructor(tokenManager: TokenManager, baseUrl: string);
|
|
607
|
+
/**
|
|
608
|
+
* Get the current basket for a session
|
|
609
|
+
* @param sessionId - The session identifier (from cookie)
|
|
610
|
+
* @returns The basket with all items, or null if no basket exists
|
|
611
|
+
*/
|
|
612
|
+
get(sessionId: string): Promise<Basket | null>;
|
|
613
|
+
/**
|
|
614
|
+
* Add an item to the basket
|
|
615
|
+
* Creates basket and guest customer if they don't exist
|
|
616
|
+
* @param request - The add to basket request
|
|
617
|
+
* @returns The response with basket item ID and item count
|
|
618
|
+
*/
|
|
619
|
+
add(request: AddToBasketRequest): Promise<AddToBasketResponse>;
|
|
620
|
+
/**
|
|
621
|
+
* Remove an item from the basket.
|
|
622
|
+
*
|
|
623
|
+
* Since each basket item represents a single physical product,
|
|
624
|
+
* removing it removes the entire item. There is no partial removal.
|
|
625
|
+
*
|
|
626
|
+
* @param sessionId - The session identifier
|
|
627
|
+
* @param basketItemId - The basket item ID to remove
|
|
628
|
+
* @returns The response with item count
|
|
629
|
+
*/
|
|
630
|
+
remove(sessionId: string, basketItemId: string): Promise<RemoveFromBasketResponse>;
|
|
631
|
+
}
|
|
479
632
|
|
|
480
633
|
declare class EventsResource extends BaseResource {
|
|
481
634
|
constructor(tokenManager: TokenManager, baseUrl: string);
|
|
@@ -497,6 +650,14 @@ declare class EventsResource extends BaseResource {
|
|
|
497
650
|
* @returns The event details
|
|
498
651
|
*/
|
|
499
652
|
get(eventId: string): Promise<Event>;
|
|
653
|
+
/**
|
|
654
|
+
* Get an event by accessor (slug)
|
|
655
|
+
* @param accessor - The event accessor (e.g., 'lunch-menu')
|
|
656
|
+
* @param options - Optional expand options
|
|
657
|
+
* @returns The event with optional schedule, timeSlots, menus, and posters
|
|
658
|
+
*/
|
|
659
|
+
getByAccessor(accessor: string, options?: GetEventOptions): Promise<EventByAccessor>;
|
|
660
|
+
private buildQueryString;
|
|
500
661
|
}
|
|
501
662
|
|
|
502
663
|
declare class MenusResource extends BaseResource {
|
|
@@ -661,6 +822,26 @@ declare class RealtimeManager {
|
|
|
661
822
|
disconnectAll(): Promise<void>;
|
|
662
823
|
}
|
|
663
824
|
|
|
825
|
+
interface ScheduleInfo {
|
|
826
|
+
/** Time range string, e.g. "11:30-15:00" */
|
|
827
|
+
timeRange: string | null;
|
|
828
|
+
/** Active days in week order */
|
|
829
|
+
activeDays: DayOfWeek[];
|
|
830
|
+
}
|
|
831
|
+
interface ScheduleInput {
|
|
832
|
+
rrule?: string | null;
|
|
833
|
+
intervalMinutes?: number | null;
|
|
834
|
+
scheduleTimeSlots?: ScheduleTimeSlot[];
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Extract schedule information from a schedule object.
|
|
838
|
+
* Returns time range and active days for display purposes.
|
|
839
|
+
*
|
|
840
|
+
* @param schedule - Schedule object with rrule, intervalMinutes, and scheduleTimeSlots
|
|
841
|
+
* @returns ScheduleInfo with timeRange and activeDays
|
|
842
|
+
*/
|
|
843
|
+
declare function getScheduleInfo(schedule: ScheduleInput | null | undefined): ScheduleInfo;
|
|
844
|
+
|
|
664
845
|
interface Order3000ClientConfig {
|
|
665
846
|
clientId: string;
|
|
666
847
|
clientSecret: string;
|
|
@@ -677,6 +858,7 @@ interface Order3000ClientConfig {
|
|
|
677
858
|
tokenUrl?: string;
|
|
678
859
|
}
|
|
679
860
|
declare class Order3000Client {
|
|
861
|
+
baskets: BasketsResource;
|
|
680
862
|
events: EventsResource;
|
|
681
863
|
menus: MenusResource;
|
|
682
864
|
orders: OrdersResource;
|
|
@@ -687,4 +869,4 @@ declare class Order3000Client {
|
|
|
687
869
|
constructor(config: Order3000ClientConfig);
|
|
688
870
|
}
|
|
689
871
|
|
|
690
|
-
export { type CropArea, type Event, type EventPoster, type EventRow, type GetMenuOptions, type ListEventsOptions, type ListEventsResponse, type Menu, type MenuAsset, type MenuBeverage, type MenuDish, type MenuItem, type MenuItemRow, type MenuItemType, Order3000Client, type Order3000ClientConfig, type Promotion, type RealtimeConfig, type RealtimeEvent, type RealtimeSubscription, type Schedule, type ScheduleOverride, type ScheduleOverrideRow, type ScheduleRow, type SubscriptionOptions, type TimeSlot };
|
|
872
|
+
export { type AddToBasketRequest, type AddToBasketResponse, type Basket, type BasketItem, type BasketItemMenuItemRef, type BasketItemMetadata, type BasketStatus, type CropArea, type Currency, type DayOfWeek, type Event, type EventByAccessor, type EventMenu, type EventPoster, type EventRow, type GetEventOptions, type GetMenuOptions, type ListEventsOptions, type ListEventsResponse, type Menu, type MenuAsset, type MenuBeverage, type MenuDish, type MenuItem, type MenuItemRow, type MenuItemType, Order3000Client, type Order3000ClientConfig, type Promotion, type RealtimeConfig, type RealtimeEvent, type RealtimeSubscription, type RemoveFromBasketResponse, type Schedule, type ScheduleInfo, type ScheduleOverride, type ScheduleOverrideRow, type ScheduleRow, type ScheduleTimeSlot, type ScheduleWithTimeSlots, type SubscriptionOptions, type TimeSlot, type Unit, getScheduleInfo };
|
package/dist/client.mjs
CHANGED
|
@@ -124,6 +124,49 @@ class BaseResource {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
class BasketsResource extends BaseResource {
|
|
128
|
+
constructor(tokenManager, baseUrl) {
|
|
129
|
+
super(tokenManager, baseUrl, "/baskets");
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Get the current basket for a session
|
|
133
|
+
* @param sessionId - The session identifier (from cookie)
|
|
134
|
+
* @returns The basket with all items, or null if no basket exists
|
|
135
|
+
*/
|
|
136
|
+
async get(sessionId) {
|
|
137
|
+
return this.request(
|
|
138
|
+
"GET",
|
|
139
|
+
`?sessionId=${encodeURIComponent(sessionId)}`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Add an item to the basket
|
|
144
|
+
* Creates basket and guest customer if they don't exist
|
|
145
|
+
* @param request - The add to basket request
|
|
146
|
+
* @returns The response with basket item ID and item count
|
|
147
|
+
*/
|
|
148
|
+
async add(request) {
|
|
149
|
+
return this.request("POST", "/items", request);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Remove an item from the basket.
|
|
153
|
+
*
|
|
154
|
+
* Since each basket item represents a single physical product,
|
|
155
|
+
* removing it removes the entire item. There is no partial removal.
|
|
156
|
+
*
|
|
157
|
+
* @param sessionId - The session identifier
|
|
158
|
+
* @param basketItemId - The basket item ID to remove
|
|
159
|
+
* @returns The response with item count
|
|
160
|
+
*/
|
|
161
|
+
async remove(sessionId, basketItemId) {
|
|
162
|
+
const params = new URLSearchParams({ sessionId });
|
|
163
|
+
return this.request(
|
|
164
|
+
"DELETE",
|
|
165
|
+
`/items/${basketItemId}?${params.toString()}`
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
127
170
|
class EventsResource extends BaseResource {
|
|
128
171
|
constructor(tokenManager, baseUrl) {
|
|
129
172
|
super(tokenManager, baseUrl, "/events");
|
|
@@ -170,6 +213,20 @@ class EventsResource extends BaseResource {
|
|
|
170
213
|
async get(eventId) {
|
|
171
214
|
return this.request("GET", `/${eventId}`);
|
|
172
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* Get an event by accessor (slug)
|
|
218
|
+
* @param accessor - The event accessor (e.g., 'lunch-menu')
|
|
219
|
+
* @param options - Optional expand options
|
|
220
|
+
* @returns The event with optional schedule, timeSlots, menus, and posters
|
|
221
|
+
*/
|
|
222
|
+
async getByAccessor(accessor, options) {
|
|
223
|
+
const queryString = this.buildQueryString(options);
|
|
224
|
+
return this.request("GET", `/${accessor}${queryString}`);
|
|
225
|
+
}
|
|
226
|
+
buildQueryString(options) {
|
|
227
|
+
if (!options?.expand?.length) return "";
|
|
228
|
+
return `?expand=${options.expand.join(",")}`;
|
|
229
|
+
}
|
|
173
230
|
}
|
|
174
231
|
|
|
175
232
|
class MenusResource extends BaseResource {
|
|
@@ -441,11 +498,126 @@ class RealtimeManager {
|
|
|
441
498
|
}
|
|
442
499
|
}
|
|
443
500
|
|
|
501
|
+
const ALL_DAYS = [
|
|
502
|
+
"monday",
|
|
503
|
+
"tuesday",
|
|
504
|
+
"wednesday",
|
|
505
|
+
"thursday",
|
|
506
|
+
"friday",
|
|
507
|
+
"saturday",
|
|
508
|
+
"sunday"
|
|
509
|
+
];
|
|
510
|
+
const RRULE_DAY_MAP = {
|
|
511
|
+
MO: "monday",
|
|
512
|
+
TU: "tuesday",
|
|
513
|
+
WE: "wednesday",
|
|
514
|
+
TH: "thursday",
|
|
515
|
+
FR: "friday",
|
|
516
|
+
SA: "saturday",
|
|
517
|
+
SU: "sunday"
|
|
518
|
+
};
|
|
519
|
+
function parseDaysFromRRule(rrule) {
|
|
520
|
+
if (!rrule) {
|
|
521
|
+
return [];
|
|
522
|
+
}
|
|
523
|
+
const byDayMatch = rrule.match(/BYDAY=([^;]+)/);
|
|
524
|
+
if (!byDayMatch) {
|
|
525
|
+
return [];
|
|
526
|
+
}
|
|
527
|
+
const rruleDays = byDayMatch[1].split(",");
|
|
528
|
+
const days = [];
|
|
529
|
+
for (const rruleDay of rruleDays) {
|
|
530
|
+
const day = RRULE_DAY_MAP[rruleDay.trim()];
|
|
531
|
+
if (day) {
|
|
532
|
+
days.push(day);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
return ALL_DAYS.filter((day) => days.includes(day));
|
|
536
|
+
}
|
|
537
|
+
function addMinutesToTime(time, minutes) {
|
|
538
|
+
const parts = time.split(":");
|
|
539
|
+
const hours = parseInt(parts[0], 10);
|
|
540
|
+
const mins = parseInt(parts[1], 10);
|
|
541
|
+
const totalMinutes = hours * 60 + mins + minutes;
|
|
542
|
+
const newHours = Math.floor(totalMinutes / 60) % 24;
|
|
543
|
+
const newMins = totalMinutes % 60;
|
|
544
|
+
return `${newHours.toString().padStart(2, "0")}:${newMins.toString().padStart(2, "0")}`;
|
|
545
|
+
}
|
|
546
|
+
function formatTime(time) {
|
|
547
|
+
const parts = time.split(":");
|
|
548
|
+
if (parts.length >= 2) {
|
|
549
|
+
return `${parts[0]}:${parts[1]}`;
|
|
550
|
+
}
|
|
551
|
+
return time;
|
|
552
|
+
}
|
|
553
|
+
function getScheduleInfo(schedule) {
|
|
554
|
+
const defaultData = {
|
|
555
|
+
timeRange: null,
|
|
556
|
+
activeDays: []
|
|
557
|
+
};
|
|
558
|
+
if (!schedule?.scheduleTimeSlots?.length) {
|
|
559
|
+
return defaultData;
|
|
560
|
+
}
|
|
561
|
+
const timeSlots = schedule.scheduleTimeSlots;
|
|
562
|
+
const rrule = schedule.rrule;
|
|
563
|
+
const intervalMinutes = schedule.intervalMinutes ?? 30;
|
|
564
|
+
const activeDaysSet = /* @__PURE__ */ new Set();
|
|
565
|
+
let hasNullDayOfWeek = false;
|
|
566
|
+
const startTimes = [];
|
|
567
|
+
let latestEndTime = null;
|
|
568
|
+
for (const slot of timeSlots) {
|
|
569
|
+
if (slot.dayOfWeek) {
|
|
570
|
+
activeDaysSet.add(slot.dayOfWeek);
|
|
571
|
+
} else {
|
|
572
|
+
hasNullDayOfWeek = true;
|
|
573
|
+
}
|
|
574
|
+
if (slot.timeSlot.startTime) {
|
|
575
|
+
startTimes.push(slot.timeSlot.startTime);
|
|
576
|
+
}
|
|
577
|
+
if (slot.timeSlot.endTime) {
|
|
578
|
+
if (!latestEndTime || slot.timeSlot.endTime > latestEndTime) {
|
|
579
|
+
latestEndTime = slot.timeSlot.endTime;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
let activeDays;
|
|
584
|
+
if (hasNullDayOfWeek) {
|
|
585
|
+
const rruleDays = parseDaysFromRRule(rrule);
|
|
586
|
+
if (rruleDays.length > 0) {
|
|
587
|
+
activeDays = rruleDays;
|
|
588
|
+
} else {
|
|
589
|
+
activeDays = ALL_DAYS.filter((day) => activeDaysSet.has(day));
|
|
590
|
+
}
|
|
591
|
+
} else {
|
|
592
|
+
activeDays = ALL_DAYS.filter((day) => activeDaysSet.has(day));
|
|
593
|
+
}
|
|
594
|
+
let timeRange = null;
|
|
595
|
+
if (startTimes.length > 0) {
|
|
596
|
+
startTimes.sort();
|
|
597
|
+
const earliestStart = startTimes[0];
|
|
598
|
+
const latestStart = startTimes[startTimes.length - 1];
|
|
599
|
+
let endTime;
|
|
600
|
+
if (latestEndTime) {
|
|
601
|
+
endTime = latestEndTime;
|
|
602
|
+
} else {
|
|
603
|
+
endTime = addMinutesToTime(latestStart, intervalMinutes);
|
|
604
|
+
}
|
|
605
|
+
const startFormatted = formatTime(earliestStart);
|
|
606
|
+
const endFormatted = formatTime(endTime);
|
|
607
|
+
timeRange = `${startFormatted}-${endFormatted}`;
|
|
608
|
+
}
|
|
609
|
+
return {
|
|
610
|
+
timeRange,
|
|
611
|
+
activeDays
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
|
|
444
615
|
var __defProp = Object.defineProperty;
|
|
445
616
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
446
617
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
447
618
|
class Order3000Client {
|
|
448
619
|
constructor(config) {
|
|
620
|
+
__publicField(this, "baskets");
|
|
449
621
|
__publicField(this, "events");
|
|
450
622
|
__publicField(this, "menus");
|
|
451
623
|
__publicField(this, "orders");
|
|
@@ -461,6 +633,7 @@ class Order3000Client {
|
|
|
461
633
|
tokenUrl,
|
|
462
634
|
config.venueId
|
|
463
635
|
);
|
|
636
|
+
this.baskets = new BasketsResource(this.tokenManager, this.baseUrl);
|
|
464
637
|
this.events = new EventsResource(this.tokenManager, this.baseUrl);
|
|
465
638
|
this.menus = new MenusResource(this.tokenManager, this.baseUrl);
|
|
466
639
|
this.orders = new OrdersResource(this.tokenManager, this.baseUrl);
|
|
@@ -472,4 +645,4 @@ class Order3000Client {
|
|
|
472
645
|
}
|
|
473
646
|
}
|
|
474
647
|
|
|
475
|
-
export { Order3000Client };
|
|
648
|
+
export { Order3000Client, getScheduleInfo };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "order3000",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "order3000 node.js sdk",
|
|
5
5
|
"main": "./dist/client.cjs",
|
|
6
6
|
"module": "./dist/client.mjs",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"prettier": "^3.7.4",
|
|
30
30
|
"tsx": "^4.19.2",
|
|
31
31
|
"typescript": "^5.9.3",
|
|
32
|
-
"@kolaveri/eslint-config": "1.0.9",
|
|
33
32
|
"@kolaveri/prettier-config": "1.0.6",
|
|
33
|
+
"@kolaveri/eslint-config": "1.0.9",
|
|
34
34
|
"@kolaveri/tsconfig": "1.0.1"
|
|
35
35
|
},
|
|
36
36
|
"files": [
|