@darkpos/pricing 1.0.31 → 1.0.32

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.
@@ -0,0 +1,192 @@
1
+ const _ = require('lodash');
2
+ const utils = require('@darkpos/utils');
3
+ const addIndirectModifierFunction = require('../../lib/item/addIndirectModifier');
4
+
5
+ describe('addIndirectModifier Function', () => {
6
+ const modifierActions = {
7
+ calculate: jest.fn(),
8
+ createIndirectModifier: jest.fn(),
9
+ };
10
+
11
+ const getComputeModField = jest.fn();
12
+ // const modifierActions = makeModifierActions(deps);
13
+
14
+ const addIndirectModifier = addIndirectModifierFunction({
15
+ utils,
16
+ modifierActions,
17
+ _,
18
+ });
19
+
20
+ beforeEach(() => {
21
+ jest.clearAllMocks();
22
+ });
23
+
24
+ test('should correctly distribute modifier across items when totals match', () => {
25
+ const modifier = {
26
+ modifier: { type: 'non-credit', action: 'add', amount: 50 },
27
+ };
28
+ const items = [
29
+ { _id: 'item1', total: 50, quantity: 2 },
30
+ { _id: 'item2', total: 50, quantity: 1 },
31
+ ];
32
+ const orderTotal = 100;
33
+ modifierActions.calculate.mockReturnValueOnce({
34
+ _computed: { amount: 100 },
35
+ });
36
+ modifierActions.createIndirectModifier
37
+ .mockReturnValueOnce({ compute: { amount: 25 }, properties: {} })
38
+ .mockReturnValueOnce({ compute: { amount: 50 }, properties: {} });
39
+
40
+ const result = addIndirectModifier({ orderTotal, items, modifier });
41
+
42
+ expect(result).toEqual({
43
+ item1: {
44
+ compute: { amount: 25 },
45
+ properties: {},
46
+ },
47
+ item2: {
48
+ compute: { amount: 50 },
49
+ properties: {},
50
+ },
51
+ });
52
+ });
53
+
54
+ test('should adjust the modifier on one item when totals do not match', () => {
55
+ const modifier = { modifier: { type: 'non-credit' } };
56
+ const items = [
57
+ { _id: 'item1', total: 50, quantity: 2 },
58
+ { _id: 'item2', total: 50, quantity: 1 },
59
+ ];
60
+ const orderTotal = 100;
61
+
62
+ modifierActions.calculate.mockReturnValueOnce({
63
+ _computed: { amount: 100 },
64
+ });
65
+ modifierActions.createIndirectModifier
66
+ .mockReturnValueOnce({ compute: { amount: 20 }, properties: {} })
67
+ .mockReturnValueOnce({ compute: { amount: 50 }, properties: {} });
68
+
69
+ const result = addIndirectModifier({ orderTotal, items, modifier });
70
+
71
+ expect(result).toEqual({
72
+ item1: {
73
+ compute: { amount: 50 }, // Adjusted amount to fix the total distribution difference
74
+ properties: { ignoreQuantity: true },
75
+ },
76
+ item2: { compute: { amount: 50 }, properties: {} },
77
+ });
78
+ });
79
+
80
+ test('should not adjust the modifier if compute type is percentage and modifier is not credit', () => {
81
+ const modifier = {
82
+ modifier: { type: 'non-credit' },
83
+ };
84
+ const items = [
85
+ {
86
+ _id: 'item1',
87
+ total: 50,
88
+ quantity: 2,
89
+ compute: { type: 'percentage', amount: 10, action: '' },
90
+ },
91
+ {
92
+ _id: 'item2',
93
+ total: 50,
94
+ quantity: 1,
95
+ compute: { type: 'percentage', amount: 10, action: '' },
96
+ },
97
+ ];
98
+ const orderTotal = 100;
99
+
100
+ getComputeModField.mockReturnValueOnce({ type: 'percentage' });
101
+ modifierActions.calculate
102
+ .mockReturnValueOnce({
103
+ compute: { amount: 20 },
104
+ properties: {},
105
+ _computed: { amount: 15 },
106
+ })
107
+ .mockReturnValueOnce({
108
+ compute: { amount: 50 },
109
+ properties: {},
110
+ _computed: { amount: 20 },
111
+ });
112
+ modifierActions.createIndirectModifier
113
+ .mockReturnValueOnce({
114
+ compute: { amount: 20 },
115
+ properties: {},
116
+ _computed: { amount: 15 },
117
+ })
118
+ .mockReturnValueOnce({
119
+ compute: { amount: 50 },
120
+ properties: {},
121
+ _computed: { amount: 20 },
122
+ });
123
+
124
+ const result = addIndirectModifier({ orderTotal, items, modifier });
125
+
126
+ expect(result).toEqual({
127
+ item1: {
128
+ compute: { amount: -35 },
129
+ properties: {
130
+ ignoreQuantity: true,
131
+ },
132
+ _computed: { amount: 15 },
133
+ },
134
+ item2: {
135
+ compute: { amount: 50 },
136
+ properties: {},
137
+ _computed: { amount: 20 },
138
+ },
139
+ });
140
+ });
141
+
142
+ test('should return itemsModifiers as is if totalDistributed equals orderModifierTotal', () => {
143
+ const modifier = { modifier: { type: 'non-credit' } };
144
+ const items = [
145
+ { _id: 'item1', total: 50, quantity: 2 },
146
+ { _id: 'item2', total: 50, quantity: 1 },
147
+ ];
148
+ const orderTotal = 100;
149
+ modifierActions.calculate.mockReturnValueOnce({
150
+ _computed: { amount: 100 },
151
+ });
152
+
153
+ modifierActions.createIndirectModifier
154
+ .mockReturnValueOnce({ compute: { amount: 25 }, properties: {} })
155
+ .mockReturnValueOnce({ compute: { amount: 50 }, properties: {} });
156
+
157
+ const result = addIndirectModifier({ orderTotal, items, modifier });
158
+
159
+ expect(result).toEqual({
160
+ item1: {
161
+ compute: { amount: -30 },
162
+ properties: {
163
+ ignoreQuantity: true,
164
+ },
165
+ },
166
+ item2: { compute: { amount: 50 }, properties: {} },
167
+ });
168
+ });
169
+
170
+ test('should not modify any items if totalDistributed exceeds orderModifierTotal and no item can cover the difference', () => {
171
+ const modifier = { modifier: { type: 'non-credit' } };
172
+ const items = [
173
+ { _id: 'item1', total: 10, quantity: 1 },
174
+ { _id: 'item2', total: 10, quantity: 1 },
175
+ ];
176
+ const orderTotal = 20;
177
+
178
+ modifierActions.calculate.mockReturnValueOnce({
179
+ _computed: { amount: 100 },
180
+ });
181
+ modifierActions.createIndirectModifier
182
+ .mockReturnValueOnce({ compute: { amount: 40 }, properties: {} })
183
+ .mockReturnValueOnce({ compute: { amount: 40 }, properties: {} });
184
+
185
+ const result = addIndirectModifier({ orderTotal, items, modifier });
186
+
187
+ expect(result).toEqual({
188
+ item1: { compute: { amount: 40 }, properties: {} },
189
+ item2: { compute: { amount: 40 }, properties: {} },
190
+ });
191
+ });
192
+ });
@@ -1,5 +1,6 @@
1
1
  const usePricing = require('../../index');
