@darkpos/pricing 1.0.145 → 1.0.146
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/__TEST__/order/addItem.test.js +69 -0
- package/__TEST__/order/pickEndDate.test.js +208 -2
- package/lib/constants/Store.js +3 -0
- package/lib/constants/index.js +2 -0
- package/lib/order/addItem.js +2 -0
- package/lib/store/getClosedDays.js +7 -0
- package/lib/store/getReadyDateCapacityDays.js +4 -0
- package/lib/store/getReadyDateCountsByDate.js +33 -0
- package/lib/store/getSchedule.js +61 -0
- package/lib/store/getStoreTimezone.js +7 -0
- package/lib/store/hasReadyDateCapacitySettings.js +8 -0
- package/lib/store/index.js +16 -0
- package/lib/store/normalizeLimit.js +5 -0
- package/lib/store/pickBaseEndDate.js +71 -0
- package/lib/store/pickEndDate.js +69 -95
- package/package.json +2 -2
|
@@ -201,6 +201,75 @@ describe('addItem function', () => {
|
|
|
201
201
|
expect(updatedOrder.items[0].modifiers).toHaveLength(2); // Added item should have modifiers
|
|
202
202
|
});
|
|
203
203
|
|
|
204
|
+
test('should return original order when item serial is duplicated', () => {
|
|
205
|
+
const { addItem } = pricingService.order;
|
|
206
|
+
|
|
207
|
+
const order = {
|
|
208
|
+
items: [
|
|
209
|
+
{
|
|
210
|
+
_id: 'existing-item',
|
|
211
|
+
itemId: '111',
|
|
212
|
+
quantity: 1,
|
|
213
|
+
price: 100,
|
|
214
|
+
serial: 'ABC-123',
|
|
215
|
+
modifiers: [],
|
|
216
|
+
},
|
|
217
|
+
],
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const item = {
|
|
221
|
+
_id: 'new-item',
|
|
222
|
+
itemId: '222',
|
|
223
|
+
quantity: 1,
|
|
224
|
+
price: 50,
|
|
225
|
+
serial: ' abc-123 ',
|
|
226
|
+
modifiers: [],
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const result = addItem({
|
|
230
|
+
order,
|
|
231
|
+
item,
|
|
232
|
+
itemIndex: -1,
|
|
233
|
+
overridenQuantity: -1,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
expect(result).toBe(order);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
test('should return original order when autoBarcode serial is duplicated', () => {
|
|
240
|
+
const { addItem } = pricingService.order;
|
|
241
|
+
|
|
242
|
+
const order = {
|
|
243
|
+
items: [
|
|
244
|
+
{
|
|
245
|
+
_id: 'existing-item',
|
|
246
|
+
itemId: '111',
|
|
247
|
+
quantity: 1,
|
|
248
|
+
price: 100,
|
|
249
|
+
serial: 'ABC-123',
|
|
250
|
+
modifiers: [],
|
|
251
|
+
},
|
|
252
|
+
],
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const item = {
|
|
256
|
+
_id: 'new-item',
|
|
257
|
+
itemId: '222',
|
|
258
|
+
quantity: 1,
|
|
259
|
+
price: 50,
|
|
260
|
+
modifiers: [],
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const result = addItem({
|
|
264
|
+
order,
|
|
265
|
+
item,
|
|
266
|
+
itemIndex: 1,
|
|
267
|
+
autoBarcode: 'ABC-123',
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
expect(result).toBe(order);
|
|
271
|
+
});
|
|
272
|
+
|
|
204
273
|
test('Add Related Item', () => {
|
|
205
274
|
const { addItem } = pricingService.order;
|
|
206
275
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const moment = require('moment-timezone');
|
|
2
2
|
const usePricing = require('../../lib/index');
|
|
3
3
|
|
|
4
|
-
const getDefaultSettings = schedules => ({
|
|
4
|
+
const getDefaultSettings = (schedules, readyDateCapacityDays = []) => ({
|
|
5
5
|
store: {
|
|
6
6
|
_settings: {
|
|
7
7
|
schedule: {
|
|
@@ -24,6 +24,9 @@ const getDefaultSettings = schedules => ({
|
|
|
24
24
|
cutHour: null,
|
|
25
25
|
},
|
|
26
26
|
],
|
|
27
|
+
readyDateCapacity: {
|
|
28
|
+
days: readyDateCapacityDays,
|
|
29
|
+
},
|
|
27
30
|
},
|
|
28
31
|
},
|
|
29
32
|
},
|
|
@@ -115,7 +118,7 @@ describe('pickEndDate function', () => {
|
|
|
115
118
|
recommended: 'nothing_recommended',
|
|
116
119
|
};
|
|
117
120
|
|
|
118
|
-
const now = moment().tz('America/New_York');
|
|
121
|
+
const now = moment('2024-08-25T15:00:00Z').tz('America/New_York');
|
|
119
122
|
|
|
120
123
|
jest.spyOn(moment, 'now').mockImplementation(() => now.valueOf());
|
|
121
124
|
const pricingServiceTest = usePricing(getDefaultSettings([schedule]));
|
|
@@ -299,4 +302,207 @@ describe('pickEndDate function', () => {
|
|
|
299
302
|
|
|
300
303
|
expect(result).toBe('2025-05-15T22:00:00Z');
|
|
301
304
|
});
|
|
305
|
+
|
|
306
|
+
test('pickEndDate - skips day when maxOrders capacity is reached', () => {
|
|
307
|
+
const schedule = {
|
|
308
|
+
addDays: 0,
|
|
309
|
+
readyHour: { hour: 17, minute: 0 },
|
|
310
|
+
skipDays: [],
|
|
311
|
+
cutHour: { hour: 16, minute: 0 },
|
|
312
|
+
cutDay: 1,
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const pricingService = usePricing(
|
|
316
|
+
getDefaultSettings([schedule], [{ day: 2, maxOrders: 1 }])
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
const now = moment('2025-05-13T15:00:00Z').tz('America/New_York');
|
|
320
|
+
jest.spyOn(moment, 'now').mockImplementation(() => now.valueOf());
|
|
321
|
+
|
|
322
|
+
const result = pricingService.store.pickEndDate(
|
|
323
|
+
undefined,
|
|
324
|
+
undefined,
|
|
325
|
+
undefined,
|
|
326
|
+
[
|
|
327
|
+
{
|
|
328
|
+
date: '2025-05-13',
|
|
329
|
+
totalOrders: 1,
|
|
330
|
+
totalItems: 0,
|
|
331
|
+
},
|
|
332
|
+
]
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
expect(result).toBe('2025-05-14T21:00:00Z');
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
test('pickEndDate - skips day when maxItems capacity is reached', () => {
|
|
339
|
+
const schedule = {
|
|
340
|
+
addDays: 0,
|
|
341
|
+
readyHour: { hour: 17, minute: 0 },
|
|
342
|
+
skipDays: [],
|
|
343
|
+
cutHour: { hour: 16, minute: 0 },
|
|
344
|
+
cutDay: 1,
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
const pricingService = usePricing(
|
|
348
|
+
getDefaultSettings([schedule], [{ day: 2, maxItems: 1 }])
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
const now = moment('2025-05-13T15:00:00Z').tz('America/New_York');
|
|
352
|
+
jest.spyOn(moment, 'now').mockImplementation(() => now.valueOf());
|
|
353
|
+
|
|
354
|
+
const result = pricingService.store.pickEndDate(
|
|
355
|
+
undefined,
|
|
356
|
+
undefined,
|
|
357
|
+
undefined,
|
|
358
|
+
[
|
|
359
|
+
{
|
|
360
|
+
date: '2025-05-13',
|
|
361
|
+
totalOrders: 0,
|
|
362
|
+
totalItems: 1,
|
|
363
|
+
},
|
|
364
|
+
]
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
expect(result).toBe('2025-05-14T21:00:00Z');
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
test('pickEndDate - moves to next available day when capacity is full', () => {
|
|
371
|
+
const schedule = {
|
|
372
|
+
addDays: 2,
|
|
373
|
+
readyHour: { hour: 17, minute: 0 },
|
|
374
|
+
skipDays: [],
|
|
375
|
+
cutHour: { hour: 16, minute: 0 },
|
|
376
|
+
cutDay: 1,
|
|
377
|
+
dayOfWeek: [1, 2, 3, 4, 5],
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
const pricingService = usePricing(
|
|
381
|
+
getDefaultSettings([schedule], [{ day: 6, maxOrders: 1 }])
|
|
382
|
+
);
|
|
383
|
+
|
|
384
|
+
const now = moment('2026-02-26T15:00:00Z').tz('America/New_York');
|
|
385
|
+
jest.spyOn(moment, 'now').mockImplementation(() => now.valueOf());
|
|
386
|
+
|
|
387
|
+
const result = pricingService.store.pickEndDate(
|
|
388
|
+
undefined,
|
|
389
|
+
undefined,
|
|
390
|
+
undefined,
|
|
391
|
+
[
|
|
392
|
+
{
|
|
393
|
+
date: '2026-02-28',
|
|
394
|
+
totalOrders: 1,
|
|
395
|
+
totalItems: 0,
|
|
396
|
+
},
|
|
397
|
+
]
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
expect(result).toBe('2026-03-01T22:00:00Z');
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
test('pickEndDate - skips closed day after capacity overflow', () => {
|
|
404
|
+
const schedule = {
|
|
405
|
+
addDays: 2,
|
|
406
|
+
readyHour: { hour: 17, minute: 0 },
|
|
407
|
+
skipDays: null,
|
|
408
|
+
cutHour: { hour: 10, minute: 0 },
|
|
409
|
+
cutDay: 1,
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
const pricingService = usePricing({
|
|
413
|
+
store: {
|
|
414
|
+
_settings: {
|
|
415
|
+
schedule: {
|
|
416
|
+
closed: [{ date: '2026-03-01' }],
|
|
417
|
+
},
|
|
418
|
+
order: {
|
|
419
|
+
schedules: [schedule],
|
|
420
|
+
readyDateCapacity: {
|
|
421
|
+
days: [
|
|
422
|
+
{ day: 6, maxOrders: 2, maxItems: 10 },
|
|
423
|
+
{ day: 1, maxOrders: 10, maxItems: 10 },
|
|
424
|
+
],
|
|
425
|
+
},
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
},
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
const now = moment('2026-02-25T16:04:51Z').tz('America/New_York');
|
|
432
|
+
jest.spyOn(moment, 'now').mockImplementation(() => now.valueOf());
|
|
433
|
+
|
|
434
|
+
const result = pricingService.store.pickEndDate(
|
|
435
|
+
undefined,
|
|
436
|
+
undefined,
|
|
437
|
+
undefined,
|
|
438
|
+
[
|
|
439
|
+
{ date: '2026-02-26', totalOrders: 4, totalItems: 5 },
|
|
440
|
+
{ date: '2026-02-27', totalOrders: 1, totalItems: 1 },
|
|
441
|
+
{ date: '2026-02-28', totalOrders: 2, totalItems: 2 },
|
|
442
|
+
]
|
|
443
|
+
);
|
|
444
|
+
|
|
445
|
+
expect(result).toBe('2026-03-02T22:00:00Z');
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
test('pickEndDate - skips multiple consecutive capacity-full days', () => {
|
|
449
|
+
const schedule = {
|
|
450
|
+
addDays: 0,
|
|
451
|
+
readyHour: { hour: 17, minute: 0 },
|
|
452
|
+
skipDays: [],
|
|
453
|
+
cutHour: { hour: 16, minute: 0 },
|
|
454
|
+
cutDay: 1,
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
const pricingService = usePricing(
|
|
458
|
+
getDefaultSettings(
|
|
459
|
+
[schedule],
|
|
460
|
+
[
|
|
461
|
+
{ day: 2, maxOrders: 1 },
|
|
462
|
+
{ day: 3, maxOrders: 1 },
|
|
463
|
+
]
|
|
464
|
+
)
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
const now = moment('2025-05-13T15:00:00Z').tz('America/New_York');
|
|
468
|
+
jest.spyOn(moment, 'now').mockImplementation(() => now.valueOf());
|
|
469
|
+
|
|
470
|
+
const result = pricingService.store.pickEndDate(
|
|
471
|
+
undefined,
|
|
472
|
+
undefined,
|
|
473
|
+
undefined,
|
|
474
|
+
[
|
|
475
|
+
{ date: '2025-05-13', totalOrders: 1, totalItems: 0 },
|
|
476
|
+
{ date: '2025-05-14', totalOrders: 1, totalItems: 0 },
|
|
477
|
+
]
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
expect(result).toBe('2025-05-15T21:00:00Z');
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
test('pickEndDate - returns base date when no capacity counts are provided', () => {
|
|
484
|
+
const schedule = {
|
|
485
|
+
addDays: 0,
|
|
486
|
+
readyHour: { hour: 17, minute: 0 },
|
|
487
|
+
skipDays: [],
|
|
488
|
+
cutHour: { hour: 16, minute: 0 },
|
|
489
|
+
cutDay: 1,
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
const pricingService = usePricing(
|
|
493
|
+
getDefaultSettings([schedule], [{ day: 2, maxOrders: 1 }])
|
|
494
|
+
);
|
|
495
|
+
|
|
496
|
+
const now = moment('2025-05-13T15:00:00Z').tz('America/New_York');
|
|
497
|
+
jest.spyOn(moment, 'now').mockImplementation(() => now.valueOf());
|
|
498
|
+
|
|
499
|
+
const result = pricingService.store.pickEndDate(
|
|
500
|
+
undefined,
|
|
501
|
+
undefined,
|
|
502
|
+
undefined,
|
|
503
|
+
[]
|
|
504
|
+
);
|
|
505
|
+
|
|
506
|
+
expect(result).toBe('2025-05-13T21:00:00Z');
|
|
507
|
+
});
|
|
302
508
|
});
|
package/lib/constants/index.js
CHANGED
package/lib/order/addItem.js
CHANGED
|
@@ -227,6 +227,8 @@ module.exports = ({ actions, itemActions, modifierActions, settings, _ }) => {
|
|
|
227
227
|
originalItem: item,
|
|
228
228
|
});
|
|
229
229
|
|
|
230
|
+
if (actions.hasSerial({ order, item: orderItem })) return orderProp;
|
|
231
|
+
|
|
230
232
|
const params = addOrderItem({
|
|
231
233
|
order,
|
|
232
234
|
item: orderItem,
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module.exports = ({ _, moment }) =>
|
|
2
|
+
function getReadyDateCountsByDate(counts = []) {
|
|
3
|
+
const countsByDate = new Map();
|
|
4
|
+
|
|
5
|
+
if (!Array.isArray(counts) || !counts.length) return countsByDate;
|
|
6
|
+
|
|
7
|
+
counts.forEach(dayCount => {
|
|
8
|
+
const rawDate = _.get(dayCount, 'date');
|
|
9
|
+
if (!rawDate) return;
|
|
10
|
+
|
|
11
|
+
const utcDateKey = moment.utc(rawDate).format('YYYY-MM-DD');
|
|
12
|
+
if (!utcDateKey || utcDateKey === 'Invalid date') return;
|
|
13
|
+
|
|
14
|
+
const currentValue = countsByDate.get(utcDateKey) || {
|
|
15
|
+
totalOrders: 0,
|
|
16
|
+
totalItems: 0,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const nextOrders = Number(_.get(dayCount, 'totalOrders'));
|
|
20
|
+
const nextItems = Number(_.get(dayCount, 'totalItems'));
|
|
21
|
+
|
|
22
|
+
countsByDate.set(utcDateKey, {
|
|
23
|
+
totalOrders:
|
|
24
|
+
currentValue.totalOrders +
|
|
25
|
+
(Number.isFinite(nextOrders) && nextOrders > 0 ? nextOrders : 0),
|
|
26
|
+
totalItems:
|
|
27
|
+
currentValue.totalItems +
|
|
28
|
+
(Number.isFinite(nextItems) && nextItems > 0 ? nextItems : 0),
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return countsByDate;
|
|
33
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module.exports = ({ _, moment, settings, actions }) =>
|
|
2
|
+
function getSchedule(schedules, isoWeekday, fromDate) {
|
|
3
|
+
const timezone = actions.getStoreTimezone();
|
|
4
|
+
let todayTZ = moment().tz(timezone);
|
|
5
|
+
|
|
6
|
+
if (fromDate) {
|
|
7
|
+
todayTZ = moment(fromDate).tz(timezone);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const day = isoWeekday || todayTZ.isoWeekday(); // monday 1 - sunday 7
|
|
11
|
+
|
|
12
|
+
let activeSchedules = _.get(settings, 'order.schedules', []).filter(
|
|
13
|
+
item => !item.departments || !item.departments.length
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
if (schedules && schedules.length) {
|
|
17
|
+
activeSchedules = schedules;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!activeSchedules.length) {
|
|
21
|
+
return {
|
|
22
|
+
todayTZ,
|
|
23
|
+
skipDays: [],
|
|
24
|
+
cutDay: 0,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const schedule = activeSchedules.find(item => {
|
|
29
|
+
const { dayOfWeek } = item || {};
|
|
30
|
+
if (!dayOfWeek || !dayOfWeek.length) return true;
|
|
31
|
+
return dayOfWeek.includes(day);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (schedule) {
|
|
35
|
+
return {
|
|
36
|
+
...schedule,
|
|
37
|
+
todayTZ,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
for (let offset = 1; offset <= 7; offset += 1) {
|
|
42
|
+
const nextIsoWeekday = ((day - 1 + offset) % 7) + 1;
|
|
43
|
+
const nextSchedule = activeSchedules.find(item => {
|
|
44
|
+
const { dayOfWeek } = item || {};
|
|
45
|
+
return Array.isArray(dayOfWeek) && dayOfWeek.includes(nextIsoWeekday);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
if (nextSchedule) {
|
|
49
|
+
return {
|
|
50
|
+
...nextSchedule,
|
|
51
|
+
todayTZ: todayTZ.clone().add(offset, 'days'),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
todayTZ,
|
|
58
|
+
skipDays: [],
|
|
59
|
+
cutDay: 0,
|
|
60
|
+
};
|
|
61
|
+
};
|
package/lib/store/index.js
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
//
|
|
2
2
|
const getScheduleByCustomer = require('./getScheduleByCustomer');
|
|
3
3
|
const isNeareastMultiple = require('./isNeareastMultiple');
|
|
4
|
+
const getClosedDays = require('./getClosedDays');
|
|
5
|
+
const getReadyDateCapacityDays = require('./getReadyDateCapacityDays');
|
|
6
|
+
const getReadyDateCountsByDate = require('./getReadyDateCountsByDate');
|
|
7
|
+
const getSchedule = require('./getSchedule');
|
|
8
|
+
const getStoreTimezone = require('./getStoreTimezone');
|
|
9
|
+
const hasReadyDateCapacitySettings = require('./hasReadyDateCapacitySettings');
|
|
10
|
+
const normalizeLimit = require('./normalizeLimit');
|
|
11
|
+
const pickBaseEndDate = require('./pickBaseEndDate');
|
|
4
12
|
const pickEndDate = require('./pickEndDate');
|
|
5
13
|
const pickEndDateByCustomer = require('./pickEndDateByCustomer');
|
|
6
14
|
|
|
@@ -13,8 +21,16 @@ const storeActions = (deps = {}) => {
|
|
|
13
21
|
};
|
|
14
22
|
|
|
15
23
|
const freezedActions = Object.freeze({
|
|
24
|
+
getClosedDays: getClosedDays(innerDeps),
|
|
25
|
+
getReadyDateCapacityDays: getReadyDateCapacityDays(innerDeps),
|
|
26
|
+
getReadyDateCountsByDate: getReadyDateCountsByDate(innerDeps),
|
|
16
27
|
getScheduleByCustomer: getScheduleByCustomer(innerDeps),
|
|
28
|
+
getSchedule: getSchedule(innerDeps),
|
|
29
|
+
getStoreTimezone: getStoreTimezone(innerDeps),
|
|
30
|
+
hasReadyDateCapacitySettings: hasReadyDateCapacitySettings(innerDeps),
|
|
17
31
|
isNeareastMultiple: isNeareastMultiple(innerDeps),
|
|
32
|
+
normalizeLimit: normalizeLimit(innerDeps),
|
|
33
|
+
pickBaseEndDate: pickBaseEndDate(innerDeps),
|
|
18
34
|
pickEndDate: pickEndDate(innerDeps),
|
|
19
35
|
pickEndDateByCustomer: pickEndDateByCustomer(innerDeps),
|
|
20
36
|
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const { MAX_ADD_DAYS } = require('../constants/Store');
|
|
2
|
+
|
|
3
|
+
module.exports = ({ moment, actions }) =>
|
|
4
|
+
function pickBaseEndDate(schedules, isoWeekday, fromDate) {
|
|
5
|
+
const {
|
|
6
|
+
addDays: addDaysParam,
|
|
7
|
+
readyHour,
|
|
8
|
+
cutHour,
|
|
9
|
+
cutDay,
|
|
10
|
+
skipDays,
|
|
11
|
+
todayTZ,
|
|
12
|
+
} = actions.getSchedule(schedules, isoWeekday, fromDate);
|
|
13
|
+
|
|
14
|
+
let endDateTZ = todayTZ.clone();
|
|
15
|
+
const closedDays = actions.getClosedDays();
|
|
16
|
+
const todayHours = todayTZ.get('hours');
|
|
17
|
+
const todayMinutes = todayTZ.get('minutes');
|
|
18
|
+
|
|
19
|
+
let addDays = 0;
|
|
20
|
+
|
|
21
|
+
if (
|
|
22
|
+
!fromDate &&
|
|
23
|
+
typeof addDaysParam === 'number' &&
|
|
24
|
+
addDaysParam <= MAX_ADD_DAYS
|
|
25
|
+
) {
|
|
26
|
+
addDays = addDaysParam;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (
|
|
30
|
+
(cutHour && todayHours > cutHour.hour) ||
|
|
31
|
+
(cutHour && todayHours >= cutHour.hour && todayMinutes > cutHour.minute)
|
|
32
|
+
) {
|
|
33
|
+
endDateTZ = endDateTZ.add(cutDay, 'days');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (readyHour && readyHour.hour !== undefined)
|
|
37
|
+
endDateTZ.set('hour', readyHour.hour);
|
|
38
|
+
if (readyHour && readyHour.minute !== undefined)
|
|
39
|
+
endDateTZ.set('minute', readyHour.minute);
|
|
40
|
+
|
|
41
|
+
endDateTZ.set('second', 0);
|
|
42
|
+
|
|
43
|
+
const isSkipDay = endDateIsoWeekDay => {
|
|
44
|
+
if (skipDays && skipDays.length >= 7) return false;
|
|
45
|
+
|
|
46
|
+
return skipDays && skipDays.includes(endDateIsoWeekDay);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const isClosedDay = endDate =>
|
|
50
|
+
closedDays.some(
|
|
51
|
+
closedDate => endDate.format('YYYY-MM-DD') === closedDate.date
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
let addedDays = 0;
|
|
55
|
+
|
|
56
|
+
while (
|
|
57
|
+
addedDays < addDays ||
|
|
58
|
+
isSkipDay(endDateTZ.isoWeekday()) ||
|
|
59
|
+
isClosedDay(endDateTZ)
|
|
60
|
+
) {
|
|
61
|
+
if (
|
|
62
|
+
endDateTZ.isSame(todayTZ, 'day') ||
|
|
63
|
+
(!isSkipDay(endDateTZ.isoWeekday()) && !isClosedDay(endDateTZ))
|
|
64
|
+
) {
|
|
65
|
+
addedDays += 1;
|
|
66
|
+
}
|
|
67
|
+
endDateTZ.add(1, 'days');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return moment.utc(endDateTZ).format();
|
|
71
|
+
};
|
package/lib/store/pickEndDate.js
CHANGED
|
@@ -1,108 +1,82 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
const { MAX_ADD_DAYS } = require('../constants/Store');
|
|
2
|
+
|
|
3
|
+
module.exports = ({ _, moment, actions }) =>
|
|
4
|
+
function pickEndDate(
|
|
5
|
+
schedules,
|
|
6
|
+
isoWeekday,
|
|
7
|
+
fromDate,
|
|
8
|
+
readyDateCapacityCounts = []
|
|
9
|
+
) {
|
|
10
|
+
const timezone = actions.getStoreTimezone();
|
|
11
|
+
|
|
12
|
+
let candidateDate = actions.pickBaseEndDate(
|
|
13
|
+
schedules,
|
|
14
|
+
isoWeekday,
|
|
15
|
+
fromDate
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
const readyDateCapacityDays = actions.getReadyDateCapacityDays();
|
|
19
|
+
if (!actions.hasReadyDateCapacitySettings(readyDateCapacityDays))
|
|
20
|
+
return candidateDate;
|
|
21
|
+
|
|
22
|
+
const countsByDate = actions.getReadyDateCountsByDate(
|
|
23
|
+
readyDateCapacityCounts
|
|
24
|
+
);
|
|
25
|
+
if (!countsByDate.size) return candidateDate;
|
|
26
|
+
|
|
27
|
+
const inspectedDays = new Set();
|
|
28
|
+
|
|
29
|
+
for (let index = 0; index < MAX_ADD_DAYS; index += 1) {
|
|
30
|
+
const candidateMomentTZ = moment(candidateDate).tz(timezone);
|
|
31
|
+
const candidateLocalDateKey = candidateMomentTZ.format('YYYY-MM-DD');
|
|
32
|
+
|
|
33
|
+
if (inspectedDays.has(candidateLocalDateKey)) break;
|
|
34
|
+
inspectedDays.add(candidateLocalDateKey);
|
|
35
|
+
|
|
36
|
+
const capacitySettingsForDay = readyDateCapacityDays.find(
|
|
37
|
+
day => Number(_.get(day, 'day')) === candidateMomentTZ.isoWeekday()
|
|
38
|
+
);
|
|
23
39
|
|
|
24
|
-
|
|
25
|
-
const { dayOfWeek } = item || {};
|
|
26
|
-
if (!dayOfWeek || !dayOfWeek.length) return true;
|
|
27
|
-
return dayOfWeek.includes(day);
|
|
28
|
-
});
|
|
40
|
+
if (!capacitySettingsForDay) return candidateDate;
|
|
29
41
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
42
|
+
const maxOrders = actions.normalizeLimit(
|
|
43
|
+
_.get(capacitySettingsForDay, 'maxOrders')
|
|
44
|
+
);
|
|
45
|
+
const maxItems = actions.normalizeLimit(
|
|
46
|
+
_.get(capacitySettingsForDay, 'maxItems')
|
|
47
|
+
);
|
|
35
48
|
|
|
36
|
-
|
|
37
|
-
const schedule = _.get(settings, 'schedule', {});
|
|
38
|
-
const { closed = [] } = schedule;
|
|
39
|
-
if (!Array.isArray(closed)) return [];
|
|
40
|
-
return closed;
|
|
41
|
-
};
|
|
49
|
+
if (maxOrders <= 0 && maxItems <= 0) return candidateDate;
|
|
42
50
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
cutDay,
|
|
51
|
-
skipDays,
|
|
52
|
-
todayTZ,
|
|
53
|
-
} = getSchedule(schedules, isoWeekday);
|
|
54
|
-
|
|
55
|
-
let endDateTZ = todayTZ.clone();
|
|
56
|
-
const closedDays = getClosedDays();
|
|
57
|
-
const todayHours = todayTZ.get('hours');
|
|
58
|
-
const todayMinutes = todayTZ.get('minutes');
|
|
59
|
-
|
|
60
|
-
const addDays =
|
|
61
|
-
typeof addDaysParam !== 'number' || addDaysParam > MAX_ADD_DAYS
|
|
62
|
-
? 0
|
|
63
|
-
: addDaysParam;
|
|
64
|
-
|
|
65
|
-
if (
|
|
66
|
-
(cutHour && todayHours > cutHour.hour) ||
|
|
67
|
-
(cutHour && todayHours >= cutHour.hour && todayMinutes > cutHour.minute)
|
|
68
|
-
) {
|
|
69
|
-
endDateTZ = endDateTZ.add(cutDay, 'days');
|
|
70
|
-
}
|
|
51
|
+
const candidateUTCDateKey = moment
|
|
52
|
+
.utc(candidateDate)
|
|
53
|
+
.format('YYYY-MM-DD');
|
|
54
|
+
const dayCount = countsByDate.get(candidateUTCDateKey) || {
|
|
55
|
+
totalOrders: 0,
|
|
56
|
+
totalItems: 0,
|
|
57
|
+
};
|
|
71
58
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
endDateTZ.set('minute', readyHour.minute);
|
|
59
|
+
const isUnavailable =
|
|
60
|
+
(maxOrders > 0 && dayCount.totalOrders >= maxOrders) ||
|
|
61
|
+
(maxItems > 0 && dayCount.totalItems >= maxItems);
|
|
76
62
|
|
|
77
|
-
|
|
63
|
+
if (!isUnavailable) return candidateDate;
|
|
78
64
|
|
|
79
|
-
|
|
80
|
-
|
|
65
|
+
const nextDateSeed = candidateMomentTZ
|
|
66
|
+
.clone()
|
|
67
|
+
.add(1, 'day')
|
|
68
|
+
.startOf('day')
|
|
69
|
+
.toISOString();
|
|
81
70
|
|
|
82
|
-
|
|
83
|
-
|
|
71
|
+
const { readyHour, cutHour, cutDay, skipDays } =
|
|
72
|
+
actions.getSchedule(schedules, undefined, candidateDate) || {};
|
|
84
73
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
74
|
+
candidateDate = actions.pickBaseEndDate(
|
|
75
|
+
[{ readyHour, cutHour, cutDay, skipDays }],
|
|
76
|
+
undefined,
|
|
77
|
+
nextDateSeed
|
|
88
78
|
);
|
|
89
|
-
|
|
90
|
-
let addedDays = 0;
|
|
91
|
-
|
|
92
|
-
while (
|
|
93
|
-
addedDays < addDays ||
|
|
94
|
-
isSkipDay(endDateTZ.isoWeekday()) ||
|
|
95
|
-
isClosedDay(endDateTZ)
|
|
96
|
-
) {
|
|
97
|
-
if (
|
|
98
|
-
endDateTZ.isSame(todayTZ, 'day') ||
|
|
99
|
-
(!isSkipDay(endDateTZ.isoWeekday()) && !isClosedDay(endDateTZ))
|
|
100
|
-
) {
|
|
101
|
-
addedDays += 1;
|
|
102
|
-
}
|
|
103
|
-
endDateTZ.add(1, 'days');
|
|
104
79
|
}
|
|
105
80
|
|
|
106
|
-
return
|
|
81
|
+
return candidateDate;
|
|
107
82
|
};
|
|
108
|
-
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@darkpos/pricing",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.146",
|
|
4
4
|
"description": "Pricing calculator",
|
|
5
5
|
"author": "Dark POS",
|
|
6
6
|
"license": "ISC",
|
|
@@ -54,5 +54,5 @@
|
|
|
54
54
|
"supertest": "^6.2.3",
|
|
55
55
|
"supervisor": "^0.12.0"
|
|
56
56
|
},
|
|
57
|
-
"gitHead": "
|
|
57
|
+
"gitHead": "50cda463bcaad6e5aa03bded3329269a9ac99398"
|
|
58
58
|
}
|