@darkpos/pricing 1.0.148 → 1.0.150

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.
@@ -197,6 +197,133 @@ describe('applyRefundToInvoices', () => {
197
197
  });
198
198
  });
199
199
 
200
+ describe('applyRefundToInvoices — 5-item order with 3 items priced to 0', () => {
201
+ const ORDER_5_ID = 'order-5items';
202
+
203
+ // Items as they appear in the payment invoice (stale totals from payment time)
204
+ const shortsInvoiceItem = {
205
+ orderId: ORDER_5_ID,
206
+ orderItemId: 'shorts',
207
+ total: 6.3,
208
+ totalPaid: 6.3,
209
+ amount: 6.3,
210
+ status: { paid: { value: true } },
211
+ };
212
+ const jacket1InvoiceItem = {
213
+ orderId: ORDER_5_ID,
214
+ orderItemId: 'jacket-1',
215
+ total: 8.93,
216
+ totalPaid: 8.93,
217
+ amount: 8.93,
218
+ status: { paid: { value: true } },
219
+ };
220
+ const longJacketInvoiceItem = {
221
+ orderId: ORDER_5_ID,
222
+ orderItemId: 'long-jacket',
223
+ total: 12.6,
224
+ totalPaid: 12.6,
225
+ amount: 12.6,
226
+ status: { paid: { value: true } },
227
+ };
228
+ const jacket2InvoiceItem = {
229
+ orderId: ORDER_5_ID,
230
+ orderItemId: 'jacket-2',
231
+ total: 8.93,
232
+ totalPaid: 8.93,
233
+ amount: 8.93,
234
+ status: { paid: { value: true } },
235
+ };
236
+ const coatInvoiceItem = {
237
+ orderId: ORDER_5_ID,
238
+ orderItemId: 'coat',
239
+ total: 13.65,
240
+ totalPaid: 3.24,
241
+ amount: 3.24,
242
+ status: { paid: { value: false } },
243
+ };
244
+
245
+ // Live order state after Jacket×2 and Long Jacket prices changed to 0
246
+ const liveOrder5 = {
247
+ _id: ORDER_5_ID,
248
+ items: [
249
+ {
250
+ _id: 'shorts',
251
+ total: 6.3,
252
+ totalPaid: 6.3,
253
+ status: { paid: { value: true } },
254
+ },
255
+ {
256
+ _id: 'jacket-1',
257
+ total: 0,
258
+ totalPaid: 8.93,
259
+ status: { paid: { value: true } },
260
+ },
261
+ {
262
+ _id: 'long-jacket',
263
+ total: 0,
264
+ totalPaid: 12.6,
265
+ status: { paid: { value: true } },
266
+ },
267
+ {
268
+ _id: 'jacket-2',
269
+ total: 0,
270
+ totalPaid: 8.93,
271
+ status: { paid: { value: true } },
272
+ },
273
+ {
274
+ _id: 'coat',
275
+ total: 13.65,
276
+ totalPaid: 3.24,
277
+ status: { paid: { value: false } },
278
+ },
279
+ ],
280
+ };
281
+
282
+ const ordersById5 = { [ORDER_5_ID]: liveOrder5 };
283
+
284
+ const paymentInvoices5 = [
285
+ {
286
+ invoiceId: 'inv-5items',
287
+ amount: 40,
288
+ paymentOrderItems: [
289
+ shortsInvoiceItem,
290
+ jacket1InvoiceItem,
291
+ longJacketInvoiceItem,
292
+ jacket2InvoiceItem,
293
+ coatInvoiceItem,
294
+ ],
295
+ },
296
+ ];
297
+
298
+ test('correctly refunds 20.05 — clears the 3 zero-priced items and credits the remaining balance to coat', () => {
299
+ const refundInvoices = pricing.invoice.applyRefundToInvoices(
300
+ paymentInvoices5,
301
+ ordersById5,
302
+ 20.05
303
+ );
304
+
305
+ expect(refundInvoices).toHaveLength(1);
306
+ expect(refundInvoices[0].amount).toBe(-20.05);
307
+ expect(refundInvoices[0].paymentOrderItems).toHaveLength(4); // shorts has 0 excess, skipped
308
+
309
+ const byItemId = Object.fromEntries(
310
+ refundInvoices[0].paymentOrderItems.map(item => [item.orderItemId, item])
311
+ );
312
+
313
+ expect(byItemId['jacket-1'].amount).toBe(-8.93);
314
+ expect(byItemId['jacket-1'].status.paid.value).toBe(true);
315
+
316
+ expect(byItemId['long-jacket'].amount).toBe(-12.6);
317
+ expect(byItemId['long-jacket'].status.paid.value).toBe(true);
318
+
319
+ expect(byItemId['jacket-2'].amount).toBe(-8.93);
320
+ expect(byItemId['jacket-2'].status.paid.value).toBe(true);
321
+
322
+ expect(byItemId.coat.amount).toBe(10.41);
323
+ expect(byItemId.coat.status.paid.value).toBe(true);
324
+ });
325
+ });
326
+
200
327
  describe('buildItemRefund', () => {
201
328
  const overpaidItemState = pricing.invoice.resolveItemState(
202
329
  overpaidInvoiceItem,
@@ -77,6 +77,29 @@ describe('hasSerial function', () => {
77
77
  expect(result).toBe(false);
78
78
  });
79
79
 
80
+ test('returns false when the matching serial belongs to a pending item', () => {
81
+ const { hasSerial } = pricingService.order;
82
+
83
+ const order = {
84
+ items: [
85
+ {
86
+ _id: '1',
87
+ serial: 'ABC-123',
88
+ isPending: true,
89
+ },
90
+ ],
91
+ };
92
+
93
+ const item = {
94
+ _id: '2',
95
+ serial: 'ABC-123',
96
+ };
97
+
98
+ const result = hasSerial({ order, item });
99
+
100
+ expect(result).toBe(false);
101
+ });
102
+
80
103
  test('returns false when order or item is missing', () => {
81
104
  const { hasSerial } = pricingService.order;
82
105
 
@@ -7,10 +7,10 @@ module.exports = ({ utils }) => {
7
7
  each => each._id === paymentOrderItem.orderItemId
8
8
  );
9
9
 
10
- const itemTotal =
11
- (orderItem && orderItem.total) || paymentOrderItem.total || 0;
12
- const itemTotalPaid =
13
- (orderItem && orderItem.totalPaid) || paymentOrderItem.totalPaid || 0;
10
+ const itemTotal = orderItem ? orderItem.total : paymentOrderItem.total || 0;
11
+ const itemTotalPaid = orderItem
12
+ ? orderItem.totalPaid
13
+ : paymentOrderItem.totalPaid || 0;
14
14
  const currentStatus =
15
15
  (orderItem && orderItem.status) || paymentOrderItem.status || {};
16
16
 
package/lib/item/index.js CHANGED
@@ -69,6 +69,7 @@ const applyNotesOverridesToItem = require('./applyNotesOverridesToItem');
69
69
  const getModifiersToNotCompute = require('./getModifiersToNotCompute');
70
70
  const getSplitDepartment = require('./getSplitDepartment');
71
71
  const isPriceChanged = require('./isPriceChanged');
72
+ const isPending = require('./isPending');
72
73
  const isSerialRequired = require('./isSerialRequired');
73
74
  const isSerialLengthValid = require('./isSerialLengthValid');
74
75
  const getSerialStatus = require('./getSerialStatus');
@@ -166,6 +167,7 @@ const itemActions = (deps = {}) => {
166
167
  getModifiersToNotCompute: getModifiersToNotCompute(innerDeps),
167
168
  getSplitDepartment: getSplitDepartment(innerDeps),
168
169
  isPriceChanged: isPriceChanged(innerDeps),
170
+ isPending: isPending(innerDeps),
169
171
  isSerialRequired: isSerialRequired(innerDeps),
170
172
  isSerialLengthValid: isSerialLengthValid(innerDeps),
171
173
  getSerialStatus: getSerialStatus(innerDeps),
@@ -0,0 +1,4 @@
1
+ module.exports = () =>
2
+ function isPending(item) {
3
+ return !!(item && item.isPending);
4
+ };
@@ -130,11 +130,12 @@ module.exports = ({ actions, itemActions, modifierActions, settings, _ }) => {
130
130
 
131
131
  const pendingItem = actions.getSelectedItem({ order, itemIndex });
132
132
 
133
- if (pendingItem && pendingItem.isPending && !combined) {
133
+ if (pendingItem && itemActions.isPending(pendingItem) && !combined) {
134
134
  idx = itemIndex;
135
135
  combined = !!pendingItem.itemId;
136
136
  orderItem.quantity = pendingItem.quantity;
137
- orderItem.isPending = orderItem.isPending || !orderItem.itemId;
137
+ orderItem.isPending =
138
+ itemActions.isPending(orderItem) || !orderItem.itemId;
138
139
  // add inventory
139
140
  if (pendingItem.inventory) {
140
141
  const inventory = getInventory(pendingItem);
@@ -1,8 +1,13 @@
1
1
  module.exports = ({ utils }) =>
2
2
  function getOverPaidAmount({ order }) {
3
3
  if (!order) return 0;
4
- const total = Number(order.total || 0);
5
- const totalPaid = Number(order.totalPaid || 0);
6
4
 
7
- return utils.math.sub(totalPaid, total);
5
+ return (order.items || []).reduce((net, item) => {
6
+ const itemTotalPaid = Number(item.totalPaid || 0);
7
+ if (itemTotalPaid <= 0) return net;
8
+ return utils.math.add(
9
+ net,
10
+ utils.math.sub(itemTotalPaid, Number(item.total || 0))
11
+ );
12
+ }, 0);
8
13
  };
@@ -21,7 +21,9 @@ module.exports = ({ itemActions }) =>
21
21
  return order.items
22
22
  .filter(
23
23
  orderItem =>
24
- orderItem._id !== item._id && !itemActions.isRelatedItem(orderItem)
24
+ orderItem._id !== item._id &&
25
+ !itemActions.isRelatedItem(orderItem) &&
26
+ !itemActions.isPending(orderItem)
25
27
  )
26
28
  .some(
27
29
  orderItem => normalizeSerial(orderItem.serial) === normalizedSerial
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@darkpos/pricing",
3
- "version": "1.0.148",
3
+ "version": "1.0.150",
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": "ef7e78a71a5fb6cfd619b8f525b7950669bd7995"
57
+ "gitHead": "5ba2aa85fa455644dfa228072d30f8a8560d161c"
58
58
  }