2
2
 
3
+ const { getComputeModField } = require('../../lib/modifier/utils');
3
4
  const pricingService = usePricing();
4
5
 
5
6
  describe('Calculate Function', () => {
@@ -13,7 +14,10 @@ describe('Calculate Function', () => {
13
14
  name: 'someModifier',
14
15
  };
15
16
  const orderItem = { price: 30, quantity: 1 };
16
- const computedModifier = pricingService.modifier.calculate(modifier, orderItem);
17
+ const computedModifier = pricingService.modifier.calculate(
18
+ modifier,
19
+ orderItem
20
+ );
17
21
  expect(computedModifier._computed).toMatchObject({
18
22
  amount: 10,
19
23
  description: 'someModifier ($10.00)',
@@ -30,7 +34,10 @@ describe('Calculate Function', () => {
30
34
  name: 'someModifier',
31
35
  };
32
36
  const orderItem = { price: 30, quantity: 1 };
33
- const computedModifier = pricingService.modifier.calculate(modifier, orderItem);
37
+ const computedModifier = pricingService.modifier.calculate(
38
+ modifier,
39
+ orderItem
40
+ );
34
41
  expect(computedModifier._computed).toMatchObject({
35
42
  amount: -10,
36
43
  description: 'someModifier (-$10.00)',
@@ -47,7 +54,10 @@ describe('Calculate Function', () => {
47
54
  name: 'someModifier',
48
55
  };
49
56
  const orderItem = { price: 30, quantity: 1 };
50
- const computedModifier = pricingService.modifier.calculate(modifier, orderItem);
57
+ const computedModifier = pricingService.modifier.calculate(
58
+ modifier,
59
+ orderItem
60
+ );
51
61
  expect(computedModifier._computed).toMatchObject({
52
62
  amount: -6,
53
63
  description: 'someModifier (-$6.00)',
@@ -64,10 +74,31 @@ describe('Calculate Function', () => {
64
74
  name: 'someModifier',
65
75
  };
66
76
  const orderItem = { price: 30, quantity: 1 };
67
- const computedModifier = pricingService.modifier.calculate(modifier, orderItem);
77
+ const computedModifier = pricingService.modifier.calculate(
78
+ modifier,
79
+ orderItem
80
+ );
68
81
  expect(computedModifier._computed).toMatchObject({
69
82
  amount: 6,
70
83
  description: 'someModifier ($6.00)',
71
84
  });
72
85
  });
86
+
87
+ test('calculate with a null modifier', () => {
88
+ const modifier = {
89
+ compute: null,
90
+ name: 'someModifier',
91
+ };
92
+ const orderItem = { price: 30, quantity: 1 };
93
+ const computedModifier = pricingService.modifier.calculate(
94
+ modifier,
95
+ orderItem
96
+ );
97
+ const testCompute = getComputeModField(computedModifier);
98
+ expect(testCompute).toMatchObject({
99
+ type: '',
100
+ amount: 0,
101
+ action: '',
102
+ });
103
+ });
73
104
  });
@@ -0,0 +1,166 @@
1
+ const _ = require('lodash');
2
+ const utils = require('@darkpos/utils');
3
+ const createIndirectModifierFunction = require('../../lib/modifier/createIndirectModifier');
4
+
5
+ describe('createIndirectModifier Function', () => {
6
+ test('create indirect modifier with an undefined modifier compute', () => {
7
+ const constants = {
8
+ Modifier: {
9
+ Compute: {
10
+ Types: {
11
+ PERCENTAGE: 'percentage',
12
+ FIXED: 'fixed',
13
+ },
14
+ Actions: {
15
+ SUBTRACT: 'subtract',
16
+ },
17
+ },
18
+ },
19
+ };
20
+ const actions = {
21
+ getProperty: (modifier, prop) => modifier[prop],
22
+ create: modifier => modifier,
23
+ };
24
+ // const getComputeModField = jest.fn().mockReturnValue(null);
25
+
26
+ const createIndirectModifier = createIndirectModifierFunction({
27
+ _,
28
+ utils,
29
+ constants,
30
+ actions,
31
+ });
32
+
33
+ const modifier = {
34
+ type: 'credit',
35
+ properties: {},
36
+ };
37
+ const options = {
38
+ orderTotal: 100,
39
+ itemQuantity: 2,
40
+ itemTotal: 50,
41
+ };
42
+
43
+ const result = createIndirectModifier(modifier, options);
44
+
45
+ expect(result).toEqual({
46
+ ...modifier,
47
+ direct: false,
48
+ compute: {
49
+ type: 'fixed',
50
+ amount: 0,
51
+ action: 'subtract',
52
+ },
53
+ properties: {
54
+ ignoreQuantity: false,
55
+ },
56
+ });
57
+ });
58
+ test('create indirect modifier with a null modifier compute', () => {
59
+ const constants = {
60
+ Modifier: {
61
+ Compute: {
62
+ Types: {
63
+ PERCENTAGE: 'percentage',
64
+ FIXED: 'fixed',
65
+ },
66
+ Actions: {
67
+ SUBTRACT: 'subtract',
68
+ },
69
+ },
70
+ },
71
+ };
72
+ const actions = {
73
+ getProperty: (modifier, prop) => modifier[prop],
74
+ create: modifier => modifier,
75
+ };
76
+
77
+ const createIndirectModifier = createIndirectModifierFunction({
78
+ _,
79
+ utils,
80
+ constants,
81
+ actions,
82
+ });
83
+
84
+ const modifier = {
85
+ type: 'credit',
86
+ properties: {},
87
+ compute: null,
88
+ };
89
+ const options = {
90
+ orderTotal: 100,
91
+ itemQuantity: 2,
92
+ itemTotal: 50,
93
+ };
94
+
95
+ const result = createIndirectModifier(modifier, options);
96
+
97
+ expect(result).toEqual({
98
+ ...modifier,
99
+ direct: false,
100
+ compute: {
101
+ type: 'fixed',
102
+ amount: 0,
103
+ action: 'subtract',
104
+ },
105
+ properties: {
106
+ ignoreQuantity: false,
107
+ },
108
+ });
109
+ });
110
+ test('create indirect modifier regular modifier', () => {
111
+ const constants = {
112
+ Modifier: {
113
+ Compute: {
114
+ Types: {
115
+ PERCENTAGE: 'percentage',
116
+ FIXED: 'fixed',
117
+ },
118
+ Actions: {
119
+ SUBTRACT: 'subtract',
120
+ },
121
+ },
122
+ },
123
+ };
124
+ const actions = {
125
+ getProperty: (modifier, prop) => modifier[prop],
126
+ create: modifier => modifier,
127
+ };
128
+
129
+ const createIndirectModifier = createIndirectModifierFunction({
130
+ _,
131
+ utils,
132
+ constants,
133
+ actions,
134
+ });
135
+
136
+ const modifier = {
137
+ type: 'credit',
138
+ properties: {},
139
+ compute: {
140
+ type: 'fixed',
141
+ action: 'add',
142
+ amount: 10,
143
+ },
144
+ };
145
+ const options = {
146
+ orderTotal: 100,
147
+ itemQuantity: 2,
148
+ itemTotal: 50,
149
+ };
150
+
151
+ const result = createIndirectModifier(modifier, options);
152
+
153
+ expect(result).toEqual({
154
+ ...modifier,
155
+ direct: false,
156
+ compute: {
157
+ type: 'fixed',
158
+ action: 'add',
159
+ amount: 2.5,
160
+ },
161
+ properties: {
162
+ ignoreQuantity: false,
163
+ },
164
+ });
165
+ });
166
+ });
@@ -0,0 +1,52 @@
1
+ const utils = require('@darkpos/utils');
2
+ const getFixedModifiersTotalFunction = require('../../lib/modifier/getFixedModifiersTotal');
3
+
4
+ describe('getFixedModifiersTotal Function', () => {
5
+ const getComputeModField = jest.fn();
6
+
7
+ const getFixedModifiersTotal = getFixedModifiersTotalFunction({
8
+ utils,
9
+ });
10
+
11
+ test('should return 0 if modifiers is not an array', () => {
12
+ const result = getFixedModifiersTotal(null);
13
+ expect(result).toBe(0);
14
+ });
15
+
16
+ test('should return 0 if there are no fixed modifiers', () => {
17
+ getComputeModField.mockReturnValueOnce({ type: 'percentage' });
18
+ const modifiers = [{}, {}];
19
+
20
+ const result = getFixedModifiersTotal(modifiers);
21
+ expect(result).toBe(0);
22
+ });
23
+
24
+ test('should correctly sum fixed modifiers even with a compute null', () => {
25
+ const modifiers = [
26
+ {
27
+ compute: { type: 'fixed', amount: 10 },
28
+ },
29
+ { compute: { type: 'fixed', amount: 20 } },
30
+ { compute: { type: 'fixed', amount: 30 } },
31
+ { compute: null },
32
+ ];
33
+
34
+ const result = getFixedModifiersTotal(modifiers);
35
+ expect(result).toBe(60);
36
+ });
37
+
38
+ test('should correctly handle a fixed modifier with no amount', () => {
39
+ const modifiers = [
40
+ { compute: { type: 'fixed', amount: undefined } },
41
+ { compute: { type: 'fixed', amount: 15 } },
42
+ ];
43
+
44
+ const result = getFixedModifiersTotal(modifiers);
45
+ expect(result).toBe(15);
46
+ });
47
+
48
+ test('should correctly handle an empty array of modifiers', () => {
49
+ const result = getFixedModifiersTotal([]);
50
+ expect(result).toBe(0);
51
+ });
52
+ });
@@ -0,0 +1,134 @@
1
+ const utils = require('@darkpos/utils');
2
+ const getSplittedModifiersFunction = require('../../lib/modifier/getSplittedModifiers');
3
+
4
+ describe('getSplittedModifiers Function', () => {
5
+ const getSplittedModifiers = getSplittedModifiersFunction({
6
+ utils,
7
+ });
8
+
9
+ test('should return split credit modifier with divided maxAmount', () => {
10
+ const modifiers = [
11
+ {
12
+ type: 'credit',
13
+ properties: { maxAmount: 100 },
14
+ },
15
+ ];
16
+ const totalOriginOrder = 200;
17
+ const totalSplitedOrder = 50;
18
+
19
+ const result = getSplittedModifiers(
20
+ modifiers,
21
+ totalOriginOrder,
22
+ totalSplitedOrder
23
+ );
24
+
25
+ expect(result).toEqual([
26
+ {
27
+ type: 'credit',
28
+ properties: { maxAmount: 25 }, // 100 * (50 / 200)
29
+ compute: {
30
+ type: '',
31
+ amount: 0,
32
+ action: '',
33
+ },
34
+ },
35
+ ]);
36
+ });
37
+
38
+ test('should return split fixed modifier with divided amount', () => {
39
+ const modifiers = [
40
+ {
41
+ compute: { amount: 80, type: 'fixed' },
42
+ },
43
+ ];
44
+ const totalOriginOrder = 160;
45
+ const totalSplitedOrder = 40;
46
+
47
+ const result = getSplittedModifiers(
48
+ modifiers,
49
+ totalOriginOrder,
50
+ totalSplitedOrder
51
+ );
52
+
53
+ expect(result).toEqual([
54
+ {
55
+ compute: { amount: 20, type: 'fixed' }, // 80 * (40 / 160)
56
+ },
57
+ ]);
58
+ });
59
+
60
+ test('should return unmodified modifier if type is not credit or fixed', () => {
61
+ const modifiers = [
62
+ {
63
+ type: 'non-fixed',
64
+ compute: { amount: 10 },
65
+ },
66
+ ];
67
+ const totalOriginOrder = 200;
68
+ const totalSplitedOrder = 50;
69
+
70
+ const result = getSplittedModifiers(
71
+ modifiers,
72
+ totalOriginOrder,
73
+ totalSplitedOrder
74
+ );
75
+
76
+ expect(result).toEqual(modifiers); // should be unchanged
77
+ });
78
+
79
+ test('should return 0 maxAmount if totalOriginOrder is 0 for credit modifier', () => {
80
+ const modifiers = [
81
+ {
82
+ type: 'credit',
83
+ properties: { maxAmount: 100 },
84
+ },
85
+ ];
86
+ const totalOriginOrder = 0;
87
+ const totalSplitedOrder = 50;
88
+
89
+ const result = getSplittedModifiers(
90
+ modifiers,
91
+ totalOriginOrder,
92
+ totalSplitedOrder
93
+ );
94
+
95
+ expect(result).toEqual([
96
+ {
97
+ type: 'credit',
98
+ properties: { maxAmount: 0 },
99
+ compute: {
100
+ action: '',
101
+ type: '',
102
+ amount: 0,
103
+ },
104
+ },
105
+ ]);
106
+ });
107
+
108
+ test('should return 0 amount if totalOriginOrder is 0 for fixed modifier', () => {
109
+ const modifiers = [
110
+ {
111
+ compute: { amount: 80, type: 'fixed' },
112
+ },
113
+ ];
114
+ const totalOriginOrder = 0;
115
+ const totalSplitedOrder = 40;
116
+
117
+ const result = getSplittedModifiers(
118
+ modifiers,
119
+ totalOriginOrder,
120
+ totalSplitedOrder
121
+ );
122
+
123
+ expect(result).toEqual([
124
+ {
125
+ compute: { amount: 0, type: 'fixed' }, // totalOriginOrder is 0, so amount should be 0
126
+ },
127
+ ]);
128
+ });
129
+
130
+ test('should handle empty modifiers array', () => {
131
+ const result = getSplittedModifiers([], 200, 50);
132
+ expect(result).toEqual([]); // empty input should return empty output
133
+ });
134
+ });
@@ -0,0 +1,38 @@
1
+ const isComputedOverrideFunction = require('../../lib/modifier/isComputedOverride');
2
+
3
+ describe('isComputedOverride Function', () => {
4
+ const Modifier = {
5
+ Attributes: {
6
+ OVERRIDE: 'override',
7
+ },
8
+ };
9
+
10
+ const isComputedOverride = isComputedOverrideFunction({
11
+ constants: { Modifier },
12
+ });
13
+
14
+ test('should return false if modifier is null or undefined', () => {
15
+ expect(isComputedOverride(null)).toBe(false);
16
+ expect(isComputedOverride(undefined)).toBe(false);
17
+ });
18
+
19
+ test('should return false if modifier does not have compute property', () => {
20
+ const modifier = {};
21
+ expect(isComputedOverride(modifier)).toBe(false);
22
+ });
23
+
24
+ test('should return false if compute does not have action property', () => {
25
+ const modifier = { compute: {} };
26
+ expect(isComputedOverride(modifier)).toBe(false);
27
+ });
28
+
29
+ test('should return false if compute action is not OVERRIDE', () => {
30
+ const modifier = { compute: { action: 'other_action' } };
31
+ expect(isComputedOverride(modifier)).toBe(false);
32
+ });
33
+
34
+ test('should return true if compute action is OVERRIDE', () => {
35
+ const modifier = { compute: { action: 'override' } };
36
+ expect(isComputedOverride(modifier)).toBe(true);
37
+ });
38
+ });
@@ -10,7 +10,7 @@ const pricingService = usePricing(session);
10
10
 
11
11
  describe('addItem function', () => {
12
12
  test('should add a new item to an empty order', () => {
13
- const addItem = pricingService.order.addItem;
13
+ const { addItem } = pricingService.order;
14
14
 
15
15
  // Mock an empty order
16
16
  const order = {
@@ -44,7 +44,7 @@ describe('addItem function', () => {
44
44
  });
45
45
 
46
46
  test('should combine with an existing item if aggregation is enabled', () => {
47
- const addItem = pricingService.order.addItem;
47
+ const { addItem } = pricingService.order;
48
48
 
49
49
  // Mock order with one existing item
50
50
  const order = {
@@ -83,7 +83,7 @@ describe('addItem function', () => {
83
83
  });
84
84
 
85
85
  test('should add item with overridden quantity', () => {
86
- const addItem = pricingService.order.addItem;
86
+ const { addItem } = pricingService.order;
87
87
 
88
88
  // Mock order with one existing item
89
89
  const order = {
@@ -99,7 +99,7 @@ describe('addItem function', () => {
99
99
  };
100
100
 
101
101
  // Call the function with an overridden quantity
102
- const [updatedOrder, itemIndex, addedItem] = addItem({
102
+ const [updatedOrder, , addedItem] = addItem({
103
103
  order,
104
104
  item,
105
105
  itemIndex: -1, // Assuming no explicit index
@@ -114,7 +114,7 @@ describe('addItem function', () => {
114
114
  });
115
115
 
116
116
  test('should handle adding an item with modifiers', () => {
117
- const addItem = pricingService.order.addItem;
117
+ const { addItem } = pricingService.order;
118
118
 
119
119
  // Mock order with one existing item
120
120
  const order = {
@@ -128,70 +128,74 @@ describe('addItem function', () => {
128
128
  price: 150,
129
129
  modifiers: [
130
130
  {
131
- "_id": "66cdf18a1e48455e128a4f63",
132
- "modifierId": 'mod1',
133
- "_parentId": null,
134
- "name": null,
135
- "sku": null,
136
- "description": null,
137
- "group": null,
138
- "type": null,
139
- "attributes": [],
140
- "color": null,
141
- "backgroundColor": null,
142
- "icon": null,
143
- "url": null,
144
- "tags": [],
145
- "order": null,
146
- "included": false,
147
- "direct": true,
148
- "hidden": false,
149
- "required": false,
150
- "code": null,
151
- "properties": null,
152
- "_computed": null
131
+ _id: '66cdf18a1e48455e128a4f63',
132
+ modifierId: 'mod1',
133
+ _parentId: null,
134
+ name: null,
135
+ sku: null,
136
+ description: null,
137
+ group: null,
138
+ type: null,
139
+ attributes: [],
140
+ color: null,
141
+ backgroundColor: null,
142
+ icon: null,
143
+ url: null,
144
+ tags: [],
145
+ order: null,
146
+ included: false,
147
+ direct: true,
148
+ hidden: false,
149
+ required: false,
150
+ code: null,
151
+ properties: null,
152
+ _computed: null,
153
153
  },
154
154
  {
155
- "_id": "66cdf18a1e48455e128a4f64",
156
- "modifierId": 'mod2',
157
- "_parentId": null,
158
- "name": null,
159
- "sku": null,
160
- "description": null,
161
- "group": null,
162
- "type": null,
163
- "attributes": [],
164
- "color": null,
165
- "backgroundColor": null,
166
- "icon": null,
167
- "url": null,
168
- "tags": [],
169
- "order": null,
170
- "included": false,
171
- "direct": true,
172
- "hidden": false,
173
- "required": false,
174
- "code": null,
175
- "properties": null,
176
- "_computed": null
155
+ _id: '66cdf18a1e48455e128a4f64',
156
+ modifierId: 'mod2',
157
+ _parentId: null,
158
+ name: null,
159
+ sku: null,
160
+ description: null,
161
+ group: null,
162
+ type: null,
163
+ attributes: [],
164
+ color: null,
165
+ backgroundColor: null,
166
+ icon: null,
167
+ url: null,
168
+ tags: [],
169
+ order: null,
170
+ included: false,
171
+ direct: true,
172
+ hidden: false,
173
+ required: false,
174
+ code: null,
175
+ properties: null,
176
+ _computed: null,
177
177
  },
178
178
  ],
179
179
  };
180
180
 
181
181
  // Call the function
182
- const [updatedOrder, itemIndex, addedItem] = addItem({
182
+ const [updatedOrder] = addItem({
183
183
  order,
184
184
  item,
185
185
  itemIndex: -1, // Assuming no explicit index
186
186
  cache: addItemObj.cache, // Assuming some cache object
187
187
  overridenQuantity: -1, // No overridden quantity
188
188
  });
189
-
189
+
190
190
  // Assertions
191
191
  expect(updatedOrder.items).toHaveLength(1); // Should have one item
192
192
  expect(updatedOrder.items[0].modifiers).toHaveLength(2); // Item should have two modifiers
193
- expect(updatedOrder.items[0].modifiers[0].modifierId).toBe('66cdf18a1e48455e128a4f63'); // Check first modifier
194
- expect(updatedOrder.items[0].modifiers[1].modifierId).toBe('66cdf18a1e48455e128a4f64'); // Check second modifier
193
+ expect(updatedOrder.items[0].modifiers[0].modifierId).toBe(
194
+ '66cdf18a1e48455e128a4f63'
195
+ ); // Check first modifier
196
+ expect(updatedOrder.items[0].modifiers[1].modifierId).toBe(
197
+ '66cdf18a1e48455e128a4f64'
198
+ ); // Check second modifier
195
199
  expect(updatedOrder.items[0].modifiers).toHaveLength(2); // Added item should have modifiers
196
200
  });
197
201
  });
@@ -0,0 +1,117 @@
1
+ const adjustFixedModifiersDifferenceFunction = require('../../lib/order/adjustFixedModifiersDifference');
2
+
3
+ describe('adjustFixedModifiersDifference Function', () => {
4
+ const math = {
5
+ add: jest.fn(),
6
+ };
7
+ const _ = {
8
+ get: jest.fn(),
9
+ };
10
+ const actions = {
11
+ isOpen: jest.fn(),
12
+ calculate: jest.fn(),
13
+ };
14
+
15
+ const modifierActions = {
16
+ hasFixedModifier: jest.fn(),
17
+ };
18
+
19
+ const getComputeModField = jest.fn();
20
+
21
+ const adjustFixedModifiersDifference = adjustFixedModifiersDifferenceFunction(
22
+ {
23
+ utils: { math },
24
+ actions,
25
+ modifierActions,
26
+ _,
27
+ }
28
+ );
29
+
30
+ beforeEach(() => {
31
+ jest.clearAllMocks();
32
+ });
33
+
34
+ test('should adjust the fixed modifier for a suitable subOrder', () => {
35
+ const subOrders = [
36
+ { id: 'subOrder1', total: 100, modifiers: [] },
37
+ {
38
+ id: 'subOrder2',
39
+ total: 200,
40
+ modifiers: [{ compute: { type: 'fixed', amount: 50 } }],
41
+ },
42
+ ];
43
+ const difference = 20;
44
+
45
+ modifierActions.hasFixedModifier
46
+ .mockReturnValueOnce(false)
47
+ .mockReturnValueOnce(true);
48
+ actions.isOpen.mockReturnValueOnce(true);
49
+ getComputeModField.mockReturnValueOnce({ compute: { amount: 50 } });
50
+ math.add.mockReturnValueOnce(70);
51
+ actions.calculate.mockReturnValueOnce({
52
+ id: 'subOrder2',
53
+ total: 200,
54
+ modifiers: [{ compute: { type: 'fixed', amount: 70 } }],
55
+ });
56
+ _.get.mockReturnValueOnce(50);
57
+
58
+ const result = adjustFixedModifiersDifference({ subOrders, difference });
59
+
60
+ expect(result).toEqual([
61
+ { id: 'subOrder1', total: 100, modifiers: [] },
62
+ {
63
+ id: 'subOrder2',
64
+ total: 200,
65
+ modifiers: [{ compute: { type: 'fixed', amount: 70 } }],
66
+ },
67
+ ]);
68
+
69
+ expect(math.add).toHaveBeenCalledWith(50, difference);
70
+ });
71
+
72
+ test('should not adjust if no suitable subOrder is found', () => {
73
+ const subOrders = [
74
+ {
75
+ id: 'subOrder1',
76
+ total: 100,
77
+ modifiers: [{ compute: { type: 'fixed', amount: 50 } }],
78
+ },
79
+ { id: 'subOrder2', total: 50, modifiers: [] },
80
+ ];
81
+ const difference = 200;
82
+
83
+ modifierActions.hasFixedModifier
84
+ .mockReturnValueOnce(true)
85
+ .mockReturnValueOnce(false);
86
+ actions.isOpen.mockReturnValueOnce(true).mockReturnValueOnce(true);
87
+
88
+ const result = adjustFixedModifiersDifference({ subOrders, difference });
89
+
90
+ expect(result).toEqual(subOrders);
91
+ expect(math.add).not.toHaveBeenCalled();
92
+ expect(actions.calculate).not.toHaveBeenCalled();
93
+ });
94
+
95
+ test('should not adjust if no suitable subOrder is found and compute is null', () => {
96
+ const subOrders = [
97
+ {
98
+ id: 'subOrder1',
99
+ total: 100,
100
+ modifiers: [{ compute: null }],
101
+ },
102
+ { id: 'subOrder2', total: 50, modifiers: [] },
103
+ ];
104
+ const difference = 200;
105
+
106
+ modifierActions.hasFixedModifier
107
+ .mockReturnValueOnce(true)
108
+ .mockReturnValueOnce(false);
109
+ actions.isOpen.mockReturnValueOnce(true).mockReturnValueOnce(true);
110
+
111
+ const result = adjustFixedModifiersDifference({ subOrders, difference });
112
+
113
+ expect(result).toEqual(subOrders);
114
+ expect(math.add).not.toHaveBeenCalled();
115
+ expect(actions.calculate).not.toHaveBeenCalled();
116
+ });
117
+ });
@@ -2240,4 +2240,51 @@ describe('Order actions', () => {
2240
2240
 
2241
2241
  expect(newOrderFixedModifier).toHaveProperty('total', 120);
2242
2242
  });
2243
+
2244
+ test('Get calculated Order, multiple items and indirect modifiers and null compute', () => {
2245
+ const item1 = {
2246
+ _id: 1,
2247
+ price: 30,
2248
+ quantity: 2,
2249
+ };
2250
+ const item2 = {
2251
+ _id: 2,
2252
+ price: 10,
2253
+ quantity: 1,
2254
+ };
2255
+ const modifier1 = {
2256
+ compute: null,
2257
+ name: 'modifier1',
2258
+ type: 'discount',
2259
+ };
2260
+
2261
+ const order = { items: [item1, item2], modifiers: [modifier1] };
2262
+
2263
+ const newOrder = pricingService.order.calculate(order);
2264
+ expect(newOrder).toHaveProperty('total', 70);
2265
+ expect(newOrder).toHaveProperty('subTotal', 70);
2266
+ expect(newOrder).toHaveProperty('subTotals', {
2267
+ discount: 0,
2268
+ });
2269
+ expect(newOrder.items[0]).toHaveProperty('total', 60);
2270
+ expect(newOrder.items[0]).toHaveProperty('subTotals', {
2271
+ discount: 0,
2272
+ _included: 0,
2273
+ _xincluded: 0,
2274
+ _direct: 0,
2275
+ _xdirect: 0,
2276
+ _simple: 60,
2277
+ _actual: 60,
2278
+ });
2279
+ expect(newOrder.items[1]).toHaveProperty('total', 10);
2280
+ expect(newOrder.items[1]).toHaveProperty('subTotals', {
2281
+ discount: 0,
2282
+ _included: 0,
2283
+ _xincluded: 0,
2284
+ _direct: 0,
2285
+ _xdirect: 0,
2286
+ _simple: 10,
2287
+ _actual: 10,
2288
+ });
2289
+ });
2243
2290
  });
@@ -1,4 +1,5 @@
1
- module.exports = ({ utils, modifierActions }) => {
1
+ module.exports = ({ utils, modifierActions, _ }) => {
2
+ const { getComputeModField } = require('../modifier/utils');
2
3
  const { math } = utils;
3
4
 
4
5
  return function addIndirectModifier({ orderTotal, items, modifier }) {
@@ -25,7 +26,9 @@ module.exports = ({ utils, modifierActions }) => {
25
26
  );
26
27
  }, 0);
27
28
 
28
- if (modifier.compute.type === 'percentage' && modifier.type !== 'credit')
29
+ const modifierType = _.get(modifier, 'modifier.type', '');
30
+ const computeField = getComputeModField(modifier);
31
+ if (computeField.type === 'percentage' && modifierType !== 'credit')
29
32
  return itemsModifiers;
30
33
 
31
34
  if (math.abs(totalDistributed) !== math.abs(orderModifierTotal)) {
@@ -2,6 +2,8 @@
2
2
  module.exports = ({ _, utils, actions, modifierActions }) => {
3
3
  const { math } = utils;
4
4
  //
5
+ const { getComputeModField } = require('../modifier/utils');
6
+
5
7
  const calculateOne = inputItem => {
6
8
  const item = _.cloneDeep(inputItem);
7
9
  if (!item) return item;
@@ -70,8 +72,10 @@ module.exports = ({ _, utils, actions, modifierActions }) => {
70
72
  const computedAmountCalc = math.mul(_computed.amount, quantity);
71
73
  const computedPriceCalc = math.mul(computedPrice * quantity);
72
74
 
75
+ // adding this computeField because now the compute from a modifier can be null
76
+ const computeField = getComputeModField(_modifier);
73
77
  let computedAmount =
74
- _modifier.compute.type === 'percentage' ||
78
+ computeField.type === 'percentage' ||
75
79
  modifierActions.isIgnoreQuantity(_modifier) ||
76
80
  (!modifierActions.isFixedAdd(_modifier) &&
77
81
  math.gt(math.abs(computedAmountCalc), computedPriceCalc))
@@ -1,3 +1,5 @@
1
+ const { getComputeModField } = require('./utils');
2
+
1
3
  /**
2
4
  * Get calculated modifier
3
5
  */
@@ -9,8 +11,9 @@ module.exports = ({ _, constants, utils, localization, actions }) => {
9
11
  modifier = {},
10
12
  options = { price: 0, quantity: 0, skip: false }
11
13
  ) {
12
- const { name, compute } = modifier;
13
- const { type, action, amount = 0 } = compute || {};
14
+ const { name } = modifier;
15
+ const compute = getComputeModField(modifier);
16
+ const { type, action, amount = 0 } = compute;
14
17
  const _computed = {
15
18
  amount: 0,
16
19
  description: '',
@@ -4,15 +4,16 @@
4
4
  module.exports = ({ _, utils, constants, actions }) => {
5
5
  const { math } = utils;
6
6
  const { Modifier } = constants;
7
-
7
+ const { getComputeModField } = require('./utils');
8
8
  return function createIndirectModifier(
9
9
  modifier,
10
10
  options = { orderTotal: 0, itemQuantity: 1, itemTotal: 0 }
11
11
  ) {
12
12
  const maxAmount = actions.getProperty(modifier, 'maxAmount');
13
13
 
14
- const compute = modifier.compute || {};
15
- const { type, amount = 0 } = compute;
14
+ const compute = getComputeModField(modifier);
15
+ const type = _.get(compute, 'type', '');
16
+ const amount = _.get(compute, 'amount', 0);
16
17
  let modifierAmount = amount;
17
18
 
18
19
  if (type === Modifier.Compute.Types.PERCENTAGE) {
@@ -1,12 +1,13 @@
1
1
  module.exports = ({ utils }) => {
2
2
  const { math } = utils;
3
-
3
+ const { getComputeModField } = require('./utils');
4
4
  return function getFixedModifiersTotal(modifiers) {
5
5
  if (!Array.isArray(modifiers)) return 0;
6
6
 
7
- const fixedModifiers = modifiers.filter(
8
- mod => mod.compute.type === 'fixed'
9
- );
7
+ const fixedModifiers = modifiers.filter(mod => {
8
+ const compute = getComputeModField(mod);
9
+ return compute.type === 'fixed';
10
+ });
10
11
 
11
12
  return fixedModifiers.reduce(
12
13
  (acc, modifier) => math.add(acc, modifier.compute.amount || 0),
@@ -1,5 +1,6 @@
1
1
  module.exports = ({ utils }) => {
2
2
  const { math } = utils;
3
+ const { getComputeModField } = require('./utils');
3
4
 
4
5
  const divideModifierAmount = ({
5
6
  totalOriginOrder,
@@ -25,10 +26,11 @@ module.exports = ({ utils }) => {
25
26
  totalOriginOrder,
26
27
  totalSplitedOrder,
27
28
  });
29
+ const compute = getComputeModField(modifier);
28
30
  return {
29
31
  ...modifier,
30
32
  compute: {
31
- ...modifier.compute,
33
+ ...compute,
32
34
  },
33
35
  properties: {
34
36
  ...modifier.properties,
@@ -63,7 +65,7 @@ module.exports = ({ utils }) => {
63
65
  ) {
64
66
  return modifiers.map(each => {
65
67
  const modifier = { ...each };
66
-
68
+ const compute = getComputeModField(modifier);
67
69
  if (modifier.type === 'credit') {
68
70
  return splitCreditModifier({
69
71
  modifier,
@@ -72,11 +74,7 @@ module.exports = ({ utils }) => {
72
74
  });
73
75
  }
74
76
 
75
- if (
76
- modifier.compute &&
77
- modifier.compute.type === 'fixed' &&
78
- modifier.compute.amount
79
- ) {
77
+ if (compute && compute.type === 'fixed' && compute.amount) {
80
78
  return splitFixedModifier({
81
79
  modifier,
82
80
  totalOriginOrder,
@@ -1,7 +1,8 @@
1
- module.exports = ({ actions, constants }) => {
1
+ module.exports = ({ constants }) => {
2
2
  const { Modifier } = constants;
3
3
  return function isComputedOverride(modifier) {
4
- const computeAction = modifier && modifier.compute && modifier.compute.action;
4
+ const computeAction =
5
+ modifier && modifier.compute && modifier.compute.action;
5
6
  return computeAction === Modifier.Attributes.OVERRIDE;
6
7
  };
7
8
  };
@@ -0,0 +1,10 @@
1
+ const _ = require('lodash');
2
+
3
+ const getComputeModField = modifier =>
4
+ _.isNull(modifier.compute) || !modifier.compute
5
+ ? { type: '', amount: 0, action: '' }
6
+ : modifier.compute;
7
+
8
+ module.exports = {
9
+ getComputeModField,
10
+ };
@@ -1,9 +1,10 @@
1
1
  module.exports = ({ actions, itemActions, modifierActions, utils, _ }) => {
2
2
  const { math } = utils;
3
+ const { getComputeModField } = require('../modifier/utils');
3
4
 
4
5
  const getPrice = ({ item, modifier }) => {
5
- const amount =
6
- (modifier && modifier.compute && modifier.compute.amount) || 0;
6
+ const compute = getComputeModField(modifier);
7
+ const amount = (modifier && compute && compute.amount) || 0;
7
8
  const { price = 0 } = item;
8
9
  if (modifierActions.isMultiplier(modifier)) return math.mul(price, amount);
9
10
  return amount;
@@ -64,6 +65,7 @@ module.exports = ({ actions, itemActions, modifierActions, utils, _ }) => {
64
65
  },
65
66
  }) => {
66
67
  let item = { ...itemProp };
68
+ const compute = getComputeModField(modifier);
67
69
  if (hasBehaivoralFields(modifier)) return item;
68
70
  // check conditions
69
71
  if (!areConditionsMet(item, modifier.conditions)) return item;
@@ -91,7 +93,7 @@ module.exports = ({ actions, itemActions, modifierActions, utils, _ }) => {
91
93
  if (modifierActions.isAmountOverride(modifier)) {
92
94
  item = {
93
95
  ...item,
94
- price: modifier.compute.amount,
96
+ price: compute.amount,
95
97
  };
96
98
  }
97
99
 
@@ -99,7 +101,10 @@ module.exports = ({ actions, itemActions, modifierActions, utils, _ }) => {
99
101
  item.quantity = modifier.compute.amount || 1;
100
102
  }
101
103
 
102
- if (modifierActions.isPriceOverride(modifier) || modifierActions.isComputedOverride(modifier)) {
104
+ if (
105
+ modifierActions.isPriceOverride(modifier) ||
106
+ modifierActions.isComputedOverride(modifier)
107
+ ) {
103
108
  item.price = getPrice({ modifier, item });
104
109
  } else {
105
110
  item.price = itemActions.getItemPrice({
@@ -1,11 +1,12 @@
1
- module.exports = ({ actions, modifierActions }) =>
2
- function addModifier({ order, modifier }) {
1
+ module.exports = ({ actions, modifierActions }) => {
2
+ const { getComputeModField } = require('../modifier/utils');
3
+ return function addModifier({ order, modifier }) {
3
4
  if (!modifier) return order;
4
5
  const { modifiers = [] } = order;
5
-
6
6
  if (modifierActions.isFixedDiscount(modifier)) {
7
+ const compute = getComputeModField(modifier);
7
8
  const orderDue = actions.calculateDue(order);
8
- if (modifier.compute.amount > orderDue) {
9
+ if (compute.amount > orderDue) {
9
10
  const err = new Error();
10
11
  err.valid = false;
11
12
  err.orderDue = orderDue;
@@ -19,3 +20,4 @@ module.exports = ({ actions, modifierActions }) =>
19
20
  modifiers: [...modifiers, { ...modifier }],
20
21
  };
21
22
  };
23
+ };
@@ -1,6 +1,6 @@
1
- module.exports = ({ utils, actions, modifierActions }) => {
1
+ module.exports = ({ utils, actions, modifierActions, _ }) => {
2
2
  const { math } = utils;
3
-
3
+ const { getComputeModField } = require('../modifier/utils');
4
4
  return function adjustFixedModifiersDifference({ subOrders, difference }) {
5
5
  const selectedSubOrderIndex = subOrders.findIndex(
6
6
  subOrder =>
@@ -15,15 +15,16 @@ module.exports = ({ utils, actions, modifierActions }) => {
15
15
  };
16
16
 
17
17
  const modifierToUpdateIdx = subOrderToUpdate.modifiers.findIndex(
18
- mod => mod.compute.type === 'fixed'
18
+ mod => mod.compute && mod.compute.type === 'fixed'
19
19
  );
20
- const prevAmount =
21
- subOrderToUpdate.modifiers[modifierToUpdateIdx].compute.amount;
22
-
23
- subOrderToUpdate.modifiers[modifierToUpdateIdx].compute.amount = math.add(
24
- prevAmount,
25
- difference
20
+ const prevCompute = getComputeModField(
21
+ subOrderToUpdate.modifiers[modifierToUpdateIdx]
26
22
  );
23
+ const prevAmount = _.get(prevCompute, 'compute.amount', 0);
24
+ if (modifierToUpdateIdx !== -1) {
25
+ subOrderToUpdate.modifiers[modifierToUpdateIdx].compute.amount =
26
+ math.add(prevAmount, difference);
27
+ }
27
28
  subOrders.splice(
28
29
  selectedSubOrderIndex,
29
30
  1,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@darkpos/pricing",
3
- "version": "1.0.31",
3
+ "version": "1.0.32",
4
4
  "description": "Pricing calculator",
5
5
  "author": "Dark POS",
6
6
  "license": "ISC",
@@ -36,5 +36,5 @@
36
36
  "supertest": "^6.2.3",
37
37
  "supervisor": "^0.12.0"
38
38
  },
39
- "gitHead": "a864feac96c47884de2da753f60ea69856bcb914"
39
+ "gitHead": "5c5b8c5f55437733d8f9d8f9bbba00d27a6f7c59"
40
40
  }