@darkpos/pricing 1.0.138 → 1.0.140

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.
@@ -2570,5 +2570,112 @@ describe('Item actions', () => {
2570
2570
  'City Tax': 3,
2571
2571
  });
2572
2572
  });
2573
+
2574
+ test('mergeWithParentItem adds price, name, and modifiers to parent', () => {
2575
+ const parentItem = {
2576
+ _id: 'parent-1',
2577
+ itemId: 'parent-1',
2578
+ name: 'Parent',
2579
+ price: 100,
2580
+ total: 100,
2581
+ quantity: 1,
2582
+ modifiers: [
2583
+ {
2584
+ _id: 'mod-parent',
2585
+ modifierId: 'mod-parent',
2586
+ },
2587
+ ],
2588
+ };
2589
+
2590
+ const order = {
2591
+ items: [parentItem],
2592
+ modifiers: [],
2593
+ };
2594
+
2595
+ const relatedItem = {
2596
+ itemId: 'child-1',
2597
+ name: 'Child',
2598
+ price: 25,
2599
+ modifiers: [
2600
+ {
2601
+ _id: 'tax',
2602
+ compute: { amount: 5, type: 'fixed', action: 'add' },
2603
+ },
2604
+ ],
2605
+ properties: {
2606
+ relatedItem: true,
2607
+ parentId: parentItem._id,
2608
+ parentItemId: parentItem.itemId,
2609
+ mergeWithParentItem: true,
2610
+ },
2611
+ };
2612
+
2613
+ const { updatedOrder } = pricingService.order.addItem({
2614
+ order,
2615
+ item: relatedItem,
2616
+ });
2617
+
2618
+ expect(updatedOrder.items.length).toBe(1);
2619
+
2620
+ expect(updatedOrder.items[0]._id).toBe('parent-1');
2621
+
2622
+ expect(updatedOrder.items[0].price).toBe(125);
2623
+ expect(updatedOrder.items[0].name).toBe('Parent - Child');
2624
+ expect(updatedOrder.items[0].modifiers.length).toBe(2);
2625
+ expect(updatedOrder.items[0].modifiers[0]._id).toBe('mod-parent');
2626
+ expect(updatedOrder.items[0].modifiers[1].modifierId).toBe('tax');
2627
+ });
2628
+
2629
+ test('mergeWithParentItem does not duplicate parent modifiers', () => {
2630
+ const parentItem = {
2631
+ _id: 'parent-2',
2632
+ itemId: 'parent-2',
2633
+ name: 'Parent',
2634
+ price: 100,
2635
+ total: 100,
2636
+ quantity: 1,
2637
+ modifiers: [
2638
+ {
2639
+ _id: 'mod-shared-parent',
2640
+ modifierId: 'mod-shared',
2641
+ },
2642
+ ],
2643
+ };
2644
+
2645
+ const order = {
2646
+ items: [parentItem],
2647
+ modifiers: [],
2648
+ };
2649
+
2650
+ const relatedItem = {
2651
+ itemId: 'child-2',
2652
+ name: 'Child',
2653
+ price: 10,
2654
+ modifiers: [
2655
+ {
2656
+ _id: 'mod-shared',
2657
+ compute: { amount: 2, type: 'fixed', action: 'add' },
2658
+ },
2659
+ ],
2660
+ properties: {
2661
+ relatedItem: true,
2662
+ parentId: parentItem._id,
2663
+ parentItemId: parentItem.itemId,
2664
+ mergeWithParentItem: true,
2665
+ },
2666
+ };
2667
+
2668
+ const { updatedOrder } = pricingService.order.addItem({
2669
+ order,
2670
+ item: relatedItem,
2671
+ });
2672
+
2673
+ expect(updatedOrder.items.length).toBe(1);
2674
+ expect(updatedOrder.items[0]._id).toBe('parent-2');
2675
+ expect(updatedOrder.items[0].price).toBe(110);
2676
+ expect(updatedOrder.items[0].name).toBe('Parent - Child');
2677
+ expect(updatedOrder.items[0].modifiers.length).toBe(1);
2678
+ expect(updatedOrder.items[0].modifiers[0].modifierId).toBe('mod-shared');
2679
+ });
2573
2680
  });
