@darkpos/pricing 1.0.105 → 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.
@@ -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
  });
@@ -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 => {
@@ -173,6 +173,9 @@ const isTotalVisitsModifier = require('./isTotalVisitsModifier');
173
173
  const isValidCustomer = require('./isValidCustomer');
174
174
  const lockCustomerStatsModifiers = require('./lockCustomerStatsModifiers');
175
175
  const unlockCustomerStatsModifiers = require('./unlockCustomerStatsModifiers');
176
+ const isAutoSplit = require('./isAutoSplit');
177
+ const isKeepRelatedItems = require('./isKeepRelatedItems');
178
+ const isSplitDepartment = require('./isSplitDepartment');
176
179
 
177
180
  const modifierActions = (deps = {}) => {
178
181
  const actions = {};
@@ -359,6 +362,9 @@ const modifierActions = (deps = {}) => {
359
362
  isValidCustomer: isValidCustomer(innerDeps),
360
363
  lockCustomerStatsModifiers: lockCustomerStatsModifiers(innerDeps),
361
364
  unlockCustomerStatsModifiers: unlockCustomerStatsModifiers(innerDeps),
365
+ isAutoSplit: isAutoSplit(innerDeps),
366
+ isKeepRelatedItems: isKeepRelatedItems(innerDeps),
367
+ isSplitDepartment: isSplitDepartment(innerDeps),
362
368
  });
363
369
 
364
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,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
+ };
@@ -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.105",
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": "09c5c7462144195081cfc13eb82f55f4530a77aa"
57
+ "gitHead": "16a66c27afee8501a123219c6653b59800654b81"
58
58
  }