@pisell/pisellos 0.10.35 → 0.10.37
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/model/strategy/adapter/promotion/index.js +0 -9
- package/dist/modules/Order/index.js +4 -18
- package/dist/server/utils/small-ticket.d.ts +4 -6
- package/dist/server/utils/small-ticket.js +359 -89
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/lib/model/strategy/adapter/promotion/index.js +46 -1
- package/lib/modules/Order/index.js +3 -17
- package/lib/server/utils/small-ticket.d.ts +4 -6
- package/lib/server/utils/small-ticket.js +233 -26
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
326
326
|
date: string;
|
|
327
327
|
status: string;
|
|
328
328
|
week: string;
|
|
329
|
-
weekNum: 0 |
|
|
329
|
+
weekNum: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|
|
@@ -1 +1,46 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "BUY_X_GET_Y_FREE_STRATEGY", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _examples.BUY_X_GET_Y_FREE_STRATEGY;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "ITEM_REWARD_STRATEGY", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () {
|
|
15
|
+
return _examples.ITEM_REWARD_STRATEGY;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(exports, "PromotionAdapter", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () {
|
|
21
|
+
return _adapter.PromotionAdapter;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(exports, "PromotionEvaluator", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: function () {
|
|
27
|
+
return _evaluator.PromotionEvaluator;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
Object.defineProperty(exports, "X_ITEMS_FOR_Y_PRICE_STRATEGY", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function () {
|
|
33
|
+
return _examples.X_ITEMS_FOR_Y_PRICE_STRATEGY;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
Object.defineProperty(exports, "default", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function () {
|
|
39
|
+
return _adapter.default;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
var _evaluator = require("./evaluator");
|
|
43
|
+
var _adapter = _interopRequireWildcard(require("./adapter"));
|
|
44
|
+
var _examples = require("./examples");
|
|
45
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
46
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
@@ -72,13 +72,6 @@ function getVoucherPaymentLifecycleKey(payment) {
|
|
|
72
72
|
if (!isVoucherPaymentRecord(payment)) return null;
|
|
73
73
|
return `${String(payment.voucher_id)}::${String(payment.status || '')}`;
|
|
74
74
|
}
|
|
75
|
-
function hasPersistedOrderId(orderId) {
|
|
76
|
-
if (orderId === undefined || orderId === null || orderId === '') return false;
|
|
77
|
-
if (typeof orderId === 'string' && orderId.startsWith('LOCAL_')) return false;
|
|
78
|
-
const normalizedOrderId = Number(orderId);
|
|
79
|
-
if (Number.isFinite(normalizedOrderId)) return normalizedOrderId > 0;
|
|
80
|
-
return String(orderId).trim() !== '';
|
|
81
|
-
}
|
|
82
75
|
class OrderModule extends _BaseModule.BaseModule {
|
|
83
76
|
defaultName = 'order';
|
|
84
77
|
defaultVersion = '1.0.0';
|
|
@@ -480,7 +473,6 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
480
473
|
this.store.virtualCurrencyList = prepareConfigResult?.virtualCurrencyList || [];
|
|
481
474
|
if (prepareConfigResult) {
|
|
482
475
|
this.writePointCardSnapshotFromPrepareConfig({
|
|
483
|
-
orderId,
|
|
484
476
|
customerId: params.customerId,
|
|
485
477
|
availableWalletPassList: prepareConfigResult.availableWalletPassList || []
|
|
486
478
|
});
|
|
@@ -986,8 +978,6 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
986
978
|
const tempOrder = this.store.tempOrder;
|
|
987
979
|
if (!tempOrder) return;
|
|
988
980
|
if (String(tempOrder.customer_id ?? '') !== String(params.customerId)) return;
|
|
989
|
-
const effectiveOrderId = params.orderId ?? tempOrder.order_id;
|
|
990
|
-
if (hasPersistedOrderId(effectiveOrderId)) return;
|
|
991
981
|
tempOrder.order_meta_list = {
|
|
992
982
|
...((0, _utils.normalizeOrderMetaList)(tempOrder.order_meta_list) || {}),
|
|
993
983
|
point_cards_snapshot: (0, _utils.buildPointCardSnapshotFromWalletPassList)(params.availableWalletPassList)
|
|
@@ -2465,7 +2455,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2465
2455
|
email: tempOrder.email
|
|
2466
2456
|
});
|
|
2467
2457
|
const nextCustomerId = tempOrder.customer_id ?? null;
|
|
2468
|
-
if (String(previousCustomerId ?? '') !== String(nextCustomerId ?? '')
|
|
2458
|
+
if (String(previousCustomerId ?? '') !== String(nextCustomerId ?? '')) {
|
|
2469
2459
|
this.store.availableWalletIds = [];
|
|
2470
2460
|
this.clearTempOrderPointCardSnapshot(tempOrder);
|
|
2471
2461
|
}
|
|
@@ -2505,9 +2495,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2505
2495
|
if (String(previousCustomerId ?? '') !== String(nextCustomerId ?? '')) {
|
|
2506
2496
|
this.store.availableWalletIds = [];
|
|
2507
2497
|
this.store.virtualCurrencyList = [];
|
|
2508
|
-
|
|
2509
|
-
this.clearTempOrderPointCardSnapshot(tempOrder);
|
|
2510
|
-
}
|
|
2498
|
+
this.clearTempOrderPointCardSnapshot(tempOrder);
|
|
2511
2499
|
(0, _utils.clearTempOrderHolderAssignments)(tempOrder);
|
|
2512
2500
|
this.clearCustomerBoundDiscounts(tempOrder);
|
|
2513
2501
|
this.applyDiscount();
|
|
@@ -2547,9 +2535,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2547
2535
|
if (tempOrder._extend) delete tempOrder._extend.customerSnapshot;
|
|
2548
2536
|
this.store.availableWalletIds = [];
|
|
2549
2537
|
this.store.virtualCurrencyList = [];
|
|
2550
|
-
|
|
2551
|
-
this.clearTempOrderPointCardSnapshot(tempOrder);
|
|
2552
|
-
}
|
|
2538
|
+
this.clearTempOrderPointCardSnapshot(tempOrder);
|
|
2553
2539
|
this.clearCustomerBoundDiscounts(tempOrder);
|
|
2554
2540
|
this.applyDiscount();
|
|
2555
2541
|
this.persistTempOrder();
|
|
@@ -28,6 +28,8 @@ export interface SmallTicketItem {
|
|
|
28
28
|
value: string;
|
|
29
29
|
size?: number;
|
|
30
30
|
align?: string;
|
|
31
|
+
product_uid?: string | number;
|
|
32
|
+
booking_uid?: string | number;
|
|
31
33
|
}
|
|
32
34
|
export interface SmallTicketProduct {
|
|
33
35
|
product_title: string;
|
|
@@ -35,7 +37,7 @@ export interface SmallTicketProduct {
|
|
|
35
37
|
selling_price: string;
|
|
36
38
|
total_selling_price: string;
|
|
37
39
|
original_price: string;
|
|
38
|
-
base_price
|
|
40
|
+
base_price?: string;
|
|
39
41
|
total_original_price: string;
|
|
40
42
|
options_total_price?: string;
|
|
41
43
|
package_items_total_price?: string;
|
|
@@ -53,11 +55,7 @@ export interface SmallTicketProduct {
|
|
|
53
55
|
variant?: string;
|
|
54
56
|
combinations?: any[];
|
|
55
57
|
}
|
|
56
|
-
export
|
|
57
|
-
product_uid?: string | number;
|
|
58
|
-
booking_uid?: string | number;
|
|
59
|
-
}
|
|
60
|
-
export type SmallTicketAppointment = SmallTicketItem[] | SmallTicketBookingSnapshot[];
|
|
58
|
+
export type SmallTicketAppointment = SmallTicketItem[];
|
|
61
59
|
export interface SmallTicketLocaleData {
|
|
62
60
|
base_data: Record<string, any>;
|
|
63
61
|
products: SmallTicketProduct[];
|
|
@@ -33,8 +33,13 @@ const LABELS = {
|
|
|
33
33
|
redeemPoints: 'Redeem points',
|
|
34
34
|
remainingPoints: 'Points balance',
|
|
35
35
|
table: 'Table',
|
|
36
|
+
bookingId: 'Booking ID',
|
|
37
|
+
bookingDateTime: 'Date & time',
|
|
38
|
+
bookingResource: 'Resource',
|
|
39
|
+
bookingHolder: 'Holder',
|
|
36
40
|
orderDiscount: 'Order discount',
|
|
37
41
|
manualDiscount: 'Manual discount',
|
|
42
|
+
manualMarkup: 'Manual markup',
|
|
38
43
|
payProcessingFee: 'Pay processing fee',
|
|
39
44
|
surchargeIncluded: 'Surcharge(Included)',
|
|
40
45
|
rounding: 'Rounding',
|
|
@@ -66,8 +71,13 @@ const LABELS = {
|
|
|
66
71
|
redeemPoints: '本次使用积分',
|
|
67
72
|
remainingPoints: '积分余额',
|
|
68
73
|
table: '桌台',
|
|
74
|
+
bookingId: '预约编号',
|
|
75
|
+
bookingDateTime: '日期和时间',
|
|
76
|
+
bookingResource: '资源',
|
|
77
|
+
bookingHolder: '预约人',
|
|
69
78
|
orderDiscount: '整单折扣',
|
|
70
79
|
manualDiscount: '手动折扣',
|
|
80
|
+
manualMarkup: '手动加价',
|
|
71
81
|
payProcessingFee: '支付手续费',
|
|
72
82
|
surchargeIncluded: '手续费(已含)',
|
|
73
83
|
rounding: '抹零',
|
|
@@ -99,8 +109,13 @@ const LABELS = {
|
|
|
99
109
|
redeemPoints: '本次使用積分',
|
|
100
110
|
remainingPoints: '積分餘額',
|
|
101
111
|
table: '桌台',
|
|
112
|
+
bookingId: '預約編號',
|
|
113
|
+
bookingDateTime: '日期和時間',
|
|
114
|
+
bookingResource: '資源',
|
|
115
|
+
bookingHolder: '預約人',
|
|
102
116
|
orderDiscount: '整單折扣',
|
|
103
117
|
manualDiscount: '手動折扣',
|
|
118
|
+
manualMarkup: '手動加價',
|
|
104
119
|
payProcessingFee: '支付手續費',
|
|
105
120
|
surchargeIncluded: '手續費(已含)',
|
|
106
121
|
rounding: '抹零',
|
|
@@ -130,8 +145,13 @@ const LABELS = {
|
|
|
130
145
|
redeemPoints: '利用ポイント',
|
|
131
146
|
remainingPoints: 'ポイント残高',
|
|
132
147
|
table: 'テーブル',
|
|
148
|
+
bookingId: '予約ID',
|
|
149
|
+
bookingDateTime: '日時',
|
|
150
|
+
bookingResource: 'リソース',
|
|
151
|
+
bookingHolder: '予約者',
|
|
133
152
|
orderDiscount: '注文割引',
|
|
134
153
|
manualDiscount: '手動割引',
|
|
154
|
+
manualMarkup: '手動値上げ',
|
|
135
155
|
payProcessingFee: '決済手数料',
|
|
136
156
|
rounding: '端数調整',
|
|
137
157
|
gross: '総重量',
|
|
@@ -162,8 +182,13 @@ const LABELS = {
|
|
|
162
182
|
redeemPoints: 'Pontos utilizados',
|
|
163
183
|
remainingPoints: 'Saldo de pontos',
|
|
164
184
|
table: 'Mesa',
|
|
185
|
+
bookingId: 'ID da reserva',
|
|
186
|
+
bookingDateTime: 'Data e hora',
|
|
187
|
+
bookingResource: 'Recurso',
|
|
188
|
+
bookingHolder: 'Titular',
|
|
165
189
|
orderDiscount: 'Desconto do pedido',
|
|
166
190
|
manualDiscount: 'Desconto manual',
|
|
191
|
+
manualMarkup: 'Acréscimo manual',
|
|
167
192
|
payProcessingFee: 'Taxa de processamento',
|
|
168
193
|
rounding: 'Arredondamento',
|
|
169
194
|
gross: 'Peso bruto',
|
|
@@ -281,7 +306,8 @@ function buildBaseData(params) {
|
|
|
281
306
|
}
|
|
282
307
|
function buildProducts(order, locale, productMap) {
|
|
283
308
|
const products = Array.isArray(order.products) ? order.products : [];
|
|
284
|
-
return products.map(
|
|
309
|
+
return products.map(rawProduct => {
|
|
310
|
+
const product = restoreReceiptDiscountHierarchy(rawProduct);
|
|
285
311
|
const quantity = toNumber(product.product_quantity ?? product.quantity ?? product.num ?? 1, 1);
|
|
286
312
|
const originalPrice = product.original_price ?? product.selling_price ?? product.payment_price ?? product.price ?? 0;
|
|
287
313
|
const sellingPrice = product.selling_price ?? product.payment_price ?? product.price ?? originalPrice;
|
|
@@ -322,13 +348,16 @@ function buildProducts(order, locale, productMap) {
|
|
|
322
348
|
const productNote = resolveProductNote(product, locale);
|
|
323
349
|
const basePrice = resolveProductBasePrice(product);
|
|
324
350
|
const resolvedCombinations = Array.isArray(product.combinations) && product.combinations.length ? normalizeExistingCombinations(product.combinations, locale, currencySymbol) : combinations;
|
|
351
|
+
const shouldIncludeBasePrice = options.length > 0 || resolvedCombinations.length > 0 || hasProductDiscount(product, extensionList);
|
|
325
352
|
return {
|
|
326
353
|
product_title: productTitle,
|
|
327
354
|
product_quantity: quantity,
|
|
328
355
|
selling_price: formatMoney(sellingPrice, currencySymbol),
|
|
329
356
|
total_selling_price: formatCalculatedMoney(new _decimal.default(toMoneyNumber(sellingPrice)).mul(quantity), currencySymbol),
|
|
330
357
|
original_price: formatMoney(originalPrice, currencySymbol),
|
|
331
|
-
|
|
358
|
+
...(shouldIncludeBasePrice ? {
|
|
359
|
+
base_price: formatCalculatedMoney(basePrice ?? 0, currencySymbol)
|
|
360
|
+
} : {}),
|
|
332
361
|
total_original_price: formatMoney(new _decimal.default(toMoneyNumber(originalPrice)).mul(quantity), currencySymbol),
|
|
333
362
|
...(options.length ? {
|
|
334
363
|
options_total_price: sumNormalizedOptionTotals(options, currencySymbol)
|
|
@@ -358,6 +387,73 @@ function buildProducts(order, locale, productMap) {
|
|
|
358
387
|
};
|
|
359
388
|
});
|
|
360
389
|
}
|
|
390
|
+
const RECEIPT_BUNDLE_MAP_ID_KEY = 'custom_product_bundle_map_id';
|
|
391
|
+
function restoreReceiptDiscountHierarchy(source) {
|
|
392
|
+
if (!source || typeof source !== 'object' || Array.isArray(source)) {
|
|
393
|
+
return source;
|
|
394
|
+
}
|
|
395
|
+
const childKey = Array.isArray(source.combinations) && source.combinations.length ? 'combinations' : Array.isArray(source.product_bundle) && source.product_bundle.length ? 'product_bundle' : null;
|
|
396
|
+
if (!childKey) return {
|
|
397
|
+
...source
|
|
398
|
+
};
|
|
399
|
+
const children = source[childKey].map(child => child && typeof child === 'object' && !Array.isArray(child) ? restoreReceiptDiscountHierarchy(child) : child);
|
|
400
|
+
const restored = {
|
|
401
|
+
...source,
|
|
402
|
+
[childKey]: children
|
|
403
|
+
};
|
|
404
|
+
if (!Array.isArray(source.discount_list) || !source.discount_list.length) {
|
|
405
|
+
return restored;
|
|
406
|
+
}
|
|
407
|
+
const descendantsByMapId = new Map();
|
|
408
|
+
indexReceiptDiscountTargets(children, descendantsByMapId);
|
|
409
|
+
if (!descendantsByMapId.size) return restored;
|
|
410
|
+
const ownDiscounts = [];
|
|
411
|
+
for (const discount of source.discount_list) {
|
|
412
|
+
const mapId = getReceiptDiscountBundleMapId(discount);
|
|
413
|
+
const target = mapId ? descendantsByMapId.get(mapId) : undefined;
|
|
414
|
+
if (!target) {
|
|
415
|
+
ownDiscounts.push(discount);
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
const targetDiscounts = Array.isArray(target.discount_list) ? target.discount_list : [];
|
|
419
|
+
if (!targetDiscounts.some(item => isSameReceiptDiscount(item, discount))) {
|
|
420
|
+
target.discount_list = [...targetDiscounts, discount];
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
restored.discount_list = ownDiscounts;
|
|
424
|
+
return restored;
|
|
425
|
+
}
|
|
426
|
+
function indexReceiptDiscountTargets(nodes, targets) {
|
|
427
|
+
for (const node of nodes) {
|
|
428
|
+
if (!node || typeof node !== 'object' || Array.isArray(node)) continue;
|
|
429
|
+
const mapId = getReceiptBundleMapId(node);
|
|
430
|
+
if (mapId && !targets.has(mapId)) targets.set(mapId, node);
|
|
431
|
+
const children = Array.isArray(node.combinations) && node.combinations.length ? node.combinations : Array.isArray(node.product_bundle) ? node.product_bundle : [];
|
|
432
|
+
indexReceiptDiscountTargets(children, targets);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
function normalizeReceiptId(value) {
|
|
436
|
+
if (value === undefined || value === null) return null;
|
|
437
|
+
const normalized = String(value).trim();
|
|
438
|
+
return normalized ? normalized : null;
|
|
439
|
+
}
|
|
440
|
+
function getReceiptBundleMapId(node) {
|
|
441
|
+
return normalizeReceiptId(node.metadata?.[RECEIPT_BUNDLE_MAP_ID_KEY] ?? node._id);
|
|
442
|
+
}
|
|
443
|
+
function getReceiptDiscountBundleMapId(discount) {
|
|
444
|
+
return normalizeReceiptId(discount?.metadata?.[RECEIPT_BUNDLE_MAP_ID_KEY]);
|
|
445
|
+
}
|
|
446
|
+
function isSameReceiptDiscount(left, right) {
|
|
447
|
+
const leftOrderDiscountId = normalizeReceiptId(left?.order_discount_id);
|
|
448
|
+
const rightOrderDiscountId = normalizeReceiptId(right?.order_discount_id);
|
|
449
|
+
if (leftOrderDiscountId && rightOrderDiscountId) {
|
|
450
|
+
return leftOrderDiscountId === rightOrderDiscountId;
|
|
451
|
+
}
|
|
452
|
+
const leftResourceId = normalizeReceiptId(left?.discount?.resource_id ?? left?.resource_id ?? left?.discount_id);
|
|
453
|
+
const rightResourceId = normalizeReceiptId(right?.discount?.resource_id ?? right?.resource_id ?? right?.discount_id);
|
|
454
|
+
if (!leftResourceId || !rightResourceId) return false;
|
|
455
|
+
return leftResourceId === rightResourceId && getReceiptDiscountBundleMapId(left) === getReceiptDiscountBundleMapId(right) && String(left?.amount ?? left?.value ?? left?.discount_amount ?? '') === String(right?.amount ?? right?.value ?? right?.discount_amount ?? '');
|
|
456
|
+
}
|
|
361
457
|
function resolveProductBasePrice(product) {
|
|
362
458
|
const metadata = product.metadata || {};
|
|
363
459
|
const origin = product._origin || metadata.origin || {};
|
|
@@ -373,18 +469,35 @@ function normalizeProductDiscounts(params) {
|
|
|
373
469
|
currencySymbol,
|
|
374
470
|
quantity
|
|
375
471
|
} = params;
|
|
376
|
-
|
|
472
|
+
const rows = normalizeArray(product.discount_list).filter(discount => {
|
|
377
473
|
const amount = discount.amount ?? discount.value ?? discount.discount_amount;
|
|
378
474
|
return isNonZero(amount);
|
|
379
475
|
}).map(discount => {
|
|
380
476
|
const title = resolveDiscountTitleWithPercent(discount, locale);
|
|
381
477
|
const amount = discount.amount ?? discount.value ?? discount.discount_amount;
|
|
382
|
-
const
|
|
478
|
+
const isMarkup = isManualMarkup(discount);
|
|
479
|
+
const totalAmount = new _decimal.default(toMoneyNumber(amount)).mul(quantity);
|
|
480
|
+
const formattedAmount = isMarkup ? formatMoney(totalAmount.abs(), currencySymbol) : formatNegativeMoney(totalAmount, currencySymbol);
|
|
383
481
|
return {
|
|
384
482
|
item: title,
|
|
385
|
-
value: formattedAmount
|
|
483
|
+
value: formattedAmount,
|
|
484
|
+
isMarkup
|
|
386
485
|
};
|
|
387
486
|
});
|
|
487
|
+
return rows.sort((left, right) => Number(right.isMarkup) - Number(left.isMarkup)).map(({
|
|
488
|
+
isMarkup: _isMarkup,
|
|
489
|
+
...row
|
|
490
|
+
}) => row);
|
|
491
|
+
}
|
|
492
|
+
function isManualMarkup(discount) {
|
|
493
|
+
if (discount.type !== 'product') return false;
|
|
494
|
+
if (discount.discount?.discount_type === 'change_price') return true;
|
|
495
|
+
const amount = discount.amount ?? discount.value ?? discount.discount_amount;
|
|
496
|
+
return new _decimal.default(toMoneyNumber(amount)).isNegative();
|
|
497
|
+
}
|
|
498
|
+
function hasProductDiscount(product, extensionList = []) {
|
|
499
|
+
const hasDiscountListAmount = normalizeArray(product.discount_list).some(discount => isNonZero(discount.amount ?? discount.value ?? discount.discount_amount));
|
|
500
|
+
return hasDiscountListAmount || extensionList.some(row => /^\s*-/.test(stringify(row?.value)));
|
|
388
501
|
}
|
|
389
502
|
function buildProductExtensionList(params) {
|
|
390
503
|
const {
|
|
@@ -467,7 +580,9 @@ function resolveDiscountTitleWithPercent(discount, locale) {
|
|
|
467
580
|
function resolveDiscountTitle(discount, locale) {
|
|
468
581
|
const title = getLocalizedValue(discount.discount?.name ?? discount.discount?.title ?? discount.discount?.message ?? discount.name ?? discount.title ?? discount.message, locale);
|
|
469
582
|
if (title) return title;
|
|
470
|
-
if (discount.type === 'product')
|
|
583
|
+
if (discount.type === 'product') {
|
|
584
|
+
return label(locale, isManualMarkup(discount) ? 'manualMarkup' : 'manualDiscount');
|
|
585
|
+
}
|
|
471
586
|
return '';
|
|
472
587
|
}
|
|
473
588
|
function resolveProductTitle(params) {
|
|
@@ -545,12 +660,22 @@ function normalizeProductCombinations(params) {
|
|
|
545
660
|
const optionsTotal = sumNormalizedOptionTotals(combinationsOptions, currencySymbol);
|
|
546
661
|
const explicitBasePrice = firstPresentValue(bundle.base_price, bundle.metadata?.source_product_price);
|
|
547
662
|
const basePrice = isPresentId(explicitBasePrice) ? explicitBasePrice : 0;
|
|
663
|
+
const extensionList = buildProductExtensionList({
|
|
664
|
+
product: bundle,
|
|
665
|
+
locale,
|
|
666
|
+
currencySymbol,
|
|
667
|
+
quantity,
|
|
668
|
+
originalPrice: formattedPrice
|
|
669
|
+
});
|
|
670
|
+
const shouldIncludeBasePrice = combinationsOptions.length > 0 || nestedCombinations.length > 0 || hasProductDiscount(bundle, extensionList);
|
|
548
671
|
return {
|
|
549
672
|
product_title: baseTitle,
|
|
550
673
|
product_quantity: quantity,
|
|
551
674
|
price: formattedPrice,
|
|
552
675
|
total_selling_price: formatCalculatedMoney(new _decimal.default(toMoneyNumber(formattedPrice)).mul(quantity), currencySymbol),
|
|
553
|
-
|
|
676
|
+
...(shouldIncludeBasePrice ? {
|
|
677
|
+
base_price: formatCalculatedMoney(basePrice, currencySymbol)
|
|
678
|
+
} : {}),
|
|
554
679
|
combinations_options: combinationsOptions,
|
|
555
680
|
...(combinationsOptions.length ? {
|
|
556
681
|
options_total_price: optionsTotal
|
|
@@ -561,6 +686,9 @@ function normalizeProductCombinations(params) {
|
|
|
561
686
|
...(productNote ? {
|
|
562
687
|
product_note: productNote
|
|
563
688
|
} : {}),
|
|
689
|
+
...(extensionList.length ? {
|
|
690
|
+
extension_list: extensionList
|
|
691
|
+
} : {}),
|
|
564
692
|
...(nestedCombinations.length ? {
|
|
565
693
|
combinations: nestedCombinations
|
|
566
694
|
} : {})
|
|
@@ -587,16 +715,27 @@ function normalizeExistingCombinations(combinations, locale, currencySymbol) {
|
|
|
587
715
|
delete snapshot.product_note;
|
|
588
716
|
delete snapshot.note;
|
|
589
717
|
delete snapshot.combinations;
|
|
718
|
+
delete snapshot.discount_list;
|
|
590
719
|
const quantity = toNumber(combination.product_quantity ?? combination.num ?? combination.quantity ?? 1, 1);
|
|
591
720
|
const unitPrice = firstPresentValue(combination.selling_price, combination.price, combination.original_price) ?? 0;
|
|
592
721
|
const optionsAmount = sumMoneyValues(normalizedOptions.map(option => option.total_price));
|
|
593
722
|
const explicitBasePrice = firstPresentValue(combination.base_price);
|
|
594
723
|
const basePrice = isPresentId(explicitBasePrice) ? explicitBasePrice : 0;
|
|
724
|
+
const extensionList = buildProductExtensionList({
|
|
725
|
+
product: combination,
|
|
726
|
+
locale,
|
|
727
|
+
currencySymbol,
|
|
728
|
+
quantity,
|
|
729
|
+
originalPrice: unitPrice
|
|
730
|
+
});
|
|
731
|
+
const shouldIncludeBasePrice = normalizedOptions.length > 0 || nestedCombinations.length > 0 || hasProductDiscount(combination, extensionList);
|
|
595
732
|
return {
|
|
596
733
|
...snapshot,
|
|
597
734
|
product_quantity: quantity,
|
|
598
735
|
total_selling_price: formatCalculatedMoney(new _decimal.default(toMoneyNumber(unitPrice)).mul(quantity), currencySymbol),
|
|
599
|
-
|
|
736
|
+
...(shouldIncludeBasePrice ? {
|
|
737
|
+
base_price: formatCalculatedMoney(basePrice, currencySymbol)
|
|
738
|
+
} : {}),
|
|
600
739
|
...(Array.isArray(combination.combinations_options) ? {
|
|
601
740
|
combinations_options: normalizedOptions
|
|
602
741
|
} : Array.isArray(combination.options) ? {
|
|
@@ -611,6 +750,9 @@ function normalizeExistingCombinations(combinations, locale, currencySymbol) {
|
|
|
611
750
|
...(productNote ? {
|
|
612
751
|
product_note: productNote
|
|
613
752
|
} : {}),
|
|
753
|
+
...(extensionList.length ? {
|
|
754
|
+
extension_list: extensionList
|
|
755
|
+
} : {}),
|
|
614
756
|
...(nestedCombinations.length ? {
|
|
615
757
|
combinations: nestedCombinations
|
|
616
758
|
} : {})
|
|
@@ -985,24 +1127,13 @@ function buildDelivery(order, locale) {
|
|
|
985
1127
|
function buildAppointment(order, locale) {
|
|
986
1128
|
const bookings = sortBookings(normalizeArray(order.bookings));
|
|
987
1129
|
if (bookings.length) {
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
const bookingUid = firstPresentValue(booking.metadata?.unique_identification_number, booking.booking_uid);
|
|
996
|
-
return {
|
|
997
|
-
...snapshot,
|
|
998
|
-
...(isPresentId(productUid) ? {
|
|
999
|
-
product_uid: productUid
|
|
1000
|
-
} : {}),
|
|
1001
|
-
...(isPresentId(bookingUid) ? {
|
|
1002
|
-
booking_uid: bookingUid
|
|
1003
|
-
} : {})
|
|
1004
|
-
};
|
|
1005
|
-
});
|
|
1130
|
+
const allResources = normalizeArray(order.resources || order.resource_list);
|
|
1131
|
+
return bookings.flatMap(booking => buildAppointmentRows({
|
|
1132
|
+
booking,
|
|
1133
|
+
allResources,
|
|
1134
|
+
bookingCount: bookings.length,
|
|
1135
|
+
locale
|
|
1136
|
+
}));
|
|
1006
1137
|
}
|
|
1007
1138
|
const tableName = order.table_name || order.metadata?.table_name || order.metadata?.table?.name || order.form_data?.table_name;
|
|
1008
1139
|
if (!tableName) return [];
|
|
@@ -1011,6 +1142,82 @@ function buildAppointment(order, locale) {
|
|
|
1011
1142
|
value: getLocalizedValue(tableName, locale)
|
|
1012
1143
|
}];
|
|
1013
1144
|
}
|
|
1145
|
+
function buildAppointmentRows(params) {
|
|
1146
|
+
const {
|
|
1147
|
+
booking,
|
|
1148
|
+
allResources,
|
|
1149
|
+
bookingCount,
|
|
1150
|
+
locale
|
|
1151
|
+
} = params;
|
|
1152
|
+
const productUid = stringify(firstPresentValue(booking.product_uid, booking.metadata?.product_uid)).trim();
|
|
1153
|
+
const bookingUid = stringify(firstPresentValue(booking.metadata?.unique_identification_number, booking.booking_uid)).trim();
|
|
1154
|
+
const association = {
|
|
1155
|
+
product_uid: productUid,
|
|
1156
|
+
booking_uid: bookingUid
|
|
1157
|
+
};
|
|
1158
|
+
const bookingId = stringify(firstPresentValue(booking.booking_id, booking.schedule_event_id, bookingUid)).trim();
|
|
1159
|
+
const bookingTime = formatBookingRange(booking, locale);
|
|
1160
|
+
const resourceText = formatBookingResources(resolveBookingResourcesForReceipt(booking, allResources, bookingCount), locale);
|
|
1161
|
+
const holder = getLocalizedValue(booking.holder?.name ?? booking.metadata?.holder?.name, locale).trim();
|
|
1162
|
+
return [{
|
|
1163
|
+
item: label(locale, 'bookingId'),
|
|
1164
|
+
value: bookingId,
|
|
1165
|
+
...association
|
|
1166
|
+
}, {
|
|
1167
|
+
item: label(locale, 'bookingDateTime'),
|
|
1168
|
+
value: bookingTime,
|
|
1169
|
+
...association
|
|
1170
|
+
}, {
|
|
1171
|
+
item: label(locale, 'bookingResource'),
|
|
1172
|
+
value: resourceText,
|
|
1173
|
+
...association
|
|
1174
|
+
}, {
|
|
1175
|
+
item: label(locale, 'bookingHolder'),
|
|
1176
|
+
value: holder,
|
|
1177
|
+
...association
|
|
1178
|
+
}].filter(row => Boolean(row.value));
|
|
1179
|
+
}
|
|
1180
|
+
function formatBookingRange(booking, locale) {
|
|
1181
|
+
const startDate = stringify(booking.start_date);
|
|
1182
|
+
const startTime = stringify(booking.start_time);
|
|
1183
|
+
const endDate = stringify(booking.end_date || startDate);
|
|
1184
|
+
const endTime = stringify(booking.end_time);
|
|
1185
|
+
const start = firstValidBookingDate(booking.start_at, booking.start_datetime, booking.start_date_time, `${startDate} ${startTime}`.trim());
|
|
1186
|
+
const end = firstValidBookingDate(booking.end_at, booking.end_datetime, booking.end_date_time, endTime ? `${endDate} ${endTime}`.trim() : '');
|
|
1187
|
+
if (!start) {
|
|
1188
|
+
return [startDate, startTime, endTime ? `- ${endDate} ${endTime}` : ''].filter(Boolean).join(' ');
|
|
1189
|
+
}
|
|
1190
|
+
const dateFormat = locale === 'en' ? 'DD/MM/YYYY' : 'YYYY/MM/DD';
|
|
1191
|
+
const startText = start.format(`${dateFormat} HH:mm`);
|
|
1192
|
+
if (!end) return startText;
|
|
1193
|
+
return `${startText} - ${end.isSame(start, 'day') ? end.format('HH:mm') : end.format(`${dateFormat} HH:mm`)}`;
|
|
1194
|
+
}
|
|
1195
|
+
function firstValidBookingDate(...values) {
|
|
1196
|
+
for (const value of values) {
|
|
1197
|
+
if (!isPresentId(value)) continue;
|
|
1198
|
+
const parsed = (0, _dayjs.default)(value);
|
|
1199
|
+
if (parsed.isValid()) return parsed;
|
|
1200
|
+
}
|
|
1201
|
+
return null;
|
|
1202
|
+
}
|
|
1203
|
+
function resolveBookingResourcesForReceipt(booking, allResources, bookingCount) {
|
|
1204
|
+
const embedded = normalizeArray(booking.resources).filter(resource => Boolean(resource) && typeof resource === 'object' && !Array.isArray(resource));
|
|
1205
|
+
const resourceIds = new Set([booking.resource_id, booking.relation_id, ...normalizeArray(booking.resource_ids), ...normalizeArray(booking.metadata?.resource_ids)].map(value => stringify(value).trim()).filter(Boolean));
|
|
1206
|
+
for (const resource of embedded) {
|
|
1207
|
+
const id = stringify(resource.id ?? resource.resource_id ?? resource.relation_id).trim();
|
|
1208
|
+
if (id) resourceIds.add(id);
|
|
1209
|
+
}
|
|
1210
|
+
if (resourceIds.size) {
|
|
1211
|
+
const matched = allResources.filter(resource => resourceIds.has(stringify(resource.id ?? resource.resource_id ?? resource.relation_id).trim()));
|
|
1212
|
+
if (matched.length) return matched;
|
|
1213
|
+
}
|
|
1214
|
+
if (embedded.length) return embedded;
|
|
1215
|
+
if (bookingCount === 1 && allResources.length) return allResources;
|
|
1216
|
+
return [];
|
|
1217
|
+
}
|
|
1218
|
+
function formatBookingResources(resources, locale) {
|
|
1219
|
+
return resources.map(resource => [getLocalizedValue(resource.form_title || resource.metadata?.form_name || resource.relation_form_name || resource.metadata?.relation_form_name, locale), getLocalizedValue(resource.title || resource.name || resource.main_field || resource.metadata?.main_field || resource.metadata?.resource_name, locale)].filter(Boolean).join(' ')).filter(Boolean).join(', ');
|
|
1220
|
+
}
|
|
1014
1221
|
function sortBookings(bookings) {
|
|
1015
1222
|
return bookings.map((booking, index) => ({
|
|
1016
1223
|
booking,
|
|
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
326
326
|
date: string;
|
|
327
327
|
status: string;
|
|
328
328
|
week: string;
|
|
329
|
-
weekNum: 0 |
|
|
329
|
+
weekNum: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|