2574
2681
  });
@@ -18,6 +18,7 @@ describe('addItem function', () => {
18
18
 
19
19
  // Mock item to add
20
20
  const item = {
21
+ _id: 'abc',
21
22
  itemId: '123',
22
23
  quantity: 1,
23
24
  price: 100,
@@ -3808,6 +3808,27 @@ describe('Order actions', () => {
3808
3808
  expect(newOrder2.items[0].status).toMatchObject({ paid: { value: true } });
3809
3809
  });
3810
3810
 
3811
+ test('Mark paid status true if totalPaid is greater than total', () => {
3812
+ const orderItem = {
3813
+ price: 25,
3814
+ quantity: 1,
3815
+ status: {},
3816
+ totalPaid: 30,
3817
+ };
3818
+ const pricing = usePricing({
3819
+ store: { _settings: { order: { autoMarkAsPaid: false } } },
3820
+ });
3821
+ const order = { items: [orderItem], status: {} };
3822
+ const newOrder = pricing.order.calculate(order);
3823
+
3824
+ expect(newOrder).toHaveProperty('total', 25);
3825
+ expect(newOrder).toHaveProperty('totalPaid', 30);
3826
+ expect(newOrder.status).toMatchObject({ paid: true });
3827
+ expect(newOrder.items[0].status).toMatchObject({
3828
+ paid: { value: true },
3829
+ });
3830
+ });
3831
+
3811
3832
  test('Dont update status if not needed', () => {
3812
3833
  const orderItem = {
3813
3834
  price: 25,
@@ -0,0 +1,7 @@
1
+ module.exports = ({ utils }) =>
2
+ function getOverpaidAmount({ item }) {
3
+ const total = Number(item.total || 0);
4
+ const totalPaid = Number(item.totalPaid || 0);
5
+
6
+ return utils.math.sub(totalPaid, total);
7
+ };
@@ -9,21 +9,21 @@ module.exports = ({ actions, settings }) =>
9
9
  const total = totalParam || 0;
10
10
  const totalPaid = totalPaidParam || 0;
11
11
 
12
- if (
13
- actions.isPaid({ item: { status: localStatus } }) &&
14
- total !== 0 &&
15
- total > totalPaid
16
- ) {
12
+ const isPaid = actions.isPaid({ item: { status: localStatus } });
13
+
14
+ const paid = { value: true, date: new Date() };
15
+
16
+ if (isPaid && total !== 0 && total > totalPaid) {
17
17
  return undefined;
18
18
  }
19
19
 
20
+ if (!isPaid && totalPaid > total) return paid;
21
+
20
22
  if (!settings || !settings.order || !settings.order.autoMarkAsPaid) {
21
23
  return localStatus.paid;
22
24
  }
23
25
 
24
- if (!actions.isPaid({ item: { status: localStatus } }) && total === 0) {
25
- return { value: true, date: new Date() };
26
- }
26
+ if (!isPaid && total === 0) return paid;
27
27
 
28
28
  return localStatus.paid;
29
29
  };
package/lib/item/index.js CHANGED
@@ -74,6 +74,7 @@ const isSerialLengthValid = require('./isSerialLengthValid');
74
74
  const getSerialStatus = require('./getSerialStatus');
75
75
  const removeDepartmentModifiers = require('./removeDepartmentModifiers');
76
76
  const isRemoveParentItem = require('./isRemoveParentItem');
77
+ const isMergeWithParentItem = require('./isMergeWithParentItem');
77
78
  const hasRelatedItems = require('./hasRelatedItems');
78
79
  const getAddModifiers = require('./getAddModifiers');
79
80
  const hasAddModifiers = require('./hasAddModifiers');
@@ -81,6 +82,8 @@ const getTaxes = require('./getTaxes');
81
82
  const getAmountToPayById = require('./getAmountToPayById');
82
83
  const applyPayment = require('./applyPayment');
83
84
  const getBalanceForPaymentModifier = require('./getBalanceForPaymentModifier');
85
+ const isOverpaid = require('./isOverpaid');
86
+ const getOverpaidAmount = require('./getOverpaidAmount');
84
87
 
85
88
  const itemActions = (deps = {}) => {
86
89
  const actions = {};
@@ -168,6 +171,7 @@ const itemActions = (deps = {}) => {
168
171
  getSerialStatus: getSerialStatus(innerDeps),
169
172
  removeDepartmentModifiers: removeDepartmentModifiers(innerDeps),
170
173
  isRemoveParentItem: isRemoveParentItem(innerDeps),
174
+ isMergeWithParentItem: isMergeWithParentItem(innerDeps),
171
175
  hasRelatedItems: hasRelatedItems(innerDeps),
172
176
  getAddModifiers: getAddModifiers(innerDeps),
173
177
  hasAddModifiers: hasAddModifiers(innerDeps),
@@ -175,6 +179,8 @@ const itemActions = (deps = {}) => {
175
179
  getAmountToPayById: getAmountToPayById(innerDeps),
176
180
  applyPayment: applyPayment(innerDeps),
177
181
  getBalanceForPaymentModifier: getBalanceForPaymentModifier(innerDeps),
182
+ isOverpaid: isOverpaid(innerDeps),
183
+ getOverpaidAmount: getOverpaidAmount(innerDeps),
178
184
  });
179
185
 
180
186
  Object.keys(freezedActions).forEach(actionName => {
@@ -0,0 +1,4 @@
1
+ module.exports = () =>
2
+ function isMergeWithParentItem(item) {
3
+ return !!(item && item.properties && item.properties.mergeWithParentItem);
4
+ };
@@ -0,0 +1,7 @@
1
+ module.exports = () =>
2
+ function isOverpaid({ item }) {
3
+ const total = Number(item.total || 0);
4
+ const totalPaid = Number(item.totalPaid || 0);
5
+
6
+ return totalPaid > total;
7
+ };
@@ -182,6 +182,7 @@ const getCountPerCustomer = require('./getCountPerCustomer');
182
182
  const getAmountMultiplier = require('./getAmountMultiplier');
183
183
  const isAmountMultiplier = require('./isAmountMultiplier');
184
184
  const isRemoveParentItem = require('./isRemoveParentItem');
185
+ const isMergeWithParentItem = require('./isMergeWithParentItem');
185
186
  const isTax = require('./isTax');
186
187
 
187
188
  const modifierActions = (deps = {}) => {
@@ -377,6 +378,7 @@ const modifierActions = (deps = {}) => {
377
378
  getAmountMultiplier: getAmountMultiplier(innerDeps),
378
379
  isAmountMultiplier: isAmountMultiplier(innerDeps),
379
380
  isRemoveParentItem: isRemoveParentItem(innerDeps),
381
+ isMergeWithParentItem: isMergeWithParentItem(innerDeps),
380
382
  isTax: isTax(innerDeps),
381
383
  });
382
384
 
@@ -0,0 +1,9 @@
1
+ module.exports = () =>
2
+ function isMergeWithParentItem(modifier) {
3
+ return !!(
4
+ modifier &&
5
+ modifier.properties &&
6
+ modifier.properties.group &&
7
+ modifier.properties.group.mergeWithParentItem
8
+ );
9
+ };
@@ -253,7 +253,7 @@ module.exports = ({ actions, itemActions, modifierActions, settings, _ }) => {
253
253
  nextItemIndex,
254
254
  });
255
255
 
256
- if (reArrangedOrder && newIndex) {
256
+ if (reArrangedOrder && newIndex >= 0) {
257
257
  nextOrder = { ...reArrangedOrder };
258
258
  nextItemIndex = newIndex;
259
259
  }
@@ -262,7 +262,7 @@ module.exports = ({ actions, itemActions, modifierActions, settings, _ }) => {
262
262
 
263
263
  if (combined && pendingItemIndex > -1 && idx !== itemIndex) {
264
264
  const idxToRemove = actions.getPendingItemIndex(nextOrder);
265
- nextOrder.items.splice(idxToRemove, 1);
265
+ if (idxToRemove > -1) nextOrder.items.splice(idxToRemove, 1);
266
266
  }
267
267
 
268
268
  nextOrder = actions.addModifiersToParentItem({
@@ -270,10 +270,29 @@ module.exports = ({ actions, itemActions, modifierActions, settings, _ }) => {
270
270
  relatedItem: orderItem,
271
271
  });
272
272
 
273
+ const relatedItemFromOrder =
274
+ actions.getSelectedItem({ order: nextOrder, itemIndex: nextItemIndex }) ||
275
+ nextItem ||
276
+ orderItem;
277
+
278
+ let newItem = relatedItemFromOrder;
279
+
280
+ if (itemActions.isMergeWithParentItem(relatedItemFromOrder)) {
281
+ const result = actions.mergeRelatedItemWithParentItem({
282
+ order: nextOrder,
283
+ relatedItem: relatedItemFromOrder,
284
+ originalItem: item,
285
+ });
286
+ nextOrder = result.order;
287
+ newItem = result.parent;
288
+ }
289
+
273
290
  return {
274
291
  updatedOrder: nextOrder,
275
- itemIndex: nextItemIndex,
276
- item: nextItem,
292
+ item: newItem,
293
+ itemIndex: nextOrder.items.findIndex(
294
+ eachItem => eachItem._id === newItem._id
295
+ ),
277
296
  };
278
297
  };
279
298
  };
@@ -0,0 +1,8 @@
1
+ module.exports = ({ utils }) =>
2
+ function getOverPaidAmount({ order }) {
3
+ if (!order) return 0;
4
+ const total = Number(order.total || 0);
5
+ const totalPaid = Number(order.totalPaid || 0);
6
+
7
+ return utils.math.sub(totalPaid, total);
8
+ };
@@ -95,10 +95,12 @@ const setPieces = require('./setPieces');
95
95
  const copyItemToParents = require('./copyItemToParents');
96
96
  const getItemsWithParents = require('./getItemsWithParents');
97
97
  const addModifiersToParentItem = require('./addModifiersToParentItem');
98
+ const mergeRelatedItemWithParentItem = require('./mergeRelatedItemWithParentItem');
98
99
  const removeEmptyNotes = require('./removeEmptyNotes');
99
100
  const getTaxes = require('./getTaxes');
100
101
  const getPickedStatus = require('./getPickedStatus');
101
102
  const calculateWithPayment = require('./calculateWithPayment');
103
+ const getOverpaidAmount = require('./getOverpaidAmount');
102
104
 
103
105
  const orderActions = (deps = {}) => {
104
106
  const actions = {};
@@ -205,10 +207,12 @@ const orderActions = (deps = {}) => {
205
207
  copyItemToParents: copyItemToParents(innerDeps),
206
208
  getItemsWithParents: getItemsWithParents(innerDeps),
207
209
  addModifiersToParentItem: addModifiersToParentItem(innerDeps),
210
+ mergeRelatedItemWithParentItem: mergeRelatedItemWithParentItem(innerDeps),
208
211
  removeEmptyNotes: removeEmptyNotes(innerDeps),
209
212
  getTaxes: getTaxes(innerDeps),
210
213
  getPickedStatus: getPickedStatus(innerDeps),
211
214
  calculateWithPayment: calculateWithPayment(innerDeps),
215
+ getOverpaidAmount: getOverpaidAmount(innerDeps),
212
216
  });
213
217
 
214
218
  Object.keys(freezedActions).forEach(actionName => {
@@ -0,0 +1,94 @@
1
+ module.exports = ({ actions, itemActions, utils }) => {
2
+ const { math } = utils;
3
+
4
+ return function mergeRelatedItemWithParentItem({
5
+ order,
6
+ relatedItem,
7
+ originalItem,
8
+ }) {
9
+ if (
10
+ !order ||
11
+ !itemActions.isRelatedItem(relatedItem) ||
12
+ (!itemActions.isMergeWithParentItem(originalItem) &&
13
+ !itemActions.isMergeWithParentItem(relatedItem))
14
+ ) {
15
+ return order;
16
+ }
17
+
18
+ if (!Array.isArray(order.items)) return order;
19
+
20
+ const nextOrder = { ...order };
21
+
22
+ const parentItem = itemActions.getParentItem(nextOrder.items, relatedItem);
23
+ if (!parentItem) return nextOrder;
24
+
25
+ const parentIndex = actions.getItemIndex({
26
+ order: nextOrder,
27
+ item: parentItem,
28
+ });
29
+ if (parentIndex < 0) return nextOrder;
30
+
31
+ const relatedIndex = actions.getItemIndex({
32
+ order: nextOrder,
33
+ item: relatedItem,
34
+ });
35
+ if (relatedIndex < 0) return nextOrder;
36
+
37
+ let updatedParent = parentItem;
38
+
39
+ if (relatedItem && relatedItem.name) {
40
+ if (!updatedParent.name) updatedParent.name = relatedItem.name;
41
+ else if (!updatedParent.name.includes(relatedItem.name)) {
42
+ updatedParent.name = `${updatedParent.name} - ${relatedItem.name}`;
43
+ }
44
+ }
45
+
46
+ if (typeof relatedItem.price === 'number') {
47
+ updatedParent.price = math.add(
48
+ updatedParent.price || 0,
49
+ relatedItem.price
50
+ );
51
+ }
52
+
53
+ nextOrder.items = [...nextOrder.items];
54
+ nextOrder.items[parentIndex] = updatedParent;
55
+
56
+ const relatedModifiers = Array.isArray(relatedItem.modifiers)
57
+ ? relatedItem.modifiers
58
+ : [];
59
+
60
+ if (relatedModifiers.length) {
61
+ const parentModifierIds = (updatedParent.modifiers || [])
62
+ .map(mod => mod.modifierId || mod._id)
63
+ .filter(Boolean);
64
+
65
+ const modifiersToAdd = relatedModifiers.filter(mod => {
66
+ const modId = mod.modifierId || mod._id;
67
+ return modId && !parentModifierIds.includes(modId);
68
+ });
69
+
70
+ if (modifiersToAdd.length) {
71
+ const orderWithModifiers = modifiersToAdd.reduce(
72
+ (acc, modifier) =>
73
+ actions.addItemModifier({
74
+ itemIndex: parentIndex,
75
+ order: acc,
76
+ modifier,
77
+ originalItem: updatedParent,
78
+ }),
79
+ nextOrder
80
+ );
81
+ nextOrder.items = orderWithModifiers.items;
82
+ }
83
+ }
84
+
85
+ updatedParent =
86
+ actions.getSelectedItem({ order: nextOrder, itemIndex: parentIndex }) ||
87
+ updatedParent;
88
+
89
+ nextOrder.items[parentIndex] = updatedParent;
90
+ nextOrder.items.splice(relatedIndex, 1);
91
+
92
+ return { order: nextOrder, parent: updatedParent };
93
+ };
94
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@darkpos/pricing",
3
- "version": "1.0.138",
3
+ "version": "1.0.140",
4
4
  "description": "Pricing calculator",
5
5
  "author": "Dark POS",
6
6
  "license": "ISC",
@@ -53,5 +53,5 @@
53
53
  "supertest": "^6.2.3",
54
54
  "supervisor": "^0.12.0"
55
55
  },
56
- "gitHead": "95d90c9dccaf934d7d4a8adc8e46115e90b81664"
56
+ "gitHead": "a679a827cb2a83762ae4ec5ce76ae5416b654a48"
57
57
  }