@darkpos/pricing 1.0.37 → 1.0.38

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,118 @@
1
+ const addItemMock = require('./mocks/addItemModifierMock.json');
2
+ const orderMock = require('./mocks/orderMock.json');
3
+ const usePricing = require('../../index');
4
+
5
+ const pricingService = usePricing();
6
+
7
+ describe('addItemModifier Function', () => {
8
+ test('Add an override price modifier to the item', () => {
9
+ let { order } = addItemMock;
10
+ const { modifier2, itemIndex } = addItemMock;
11
+
12
+ /**
13
+ * modifier2 properties
14
+ * "override": {
15
+ "field": "price",
16
+ "type": "fixed",
17
+ "multiplier": null,
18
+ "fixedValue": 40
19
+ },
20
+ */
21
+ order = pricingService.order.addItemModifier({
22
+ order,
23
+ modifier: modifier2,
24
+ itemIndex,
25
+ });
26
+
27
+ const calculatedOrder = pricingService.order.calculate({
28
+ ...order,
29
+ items: order.items,
30
+ });
31
+
32
+ const item0 = calculatedOrder.items[0];
33
+ // Check that the modifier adds the correct fixed amount
34
+ expect(item0.price).toBe(40);
35
+ });
36
+ test('Add an override amount to the item', () => {
37
+ let { order } = addItemMock;
38
+ const { modifier1, itemIndex } = addItemMock;
39
+
40
+ /**
41
+ * modifier2 properties
42
+ "override": {
43
+ "field": "amount",
44
+ "type": "fixed",
45
+ "multiplier": null,
46
+ "fixedValue": 20
47
+ },
48
+ */
49
+ order = pricingService.order.addItemModifier({
50
+ order,
51
+ modifier: modifier1,
52
+ itemIndex,
53
+ });
54
+
55
+ const calculatedOrder = pricingService.order.calculate({
56
+ ...order,
57
+ items: order.items,
58
+ });
59
+ const item0 = calculatedOrder.items[0];
60
+
61
+ // The item price shouldn't change
62
+ expect(item0.price).toBe(2);
63
+
64
+ // expect the modifier compute amount to match the item
65
+ expect(item0.modifiers[0].compute.amount).toBe(20);
66
+ });
67
+ test('Add an override amount and override at the same time to the item', () => {
68
+ let { order } = addItemMock;
69
+ const { modifier1, modifier2, itemIndex } = addItemMock;
70
+
71
+ order = pricingService.order.addItemModifier({
72
+ order,
73
+ modifier: modifier1,
74
+ itemIndex,
75
+ });
76
+
77
+ order = pricingService.order.addItemModifier({
78
+ order,
79
+ modifier: modifier2,
80
+ itemIndex,
81
+ });
82
+
83
+ const calculatedOrder = pricingService.order.calculate({
84
+ ...order,
85
+ items: order.items,
86
+ });
87
+ const item0 = calculatedOrder.items[0];
88
+ // item price should match the price override
89
+ expect(item0.price).toBe(40);
90
+ // amount override should be 20
91
+ expect(item0.modifiers[1].compute.amount).toBe(20);
92
+ /// price override should be 40
93
+ expect(item0.modifiers[0].compute.amount).toBe(40);
94
+ });
95
+
96
+ test('Verify item total after adding the modifier', () => {
97
+ const order = pricingService.order.addItemModifier(addItemMock, orderMock);
98
+ const item0 = order.items[0];
99
+ expect(item0.total).toBe(item0.price * item0.quantity); // Ensure total is calculated correctly
100
+ });
101
+
102
+ test('Ensure no price change when no modifiers are applied', () => {
103
+ const noModifierMock = { ...addItemMock, modifiers: [] }; // Mock with no modifiers
104
+ const order = pricingService.order.addItemModifier(
105
+ noModifierMock,
106
+ orderMock
107
+ );
108
+ const item0 = order.items[0];
109
+ expect(item0.price).toBe(2); // Expect original price if no modifiers
110
+ });
111
+
112
+ test('Handle invalid or null modifier input', () => {
113
+ const invalidModifierMock = null; // Simulate invalid modifier
114
+ expect(() => {
115
+ pricingService.order.addItemModifier(invalidModifierMock, orderMock);
116
+ }).toThrow(Error); // Expect an error to be thrown with invalid input
117
+ });
118
+ });
@@ -0,0 +1,284 @@
1
+ {
2
+ "itemIndex": 0,
3
+ "modifier1": {
4
+ "_id": "66ec3e3efe02e7ee35f595bd",
5
+ "attributes": [
6
+ "override"
7
+ ],
8
+ "modifierId": "66ec3e3efe02e7ee35f595bd",
9
+ "_parentId": null,
10
+ "locked": false,
11
+ "name": "Modifier1",
12
+ "sku": "123123",
13
+ "description": "",
14
+ "group": "",
15
+ "type": "",
16
+ "tags": [
17
+ "default"
18
+ ],
19
+ "order": 2,
20
+ "included": false,
21
+ "direct": true,
22
+ "hidden": false,
23
+ "print": true,
24
+ "required": false,
25
+ "recommended": false,
26
+ "default": false,
27
+ "code": "",
28
+ "properties": {
29
+ "subscription": {},
30
+ "override": {
31
+ "field": "amount",
32
+ "type": "fixed",
33
+ "multiplier": null,
34
+ "fixedValue": 20
35
+ },
36
+ "group": {
37
+ "items": [],
38
+ "modifiers": []
39
+ },
40
+ "department": {},
41
+ "sort": null,
42
+ "label": {
43
+ "text": ""
44
+ }
45
+ },
46
+ "_computed": null,
47
+ "addModifiers": [],
48
+ "delModifiers": [],
49
+ "conditions": null,
50
+ "compute": null,
51
+ "_createdAt": "2024-09-19T15:08:50.263Z",
52
+ "_updatedAt": "2024-09-19T17:35:26.661Z"
53
+ },
54
+ "modifier2": {
55
+ "_id": "66ec3e3efe02e7ee35f595be",
56
+ "attributes": [
57
+ "override"
58
+ ],
59
+ "modifierId": "66ec3e3efe02e7ee35f595be",
60
+ "_parentId": null,
61
+ "locked": false,
62
+ "name": "Modifier2",
63
+ "sku": "1231234",
64
+ "description": "",
65
+ "group": "",
66
+ "type": "",
67
+ "tags": [
68
+ "default"
69
+ ],
70
+ "order": 1,
71
+ "included": false,
72
+ "direct": true,
73
+ "hidden": false,
74
+ "print": true,
75
+ "required": false,
76
+ "recommended": false,
77
+ "default": false,
78
+ "code": "",
79
+ "properties": {
80
+ "subscription": {},
81
+ "override": {
82
+ "field": "price",
83
+ "type": "fixed",
84
+ "multiplier": null,
85
+ "fixedValue": 40
86
+ },
87
+ "group": {
88
+ "items": [],
89
+ "modifiers": []
90
+ },
91
+ "department": {},
92
+ "sort": null,
93
+ "label": {
94
+ "text": ""
95
+ }
96
+ },
97
+ "_computed": null,
98
+ "addModifiers": [],
99
+ "delModifiers": [],
100
+ "conditions": null,
101
+ "compute": null,
102
+ "_createdAt": "2024-09-19T15:08:50.263Z",
103
+ "_updatedAt": "2024-09-19T17:35:26.661Z"
104
+ },
105
+ "order": {
106
+ "_id": "66ec7594d57e32c34557249f",
107
+ "parentId": null,
108
+ "isParent": false,
109
+ "subTotal": 2,
110
+ "tax": 0,
111
+ "modifiers": [],
112
+ "discount": 0,
113
+ "total": 2,
114
+ "description": "",
115
+ "displayId": "",
116
+ "type": "",
117
+ "location": {},
118
+ "status": {
119
+ "order": "open",
120
+ "kitchen": "open",
121
+ "delivery": "none",
122
+ "detailed": true
123
+ },
124
+ "attributes": [],
125
+ "properties": {},
126
+ "fee": 0,
127
+ "user": null,
128
+ "items": [
129
+ {
130
+ "location": {},
131
+ "status": {
132
+ "picked": {
133
+ "value": false,
134
+ "date": ""
135
+ },
136
+ "paid": {
137
+ "value": false,
138
+ "date": ""
139
+ },
140
+ "tracker": []
141
+ },
142
+ "name": "Andre Pants",
143
+ "description": "Andre Pants",
144
+ "pieces": 1,
145
+ "modifiersTotalAmount": 0,
146
+ "total": 2,
147
+ "totalPaid": 0,
148
+ "price": 2,
149
+ "quantity": 1,
150
+ "path": ",66da070aac2d4ae39904050f,66da131a81cf1303bc32a2c7,",
151
+ "notes": [],
152
+ "serial": null,
153
+ "sku": "AND-PAN",
154
+ "modifiers": [],
155
+ "_id": "66ec759cd57e32c3455724a0",
156
+ "weight": null,
157
+ "properties": null,
158
+ "hasInventory": true,
159
+ "inventoryType": "pull",
160
+ "category": null,
161
+ "priceLevels": [
162
+ {
163
+ "value": 10,
164
+ "tags": [
165
+ "default"
166
+ ]
167
+ },
168
+ {
169
+ "value": 2,
170
+ "tags": [
171
+ "vip"
172
+ ]
173
+ },
174
+ {
175
+ "value": 10,
176
+ "tags": [
177
+ "default",
178
+ "press only"
179
+ ]
180
+ },
181
+ {
182
+ "value": 2,
183
+ "tags": [
184
+ "vip",
185
+ "press only"
186
+ ]
187
+ }
188
+ ],
189
+ "costLevels": [],
190
+ "itemId": "66da11fdac2d4ae39904465e",
191
+ "menuRuleId": "66da132381cf1303bc32a2c8",
192
+ "__typename": "OrderItem",
193
+ "subTotals": {
194
+ "_included": 0,
195
+ "_xincluded": 0,
196
+ "_direct": 0,
197
+ "_xdirect": 0,
198
+ "_simple": 2,
199
+ "_actual": 2
200
+ }
201
+ }
202
+ ],
203
+ "notes": [],
204
+ "customer": {
205
+ "_id": "66bb8d1e38ebaee653177a92",
206
+ "username": "apinto.dev@gmail.com",
207
+ "firstName": "Andre",
208
+ "lastName": "Pinto2",
209
+ "description": null,
210
+ "attributes": [],
211
+ "properties": {
212
+ "charge": {
213
+ "enabled": null
214
+ },
215
+ "billing": {
216
+ "enabled": null,
217
+ "limit": 0
218
+ },
219
+ "events": [],
220
+ "relationships": [],
221
+ "gender": "",
222
+ "company": "",
223
+ "profilePic": null,
224
+ "starch": "62cdbfd01ee1b4001932822f"
225
+ },
226
+ "tags": [
227
+ "default",
228
+ "vip"
229
+ ],
230
+ "status": null,
231
+ "parentId": null,
232
+ "loyalty": null,
233
+ "wallet": [],
234
+ "modifiers": [],
235
+ "addresses": [],
236
+ "contacts": [
237
+ {
238
+ "value": "game.adsp@gmail.com",
239
+ "description": "",
240
+ "type": "email",
241
+ "tags": [
242
+ "personal"
243
+ ],
244
+ "primary": true,
245
+ "notification": false,
246
+ "config": null,
247
+ "verified": false
248
+ }
249
+ ],
250
+ "notes": [],
251
+ "_accountId": "62cdbfcdaaf93c00193d2dd3",
252
+ "_storeId": "62cdbfce1ee1b40019328156",
253
+ "_isDeleted": false,
254
+ "_deletedAt": null,
255
+ "_updatedAt": "2024-09-16T13:57:47.426Z",
256
+ "_createdAt": "2024-08-13T16:43:10.457Z",
257
+ "isEmbedded": true
258
+ },
259
+ "start": {
260
+ "actualDate": "2024-09-19T19:03:48.469Z",
261
+ "requestDate": "2024-09-19T19:03:48.469Z",
262
+ "__typename": "OrderStart",
263
+ "location": {
264
+ "name": "Tico Store #1",
265
+ "locationType": "store",
266
+ "storeId": "62cdbfce1ee1b40019328156"
267
+ }
268
+ },
269
+ "end": {
270
+ "location": {
271
+ "name": "Tico Store #1",
272
+ "locationType": "store",
273
+ "storeId": "62cdbfce1ee1b40019328156"
274
+ },
275
+ "__typename": "OrderEnd",
276
+ "actualDate": "",
277
+ "requestDate": ""
278
+ },
279
+ "_storeId": "",
280
+ "__typename": "Order",
281
+ "isOrderNew": true,
282
+ "subTotals": {}
283
+ }
284
+ }
@@ -0,0 +1,179 @@
1
+ {
2
+ "_id": "66ec7594d57e32c34557249f",
3
+ "parentId": null,
4
+ "isParent": false,
5
+ "subTotal": 2,
6
+ "tax": 0,
7
+ "modifiers": [],
8
+ "discount": 0,
9
+ "total": 2,
10
+ "description": "",
11
+ "displayId": "",
12
+ "type": "",
13
+ "location": {},
14
+ "status": {
15
+ "order": "open",
16
+ "kitchen": "open",
17
+ "delivery": "none",
18
+ "detailed": true
19
+ },
20
+ "attributes": [],
21
+ "properties": {},
22
+ "fee": 0,
23
+ "user": null,
24
+ "items": [
25
+ {
26
+ "location": {},
27
+ "status": {
28
+ "picked": {
29
+ "value": false,
30
+ "date": ""
31
+ },
32
+ "paid": {
33
+ "value": false,
34
+ "date": ""
35
+ },
36
+ "tracker": []
37
+ },
38
+ "name": "Andre Pants",
39
+ "description": "Andre Pants",
40
+ "pieces": 1,
41
+ "modifiersTotalAmount": 0,
42
+ "total": 2,
43
+ "totalPaid": 0,
44
+ "price": 2,
45
+ "quantity": 1,
46
+ "path": ",66da070aac2d4ae39904050f,66da131a81cf1303bc32a2c7,",
47
+ "notes": [],
48
+ "serial": null,
49
+ "sku": "AND-PAN",
50
+ "modifiers": [],
51
+ "_id": "66ec759cd57e32c3455724a0",
52
+ "weight": null,
53
+ "properties": null,
54
+ "hasInventory": true,
55
+ "inventoryType": "pull",
56
+ "category": null,
57
+ "priceLevels": [
58
+ {
59
+ "value": 10,
60
+ "tags": [
61
+ "default"
62
+ ]
63
+ },
64
+ {
65
+ "value": 2,
66
+ "tags": [
67
+ "vip"
68
+ ]
69
+ },
70
+ {
71
+ "value": 10,
72
+ "tags": [
73
+ "default",
74
+ "press only"
75
+ ]
76
+ },
77
+ {
78
+ "value": 2,
79
+ "tags": [
80
+ "vip",
81
+ "press only"
82
+ ]
83
+ }
84
+ ],
85
+ "costLevels": [],
86
+ "itemId": "66da11fdac2d4ae39904465e",
87
+ "menuRuleId": "66da132381cf1303bc32a2c8",
88
+ "__typename": "OrderItem",
89
+ "subTotals": {
90
+ "_included": 0,
91
+ "_xincluded": 0,
92
+ "_direct": 0,
93
+ "_xdirect": 0,
94
+ "_simple": 2,
95
+ "_actual": 2
96
+ }
97
+ }
98
+ ],
99
+ "notes": [],
100
+ "customer": {
101
+ "_id": "66bb8d1e38ebaee653177a92",
102
+ "username": "apinto.dev@gmail.com",
103
+ "firstName": "Andre",
104
+ "lastName": "Pinto2",
105
+ "description": null,
106
+ "attributes": [],
107
+ "properties": {
108
+ "charge": {
109
+ "enabled": null
110
+ },
111
+ "billing": {
112
+ "enabled": null,
113
+ "limit": 0
114
+ },
115
+ "events": [],
116
+ "relationships": [],
117
+ "gender": "",
118
+ "company": "",
119
+ "profilePic": null,
120
+ "starch": "62cdbfd01ee1b4001932822f"
121
+ },
122
+ "tags": [
123
+ "default",
124
+ "vip"
125
+ ],
126
+ "status": null,
127
+ "parentId": null,
128
+ "loyalty": null,
129
+ "wallet": [],
130
+ "modifiers": [],
131
+ "addresses": [],
132
+ "contacts": [
133
+ {
134
+ "value": "game.adsp@gmail.com",
135
+ "description": "",
136
+ "type": "email",
137
+ "tags": [
138
+ "personal"
139
+ ],
140
+ "primary": true,
141
+ "notification": false,
142
+ "config": null,
143
+ "verified": false
144
+ }
145
+ ],
146
+ "notes": [],
147
+ "_accountId": "62cdbfcdaaf93c00193d2dd3",
148
+ "_storeId": "62cdbfce1ee1b40019328156",
149
+ "_isDeleted": false,
150
+ "_deletedAt": null,
151
+ "_updatedAt": "2024-09-16T13:57:47.426Z",
152
+ "_createdAt": "2024-08-13T16:43:10.457Z",
153
+ "isEmbedded": true
154
+ },
155
+ "start": {
156
+ "actualDate": "2024-09-19T19:03:48.469Z",
157
+ "requestDate": "2024-09-19T19:03:48.469Z",
158
+ "__typename": "OrderStart",
159
+ "location": {
160
+ "name": "Tico Store #1",
161
+ "locationType": "store",
162
+ "storeId": "62cdbfce1ee1b40019328156"
163
+ }
164
+ },
165
+ "end": {
166
+ "location": {
167
+ "name": "Tico Store #1",
168
+ "locationType": "store",
169
+ "storeId": "62cdbfce1ee1b40019328156"
170
+ },
171
+ "__typename": "OrderEnd",
172
+ "actualDate": "",
173
+ "requestDate": ""
174
+ },
175
+ "_storeId": "",
176
+ "__typename": "Order",
177
+ "isOrderNew": true,
178
+ "subTotals": {}
179
+ }
@@ -63,7 +63,6 @@ module.exports = ({ _, utils, actions, modifierActions }) => {
63
63
  const _modifier = modifierActions.calculate(modifier, {
64
64
  price: computedPrice,
65
65
  quantity,
66
- skip: !!amountOverride,
67
66
  });
68
67
 
69
68
  modifiers.push(_modifier);
@@ -8,11 +8,13 @@ module.exports = ({ _, constants, utils, localization, actions }) => {
8
8
  const { Modifier } = constants;
9
9
 
10
10
  return function calculate(
11
- modifier = {},
11
+ _modifier = {},
12
12
  options = { price: 0, quantity: 0, skip: false }
13
13
  ) {
14
+ const modifier = _modifier;
14
15
  const { name } = modifier;
15
16
  const compute = getComputeModField(modifier);
17
+ modifier.compute = compute;
16
18
  const { type, action, amount = 0 } = compute;
17
19
  const _computed = {
18
20
  amount: 0,
@@ -123,6 +123,7 @@ const isFixed = require('./isFixed');
123
123
  const isFixedAdd = require('./isFixedAdd');
124
124
  const isFee = require('./isFee');
125
125
  const isAdd = require('./isAdd');
126
+ const mutateModifier = require('./mutateModifier');
126
127
 
127
128
  const isFixedDiscount = require('./isFixedDiscount');
128
129
  const removeLocked = require('./removeLocked');
@@ -267,6 +268,7 @@ const modifierActions = (deps = {}) => {
267
268
  isFixedAdd: isFixedAdd(innerDeps),
268
269
  isFee: isFee(innerDeps),
269
270
  isAdd: isAdd(innerDeps),
271
+ mutateModifier: mutateModifier(innerDeps),
270
272
  });
271
273
 
272
274
  Object.keys(freezedActions).forEach(actionName => {
@@ -0,0 +1,23 @@
1
+ module.exports = ({ _, actions }) =>
2
+ function mutateModifier(mod) {
3
+ const modifier = actions.duplicate(mod);
4
+ const fixedValue = _.get(modifier, 'properties.override.fixedValue', '');
5
+ const isAmountOverride = actions.isAmountOverride(mod);
6
+ const isPriceOverride = actions.isPriceOverride(mod);
7
+
8
+ if (isPriceOverride && fixedValue) {
9
+ modifier.compute = {
10
+ amount: fixedValue,
11
+ };
12
+ }
13
+
14
+ if (isAmountOverride && fixedValue) {
15
+ modifier.compute = {
16
+ type: 'fixed',
17
+ amount: fixedValue,
18
+ action: 'add',
19
+ };
20
+ }
21
+
22
+ return modifier;
23
+ };
@@ -1,9 +1,13 @@
1
1
  const _ = require('lodash');
2
2
 
3
- const getComputeModField = modifier =>
4
- _.isNull(modifier.compute) || !modifier.compute
5
- ? { type: '', amount: 0, action: '' }
6
- : modifier.compute;
3
+ const getComputeModField = modifier => {
4
+ if (modifier.compute && !_.isEmpty(modifier.compute)) {
5
+ // Ensure the compute is not an empty object
6
+ return modifier.compute;
7
+ }
8
+
9
+ return { type: '', amount: 0, action: '' };
10
+ };
7
11
 
8
12
  module.exports = {
9
13
  getComputeModField,
@@ -55,7 +55,7 @@ module.exports = ({ actions, itemActions, modifierActions, utils, _ }) => {
55
55
  };
56
56
 
57
57
  const addModifier = ({
58
- modifier,
58
+ modifier: _modifier,
59
59
  item: itemProp,
60
60
  customer,
61
61
  cache = {
@@ -64,21 +64,25 @@ module.exports = ({ actions, itemActions, modifierActions, utils, _ }) => {
64
64
  itemModifiers: [],
65
65
  },
66
66
  }) => {
67
+ const modifier = _modifier; // to avoid no param reassign lint rule
67
68
  let item = { ...itemProp };
68
69
  const compute = getComputeModField(modifier);
69
70
  if (hasBehaivoralFields(modifier)) return item;
70
71
  // check conditions
71
72
  if (!areConditionsMet(item, modifier.conditions)) return item;
73
+ const isAmountOverride = modifierActions.isAmountOverride(modifier);
74
+ const isPriceOverride = modifierActions.isPriceOverride(modifier);
75
+
76
+ // change modifier compute based on onverride and creates a clone of the modifier
77
+ const modifierToAdd = modifierActions.mutateModifier(modifier);
72
78
 
73
- const modifierToAdd = modifierActions.duplicate(modifier);
74
79
  const modifierIndex = item.modifiers.findIndex(
75
80
  ieach => ieach.modifierId === modifier._id
76
81
  );
77
-
78
82
  // group of values use case
79
83
  if (
80
84
  modifierActions.isGroupOfValues(modifier) ||
81
- modifierActions.isOverride(modifier)
85
+ (modifierActions.isOverride(modifier) && !isAmountOverride)
82
86
  ) {
83
87
  if (modifierIndex > -1) item.modifiers[modifierIndex] = modifierToAdd;
84
88
  else item.modifiers.push(modifierToAdd);
@@ -101,11 +105,8 @@ module.exports = ({ actions, itemActions, modifierActions, utils, _ }) => {
101
105
  item.quantity = modifier.compute.amount || 1;
102
106
  }
103
107
 
104
- if (
105
- modifierActions.isPriceOverride(modifier) ||
106
- modifierActions.isComputedOverride(modifier)
107
- ) {
108
- item.price = getPrice({ modifier, item });
108
+ if (isPriceOverride || modifierActions.isComputedOverride(modifier)) {
109
+ item.price = getPrice({ modifier: modifierToAdd, item });
109
110
  } else {
110
111
  item.price = itemActions.getItemPrice({
111
112
  item,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@darkpos/pricing",
3
- "version": "1.0.37",
3
+ "version": "1.0.38",
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": "880122bbb47242484095cd2db3f68036c95c569a"
39
+ "gitHead": "6d87c96080369a419d9f2ae7fb77205be0c62d02"
40
40
  }