@darkpos/pricing 1.0.104 → 1.0.107

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.
@@ -1315,6 +1315,10 @@ describe('Conditions not met for the item', () => {
1315
1315
  expect(calculatedOrder.total).toBe(7.5);
1316
1316
  expect(calculatedOrder.items[0].total).toBe(7.5);
1317
1317
  expect(calculatedOrder.items[0].modifiers[0].conditions.valid).toBe(true);
1318
+ expect(calculatedOrder.items[0].modifiers[0].locked).toBe(true);
1319
+ expect(calculatedOrder.items[0].modifiers[0].properties.customerId).toBe(
1320
+ '123456789'
1321
+ );
1318
1322
  });
1319
1323
 
1320
1324
  test('Should mark modifier as not valid if customerTotalSales !== 0', () => {
@@ -1372,6 +1376,7 @@ describe('Conditions not met for the item', () => {
1372
1376
  expect(calculatedOrder.total).toBe(10);
1373
1377
  expect(calculatedOrder.items[0].total).toBe(10);
1374
1378
  expect(calculatedOrder.items[0].modifiers[0].conditions.valid).toBe(false);
1379
+ expect(calculatedOrder.items[0].modifiers[0].locked).toBe(undefined);
1375
1380
  });
1376
1381
 
1377
1382
  test('Should mark modifier as valid if customerTotalVisits === 0', () => {
@@ -1429,6 +1434,10 @@ describe('Conditions not met for the item', () => {
1429
1434
  expect(calculatedOrder.total).toBe(7.5);
1430
1435
  expect(calculatedOrder.items[0].total).toBe(7.5);
1431
1436
  expect(calculatedOrder.items[0].modifiers[0].conditions.valid).toBe(true);
1437
+ expect(calculatedOrder.items[0].modifiers[0].locked).toBe(true);
1438
+ expect(calculatedOrder.items[0].modifiers[0].properties.customerId).toBe(
1439
+ '123456789'
1440
+ );
1432
1441
  });
1433
1442
 
1434
1443
  test('Should mark modifier as not valid if customerTotalVisits !== 0', () => {
@@ -1486,5 +1495,133 @@ describe('Conditions not met for the item', () => {
1486
1495
  expect(calculatedOrder.total).toBe(10);
1487
1496
  expect(calculatedOrder.items[0].total).toBe(10);
1488
1497
  expect(calculatedOrder.items[0].modifiers[0].conditions.valid).toBe(false);
1498
+ expect(calculatedOrder.items[0].modifiers[0].locked).toBe(undefined);
1499
+ });
1500
+
1501
+ test('Should mark modifier as not valid if there is no customer', () => {
1502
+ const modifier = {
1503
+ _id: '6819114c06c23d37c1f19412',
1504
+ name: 'first order discount',
1505
+ type: 'discount',
1506
+ tags: ['default'],
1507
+ direct: true,
1508
+ conditions: {
1509
+ valid: null,
1510
+ rules: [
1511
+ {
1512
+ key: 'customerTotalVisits',
1513
+ value: 0,
1514
+ operand: '$eq',
1515
+ },
1516
+ ],
1517
+ },
1518
+ compute: {
1519
+ type: 'percentage',
1520
+ action: 'subtract',
1521
+ amount: 25,
1522
+ },
1523
+ };
1524
+
1525
+ const item = {
1526
+ _id: 'abc',
1527
+ price: 10,
1528
+ quantity: 1,
1529
+ modifiers: [],
1530
+ };
1531
+
1532
+ let order = {
1533
+ items: [item],
1534
+ };
1535
+
1536
+ order = pricingService.order.addItemModifier({
1537
+ order,
1538
+ modifier,
1539
+ itemIndex: 0,
1540
+ });
1541
+
1542
+ expect(order.items[0].modifiers.length).toBe(1);
1543
+
1544
+ const calculatedOrder = pricingService.order.calculate(order);
1545
+
1546
+ expect(calculatedOrder.total).toBe(10);
1547
+ expect(calculatedOrder.items[0].total).toBe(10);
1548
+ expect(calculatedOrder.items[0].modifiers[0].conditions.valid).toBe(false);
1549
+ expect(calculatedOrder.items[0].modifiers[0].locked).toBe(undefined);
1550
+ expect(calculatedOrder.items[0].modifiers[0].properties).toBe(undefined);
1551
+ });
1552
+
1553
+ test('Should mark modifier as valid if there is a customer, no matter is stats is undefined', () => {
1554
+ const modifier = {
1555
+ _id: '6819114c06c23d37c1f19412',
1556
+ name: 'first order discount',
1557
+ type: 'discount',
1558
+ tags: ['default'],
1559
+ direct: true,
1560
+ conditions: {
1561
+ valid: null,
1562
+ rules: [
1563
+ {
1564
+ key: 'customerTotalVisits',
1565
+ value: 0,
1566
+ operand: '$eq',
1567
+ },
1568
+ ],
1569
+ },
1570
+ compute: {
1571
+ type: 'percentage',
1572
+ action: 'subtract',
1573
+ amount: 25,
1574
+ },
1575
+ };
1576
+
1577
+ const item = {
1578
+ _id: 'abc',
1579
+ price: 10,
1580
+ quantity: 1,
1581
+ modifiers: [],
1582
+ };
1583
+
1584
+ let order = {
1585
+ items: [item],
1586
+ customer: {
1587
+ _id: 'abcd1234',
1588
+ },
1589
+ };
1590
+
1591
+ order = pricingService.order.addItemModifier({
1592
+ order,
1593
+ modifier,
1594
+ itemIndex: 0,
1595
+ });
1596
+
1597
+ expect(order.items[0].modifiers.length).toBe(1);
1598
+
1599
+ let calculatedOrder = pricingService.order.calculate(order);
1600
+
1601
+ expect(calculatedOrder.total).toBe(7.5);
1602
+ expect(calculatedOrder.items[0].total).toBe(7.5);
1603
+ expect(calculatedOrder.items[0].modifiers[0].conditions.valid).toBe(true);
1604
+ expect(calculatedOrder.items[0].modifiers[0].locked).toBe(true);
1605
+ expect(calculatedOrder.items[0].modifiers[0].properties.customerId).toBe(
1606
+ 'abcd1234'
1607
+ );
1608
+
1609
+ calculatedOrder = pricingService.order.calculate({
1610
+ ...calculatedOrder,
1611
+ customer: {
1612
+ _id: '11122555',
1613
+ stats: {
1614
+ totalVisits: 15,
1615
+ },
1616
+ },
1617
+ });
1618
+
1619
+ expect(calculatedOrder.total).toBe(10);
1620
+ expect(calculatedOrder.items[0].total).toBe(10);
1621
+ expect(calculatedOrder.items[0].modifiers[0].conditions.valid).toBe(false);
1622
+ expect(calculatedOrder.items[0].modifiers[0].locked).toBe(false);
1623
+ expect(calculatedOrder.items[0].modifiers[0].properties.customerId).toBe(
1624
+ undefined
1625
+ );
1489
1626
  });
1490
1627
  });
@@ -1602,9 +1602,6 @@ describe('Order actions', () => {
1602
1602
  expect(subOrders[0].displayId).toBe('1-1');
1603
1603
  expect(subOrders[0].items.map(item => item.name)).toEqual([
1604
1604
  'Box Shirt - Fold',
1605
- ]);
1606
- expect(subOrders[1].displayId).toBe('1-2');
1607
- expect(subOrders[1].items.map(item => item.name)).toEqual([
1608
1605
  'Pants',
1609
1606
  'M-L 2pc Suit',
1610
1607
  ]);
@@ -3193,7 +3190,7 @@ describe('Order actions', () => {
3193
3190
  test('should return the latest location= assembled', () => {
3194
3191
  const status = {
3195
3192
  assembled: { location: '1', date: '2024-02-27T12:00:00Z' },
3196
- tracker: { location: 'Truck', date: '2024-02-26T12:00:00Z' },
3193
+ tracker: [{ location: 'Truck', date: '2024-02-26T12:00:00Z' }],
3197
3194
  racked: { location: '%AB', date: '2024-02-25T15:00:00Z' },
3198
3195
  };
3199
3196
  expect(pricingService.order.getLastLocation({ status })).toEqual({
@@ -3207,7 +3204,7 @@ describe('Order actions', () => {
3207
3204
  test('should return the latest location= racked', () => {
3208
3205
  const status = {
3209
3206
  assembled: { location: '1', date: '2024-02-25T12:00:00Z' },
3210
- tracker: { location: 'Truck', date: '2024-02-26T12:00:00Z' },
3207
+ tracker: [{ location: 'Truck', date: '2024-02-26T12:00:00Z' }],
3211
3208
  racked: { location: '%AB', date: '2024-02-27T15:00:00Z' },
3212
3209
  };
3213
3210
  expect(pricingService.order.getLastLocation({ status })).toEqual({
@@ -3221,7 +3218,7 @@ describe('Order actions', () => {
3221
3218
  test('should handle null values correctly and still return the latest location', () => {
3222
3219
  const status = {
3223
3220
  assembled: null,
3224
- tracker: { location: 'Truck', date: '2024-02-26T12:00:00Z' },
3221
+ tracker: [{ location: 'Truck', date: '2024-02-26T12:00:00Z' }],
3225
3222
  racked: { location: '%AB', date: '2024-02-27T15:00:00Z' },
3226
3223
  };
3227
3224
  expect(pricingService.order.getLastLocation({ status })).toEqual({
@@ -37,12 +37,14 @@ describe('Auto Split', () => {
37
37
  _id: '123',
38
38
  itemId: '234',
39
39
  modifiers: [laundryModNoAutoSplit],
40
+ quantity: 1,
40
41
  };
41
42
 
42
43
  const item2 = {
43
44
  _id: '123',
44
45
  itemId: '234',
45
46
  modifiers: [dryCleaningModNoAutoSplit],
47
+ quantity: 1,
46
48
  };
47
49
 
48
50
  const item3 = {
@@ -70,7 +72,11 @@ describe('Auto Split', () => {
70
72
  },
71
73
  });
72
74
 
73
- expect(subOrders.length).toEqual(3);
75
+ expect(subOrders.length).toEqual(1);
76
+ expect(subOrders[0].items.length).toEqual(3);
77
+ expect(subOrders[0].items[0].quantity).toEqual(2);
78
+ expect(subOrders[0].items[1].quantity).toEqual(1000);
79
+ expect(subOrders[0].items[2].quantity).toEqual(1000);
74
80
  });
75
81
 
76
82
  test('Auto split by department and Items Quantity', () => {
@@ -125,7 +131,7 @@ describe('Auto Split', () => {
125
131
  },
126
132
  });
127
133
 
128
- expect(subOrders.length).toEqual(7);
134
+ expect(subOrders.length).toEqual(6);
129
135
  });
130
136
 
131
137
  test('Auto split by department and Items Pieces', () => {
@@ -180,7 +186,7 @@ describe('Auto Split', () => {
180
186
  },
181
187
  });
182
188
 
183
- expect(subOrders.length).toEqual(12);
189
+ expect(subOrders.length).toEqual(11);
184
190
  });
185
191
 
186
192
  test('Auto split by department and Items Pieces 2', () => {
@@ -260,13 +266,13 @@ describe('Auto Split', () => {
260
266
  },
261
267
  });
262
268
 
263
- expect(subOrders.length).toEqual(6);
269
+ expect(subOrders.length).toEqual(5);
264
270
  expect(subOrders[0].items[0].quantity).toEqual(3);
265
271
  expect(subOrders[1].items[0].quantity).toEqual(3);
266
272
  expect(subOrders[2].items[0].quantity).toEqual(3);
267
273
  expect(subOrders[3].items[0].quantity).toEqual(1);
268
274
  expect(subOrders[4].items[0].quantity).toEqual(5);
269
- expect(subOrders[5].items[0].quantity).toEqual(1000);
275
+ expect(subOrders[4].items[1].quantity).toEqual(1000);
270
276
  });
271
277
 
272
278
  test('Auto split by department and Items Weight', () => {
@@ -395,4 +401,283 @@ describe('Auto Split', () => {
395
401
  expect(subOrders[0].items[1].modifiers[0]._id).toEqual('234');
396
402
  expect(subOrders[0].items[1].modifiers[1]._id).toEqual('456');
397
403
  });
404
+
405
+ test('Auto split by department and Items Weight 0 (unlimited)', () => {
406
+ const { autoSplit } = pricingService.order;
407
+
408
+ const laundryModMaxItems = {
409
+ ...laundryModNoAutoSplit,
410
+ properties: {
411
+ department: {
412
+ autoSplit: true,
413
+ maxItems: 0,
414
+ splitUnit: 'weight',
415
+ },
416
+ },
417
+ };
418
+
419
+ const item1 = {
420
+ _id: '123',
421
+ itemId: '234',
422
+ modifiers: [laundryModMaxItems],
423
+ quantity: 1,
424
+ pieces: 2,
425
+ weight: 25,
426
+ };
427
+
428
+ const item2 = {
429
+ _id: '322',
430
+ itemId: '4555',
431
+ modifiers: [laundryModMaxItems],
432
+ quantity: 1,
433
+ pieces: 2,
434
+ weight: 25,
435
+ };
436
+
437
+ const subOrders = autoSplit({
438
+ parentOrder: {
439
+ items: [item1, item2],
440
+ status: {},
441
+ modifiers: [],
442
+ displayId: 1,
443
+ },
444
+ });
445
+
446
+ expect(subOrders.length).toEqual(1);
447
+ expect(subOrders[0].items[0].quantity).toEqual(1);
448
+ expect(subOrders[0].items[0].weight).toEqual(25);
449
+
450
+ expect(subOrders[0].items[1].quantity).toEqual(1);
451
+ expect(subOrders[0].items[1].weight).toEqual(25);
452
+ });
453
+
454
+ test('Should keep both the parent and the related items in a single order. (keepRelatedItems=true)', () => {
455
+ const tailoringModifier = {
456
+ _id: '686d62bee0f59b1de5d93b2d',
457
+ attributes: ['department'],
458
+ modifierId: '67fea241af24e570c032b339',
459
+ name: 'Tailoring',
460
+ tags: ['default'],
461
+ code: 'T',
462
+ properties: {
463
+ group: null,
464
+ department: {
465
+ tagSize: null,
466
+ customerTagsExtend: null,
467
+ autoSplit: true,
468
+ },
469
+ },
470
+ conditions: {
471
+ valid: true,
472
+ },
473
+ };
474
+
475
+ const dtModifier = {
476
+ _id: '686d62bee0f59b1de5d93b2f',
477
+ attributes: ['department'],
478
+ modifierId: '686c4033399a3a7376b7ec3a',
479
+ _parentId: null,
480
+ locked: false,
481
+ name: 'D + T',
482
+ sku: '',
483
+ description: '',
484
+ group: '',
485
+ type: '',
486
+ tags: ['default'],
487
+ order: 0,
488
+ included: false,
489
+ direct: true,
490
+ hidden: false,
491
+ print: true,
492
+ required: false,
493
+ recommended: false,
494
+ default: false,
495
+ code: 'DT',
496
+ properties: {
497
+ subscription: {},
498
+ override: {},
499
+ group: {
500
+ items: [],
501
+ modifiers: [],
502
+ },
503
+ department: {
504
+ tagSize: 'small',
505
+ splitUnit: 'quantity',
506
+ maxItems: '',
507
+ autoSplit: true,
508
+ keepRelatedItems: true,
509
+ },
510
+ sort: null,
511
+ },
512
+ _computed: {
513
+ amount: 0,
514
+ description: 'D + T',
515
+ },
516
+ conditions: {
517
+ valid: true,
518
+ },
519
+ compute: null,
520
+ _createdAt: '2025-07-07T21:46:27.393Z',
521
+ _updatedAt: '2025-07-08T15:48:47.145Z',
522
+ __typename: 'Modifier',
523
+ };
524
+
525
+ const parentOrder = {
526
+ _id: '686d62ace0f59b1de5d93b27',
527
+
528
+ items: [
529
+ {
530
+ name: 'Jacket Zipper Long',
531
+ modifiers: [tailoringModifier],
532
+ _id: '686d62bee0f59b1de5d93b2c',
533
+ weight: 0,
534
+ properties: {
535
+ relatedItem: true,
536
+ parentItemId: '67fea241af24e570c032b319',
537
+ parentId: '686d62b3e0f59b1de5d93b28',
538
+ includeParent: true,
539
+ },
540
+ },
541
+ {
542
+ name: "2pc Men's Suit",
543
+ modifiers: [dtModifier],
544
+ _id: '686d62b3e0f59b1de5d93b28',
545
+ pieces: 2,
546
+ quantity: 1,
547
+ weight: 0,
548
+ properties: {},
549
+ },
550
+ ],
551
+ modifiers: [],
552
+ status: {},
553
+ };
554
+
555
+ const subOrders = pricingService.order.autoSplit({
556
+ parentOrder,
557
+ });
558
+
559
+ expect(subOrders.length).toBe(1);
560
+ expect(subOrders[0].items.length).toBe(2);
561
+ });
562
+
563
+ test('Should split the parent and the related items in different orders. (keepRelatedItems=false)', () => {
564
+ const tailoringModifier = {
565
+ _id: '686d62bee0f59b1de5d93b2d',
566
+ attributes: ['department'],
567
+ modifierId: '67fea241af24e570c032b339',
568
+ name: 'Tailoring',
569
+ tags: ['default'],
570
+ code: 'T',
571
+ properties: {
572
+ group: null,
573
+ department: {
574
+ tagSize: null,
575
+ customerTagsExtend: null,
576
+ autoSplit: true,
577
+ },
578
+ },
579
+ conditions: {
580
+ valid: true,
581
+ },
582
+ };
583
+
584
+ const dtModifier = {
585
+ _id: '686d62bee0f59b1de5d93b2f',
586
+ attributes: ['department'],
587
+ modifierId: '686c4033399a3a7376b7ec3a',
588
+ _parentId: null,
589
+ locked: false,
590
+ name: 'D + T',
591
+ sku: '',
592
+ description: '',
593
+ group: '',
594
+ type: '',
595
+ tags: ['default'],
596
+ order: 0,
597
+ included: false,
598
+ direct: true,
599
+ hidden: false,
600
+ print: true,
601
+ required: false,
602
+ recommended: false,
603
+ default: false,
604
+ code: 'DT',
605
+ properties: {
606
+ subscription: {},
607
+ override: {},
608
+ group: {
609
+ items: [],
610
+ modifiers: [],
611
+ },
612
+ department: {
613
+ tagSize: 'small',
614
+ splitUnit: 'quantity',
615
+ maxItems: '',
616
+ autoSplit: true,
617
+ keepRelatedItems: false,
618
+ },
619
+ sort: null,
620
+ },
621
+ _computed: {
622
+ amount: 0,
623
+ description: 'D + T',
624
+ },
625
+ conditions: {
626
+ valid: true,
627
+ },
628
+ compute: null,
629
+ _createdAt: '2025-07-07T21:46:27.393Z',
630
+ _updatedAt: '2025-07-08T15:48:47.145Z',
631
+ __typename: 'Modifier',
632
+ };
633
+
634
+ const parentOrder = {
635
+ _id: '686d62ace0f59b1de5d93b27',
636
+
637
+ items: [
638
+ {
639
+ name: 'Jacket Zipper Long',
640
+ modifiers: [tailoringModifier],
641
+ _id: '686d62bee0f59b1de5d93b2c',
642
+ weight: 0,
643
+ properties: {
644
+ relatedItem: true,
645
+ parentItemId: '67fea241af24e570c032b319',
646
+ parentId: '686d62b3e0f59b1de5d93b28',
647
+ includeParent: true,
648
+ },
649
+ },
650
+ {
651
+ name: "2pc Men's Suit",
652
+ modifiers: [dtModifier],
653
+ _id: '686d62b3e0f59b1de5d93b28',
654
+ pieces: 2,
655
+ quantity: 1,
656
+ weight: 0,
657
+ properties: {},
658
+ },
659
+
660
+ {
661
+ name: 'other item',
662
+ modifiers: [],
663
+ _id: '12356487',
664
+ pieces: 2,
665
+ quantity: 1,
666
+ weight: 0,
667
+ properties: {},
668
+ },
669
+ ],
670
+ modifiers: [],
671
+ status: {},
672
+ };
673
+
674
+ const subOrders = pricingService.order.autoSplit({
675
+ parentOrder,
676
+ });
677
+
678
+ expect(subOrders.length).toBe(3);
679
+ expect(subOrders[0].items.length).toBe(1);
680
+ expect(subOrders[1].items.length).toBe(1);
681
+ expect(subOrders[2].items.length).toBe(1);
682
+ });
398
683
  });
@@ -12,18 +12,7 @@ module.exports = ({ _, utils, actions, modifierActions }) => {
12
12
  const isPrepay = opts.isPrepay || false;
13
13
  const startRequestDate = opts.startRequestDate || null;
14
14
  const endRequestDate = opts.endRequestDate || null;
15
-
16
- let customerTotalVisits = 0;
17
- let customerTotalSales = 0;
18
-
19
- if (
20
- opts.customer &&
21
- typeof opts.customer !== 'string' &&
22
- opts.customer.stats
23
- ) {
24
- customerTotalVisits = opts.customer.stats.totalVisits || 0;
25
- customerTotalSales = opts.customer.stats.totalSales || 0;
26
- }
15
+ const customer = opts.customer || null;
27
16
 
28
17
  const lockPaymentModifiers = !!opts.lockPaymentModifiers;
29
18
  const allItems = Array.isArray(opts.items) ? opts.items : [];
@@ -56,16 +45,21 @@ module.exports = ({ _, utils, actions, modifierActions }) => {
56
45
  subTotals._simple = math.mul(price, quantity);
57
46
 
58
47
  const modifiers = [];
59
- const { modifiers: itemModifiersPrev = [] } =
48
+ let { modifiers: itemModifiersPrev = [] } =
60
49
  actions.removeModifiersByQuantity(item);
61
50
 
51
+ itemModifiersPrev = modifierActions.unlockCustomerStatsModifiers({
52
+ modifiers: itemModifiersPrev,
53
+ customer,
54
+ });
55
+
62
56
  const itemModifiers = [...itemModifiersPrev].filter(
63
57
  mod =>
64
58
  !modifierActions.isCalculatedPaymentModifier(mod) ||
65
59
  modifierActions.isLocked(mod)
66
60
  );
67
61
 
68
- const validatedModifiers = actions.validateModifiers({
62
+ let validatedModifiers = actions.validateModifiers({
69
63
  item,
70
64
  itemModifiers,
71
65
  startRequestDate,
@@ -74,8 +68,12 @@ module.exports = ({ _, utils, actions, modifierActions }) => {
74
68
  paymentMethod,
75
69
  paymentType,
76
70
  isPrepay,
77
- customerTotalVisits,
78
- customerTotalSales,
71
+ customer,
72
+ });
73
+
74
+ validatedModifiers = modifierActions.lockCustomerStatsModifiers({
75
+ modifiers: validatedModifiers,
76
+ customer,
79
77
  });
80
78
 
81
79
  const modifiersToCompute = validatedModifiers.filter(
@@ -0,0 +1,23 @@
1
+ module.exports = ({ actions, modifierActions }) =>
2
+ function getSplitDepartment({ items, item }) {
3
+ if (actions.isRelatedItem(item)) {
4
+ const parentItem = actions.getParentItem(items, item);
5
+
6
+ if (parentItem) {
7
+ const parentDeps = actions.getDepartmentModifiers(parentItem);
8
+ if (
9
+ parentDeps.length &&
10
+ modifierActions.isSplitDepartment(parentDeps[0]) &&
11
+ modifierActions.isKeepRelatedItems(parentDeps[0])
12
+ )
13
+ return parentDeps[0].name;
14
+ }
15
+ }
16
+
17
+ const deps = actions.getDepartmentModifiers(item);
18
+
19
+ if (deps.length && modifierActions.isSplitDepartment(deps[0]))
20
+ return deps[0].name;
21
+
22
+ return 'other';
23
+ };
package/lib/item/index.js CHANGED
@@ -69,6 +69,7 @@ const validateModifiers = require('./validateModifiers');
69
69
  const adjustNegativeTotal = require('./adjustNegativeTotal');
70
70
  const applyNotesOverridesToItem = require('./applyNotesOverridesToItem');
71
71
  const getModifiersToNotCompute = require('./getModifiersToNotCompute');
72
+ const getSplitDepartment = require('./getSplitDepartment');
72
73
 
73
74
  const itemActions = (deps = {}) => {
74
75
  const actions = {};
@@ -151,6 +152,7 @@ const itemActions = (deps = {}) => {
151
152
  adjustNegativeTotal: adjustNegativeTotal(innerDeps),
152
153
  applyNotesOverridesToItem: applyNotesOverridesToItem(innerDeps),
153
154
  getModifiersToNotCompute: getModifiersToNotCompute(innerDeps),
155
+ getSplitDepartment: getSplitDepartment(innerDeps),
154
156
  });
155
157
 
156
158
  Object.keys(freezedActions).forEach(actionName => {
@@ -8,8 +8,7 @@ module.exports = ({ modifierActions }) =>
8
8
  paymentMethod,
9
9
  paymentType,
10
10
  isPrepay,
11
- customerTotalVisits,
12
- customerTotalSales,
11
+ customer,
13
12
  }) {
14
13
  const validatedModifiers = [];
15
14
  const firstValidatedModifiers = itemModifiers.map(each =>
@@ -21,8 +20,7 @@ module.exports = ({ modifierActions }) =>
21
20
  paymentMethod,
22
21
  paymentType,
23
22
  isPrepay,
24
- customerTotalVisits,
25
- customerTotalSales,
23
+ customer,
26
24
  })
27
25
  );
28
26
 
@@ -1,4 +1,15 @@
1
1
  module.exports = ({ actions, utils }) => {
2
+ const getCustomerStat = (customer, key) => {
3
+ if (
4
+ !customer ||
5
+ !customer.stats ||
6
+ typeof customer.stats[key] !== 'number'
7
+ ) {
8
+ return 0;
9
+ }
10
+ return customer.stats[key];
11
+ };
12
+
2
13
  const modifierConditionPass = (
3
14
  modifier,
4
15
  {
@@ -9,8 +20,7 @@ module.exports = ({ actions, utils }) => {
9
20
  paymentMethod,
10
21
  paymentType,
11
22
  isPrepay,
12
- customerTotalVisits,
13
- customerTotalSales,
23
+ customer,
14
24
  }
15
25
  ) =>
16
26
  modifier.conditions && Array.isArray(modifier.conditions.rules)
@@ -86,14 +96,16 @@ module.exports = ({ actions, utils }) => {
86
96
  condition.operand
87
97
  );
88
98
  case 'customerTotalVisits':
99
+ if (!actions.isValidCustomer(customer)) return false;
89
100
  return actions.validateNumberCondition(
90
- customerTotalVisits,
101
+ getCustomerStat(customer, 'totalVisits'),
91
102
  condition.value,
92
103
  condition.operand
93
104
  );
94
105
  case 'customerTotalSales':
106
+ if (!actions.isValidCustomer(customer)) return false;
95
107
  return actions.validateNumberCondition(
96
- customerTotalSales,
108
+ getCustomerStat(customer, 'totalSales'),
97
109
  condition.value,
98
110
  condition.operand
99
111
  );
@@ -138,8 +150,7 @@ module.exports = ({ actions, utils }) => {
138
150
  paymentMethod,
139
151
  paymentType,
140
152
  isPrepay,
141
- customerTotalVisits,
142
- customerTotalSales,
153
+ customer,
143
154
  } = opts;
144
155
  return (
145
156
  modifier &&
@@ -151,8 +162,7 @@ module.exports = ({ actions, utils }) => {
151
162
  paymentMethod,
152
163
  paymentType,
153
164
  isPrepay,
154
- customerTotalVisits,
155
- customerTotalSales,
165
+ customer,
156
166
  })
157
167
  );
158
168
  }
@@ -167,6 +167,15 @@ const isNotesOverride = require('./isNotesOverride');
167
167
  const isOverrideSubtotal = require('./isOverrideSubtotal');
168
168
  const validatePaymentCondition = require('./validatePaymentCondition');
169
169
  const createManualModifier = require('./createManualModifier');
170
+ const isCustomerStatsModifier = require('./isCustomerStatsModifier');
171
+ const isTotalSalesModifier = require('./isTotalSalesModifier');
172
+ const isTotalVisitsModifier = require('./isTotalVisitsModifier');
173
+ const isValidCustomer = require('./isValidCustomer');
174
+ const lockCustomerStatsModifiers = require('./lockCustomerStatsModifiers');
175
+ const unlockCustomerStatsModifiers = require('./unlockCustomerStatsModifiers');
176
+ const isAutoSplit = require('./isAutoSplit');
177
+ const isKeepRelatedItems = require('./isKeepRelatedItems');
178
+ const isSplitDepartment = require('./isSplitDepartment');
170
179
 
171
180
  const modifierActions = (deps = {}) => {
172
181
  const actions = {};
@@ -347,6 +356,15 @@ const modifierActions = (deps = {}) => {
347
356
  isOverrideSubtotal: isOverrideSubtotal(innerDeps),
348
357
  validatePaymentCondition: validatePaymentCondition(innerDeps),
349
358
  createManualModifier: createManualModifier(innerDeps),
359
+ isCustomerStatsModifier: isCustomerStatsModifier(innerDeps),
360
+ isTotalSalesModifier: isTotalSalesModifier(innerDeps),
361
+ isTotalVisitsModifier: isTotalVisitsModifier(innerDeps),
362
+ isValidCustomer: isValidCustomer(innerDeps),
363
+ lockCustomerStatsModifiers: lockCustomerStatsModifiers(innerDeps),
364
+ unlockCustomerStatsModifiers: unlockCustomerStatsModifiers(innerDeps),
365
+ isAutoSplit: isAutoSplit(innerDeps),
366
+ isKeepRelatedItems: isKeepRelatedItems(innerDeps),
367
+ isSplitDepartment: isSplitDepartment(innerDeps),
350
368
  });
351
369
 
352
370
  Object.keys(freezedActions).forEach(actionName => {
@@ -0,0 +1,4 @@
1
+ module.exports = ({ _ }) =>
2
+ function isAutoSplit(modifier) {
3
+ return _.get(modifier || {}, 'properties.department.autoSplit', false);
4
+ };
@@ -0,0 +1,7 @@
1
+ module.exports = ({ actions }) =>
2
+ function isCustomerStatModifier(modifier) {
3
+ return (
4
+ actions.isTotalSalesModifier(modifier) ||
5
+ actions.isTotalVisitsModifier(modifier)
6
+ );
7
+ };
@@ -0,0 +1,8 @@
1
+ module.exports = ({ _ }) =>
2
+ function isAutoSplit(modifier) {
3
+ return _.get(
4
+ modifier || {},
5
+ 'properties.department.keepRelatedItems',
6
+ false
7
+ );
8
+ };
@@ -0,0 +1,5 @@
1
+ module.exports = ({ actions }) =>
2
+ function isSplitDepartment(modifier) {
3
+ if (!modifier || !actions.isDepartment(modifier)) return false;
4
+ return actions.isValid(modifier) && actions.isAutoSplit(modifier);
5
+ };
@@ -0,0 +1,11 @@
1
+ module.exports = () =>
2
+ function isPaymentTypeModifier(modifier) {
3
+ return !!(
4
+ modifier &&
5
+ modifier.conditions &&
6
+ Array.isArray(modifier.conditions.rules) &&
7
+ modifier.conditions.rules.some(
8
+ condition => condition.key === 'customerTotalSales'
9
+ )
10
+ );
11
+ };
@@ -0,0 +1,11 @@
1
+ module.exports = () =>
2
+ function isTotalVisitsModifier(modifier) {
3
+ return !!(
4
+ modifier &&
5
+ modifier.conditions &&
6
+ Array.isArray(modifier.conditions.rules) &&
7
+ modifier.conditions.rules.some(
8
+ condition => condition.key === 'customerTotalVisits'
9
+ )
10
+ );
11
+ };
@@ -0,0 +1,4 @@
1
+ module.exports = () =>
2
+ function isValid(customer) {
3
+ return customer && typeof customer !== 'string' && customer._id;
4
+ };
@@ -0,0 +1,22 @@
1
+ module.exports = ({ actions }) =>
2
+ function lockCustomerStatsModifiers({ modifiers, customer }) {
3
+ if (!Array.isArray(modifiers)) return [];
4
+ return modifiers.map(valMod => {
5
+ if (
6
+ actions.isValidCustomer(customer) &&
7
+ actions.isCustomerStatsModifier(valMod) &&
8
+ actions.isValid(valMod)
9
+ ) {
10
+ return {
11
+ ...valMod,
12
+ locked: true,
13
+ properties: {
14
+ ...(valMod.properties || {}),
15
+ customerId: customer._id,
16
+ },
17
+ };
18
+ }
19
+
20
+ return valMod;
21
+ });
22
+ };
@@ -0,0 +1,23 @@
1
+ module.exports = ({ actions }) =>
2
+ function unlockCustomerStatsModifiers({ modifiers, customer }) {
3
+ if (!Array.isArray(modifiers)) return [];
4
+ return modifiers.map(valMod => {
5
+ if (
6
+ actions.isValidCustomer(customer) &&
7
+ actions.isCustomerStatsModifier(valMod) &&
8
+ actions.isLocked(valMod) &&
9
+ valMod.properties.customerId !== customer._id
10
+ ) {
11
+ return {
12
+ ...valMod,
13
+ locked: false,
14
+ properties: {
15
+ ...(valMod.properties || {}),
16
+ customerId: undefined,
17
+ },
18
+ };
19
+ }
20
+
21
+ return valMod;
22
+ });
23
+ };
@@ -1,11 +1,20 @@
1
- module.exports = () =>
2
- function getLastLocation(order) {
1
+ module.exports = () => {
2
+ const sortByDateAsc = (obj1, obj2) =>
3
+ new Date(obj1.date) - new Date(obj2.date);
4
+
5
+ return function getLastLocation(order) {
3
6
  if (!order || !order.status) return null;
4
7
 
5
- const { assembled = {}, tracker = {}, racked = {} } = order.status;
8
+ const { assembled = {}, tracker = [], racked = {} } = order.status;
9
+ const trackerArr = (Array.isArray(tracker) ? tracker : [tracker]).filter(
10
+ Boolean
11
+ );
12
+ trackerArr.sort(sortByDateAsc);
6
13
 
7
14
  let latestLocation =
8
- tracker && tracker.date ? { ...tracker, isTracker: true } : {};
15
+ trackerArr.length > 0
16
+ ? { ...trackerArr[trackerArr.length - 1], isTracker: true }
17
+ : {};
9
18
 
10
19
  if (
11
20
  assembled &&
@@ -26,3 +35,4 @@ module.exports = () =>
26
35
 
27
36
  return Object.keys(latestLocation).length !== 0 ? latestLocation : null;
28
37
  };
38
+ };
@@ -13,11 +13,6 @@ module.exports = ({
13
13
 
14
14
  const isSplitByWeight = splitUnit => splitUnit === 'weight';
15
15
 
16
- const getDepartmentName = item => {
17
- const deps = itemActions.getDepartmentModifiers(item);
18
- return (deps.length && deps[0].name) || 'other';
19
- };
20
-
21
16
  const joinItemQuantityById = orders =>
22
17
  orders.map(order => {
23
18
  const items = order.items.reduce((arr, item) => {
@@ -37,8 +32,10 @@ module.exports = ({
37
32
  const getDepartmentSchedules = department => {
38
33
  if (!department) return null;
39
34
  const allSchedules = _.get(settings, 'order.schedules', []);
40
- return allSchedules.filter(item =>
41
- item.departments.some(dep => dep._id === department.modifierId)
35
+ return allSchedules.filter(
36
+ item =>
37
+ Array.isArray(item.departments) &&
38
+ item.departments.some(dep => dep._id === department.modifierId)
42
39
  );
43
40
  };
44
41
 
@@ -46,7 +43,15 @@ module.exports = ({
46
43
  parentOrder: parentOrderParam,
47
44
  newItems,
48
45
  }) {
49
- const itemsByDepartments = _.groupBy(newItems, getDepartmentName);
46
+ const sortedItems = [...newItems].sort((a, b) => {
47
+ const aIsRelated = itemActions.isRelatedItem(a);
48
+ const bIsRelated = itemActions.isRelatedItem(b);
49
+ return Number(aIsRelated) - Number(bIsRelated);
50
+ });
51
+
52
+ const itemsByDepartments = _.groupBy(sortedItems, item =>
53
+ itemActions.getSplitDepartment({ items: sortedItems, item })
54
+ );
50
55
  const itemGroups = Object.values(itemsByDepartments);
51
56
  let splitOrders = [];
52
57
  const defaultEndDate = storeActions.pickEndDate();
@@ -58,7 +63,10 @@ module.exports = ({
58
63
  itemGroups.forEach(items => {
59
64
  // Assuming there is one department in the item
60
65
  const department = itemActions.getDepartmentModifiers(items[0])[0];
61
- const departmentName = getDepartmentName(items[0]);
66
+ const departmentName = itemActions.getSplitDepartment({
67
+ items: sortedItems,
68
+ item: items[0],
69
+ });
62
70
  const maxItems = modifierActions.getDepartmentMaxItems(department);
63
71
  const departmentSchedules = getDepartmentSchedules(department);
64
72
  let parentOrder = { ...parentOrderParam };
@@ -74,11 +82,7 @@ module.exports = ({
74
82
  });
75
83
  }
76
84
 
77
- const autoSplit = _.get(
78
- department || {},
79
- 'properties.department.autoSplit',
80
- false
81
- );
85
+ const autoSplit = modifierActions.isAutoSplit(department);
82
86
 
83
87
  const splitUnit = _.get(
84
88
  department || {},
@@ -123,7 +127,11 @@ module.exports = ({
123
127
  newOrder.items &&
124
128
  getItemsTotalCount(newOrder.items) + totalCountPerItem <=
125
129
  maxItems &&
126
- departmentName === getDepartmentName(newOrder.items[0])
130
+ departmentName ===
131
+ itemActions.getSplitDepartment({
132
+ items: sortedItems,
133
+ item: items[0],
134
+ })
127
135
  );
128
136
  if (index > -1) {
129
137
  splitOrders[index].items.push(item);
@@ -138,7 +146,9 @@ module.exports = ({
138
146
  }
139
147
  }
140
148
  });
141
- } else splitOrders.push(actions.createSubOrder({ parentOrder, items }));
149
+ } else {
150
+ splitOrders.push(actions.createSubOrder({ parentOrder, items }));
151
+ }
142
152
  });
143
153
 
144
154
  splitOrders = joinItemQuantityById(splitOrders);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@darkpos/pricing",
3
- "version": "1.0.104",
3
+ "version": "1.0.107",
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": "0a74400677d6852460e9a7773a3e6480912ad8b3"
57
+ "gitHead": "16a66c27afee8501a123219c6653b59800654b81"
58
58
  }