@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.
- package/__TEST__/invoice/refundInvoices.test.js +127 -0
- package/__TEST__/order/hasSerial.test.js +23 -0
- package/lib/invoice/resolveItemState.js +4 -4
- package/lib/item/index.js +2 -0
- package/lib/item/isPending.js +4 -0
- package/lib/order/addItem.js +3 -2
- package/lib/order/getOverpaidAmount.js +8 -3
- package/lib/order/hasSerial.js +3 -1
- package/package.json +2 -2
|
@@ -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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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),
|
package/lib/order/addItem.js
CHANGED
|
@@ -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 &&
|
|
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 =
|
|
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
|
|
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
|
};
|
package/lib/order/hasSerial.js
CHANGED
|
@@ -21,7 +21,9 @@ module.exports = ({ itemActions }) =>
|
|
|
21
21
|
return order.items
|
|
22
22
|
.filter(
|
|
23
23
|
orderItem =>
|
|
24
|
-
orderItem._id !== item._id &&
|
|
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.
|
|
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": "
|
|
57
|
+
"gitHead": "5ba2aa85fa455644dfa228072d30f8a8560d161c"
|
|
58
58
|
}
|