@munchi_oy/cart-engine 0.1.1 → 0.1.4
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/dist/index.cjs +576 -63
- package/dist/index.d.cts +81 -5
- package/dist/index.d.ts +81 -5
- package/dist/index.js +581 -64
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -36,7 +36,9 @@ __export(index_exports, {
|
|
|
36
36
|
allocateProportionalMinorUnits: () => allocateProportionalMinorUnits,
|
|
37
37
|
calculateCartPriceSnapshot: () => calculateCartPriceSnapshot,
|
|
38
38
|
calculateDiscountAmount: () => calculateDiscountAmount,
|
|
39
|
+
calculateEqualSplitPartPricing: () => calculateEqualSplitPartPricing,
|
|
39
40
|
calculateItemPrice: () => calculateItemPrice,
|
|
41
|
+
calculateItemSplitSeatPricing: () => calculateItemSplitSeatPricing,
|
|
40
42
|
calculateOrderTaxSummary: () => calculateOrderTaxSummary,
|
|
41
43
|
calculateSequentialDiscountTotal: () => calculateSequentialDiscountTotal,
|
|
42
44
|
splitTaxInclusiveAmount: () => splitTaxInclusiveAmount
|
|
@@ -111,7 +113,49 @@ function calculateSequentialDiscountTotal(discounts, initialAmount) {
|
|
|
111
113
|
};
|
|
112
114
|
}
|
|
113
115
|
|
|
116
|
+
// src/discount/modulo.ts
|
|
117
|
+
var allocateProportionalMinorUnits = withSafeIntegers(
|
|
118
|
+
(weights, totalAmount) => {
|
|
119
|
+
for (let i = 0; i < weights.length; i++) {
|
|
120
|
+
if (!Number.isInteger(weights[i])) {
|
|
121
|
+
throw new Error(
|
|
122
|
+
`[CartEngine SafeLock] Weight at index ${i} MUST be an integer. Received: ${weights[i]}`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (weights.length === 0 || totalAmount <= 0) {
|
|
127
|
+
return new Array(weights.length).fill(0);
|
|
128
|
+
}
|
|
129
|
+
const totalWeight = weights.reduce((sum, weight) => sum + weight, 0);
|
|
130
|
+
if (totalWeight <= 0) {
|
|
131
|
+
return new Array(weights.length).fill(0);
|
|
132
|
+
}
|
|
133
|
+
const baseAllocations = weights.map(
|
|
134
|
+
(weight) => Math.floor(weight * totalAmount / totalWeight)
|
|
135
|
+
);
|
|
136
|
+
const remainderOrder = weights.map((weight, index) => ({
|
|
137
|
+
index,
|
|
138
|
+
remainder: weight * totalAmount % totalWeight
|
|
139
|
+
})).sort(
|
|
140
|
+
(left, right) => right.remainder - left.remainder || left.index - right.index
|
|
141
|
+
);
|
|
142
|
+
let remainingAmount = totalAmount - baseAllocations.reduce((sum, amount) => sum + amount, 0);
|
|
143
|
+
for (const { index } of remainderOrder) {
|
|
144
|
+
if (remainingAmount <= 0) break;
|
|
145
|
+
baseAllocations[index] = (baseAllocations[index] ?? 0) + 1;
|
|
146
|
+
remainingAmount -= 1;
|
|
147
|
+
}
|
|
148
|
+
return baseAllocations;
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
|
|
114
152
|
// src/pricing/calculator.ts
|
|
153
|
+
var EMPTY_SPLIT_PRICING_RESULT = {
|
|
154
|
+
targets: [],
|
|
155
|
+
totalGrossAmount: 0,
|
|
156
|
+
totalDiscountAmount: 0,
|
|
157
|
+
totalNetAmount: 0
|
|
158
|
+
};
|
|
115
159
|
var assertMinorUnit = (value, fieldName) => {
|
|
116
160
|
if (!Number.isInteger(value)) {
|
|
117
161
|
throw new Error(
|
|
@@ -119,6 +163,93 @@ var assertMinorUnit = (value, fieldName) => {
|
|
|
119
163
|
);
|
|
120
164
|
}
|
|
121
165
|
};
|
|
166
|
+
var sortDiscountsByCreatedAt = (discounts) => {
|
|
167
|
+
return [...discounts].sort(
|
|
168
|
+
(left, right) => new Date(left.createdAt).getTime() - new Date(right.createdAt).getTime()
|
|
169
|
+
);
|
|
170
|
+
};
|
|
171
|
+
var calculateTargetPricing = (id, grossAmount, discounts) => {
|
|
172
|
+
assertMinorUnit(grossAmount, `target gross amount (${id})`);
|
|
173
|
+
const { totalDiscountAmount, remainingAmount } = calculateSequentialDiscountTotal(discounts, grossAmount);
|
|
174
|
+
return {
|
|
175
|
+
id,
|
|
176
|
+
grossAmount,
|
|
177
|
+
discountAmount: totalDiscountAmount,
|
|
178
|
+
netAmount: remainingAmount
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
var sumAmounts = (targets, field) => {
|
|
182
|
+
return targets.reduce((sum, target) => sum + target[field], 0);
|
|
183
|
+
};
|
|
184
|
+
var buildSplitPricingResult = (targets) => {
|
|
185
|
+
return {
|
|
186
|
+
targets,
|
|
187
|
+
totalGrossAmount: sumAmounts(targets, "grossAmount"),
|
|
188
|
+
totalDiscountAmount: sumAmounts(targets, "discountAmount"),
|
|
189
|
+
totalNetAmount: sumAmounts(targets, "netAmount")
|
|
190
|
+
};
|
|
191
|
+
};
|
|
192
|
+
var filterTargetedDiscounts = (discounts, targetType, targetId) => {
|
|
193
|
+
return sortDiscountsByCreatedAt(
|
|
194
|
+
discounts.filter(
|
|
195
|
+
(discount) => discount.targetType === targetType && discount.targetId === targetId
|
|
196
|
+
)
|
|
197
|
+
);
|
|
198
|
+
};
|
|
199
|
+
var getSeatGrossAmount = (seat) => {
|
|
200
|
+
return seat.assignments.reduce((sum, assignment) => {
|
|
201
|
+
assertMinorUnit(assignment.amount, `seat assignment amount (${seat.id})`);
|
|
202
|
+
return sum + assignment.amount;
|
|
203
|
+
}, 0);
|
|
204
|
+
};
|
|
205
|
+
var getEqualSplitPartIds = (equalSplitState) => {
|
|
206
|
+
const partCount = Math.max(equalSplitState.partCount, equalSplitState.parts.length);
|
|
207
|
+
const ids = equalSplitState.parts.map((part) => part.id);
|
|
208
|
+
for (let index = ids.length; index < partCount; index += 1) {
|
|
209
|
+
ids.push(`__generated_equal_split_part_${index + 1}`);
|
|
210
|
+
}
|
|
211
|
+
return ids;
|
|
212
|
+
};
|
|
213
|
+
function calculateItemSplitSeatPricing(details) {
|
|
214
|
+
if (!details.tableService) {
|
|
215
|
+
return EMPTY_SPLIT_PRICING_RESULT;
|
|
216
|
+
}
|
|
217
|
+
const targets = details.tableService.itemSplitSeats.map(
|
|
218
|
+
(seat) => calculateTargetPricing(
|
|
219
|
+
seat.id,
|
|
220
|
+
getSeatGrossAmount(seat),
|
|
221
|
+
filterTargetedDiscounts(
|
|
222
|
+
details.discounts,
|
|
223
|
+
import_core2.PosDiscountTargetType.ItemSplitSeat,
|
|
224
|
+
seat.id
|
|
225
|
+
)
|
|
226
|
+
)
|
|
227
|
+
);
|
|
228
|
+
return buildSplitPricingResult(targets);
|
|
229
|
+
}
|
|
230
|
+
function calculateEqualSplitPartPricing(details) {
|
|
231
|
+
assertMinorUnit(details.totalAmount, "details.totalAmount");
|
|
232
|
+
if (!details.equalSplitState || details.equalSplitState.partCount <= 0) {
|
|
233
|
+
return EMPTY_SPLIT_PRICING_RESULT;
|
|
234
|
+
}
|
|
235
|
+
const partIds = getEqualSplitPartIds(details.equalSplitState);
|
|
236
|
+
const grossAmounts = allocateProportionalMinorUnits(
|
|
237
|
+
new Array(partIds.length).fill(1),
|
|
238
|
+
details.totalAmount
|
|
239
|
+
);
|
|
240
|
+
const targets = partIds.map(
|
|
241
|
+
(partId, index) => calculateTargetPricing(
|
|
242
|
+
partId,
|
|
243
|
+
grossAmounts[index] ?? 0,
|
|
244
|
+
filterTargetedDiscounts(
|
|
245
|
+
details.discounts,
|
|
246
|
+
import_core2.PosDiscountTargetType.EqualSplitPart,
|
|
247
|
+
partId
|
|
248
|
+
)
|
|
249
|
+
)
|
|
250
|
+
);
|
|
251
|
+
return buildSplitPricingResult(targets);
|
|
252
|
+
}
|
|
122
253
|
function calculateItemPrice(details) {
|
|
123
254
|
assertMinorUnit(details.basePriceInMinorUnit, "details.basePriceInMinorUnit");
|
|
124
255
|
assertMinorUnit(details.quantity, "details.quantity");
|
|
@@ -181,7 +312,9 @@ function calculateCartPriceSnapshot(details) {
|
|
|
181
312
|
(sum, item) => sum + (item.itemPrice.priceBreakdown.totalDiscounts.amount ?? 0),
|
|
182
313
|
0
|
|
183
314
|
);
|
|
184
|
-
const cartDiscounts = details.discounts.filter(
|
|
315
|
+
const cartDiscounts = details.discounts.filter(
|
|
316
|
+
(discount) => discount.scope === import_core2.DiscountScope.Cart && (discount.targetType === null || discount.targetType === void 0 || discount.targetType === import_core2.PosDiscountTargetType.Order)
|
|
317
|
+
).sort(
|
|
185
318
|
(left, right) => new Date(left.createdAt).getTime() - new Date(right.createdAt).getTime()
|
|
186
319
|
);
|
|
187
320
|
const grossAfterItemDiscounts = Math.max(
|
|
@@ -192,7 +325,21 @@ function calculateCartPriceSnapshot(details) {
|
|
|
192
325
|
cartDiscounts,
|
|
193
326
|
grossAfterItemDiscounts
|
|
194
327
|
);
|
|
195
|
-
const
|
|
328
|
+
const itemSplitSeatPricing = details.checkoutModel === import_core2.CheckoutModelEnum.ItemSplit ? calculateItemSplitSeatPricing({
|
|
329
|
+
tableService: details.tableService,
|
|
330
|
+
discounts: details.discounts
|
|
331
|
+
}) : null;
|
|
332
|
+
const equalSplitPartPricing = details.checkoutModel === import_core2.CheckoutModelEnum.EqualSplit ? calculateEqualSplitPartPricing({
|
|
333
|
+
totalAmount: cartDiscountCalculation.remainingAmount,
|
|
334
|
+
equalSplitState: details.equalSplitState,
|
|
335
|
+
discounts: details.discounts
|
|
336
|
+
}) : null;
|
|
337
|
+
const subtotalTargetedDiscountsAmount = itemSplitSeatPricing?.totalDiscountAmount ?? equalSplitPartPricing?.totalDiscountAmount ?? 0;
|
|
338
|
+
const totalAmount = Math.max(
|
|
339
|
+
0,
|
|
340
|
+
cartDiscountCalculation.remainingAmount - subtotalTargetedDiscountsAmount
|
|
341
|
+
);
|
|
342
|
+
const totalDiscountsAmount = subtotalItemDiscountsAmount + cartDiscountCalculation.totalDiscountAmount + subtotalTargetedDiscountsAmount;
|
|
196
343
|
const price = {
|
|
197
344
|
priceBreakdown: {
|
|
198
345
|
totalBeforeDiscounts: {
|
|
@@ -213,7 +360,7 @@ function calculateCartPriceSnapshot(details) {
|
|
|
213
360
|
}
|
|
214
361
|
},
|
|
215
362
|
total: {
|
|
216
|
-
amount:
|
|
363
|
+
amount: totalAmount,
|
|
217
364
|
currency: details.currency
|
|
218
365
|
}
|
|
219
366
|
};
|
|
@@ -222,52 +369,17 @@ function calculateCartPriceSnapshot(details) {
|
|
|
222
369
|
totalBeforeDiscountsAmount,
|
|
223
370
|
subtotalItemDiscountsAmount,
|
|
224
371
|
subtotalBasketDiscountsAmount: cartDiscountCalculation.totalDiscountAmount,
|
|
372
|
+
subtotalTargetedDiscountsAmount,
|
|
225
373
|
totalDiscountsAmount,
|
|
226
|
-
totalAmount
|
|
374
|
+
totalAmount,
|
|
375
|
+
itemSplitSeatPricing,
|
|
376
|
+
equalSplitPartPricing,
|
|
227
377
|
price
|
|
228
378
|
};
|
|
229
379
|
}
|
|
230
380
|
|
|
231
381
|
// src/tax/index.ts
|
|
232
382
|
var import_core3 = require("@munchi_oy/core");
|
|
233
|
-
|
|
234
|
-
// src/discount/modulo.ts
|
|
235
|
-
var allocateProportionalMinorUnits = withSafeIntegers(
|
|
236
|
-
(weights, totalAmount) => {
|
|
237
|
-
for (let i = 0; i < weights.length; i++) {
|
|
238
|
-
if (!Number.isInteger(weights[i])) {
|
|
239
|
-
throw new Error(
|
|
240
|
-
`[CartEngine SafeLock] Weight at index ${i} MUST be an integer. Received: ${weights[i]}`
|
|
241
|
-
);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
if (weights.length === 0 || totalAmount <= 0) {
|
|
245
|
-
return new Array(weights.length).fill(0);
|
|
246
|
-
}
|
|
247
|
-
const totalWeight = weights.reduce((sum, weight) => sum + weight, 0);
|
|
248
|
-
if (totalWeight <= 0) {
|
|
249
|
-
return new Array(weights.length).fill(0);
|
|
250
|
-
}
|
|
251
|
-
const baseAllocations = weights.map(
|
|
252
|
-
(weight) => Math.floor(weight * totalAmount / totalWeight)
|
|
253
|
-
);
|
|
254
|
-
const remainderOrder = weights.map((weight, index) => ({
|
|
255
|
-
index,
|
|
256
|
-
remainder: weight * totalAmount % totalWeight
|
|
257
|
-
})).sort(
|
|
258
|
-
(left, right) => right.remainder - left.remainder || left.index - right.index
|
|
259
|
-
);
|
|
260
|
-
let remainingAmount = totalAmount - baseAllocations.reduce((sum, amount) => sum + amount, 0);
|
|
261
|
-
for (const { index } of remainderOrder) {
|
|
262
|
-
if (remainingAmount <= 0) break;
|
|
263
|
-
baseAllocations[index] = (baseAllocations[index] ?? 0) + 1;
|
|
264
|
-
remainingAmount -= 1;
|
|
265
|
-
}
|
|
266
|
-
return baseAllocations;
|
|
267
|
-
}
|
|
268
|
-
);
|
|
269
|
-
|
|
270
|
-
// src/tax/index.ts
|
|
271
383
|
function assertMinorUnit2(value, fieldName) {
|
|
272
384
|
if (!Number.isInteger(value)) {
|
|
273
385
|
throw new Error(
|
|
@@ -375,6 +487,76 @@ function calculateOrderTaxSummary(details) {
|
|
|
375
487
|
|
|
376
488
|
// src/cart/Cart.ts
|
|
377
489
|
var { isEqual } = import_lodash.default;
|
|
490
|
+
function cloneEqualSplitPart(part) {
|
|
491
|
+
return {
|
|
492
|
+
...part,
|
|
493
|
+
name: part.name ?? null,
|
|
494
|
+
loyaltyId: part.loyaltyId ?? null,
|
|
495
|
+
loyaltyUserName: part.loyaltyUserName ?? null,
|
|
496
|
+
appliedDiscountIds: [...part.appliedDiscountIds ?? []]
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
function cloneEqualSplitState(equalSplitState) {
|
|
500
|
+
if (!equalSplitState) {
|
|
501
|
+
return null;
|
|
502
|
+
}
|
|
503
|
+
return {
|
|
504
|
+
partCount: equalSplitState.partCount,
|
|
505
|
+
parts: (equalSplitState.parts ?? []).map(cloneEqualSplitPart)
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
function createEmptyEqualSplitState() {
|
|
509
|
+
return {
|
|
510
|
+
partCount: 0,
|
|
511
|
+
parts: []
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
function cloneItemSplitSeatAssignment(assignment) {
|
|
515
|
+
return {
|
|
516
|
+
...assignment,
|
|
517
|
+
appliedDiscountIds: [...assignment.appliedDiscountIds ?? []]
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
function cloneItemSplitSeat(seat) {
|
|
521
|
+
return {
|
|
522
|
+
...seat,
|
|
523
|
+
name: seat.name ?? null,
|
|
524
|
+
loyaltyId: seat.loyaltyId ?? null,
|
|
525
|
+
loyaltyUserName: seat.loyaltyUserName ?? null,
|
|
526
|
+
appliedDiscountIds: [...seat.appliedDiscountIds ?? []],
|
|
527
|
+
assignments: (seat.assignments ?? []).map(cloneItemSplitSeatAssignment)
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
function cloneTableService(tableService) {
|
|
531
|
+
if (!tableService) {
|
|
532
|
+
return null;
|
|
533
|
+
}
|
|
534
|
+
return {
|
|
535
|
+
name: tableService.name ?? null,
|
|
536
|
+
seats: tableService.seats,
|
|
537
|
+
itemSplitSeats: (tableService.itemSplitSeats ?? []).map(cloneItemSplitSeat)
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function createEmptyTableService() {
|
|
541
|
+
return {
|
|
542
|
+
name: null,
|
|
543
|
+
seats: 0,
|
|
544
|
+
itemSplitSeats: []
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
function validateEqualSplitState(equalSplitState) {
|
|
548
|
+
if (!equalSplitState) {
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
if (!Number.isInteger(equalSplitState.partCount) || equalSplitState.partCount < 0) {
|
|
552
|
+
throw new Error("Equal split part count must be a non-negative integer");
|
|
553
|
+
}
|
|
554
|
+
if (equalSplitState.parts.length > equalSplitState.partCount) {
|
|
555
|
+
throw new Error(
|
|
556
|
+
"Equal split state cannot contain more parts than partCount"
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
378
560
|
var Cart = class _Cart {
|
|
379
561
|
id;
|
|
380
562
|
businessId;
|
|
@@ -399,6 +581,7 @@ var Cart = class _Cart {
|
|
|
399
581
|
_customer = null;
|
|
400
582
|
_refunds = [];
|
|
401
583
|
_tableService;
|
|
584
|
+
_equalSplitState;
|
|
402
585
|
_taxSummary;
|
|
403
586
|
_newlyCancelledItemIds;
|
|
404
587
|
_invoiceCompany;
|
|
@@ -424,7 +607,8 @@ var Cart = class _Cart {
|
|
|
424
607
|
this.status = import_core4.OrderStatusEnum.Draft;
|
|
425
608
|
this.orderFormat = import_core4.OrderFormat.Instant;
|
|
426
609
|
this._locatorType = import_core4.LocatorType.Table;
|
|
427
|
-
this._tableService = options.tableService
|
|
610
|
+
this._tableService = cloneTableService(options.tableService);
|
|
611
|
+
this._equalSplitState = cloneEqualSplitState(options.equalSplitState);
|
|
428
612
|
this._newlyCancelledItemIds = /* @__PURE__ */ new Set();
|
|
429
613
|
this._staffId = options.staffId ?? null;
|
|
430
614
|
this._shiftId = options.shiftId ?? null;
|
|
@@ -438,6 +622,7 @@ var Cart = class _Cart {
|
|
|
438
622
|
orderNumber: options.orderNumber,
|
|
439
623
|
checkoutModel: options.checkoutModel ?? import_core4.CheckoutModelEnum.Full,
|
|
440
624
|
tableService: options.tableService ?? null,
|
|
625
|
+
equalSplitState: options.equalSplitState ?? null,
|
|
441
626
|
currency: options.currency,
|
|
442
627
|
business: options.business,
|
|
443
628
|
staffId: options.staffId,
|
|
@@ -452,6 +637,7 @@ var Cart = class _Cart {
|
|
|
452
637
|
orderNumber: orderDto.orderNumber,
|
|
453
638
|
checkoutModel: orderDto.checkoutModel,
|
|
454
639
|
tableService: orderDto.tableService ?? null,
|
|
640
|
+
equalSplitState: orderDto.equalSplitState ?? null,
|
|
455
641
|
currency: orderDto.currency,
|
|
456
642
|
business: orderDto.business,
|
|
457
643
|
staffId: orderDto.staffId ?? null,
|
|
@@ -473,7 +659,8 @@ var Cart = class _Cart {
|
|
|
473
659
|
cart._refunds = orderDto.refunds ? [...orderDto.refunds] : [];
|
|
474
660
|
cart._loyaltyTransactionIds = [...orderDto.loyaltyTransactionIds];
|
|
475
661
|
cart._loyaltyProgramId = orderDto.loyaltyProgramId ?? null;
|
|
476
|
-
cart._tableService = orderDto.tableService
|
|
662
|
+
cart._tableService = cloneTableService(orderDto.tableService);
|
|
663
|
+
cart._equalSplitState = cloneEqualSplitState(orderDto.equalSplitState);
|
|
477
664
|
cart._newlyCancelledItemIds = /* @__PURE__ */ new Set();
|
|
478
665
|
cart._taxSummary = orderDto.taxSummary;
|
|
479
666
|
cart._invoiceCompany = orderDto.invoiceCompany ?? null;
|
|
@@ -513,13 +700,22 @@ var Cart = class _Cart {
|
|
|
513
700
|
return this._tableService?.seats ?? null;
|
|
514
701
|
}
|
|
515
702
|
get tableService() {
|
|
516
|
-
return this.
|
|
703
|
+
return this.getTableService();
|
|
704
|
+
}
|
|
705
|
+
get equalSplitState() {
|
|
706
|
+
return this.getEqualSplitState();
|
|
707
|
+
}
|
|
708
|
+
get equalSplitPartCount() {
|
|
709
|
+
return this._equalSplitState?.partCount ?? null;
|
|
517
710
|
}
|
|
518
711
|
get price() {
|
|
519
712
|
return calculateCartPriceSnapshot({
|
|
520
713
|
items: this._items,
|
|
521
714
|
discounts: this._discounts,
|
|
522
|
-
currency: this.currency
|
|
715
|
+
currency: this.currency,
|
|
716
|
+
checkoutModel: this.checkoutModel,
|
|
717
|
+
tableService: this._tableService,
|
|
718
|
+
equalSplitState: this._equalSplitState
|
|
523
719
|
}).price;
|
|
524
720
|
}
|
|
525
721
|
setInvoiceCompany(company) {
|
|
@@ -622,21 +818,25 @@ var Cart = class _Cart {
|
|
|
622
818
|
this._newlyCancelledItemIds.clear();
|
|
623
819
|
}
|
|
624
820
|
applyDiscountToCart(discountData) {
|
|
625
|
-
this._discounts.push(
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
821
|
+
this._discounts.push(
|
|
822
|
+
this.createDiscountRecord(
|
|
823
|
+
discountData,
|
|
824
|
+
import_core4.DiscountScope.Cart,
|
|
825
|
+
null,
|
|
826
|
+
import_core4.PosDiscountTargetType.Order,
|
|
827
|
+
null
|
|
828
|
+
)
|
|
829
|
+
);
|
|
631
830
|
this.touch();
|
|
632
831
|
}
|
|
633
832
|
applyDiscountToItem(lineItemId, discountData) {
|
|
634
|
-
const newDiscount =
|
|
635
|
-
|
|
636
|
-
|
|
833
|
+
const newDiscount = this.createDiscountRecord(
|
|
834
|
+
discountData,
|
|
835
|
+
import_core4.DiscountScope.Item,
|
|
637
836
|
lineItemId,
|
|
638
|
-
|
|
639
|
-
|
|
837
|
+
import_core4.PosDiscountTargetType.LineItem,
|
|
838
|
+
lineItemId
|
|
839
|
+
);
|
|
640
840
|
const existingDiscountIndex = this._discounts.findIndex(
|
|
641
841
|
(discount) => discount.lineItemId === lineItemId && discount.scope === import_core4.DiscountScope.Item
|
|
642
842
|
);
|
|
@@ -667,6 +867,42 @@ var Cart = class _Cart {
|
|
|
667
867
|
});
|
|
668
868
|
this.touch();
|
|
669
869
|
}
|
|
870
|
+
applyDiscountToItemSplitSeat(seatId, discountData) {
|
|
871
|
+
this._discounts.push(
|
|
872
|
+
this.createDiscountRecord(
|
|
873
|
+
discountData,
|
|
874
|
+
import_core4.DiscountScope.Cart,
|
|
875
|
+
null,
|
|
876
|
+
import_core4.PosDiscountTargetType.ItemSplitSeat,
|
|
877
|
+
seatId
|
|
878
|
+
)
|
|
879
|
+
);
|
|
880
|
+
this.touch();
|
|
881
|
+
}
|
|
882
|
+
applyDiscountToItemSplitAssignment(assignmentId, discountData) {
|
|
883
|
+
this._discounts.push(
|
|
884
|
+
this.createDiscountRecord(
|
|
885
|
+
discountData,
|
|
886
|
+
import_core4.DiscountScope.Cart,
|
|
887
|
+
null,
|
|
888
|
+
import_core4.PosDiscountTargetType.ItemSplitAssignment,
|
|
889
|
+
assignmentId
|
|
890
|
+
)
|
|
891
|
+
);
|
|
892
|
+
this.touch();
|
|
893
|
+
}
|
|
894
|
+
applyDiscountToEqualSplitPart(partId, discountData) {
|
|
895
|
+
this._discounts.push(
|
|
896
|
+
this.createDiscountRecord(
|
|
897
|
+
discountData,
|
|
898
|
+
import_core4.DiscountScope.Cart,
|
|
899
|
+
null,
|
|
900
|
+
import_core4.PosDiscountTargetType.EqualSplitPart,
|
|
901
|
+
partId
|
|
902
|
+
)
|
|
903
|
+
);
|
|
904
|
+
this.touch();
|
|
905
|
+
}
|
|
670
906
|
removeItemDiscount(lineItemId) {
|
|
671
907
|
this._items = this._items.map((item) => {
|
|
672
908
|
if (item.lineItemId !== lineItemId) {
|
|
@@ -779,15 +1015,277 @@ var Cart = class _Cart {
|
|
|
779
1015
|
this.setCheckoutModel(checkoutModel);
|
|
780
1016
|
}
|
|
781
1017
|
setGuestCount(guestCount) {
|
|
782
|
-
if (
|
|
1018
|
+
if (guestCount === null) {
|
|
1019
|
+
if (this._tableService === null) {
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
this._tableService = null;
|
|
1023
|
+
this.touch();
|
|
783
1024
|
return;
|
|
784
1025
|
}
|
|
785
|
-
this.
|
|
786
|
-
this.touch();
|
|
1026
|
+
this.setSeatsCount(guestCount);
|
|
787
1027
|
}
|
|
788
1028
|
setSeatNumber(guestCount) {
|
|
789
1029
|
this.setGuestCount(guestCount);
|
|
790
1030
|
}
|
|
1031
|
+
getTableService() {
|
|
1032
|
+
return cloneTableService(this._tableService);
|
|
1033
|
+
}
|
|
1034
|
+
setTableService(tableService) {
|
|
1035
|
+
const nextTableService = cloneTableService(tableService);
|
|
1036
|
+
if (isEqual(this._tableService, nextTableService)) {
|
|
1037
|
+
return this;
|
|
1038
|
+
}
|
|
1039
|
+
this._tableService = nextTableService;
|
|
1040
|
+
this.touch();
|
|
1041
|
+
return this;
|
|
1042
|
+
}
|
|
1043
|
+
clearTableService() {
|
|
1044
|
+
return this.setTableService(null);
|
|
1045
|
+
}
|
|
1046
|
+
getTableName() {
|
|
1047
|
+
return this._tableService?.name ?? null;
|
|
1048
|
+
}
|
|
1049
|
+
setTableName(name) {
|
|
1050
|
+
const tableService = this.getTableService() ?? createEmptyTableService();
|
|
1051
|
+
if (tableService.name === name) {
|
|
1052
|
+
return this;
|
|
1053
|
+
}
|
|
1054
|
+
tableService.name = name;
|
|
1055
|
+
return this.setTableService(tableService);
|
|
1056
|
+
}
|
|
1057
|
+
getSeatsCount() {
|
|
1058
|
+
return this._tableService?.seats ?? null;
|
|
1059
|
+
}
|
|
1060
|
+
setSeatsCount(seats) {
|
|
1061
|
+
if (!Number.isInteger(seats) || seats < 0) {
|
|
1062
|
+
throw new Error("Seats count must be a non-negative integer");
|
|
1063
|
+
}
|
|
1064
|
+
const tableService = this.getTableService() ?? createEmptyTableService();
|
|
1065
|
+
if (tableService.seats === seats) {
|
|
1066
|
+
return this;
|
|
1067
|
+
}
|
|
1068
|
+
tableService.seats = seats;
|
|
1069
|
+
return this.setTableService(tableService);
|
|
1070
|
+
}
|
|
1071
|
+
getItemSplitSeats() {
|
|
1072
|
+
return this._tableService ? this._tableService.itemSplitSeats.map(cloneItemSplitSeat) : [];
|
|
1073
|
+
}
|
|
1074
|
+
setItemSplitSeats(seats) {
|
|
1075
|
+
const tableService = this.getTableService() ?? createEmptyTableService();
|
|
1076
|
+
tableService.itemSplitSeats = seats.map(cloneItemSplitSeat);
|
|
1077
|
+
return this.setTableService(tableService);
|
|
1078
|
+
}
|
|
1079
|
+
clearItemSplitSeats() {
|
|
1080
|
+
return this.setItemSplitSeats([]);
|
|
1081
|
+
}
|
|
1082
|
+
addItemSplitSeat(seat) {
|
|
1083
|
+
if (this.getItemSplitSeatById(seat.id)) {
|
|
1084
|
+
return this;
|
|
1085
|
+
}
|
|
1086
|
+
const seats = this.getItemSplitSeats();
|
|
1087
|
+
seats.push(cloneItemSplitSeat(seat));
|
|
1088
|
+
return this.setItemSplitSeats(seats);
|
|
1089
|
+
}
|
|
1090
|
+
updateItemSplitSeat(seatId, updater) {
|
|
1091
|
+
const seats = this.getItemSplitSeats();
|
|
1092
|
+
const seatIndex = seats.findIndex((seat) => seat.id === seatId);
|
|
1093
|
+
if (seatIndex === -1 || !seats[seatIndex]) {
|
|
1094
|
+
return this;
|
|
1095
|
+
}
|
|
1096
|
+
seats[seatIndex] = cloneItemSplitSeat(updater(cloneItemSplitSeat(seats[seatIndex])));
|
|
1097
|
+
return this.setItemSplitSeats(seats);
|
|
1098
|
+
}
|
|
1099
|
+
removeItemSplitSeat(seatId) {
|
|
1100
|
+
const seats = this.getItemSplitSeats();
|
|
1101
|
+
const nextSeats = seats.filter((seat) => seat.id !== seatId);
|
|
1102
|
+
if (nextSeats.length === seats.length) {
|
|
1103
|
+
return this;
|
|
1104
|
+
}
|
|
1105
|
+
return this.setItemSplitSeats(nextSeats);
|
|
1106
|
+
}
|
|
1107
|
+
getItemSplitSeatById(seatId) {
|
|
1108
|
+
const seat = this._tableService?.itemSplitSeats.find(
|
|
1109
|
+
(itemSplitSeat) => itemSplitSeat.id === seatId
|
|
1110
|
+
);
|
|
1111
|
+
return seat ? cloneItemSplitSeat(seat) : null;
|
|
1112
|
+
}
|
|
1113
|
+
setItemSplitSeatAssignments(seatId, assignments) {
|
|
1114
|
+
return this.updateItemSplitSeat(seatId, (seat) => ({
|
|
1115
|
+
...seat,
|
|
1116
|
+
assignments: assignments.map(cloneItemSplitSeatAssignment)
|
|
1117
|
+
}));
|
|
1118
|
+
}
|
|
1119
|
+
addItemSplitSeatAssignment(seatId, assignment) {
|
|
1120
|
+
return this.updateItemSplitSeat(seatId, (seat) => ({
|
|
1121
|
+
...seat,
|
|
1122
|
+
assignments: [...seat.assignments, cloneItemSplitSeatAssignment(assignment)]
|
|
1123
|
+
}));
|
|
1124
|
+
}
|
|
1125
|
+
removeItemSplitSeatAssignmentsByLineItem(seatId, lineItemId) {
|
|
1126
|
+
return this.updateItemSplitSeat(seatId, (seat) => ({
|
|
1127
|
+
...seat,
|
|
1128
|
+
assignments: seat.assignments.filter(
|
|
1129
|
+
(assignment) => assignment.lineItemId !== lineItemId
|
|
1130
|
+
)
|
|
1131
|
+
}));
|
|
1132
|
+
}
|
|
1133
|
+
clearItemSplitSeatAssignments(seatId) {
|
|
1134
|
+
return this.setItemSplitSeatAssignments(seatId, []);
|
|
1135
|
+
}
|
|
1136
|
+
setItemSplitSeatLoyalty(seatId, loyaltyId, loyaltyUserName) {
|
|
1137
|
+
return this.updateItemSplitSeat(seatId, (seat) => ({
|
|
1138
|
+
...seat,
|
|
1139
|
+
loyaltyId,
|
|
1140
|
+
loyaltyUserName
|
|
1141
|
+
}));
|
|
1142
|
+
}
|
|
1143
|
+
clearItemSplitSeatLoyalty(seatId) {
|
|
1144
|
+
return this.setItemSplitSeatLoyalty(seatId, null, null);
|
|
1145
|
+
}
|
|
1146
|
+
setItemSplitSeatAppliedDiscountIds(seatId, appliedDiscountIds) {
|
|
1147
|
+
return this.updateItemSplitSeat(seatId, (seat) => ({
|
|
1148
|
+
...seat,
|
|
1149
|
+
appliedDiscountIds: [...appliedDiscountIds]
|
|
1150
|
+
}));
|
|
1151
|
+
}
|
|
1152
|
+
addItemSplitSeatAppliedDiscountId(seatId, discountId) {
|
|
1153
|
+
return this.updateItemSplitSeat(seatId, (seat) => {
|
|
1154
|
+
if (seat.appliedDiscountIds.includes(discountId)) {
|
|
1155
|
+
return seat;
|
|
1156
|
+
}
|
|
1157
|
+
return {
|
|
1158
|
+
...seat,
|
|
1159
|
+
appliedDiscountIds: [...seat.appliedDiscountIds, discountId]
|
|
1160
|
+
};
|
|
1161
|
+
});
|
|
1162
|
+
}
|
|
1163
|
+
removeItemSplitSeatAppliedDiscountId(seatId, discountId) {
|
|
1164
|
+
return this.updateItemSplitSeat(seatId, (seat) => ({
|
|
1165
|
+
...seat,
|
|
1166
|
+
appliedDiscountIds: seat.appliedDiscountIds.filter(
|
|
1167
|
+
(appliedDiscountId) => appliedDiscountId !== discountId
|
|
1168
|
+
)
|
|
1169
|
+
}));
|
|
1170
|
+
}
|
|
1171
|
+
clearItemSplitSeatAppliedDiscountIds(seatId) {
|
|
1172
|
+
return this.setItemSplitSeatAppliedDiscountIds(seatId, []);
|
|
1173
|
+
}
|
|
1174
|
+
getEqualSplitState() {
|
|
1175
|
+
return cloneEqualSplitState(this._equalSplitState);
|
|
1176
|
+
}
|
|
1177
|
+
setEqualSplitState(equalSplitState) {
|
|
1178
|
+
const nextEqualSplitState = cloneEqualSplitState(equalSplitState);
|
|
1179
|
+
validateEqualSplitState(nextEqualSplitState);
|
|
1180
|
+
if (isEqual(this._equalSplitState, nextEqualSplitState)) {
|
|
1181
|
+
return this;
|
|
1182
|
+
}
|
|
1183
|
+
this._equalSplitState = nextEqualSplitState;
|
|
1184
|
+
this.touch();
|
|
1185
|
+
return this;
|
|
1186
|
+
}
|
|
1187
|
+
clearEqualSplitState() {
|
|
1188
|
+
return this.setEqualSplitState(null);
|
|
1189
|
+
}
|
|
1190
|
+
getEqualSplitParts() {
|
|
1191
|
+
return this._equalSplitState ? this._equalSplitState.parts.map(cloneEqualSplitPart) : [];
|
|
1192
|
+
}
|
|
1193
|
+
setEqualSplitParts(parts) {
|
|
1194
|
+
if (parts.length === 0) {
|
|
1195
|
+
return this.clearEqualSplitState();
|
|
1196
|
+
}
|
|
1197
|
+
const equalSplitState = this.getEqualSplitState() ?? createEmptyEqualSplitState();
|
|
1198
|
+
equalSplitState.parts = parts.map(cloneEqualSplitPart);
|
|
1199
|
+
equalSplitState.partCount = parts.length;
|
|
1200
|
+
return this.setEqualSplitState(equalSplitState);
|
|
1201
|
+
}
|
|
1202
|
+
clearEqualSplitParts() {
|
|
1203
|
+
return this.clearEqualSplitState();
|
|
1204
|
+
}
|
|
1205
|
+
addEqualSplitPart(part) {
|
|
1206
|
+
if (this.getEqualSplitPartById(part.id)) {
|
|
1207
|
+
return this;
|
|
1208
|
+
}
|
|
1209
|
+
const parts = this.getEqualSplitParts();
|
|
1210
|
+
parts.push(cloneEqualSplitPart(part));
|
|
1211
|
+
return this.setEqualSplitParts(parts);
|
|
1212
|
+
}
|
|
1213
|
+
updateEqualSplitPart(partId, updater) {
|
|
1214
|
+
const parts = this.getEqualSplitParts();
|
|
1215
|
+
const partIndex = parts.findIndex((part) => part.id === partId);
|
|
1216
|
+
if (partIndex === -1 || !parts[partIndex]) {
|
|
1217
|
+
return this;
|
|
1218
|
+
}
|
|
1219
|
+
parts[partIndex] = cloneEqualSplitPart(updater(cloneEqualSplitPart(parts[partIndex])));
|
|
1220
|
+
return this.setEqualSplitParts(parts);
|
|
1221
|
+
}
|
|
1222
|
+
removeEqualSplitPart(partId) {
|
|
1223
|
+
const parts = this.getEqualSplitParts();
|
|
1224
|
+
const nextParts = parts.filter((part) => part.id !== partId);
|
|
1225
|
+
if (nextParts.length === parts.length) {
|
|
1226
|
+
return this;
|
|
1227
|
+
}
|
|
1228
|
+
return nextParts.length === 0 ? this.clearEqualSplitState() : this.setEqualSplitParts(nextParts);
|
|
1229
|
+
}
|
|
1230
|
+
getEqualSplitPartById(partId) {
|
|
1231
|
+
const part = this._equalSplitState?.parts.find(
|
|
1232
|
+
(equalSplitPart) => equalSplitPart.id === partId
|
|
1233
|
+
);
|
|
1234
|
+
return part ? cloneEqualSplitPart(part) : null;
|
|
1235
|
+
}
|
|
1236
|
+
getEqualSplitPartCount() {
|
|
1237
|
+
return this._equalSplitState?.partCount ?? null;
|
|
1238
|
+
}
|
|
1239
|
+
setEqualSplitPartCount(partCount) {
|
|
1240
|
+
if (partCount === null) {
|
|
1241
|
+
return this.clearEqualSplitState();
|
|
1242
|
+
}
|
|
1243
|
+
if (!Number.isInteger(partCount) || partCount <= 0) {
|
|
1244
|
+
throw new Error("Equal split part count must be a positive integer or null");
|
|
1245
|
+
}
|
|
1246
|
+
const equalSplitState = this.getEqualSplitState() ?? createEmptyEqualSplitState();
|
|
1247
|
+
if (equalSplitState.parts.length > partCount) {
|
|
1248
|
+
throw new Error(
|
|
1249
|
+
"Equal split part count cannot be less than persisted parts length"
|
|
1250
|
+
);
|
|
1251
|
+
}
|
|
1252
|
+
if (equalSplitState.partCount === partCount) {
|
|
1253
|
+
return this;
|
|
1254
|
+
}
|
|
1255
|
+
equalSplitState.partCount = partCount;
|
|
1256
|
+
return this.setEqualSplitState(equalSplitState);
|
|
1257
|
+
}
|
|
1258
|
+
clearEqualSplitPartCount() {
|
|
1259
|
+
return this.clearEqualSplitState();
|
|
1260
|
+
}
|
|
1261
|
+
setEqualSplitPartAppliedDiscountIds(partId, appliedDiscountIds) {
|
|
1262
|
+
return this.updateEqualSplitPart(partId, (part) => ({
|
|
1263
|
+
...part,
|
|
1264
|
+
appliedDiscountIds: [...appliedDiscountIds]
|
|
1265
|
+
}));
|
|
1266
|
+
}
|
|
1267
|
+
addEqualSplitPartAppliedDiscountId(partId, discountId) {
|
|
1268
|
+
return this.updateEqualSplitPart(partId, (part) => {
|
|
1269
|
+
if (part.appliedDiscountIds.includes(discountId)) {
|
|
1270
|
+
return part;
|
|
1271
|
+
}
|
|
1272
|
+
return {
|
|
1273
|
+
...part,
|
|
1274
|
+
appliedDiscountIds: [...part.appliedDiscountIds, discountId]
|
|
1275
|
+
};
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
1278
|
+
removeEqualSplitPartAppliedDiscountId(partId, discountId) {
|
|
1279
|
+
return this.updateEqualSplitPart(partId, (part) => ({
|
|
1280
|
+
...part,
|
|
1281
|
+
appliedDiscountIds: part.appliedDiscountIds.filter(
|
|
1282
|
+
(appliedDiscountId) => appliedDiscountId !== discountId
|
|
1283
|
+
)
|
|
1284
|
+
}));
|
|
1285
|
+
}
|
|
1286
|
+
clearEqualSplitPartAppliedDiscountIds(partId) {
|
|
1287
|
+
return this.setEqualSplitPartAppliedDiscountIds(partId, []);
|
|
1288
|
+
}
|
|
791
1289
|
updateOrderStatus(newStatus) {
|
|
792
1290
|
if (this.status === newStatus) {
|
|
793
1291
|
return;
|
|
@@ -846,7 +1344,8 @@ var Cart = class _Cart {
|
|
|
846
1344
|
locatorType: this._locatorType,
|
|
847
1345
|
spotNumber: this.spotNumber,
|
|
848
1346
|
comments: this.comments,
|
|
849
|
-
tableService: this._tableService,
|
|
1347
|
+
tableService: cloneTableService(this._tableService),
|
|
1348
|
+
equalSplitState: cloneEqualSplitState(this._equalSplitState),
|
|
850
1349
|
orderRefundStatus: this.orderRefundStatus,
|
|
851
1350
|
items: this._items,
|
|
852
1351
|
status: this.status,
|
|
@@ -875,6 +1374,7 @@ var Cart = class _Cart {
|
|
|
875
1374
|
orderNumber: this.orderNumber,
|
|
876
1375
|
checkoutModel: this.checkoutModel,
|
|
877
1376
|
tableService: this._tableService,
|
|
1377
|
+
equalSplitState: this._equalSplitState,
|
|
878
1378
|
currency: this.currency,
|
|
879
1379
|
business: this._business,
|
|
880
1380
|
staffId: this._staffId,
|
|
@@ -893,7 +1393,8 @@ var Cart = class _Cart {
|
|
|
893
1393
|
newCart._refunds = [...this._refunds];
|
|
894
1394
|
newCart._loyaltyProgramId = this._loyaltyProgramId;
|
|
895
1395
|
newCart._loyaltyTransactionIds = [...this._loyaltyTransactionIds];
|
|
896
|
-
newCart._tableService = this._tableService
|
|
1396
|
+
newCart._tableService = cloneTableService(this._tableService);
|
|
1397
|
+
newCart._equalSplitState = cloneEqualSplitState(this._equalSplitState);
|
|
897
1398
|
newCart._taxSummary = this._taxSummary;
|
|
898
1399
|
newCart._newlyCancelledItemIds = new Set(this._newlyCancelledItemIds);
|
|
899
1400
|
newCart._invoiceCompany = this._invoiceCompany ? { ...this._invoiceCompany } : null;
|
|
@@ -906,6 +1407,16 @@ var Cart = class _Cart {
|
|
|
906
1407
|
currency: this.currency
|
|
907
1408
|
});
|
|
908
1409
|
}
|
|
1410
|
+
createDiscountRecord(discountData, scope, lineItemId, targetType, targetId) {
|
|
1411
|
+
return {
|
|
1412
|
+
...discountData,
|
|
1413
|
+
scope,
|
|
1414
|
+
lineItemId,
|
|
1415
|
+
targetType,
|
|
1416
|
+
targetId,
|
|
1417
|
+
createdAt: (0, import_dayjs.default)().toDate().toISOString()
|
|
1418
|
+
};
|
|
1419
|
+
}
|
|
909
1420
|
touch() {
|
|
910
1421
|
this.updatedAt = (0, import_dayjs.default)().toDate();
|
|
911
1422
|
}
|
|
@@ -919,7 +1430,7 @@ var ApplyTo = /* @__PURE__ */ ((ApplyTo2) => {
|
|
|
919
1430
|
})(ApplyTo || {});
|
|
920
1431
|
|
|
921
1432
|
// src/version.ts
|
|
922
|
-
var VERSION = "0.1.
|
|
1433
|
+
var VERSION = "0.1.4";
|
|
923
1434
|
// Annotate the CommonJS export names for ESM import in node:
|
|
924
1435
|
0 && (module.exports = {
|
|
925
1436
|
ApplyTo,
|
|
@@ -928,7 +1439,9 @@ var VERSION = "0.1.1";
|
|
|
928
1439
|
allocateProportionalMinorUnits,
|
|
929
1440
|
calculateCartPriceSnapshot,
|
|
930
1441
|
calculateDiscountAmount,
|
|
1442
|
+
calculateEqualSplitPartPricing,
|
|
931
1443
|
calculateItemPrice,
|
|
1444
|
+
calculateItemSplitSeatPricing,
|
|
932
1445
|
calculateOrderTaxSummary,
|
|
933
1446
|
calculateSequentialDiscountTotal,
|
|
934
1447
|
splitTaxInclusiveAmount
|