@pisell/pisellos 0.10.28 → 0.10.29
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/core/index.d.ts +7 -0
- package/dist/core/index.js +108 -65
- package/dist/model/strategy/adapter/dataVariant/evaluator.js +13 -2
- package/dist/model/strategy/adapter/promotion/index.js +0 -9
- package/dist/modules/Discount/index.js +4 -1
- package/dist/modules/Discount/types.d.ts +14 -4
- package/dist/modules/Order/index.d.ts +4 -2
- package/dist/modules/Order/index.js +89 -16
- package/dist/modules/Order/types.d.ts +13 -0
- package/dist/modules/Order/utils.d.ts +17 -2
- package/dist/modules/Order/utils.js +133 -27
- package/dist/modules/Quotation/index.d.ts +6 -0
- package/dist/modules/Quotation/index.js +77 -25
- package/dist/modules/ResourcePlanner/planner.js +14 -4
- package/dist/modules/ResourcePlanner/types.d.ts +2 -0
- package/dist/plugins/request.d.ts +1 -0
- package/dist/server/index.d.ts +13 -2
- package/dist/server/index.js +1531 -1230
- package/dist/server/modules/floor-plan/index.d.ts +4 -0
- package/dist/server/modules/floor-plan/index.js +240 -98
- package/dist/server/modules/menu/index.js +48 -23
- package/dist/server/modules/order/index.d.ts +17 -7
- package/dist/server/modules/order/index.js +419 -207
- package/dist/server/modules/order/types.d.ts +50 -0
- package/dist/server/modules/order/types.js +2 -0
- package/dist/server/modules/products/index.d.ts +10 -4
- package/dist/server/modules/products/index.js +177 -84
- package/dist/server/modules/resource/index.js +21 -13
- package/dist/server/utils/product.d.ts +1 -1
- package/dist/server/utils/product.js +186 -22
- package/dist/server/utils/small-ticket.d.ts +4 -1
- package/dist/server/utils/small-ticket.js +482 -100
- package/dist/solution/BaseSales/index.d.ts +3 -3
- package/dist/solution/BaseSales/index.js +171 -198
- package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +2 -0
- package/dist/solution/BaseSales/utils/parseSalesResponse.js +1 -1
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +3 -2
- package/dist/solution/BookingByStep/index.d.ts +2 -2
- package/dist/solution/Sales/index.d.ts +7 -0
- package/dist/solution/Sales/index.js +87 -31
- package/dist/solution/UnifiedBookingSales/index.d.ts +2 -2
- package/dist/solution/UnifiedBookingSales/index.js +38 -21
- package/lib/core/index.d.ts +7 -0
- package/lib/core/index.js +20 -2
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +12 -2
- package/lib/modules/Discount/index.js +4 -1
- package/lib/modules/Discount/types.d.ts +14 -4
- package/lib/modules/Order/index.d.ts +4 -2
- package/lib/modules/Order/index.js +69 -1
- package/lib/modules/Order/types.d.ts +13 -0
- package/lib/modules/Order/utils.d.ts +17 -2
- package/lib/modules/Order/utils.js +131 -18
- package/lib/modules/Quotation/index.d.ts +6 -0
- package/lib/modules/Quotation/index.js +52 -8
- package/lib/modules/ResourcePlanner/planner.js +9 -1
- package/lib/modules/ResourcePlanner/types.d.ts +2 -0
- package/lib/plugins/request.d.ts +1 -0
- package/lib/server/index.d.ts +13 -2
- package/lib/server/index.js +210 -19
- package/lib/server/modules/floor-plan/index.d.ts +4 -0
- package/lib/server/modules/floor-plan/index.js +60 -7
- package/lib/server/modules/menu/index.js +26 -4
- package/lib/server/modules/order/index.d.ts +17 -7
- package/lib/server/modules/order/index.js +194 -57
- package/lib/server/modules/order/types.d.ts +50 -0
- package/lib/server/modules/order/types.js +1 -0
- package/lib/server/modules/products/index.d.ts +10 -4
- package/lib/server/modules/products/index.js +93 -23
- package/lib/server/modules/resource/index.js +12 -2
- package/lib/server/utils/product.d.ts +1 -1
- package/lib/server/utils/product.js +163 -3
- package/lib/server/utils/small-ticket.d.ts +4 -1
- package/lib/server/utils/small-ticket.js +448 -75
- package/lib/solution/BaseSales/index.d.ts +3 -3
- package/lib/solution/BaseSales/index.js +9 -14
- package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +2 -0
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +1 -1
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +3 -2
- package/lib/solution/BookingByStep/index.d.ts +2 -2
- package/lib/solution/Sales/index.d.ts +7 -0
- package/lib/solution/Sales/index.js +48 -3
- package/lib/solution/UnifiedBookingSales/index.d.ts +2 -2
- package/lib/solution/UnifiedBookingSales/index.js +19 -3
- package/package.json +1 -1
|
@@ -22,9 +22,12 @@ const LABELS = {
|
|
|
22
22
|
pickUpTime: 'Pick-up time',
|
|
23
23
|
asap: 'ASAP',
|
|
24
24
|
cash: 'Cash',
|
|
25
|
+
cashReceived: 'Cash received',
|
|
26
|
+
changeDue: 'Change due',
|
|
25
27
|
eftpos: 'Eftpos',
|
|
26
28
|
wallet: 'Wallet',
|
|
27
29
|
giftCard: 'Gift card',
|
|
30
|
+
balance: 'Balance',
|
|
28
31
|
remainingAmount: 'Remaining amount',
|
|
29
32
|
redeemPoints: 'Redeem points',
|
|
30
33
|
remainingPoints: 'Remaining points',
|
|
@@ -32,9 +35,12 @@ const LABELS = {
|
|
|
32
35
|
orderDiscount: 'Order discount',
|
|
33
36
|
manualDiscount: 'Manual discount',
|
|
34
37
|
payProcessingFee: 'Pay processing fee',
|
|
38
|
+
surchargeIncluded: 'Surcharge(Included)',
|
|
35
39
|
rounding: 'Rounding',
|
|
36
40
|
gross: 'Gross',
|
|
37
|
-
tare: 'Tare'
|
|
41
|
+
tare: 'Tare',
|
|
42
|
+
handoverTime: 'Handover time',
|
|
43
|
+
refund: 'Refund'
|
|
38
44
|
},
|
|
39
45
|
zh_CN: {
|
|
40
46
|
contactName: '联系人姓名',
|
|
@@ -48,9 +54,12 @@ const LABELS = {
|
|
|
48
54
|
pickUpTime: '取餐时间',
|
|
49
55
|
asap: '尽快',
|
|
50
56
|
cash: '现金支付',
|
|
57
|
+
cashReceived: '收取现金',
|
|
58
|
+
changeDue: '找零',
|
|
51
59
|
eftpos: '刷卡支付',
|
|
52
60
|
wallet: '钱包支付',
|
|
53
61
|
giftCard: '礼品卡',
|
|
62
|
+
balance: '余额',
|
|
54
63
|
remainingAmount: '剩余金额',
|
|
55
64
|
redeemPoints: '本次使用积分',
|
|
56
65
|
remainingPoints: '剩余积分',
|
|
@@ -58,9 +67,12 @@ const LABELS = {
|
|
|
58
67
|
orderDiscount: '整单折扣',
|
|
59
68
|
manualDiscount: '手动折扣',
|
|
60
69
|
payProcessingFee: '支付手续费',
|
|
70
|
+
surchargeIncluded: '手续费(已含)',
|
|
61
71
|
rounding: '抹零',
|
|
62
72
|
gross: '重量',
|
|
63
|
-
tare: '去皮'
|
|
73
|
+
tare: '去皮',
|
|
74
|
+
handoverTime: '交付时间',
|
|
75
|
+
refund: '退款'
|
|
64
76
|
},
|
|
65
77
|
zh_HK: {
|
|
66
78
|
contactName: '聯絡人姓名',
|
|
@@ -74,9 +86,12 @@ const LABELS = {
|
|
|
74
86
|
pickUpTime: '取餐時間',
|
|
75
87
|
asap: '盡快',
|
|
76
88
|
cash: '現金支付',
|
|
89
|
+
cashReceived: '收取現金',
|
|
90
|
+
changeDue: '找零',
|
|
77
91
|
eftpos: '刷卡支付',
|
|
78
92
|
wallet: '錢包支付',
|
|
79
93
|
giftCard: '禮品卡',
|
|
94
|
+
balance: '餘額',
|
|
80
95
|
remainingAmount: '剩餘金額',
|
|
81
96
|
redeemPoints: '本次使用積分',
|
|
82
97
|
remainingPoints: '剩餘積分',
|
|
@@ -84,9 +99,12 @@ const LABELS = {
|
|
|
84
99
|
orderDiscount: '整單折扣',
|
|
85
100
|
manualDiscount: '手動折扣',
|
|
86
101
|
payProcessingFee: '支付手續費',
|
|
102
|
+
surchargeIncluded: '手續費(已含)',
|
|
87
103
|
rounding: '抹零',
|
|
88
104
|
gross: '重量',
|
|
89
|
-
tare: '去皮'
|
|
105
|
+
tare: '去皮',
|
|
106
|
+
handoverTime: '交付時間',
|
|
107
|
+
refund: '退款'
|
|
90
108
|
},
|
|
91
109
|
ja: {
|
|
92
110
|
contactName: '連絡先名',
|
|
@@ -103,6 +121,7 @@ const LABELS = {
|
|
|
103
121
|
eftpos: 'カード',
|
|
104
122
|
wallet: 'ウォレット',
|
|
105
123
|
giftCard: 'ギフトカード',
|
|
124
|
+
balance: '残高',
|
|
106
125
|
remainingAmount: '残高',
|
|
107
126
|
redeemPoints: '利用ポイント',
|
|
108
127
|
remainingPoints: '残りポイント',
|
|
@@ -112,7 +131,11 @@ const LABELS = {
|
|
|
112
131
|
payProcessingFee: '決済手数料',
|
|
113
132
|
rounding: '端数調整',
|
|
114
133
|
gross: '総重量',
|
|
115
|
-
tare: '風袋'
|
|
134
|
+
tare: '風袋',
|
|
135
|
+
handoverTime: '受け渡し時間',
|
|
136
|
+
refund: '返金',
|
|
137
|
+
cashReceived: 'お預かり',
|
|
138
|
+
changeDue: 'お釣り'
|
|
116
139
|
},
|
|
117
140
|
pt: {
|
|
118
141
|
contactName: 'Nome de contato',
|
|
@@ -129,6 +152,7 @@ const LABELS = {
|
|
|
129
152
|
eftpos: 'Cartão',
|
|
130
153
|
wallet: 'Carteira',
|
|
131
154
|
giftCard: 'Cartão-presente',
|
|
155
|
+
balance: 'Saldo',
|
|
132
156
|
remainingAmount: 'Saldo restante',
|
|
133
157
|
redeemPoints: 'Pontos utilizados',
|
|
134
158
|
remainingPoints: 'Pontos restantes',
|
|
@@ -138,7 +162,11 @@ const LABELS = {
|
|
|
138
162
|
payProcessingFee: 'Taxa de processamento',
|
|
139
163
|
rounding: 'Arredondamento',
|
|
140
164
|
gross: 'Peso bruto',
|
|
141
|
-
tare: 'Tara'
|
|
165
|
+
tare: 'Tara',
|
|
166
|
+
handoverTime: 'Hora de entrega',
|
|
167
|
+
refund: 'Reembolso',
|
|
168
|
+
cashReceived: 'Dinheiro recebido',
|
|
169
|
+
changeDue: 'Troco'
|
|
142
170
|
}
|
|
143
171
|
};
|
|
144
172
|
function buildSmallTicketData(params) {
|
|
@@ -169,11 +197,15 @@ function buildLocaleData(params) {
|
|
|
169
197
|
const products = buildProducts(order, locale, productMap);
|
|
170
198
|
const summary = getSummary(order);
|
|
171
199
|
const currencySymbol = getCurrencySymbol(order, shopInfo);
|
|
200
|
+
const financials = resolveReceiptFinancials(order, summary);
|
|
201
|
+
const delivery = buildDelivery(order, locale);
|
|
172
202
|
return {
|
|
173
203
|
base_data: buildBaseData({
|
|
174
204
|
order,
|
|
175
205
|
shopInfo,
|
|
176
|
-
locale
|
|
206
|
+
locale,
|
|
207
|
+
currencySymbol,
|
|
208
|
+
financials
|
|
177
209
|
}),
|
|
178
210
|
products,
|
|
179
211
|
fees: buildFees({
|
|
@@ -182,11 +214,14 @@ function buildLocaleData(params) {
|
|
|
182
214
|
locale,
|
|
183
215
|
products,
|
|
184
216
|
summary,
|
|
185
|
-
currencySymbol
|
|
217
|
+
currencySymbol,
|
|
218
|
+
financials
|
|
186
219
|
}),
|
|
187
220
|
customer: buildCustomer(order, locale),
|
|
188
221
|
appointment: buildAppointment(order, locale),
|
|
189
|
-
|
|
222
|
+
...(delivery.length ? {
|
|
223
|
+
delivery
|
|
224
|
+
} : {}),
|
|
190
225
|
resources: buildResources(order, locale),
|
|
191
226
|
payment_data: buildPaymentData({
|
|
192
227
|
order,
|
|
@@ -200,7 +235,11 @@ function buildLocaleData(params) {
|
|
|
200
235
|
}),
|
|
201
236
|
tickets: Array.isArray(order.tickets) ? order.tickets : [],
|
|
202
237
|
source_shop: [],
|
|
203
|
-
refund_data:
|
|
238
|
+
refund_data: buildRefundData({
|
|
239
|
+
order,
|
|
240
|
+
locale,
|
|
241
|
+
currencySymbol
|
|
242
|
+
}),
|
|
204
243
|
expend_data: []
|
|
205
244
|
};
|
|
206
245
|
}
|
|
@@ -208,7 +247,9 @@ function buildBaseData(params) {
|
|
|
208
247
|
const {
|
|
209
248
|
order,
|
|
210
249
|
shopInfo,
|
|
211
|
-
locale
|
|
250
|
+
locale,
|
|
251
|
+
currencySymbol,
|
|
252
|
+
financials
|
|
212
253
|
} = params;
|
|
213
254
|
const orderNumber = stringify(order.buzzer || order.shop_full_order_number);
|
|
214
255
|
return {
|
|
@@ -219,7 +260,13 @@ function buildBaseData(params) {
|
|
|
219
260
|
shop_tax_number: stringify(shopInfo.tax_number || order.shop_tax_number),
|
|
220
261
|
shop_phone: stringify(shopInfo.phone || order.shop_phone),
|
|
221
262
|
shop_address: stringify(shopInfo.receipt_address || shopInfo.address || buildShopAddress(shopInfo) || order.shop_address),
|
|
222
|
-
original_payment_status:
|
|
263
|
+
original_payment_status: financials.paymentStatus,
|
|
264
|
+
payment_status: financials.paymentStatus,
|
|
265
|
+
total_amount: formatMoney(financials.totalAmount, currencySymbol),
|
|
266
|
+
has_pay: formatMoney(financials.netPaymentApplied, currencySymbol),
|
|
267
|
+
...(isPresentId(financials.amountGap) ? {
|
|
268
|
+
amount_gap: formatMoney(financials.amountGap, currencySymbol)
|
|
269
|
+
} : {}),
|
|
223
270
|
is_repeat: 0,
|
|
224
271
|
buzzer: stringify(order.buzzer || order.pickup_number || order.metadata?.buzzer),
|
|
225
272
|
order_no: orderNumber,
|
|
@@ -269,11 +316,16 @@ function buildProducts(order, locale, productMap) {
|
|
|
269
316
|
quantity,
|
|
270
317
|
originalPrice
|
|
271
318
|
});
|
|
319
|
+
const productNote = resolveProductNote(product, locale);
|
|
320
|
+
const basePrice = resolveProductBasePrice(product);
|
|
272
321
|
return {
|
|
273
322
|
product_title: productTitle,
|
|
274
323
|
product_quantity: quantity,
|
|
275
324
|
selling_price: formatMoney(sellingPrice, currencySymbol),
|
|
276
325
|
original_price: formatMoney(originalPrice, currencySymbol),
|
|
326
|
+
...(isPresentId(basePrice) ? {
|
|
327
|
+
base_price: formatMoney(basePrice, currencySymbol)
|
|
328
|
+
} : {}),
|
|
277
329
|
total_original_price: formatMoney(new _decimal.default(toMoneyNumber(originalPrice)).mul(quantity), currencySymbol),
|
|
278
330
|
extension_list: extensionList,
|
|
279
331
|
...(isPresentId(productUid) ? {
|
|
@@ -282,20 +334,31 @@ function buildProducts(order, locale, productMap) {
|
|
|
282
334
|
...(isPresentId(bookingUid) ? {
|
|
283
335
|
booking_uid: bookingUid
|
|
284
336
|
} : {}),
|
|
337
|
+
...(productNote ? {
|
|
338
|
+
product_note: productNote
|
|
339
|
+
} : {}),
|
|
285
340
|
...(options.length ? {
|
|
286
341
|
options
|
|
287
342
|
} : {}),
|
|
288
343
|
...(resolvedVariant ? {
|
|
289
344
|
variant: resolvedVariant
|
|
290
345
|
} : {}),
|
|
291
|
-
...(Array.isArray(product.combinations) ? {
|
|
292
|
-
combinations: product.combinations
|
|
346
|
+
...(Array.isArray(product.combinations) && product.combinations.length ? {
|
|
347
|
+
combinations: normalizeExistingCombinations(product.combinations, locale)
|
|
293
348
|
} : combinations.length ? {
|
|
294
349
|
combinations
|
|
295
350
|
} : {})
|
|
296
351
|
};
|
|
297
352
|
});
|
|
298
353
|
}
|
|
354
|
+
function resolveProductBasePrice(product) {
|
|
355
|
+
const metadata = product.metadata || {};
|
|
356
|
+
const origin = product._origin || metadata.origin || {};
|
|
357
|
+
const variantId = product.product_variant_id ?? product.variant_id;
|
|
358
|
+
const variant = Array.isArray(origin.variant) && isPresentId(variantId) ? origin.variant.find(item => isSameId(item?.id, variantId)) : undefined;
|
|
359
|
+
const isV2 = metadata.price_schema_version === 2 || metadata.price_schema_version === '2';
|
|
360
|
+
return firstPresentValue(metadata.source_product_price, variant?.price, product._origin?.price, product._origin?.base_price, !isV2 ? metadata.main_product_original_price : undefined, product.base_price, product.price);
|
|
361
|
+
}
|
|
299
362
|
function normalizeProductDiscounts(params) {
|
|
300
363
|
const {
|
|
301
364
|
product,
|
|
@@ -463,15 +526,50 @@ function normalizeProductCombinations(params) {
|
|
|
463
526
|
locale,
|
|
464
527
|
parentProduct
|
|
465
528
|
});
|
|
466
|
-
const
|
|
529
|
+
const productNote = resolveProductNote(bundle, locale);
|
|
530
|
+
const nestedCombinations = Array.isArray(bundle.combinations) ? normalizeExistingCombinations(bundle.combinations, locale) : [];
|
|
467
531
|
return {
|
|
468
|
-
product_title:
|
|
532
|
+
product_title: baseTitle,
|
|
469
533
|
product_quantity: toNumber(bundle.num ?? bundle.quantity ?? 1, 1),
|
|
470
534
|
price: formatBundlePrice(bundle, currencySymbol),
|
|
471
|
-
combinations_options: combinationsOptions
|
|
535
|
+
combinations_options: combinationsOptions,
|
|
536
|
+
...(productNote ? {
|
|
537
|
+
product_note: productNote
|
|
538
|
+
} : {}),
|
|
539
|
+
...(nestedCombinations.length ? {
|
|
540
|
+
combinations: nestedCombinations
|
|
541
|
+
} : {})
|
|
542
|
+
};
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
function normalizeExistingCombinations(combinations, locale) {
|
|
546
|
+
return combinations.map(combination => {
|
|
547
|
+
if (!combination || typeof combination !== 'object' || Array.isArray(combination)) {
|
|
548
|
+
return combination;
|
|
549
|
+
}
|
|
550
|
+
const productNote = resolveProductNote(combination, locale);
|
|
551
|
+
const nestedCombinations = Array.isArray(combination.combinations) ? normalizeExistingCombinations(combination.combinations, locale) : undefined;
|
|
552
|
+
const snapshot = {
|
|
553
|
+
...combination
|
|
554
|
+
};
|
|
555
|
+
delete snapshot.product_note;
|
|
556
|
+
delete snapshot.note;
|
|
557
|
+
return {
|
|
558
|
+
...snapshot,
|
|
559
|
+
...(productNote ? {
|
|
560
|
+
product_note: productNote
|
|
561
|
+
} : {}),
|
|
562
|
+
...(nestedCombinations ? {
|
|
563
|
+
combinations: nestedCombinations
|
|
564
|
+
} : {})
|
|
472
565
|
};
|
|
473
566
|
});
|
|
474
567
|
}
|
|
568
|
+
function resolveProductNote(product, locale) {
|
|
569
|
+
const productNote = getLocalizedValue(product.product_note, locale).trim();
|
|
570
|
+
if (productNote) return productNote;
|
|
571
|
+
return getLocalizedValue(product.note, locale).trim();
|
|
572
|
+
}
|
|
475
573
|
function resolveBundleProductTitle(params) {
|
|
476
574
|
const {
|
|
477
575
|
bundle,
|
|
@@ -654,15 +752,6 @@ function isSameId(left, right) {
|
|
|
654
752
|
if (!isPresentId(left) || !isPresentId(right)) return false;
|
|
655
753
|
return String(left) === String(right);
|
|
656
754
|
}
|
|
657
|
-
function buildOptionTitleSuffix(options) {
|
|
658
|
-
const text = options.map(option => {
|
|
659
|
-
const name = stringify(option.name).trim();
|
|
660
|
-
if (!name) return '';
|
|
661
|
-
const quantity = option.num ?? 1;
|
|
662
|
-
return `${name} x ${quantity}`;
|
|
663
|
-
}).filter(Boolean).join(', ');
|
|
664
|
-
return text ? `(${text})` : '';
|
|
665
|
-
}
|
|
666
755
|
function formatBundlePrice(bundle, currencySymbol) {
|
|
667
756
|
const value = bundle.bundle_selling_price ?? bundle.bundle_sum_price ?? bundle.price ?? 0;
|
|
668
757
|
const amount = new _decimal.default(toMoneyNumber(value));
|
|
@@ -678,7 +767,8 @@ function buildFees(params) {
|
|
|
678
767
|
locale,
|
|
679
768
|
products,
|
|
680
769
|
summary,
|
|
681
|
-
currencySymbol
|
|
770
|
+
currencySymbol,
|
|
771
|
+
financials
|
|
682
772
|
} = params;
|
|
683
773
|
const fees = [];
|
|
684
774
|
for (const surcharge of normalizeArray(order.surcharges || summary.surcharges)) {
|
|
@@ -689,64 +779,101 @@ function buildFees(params) {
|
|
|
689
779
|
value: formatMoney(value, currencySymbol)
|
|
690
780
|
});
|
|
691
781
|
}
|
|
692
|
-
const discountAmount = order.shop_discount
|
|
782
|
+
const discountAmount = firstPresentValue(order.shop_discount, summary.discount_amount, order.discount_amount);
|
|
693
783
|
if (isNonZero(discountAmount)) {
|
|
694
784
|
fees.push({
|
|
695
785
|
item: label(locale, 'orderDiscount'),
|
|
696
786
|
value: formatNegativeMoney(discountAmount, currencySymbol)
|
|
697
787
|
});
|
|
698
788
|
}
|
|
699
|
-
const taxFee = summary.tax_fee
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
}
|
|
706
|
-
const
|
|
789
|
+
const taxFee = firstPresentValue(summary.tax_fee, order.tax_fee);
|
|
790
|
+
const taxTitle = resolveTaxTitle({
|
|
791
|
+
summary,
|
|
792
|
+
order,
|
|
793
|
+
shopInfo,
|
|
794
|
+
locale
|
|
795
|
+
});
|
|
796
|
+
const isPriceIncludeTax = firstPresentValue(summary.is_price_include_tax, order.is_price_include_tax, shopInfo.is_price_include_tax);
|
|
797
|
+
const roundingAmount = firstPresentValue(summary.rounding_amount, order.rounding_amount);
|
|
707
798
|
if (isNonZero(roundingAmount)) {
|
|
708
799
|
fees.push({
|
|
709
800
|
item: label(locale, 'rounding'),
|
|
710
801
|
value: formatMoney(roundingAmount, currencySymbol)
|
|
711
802
|
});
|
|
712
803
|
}
|
|
713
|
-
const payProcessingFee =
|
|
804
|
+
const payProcessingFee = financials.payProcessingFee;
|
|
714
805
|
if (isNonZero(payProcessingFee)) {
|
|
715
806
|
fees.push({
|
|
716
807
|
item: label(locale, 'payProcessingFee'),
|
|
717
808
|
value: formatMoney(payProcessingFee, currencySymbol)
|
|
718
809
|
});
|
|
719
810
|
}
|
|
720
|
-
const productExpectAmount = summary.product_expect_amount
|
|
811
|
+
const productExpectAmount = firstPresentValue(summary.product_expect_amount, summary.product_amount, order.product_expect_amount);
|
|
721
812
|
const productOriginalAmount = firstPresentValue(summary.product_original_amount, order.product_original_amount) ?? calculateProductOriginalAmount(order);
|
|
722
813
|
const totalSavingsAmount = new _decimal.default(toMoneyNumber(productOriginalAmount)).minus(toMoneyNumber(productExpectAmount)).plus(toMoneyNumber(discountAmount));
|
|
723
814
|
return {
|
|
724
815
|
fees,
|
|
725
816
|
countFee: {
|
|
726
|
-
total_amount: formatMoney(summary.total_amount
|
|
817
|
+
total_amount: formatMoney(firstPresentValue(summary.total_amount, order.total_amount) ?? 0, currencySymbol),
|
|
727
818
|
original_item_amount: formatMoney(productOriginalAmount, currencySymbol),
|
|
728
|
-
product_expect_amount: formatMoney(productExpectAmount, currencySymbol),
|
|
729
|
-
expect_amount: formatMoney(
|
|
730
|
-
product_quantity: toNumber(summary.product_quantity
|
|
731
|
-
has_pay: formatMoney(
|
|
819
|
+
product_expect_amount: formatMoney(productExpectAmount ?? 0, currencySymbol),
|
|
820
|
+
expect_amount: formatMoney(financials.totalAmount, currencySymbol),
|
|
821
|
+
product_quantity: toNumber(firstPresentValue(summary.product_quantity, products.reduce((sum, product) => sum + product.product_quantity, 0)), 0),
|
|
822
|
+
has_pay: formatMoney(financials.orderPaidAmount, currencySymbol),
|
|
732
823
|
payment_method: '',
|
|
733
|
-
tax_title:
|
|
734
|
-
total_refund_amount: formatMoney(
|
|
735
|
-
|
|
824
|
+
tax_title: taxTitle,
|
|
825
|
+
total_refund_amount: formatMoney(financials.totalRefundAmount, currencySymbol),
|
|
826
|
+
customer_paid_amount: formatMoney(financials.customerPaidAmount, currencySymbol),
|
|
827
|
+
net_payment_applied: formatMoney(financials.netPaymentApplied, currencySymbol),
|
|
828
|
+
...(isPresentId(roundingAmount) ? {
|
|
736
829
|
rounding_amount: formatMoney(roundingAmount, currencySymbol)
|
|
737
830
|
} : {}),
|
|
738
831
|
...(isNonZero(totalSavingsAmount) ? {
|
|
739
832
|
order_total_discount: formatMoney(totalSavingsAmount, currencySymbol)
|
|
740
833
|
} : {}),
|
|
741
|
-
...(
|
|
834
|
+
...(financials.hasPayProcessingFee ? {
|
|
742
835
|
pay_processing_fee: formatMoney(payProcessingFee, currencySymbol)
|
|
743
836
|
} : {}),
|
|
744
|
-
...(
|
|
837
|
+
...(isPresentId(taxFee) ? {
|
|
745
838
|
tax_fee: formatMoney(taxFee, currencySymbol)
|
|
839
|
+
} : {}),
|
|
840
|
+
...(isPresentId(isPriceIncludeTax) ? {
|
|
841
|
+
is_price_include_tax: normalizeBooleanFlag(isPriceIncludeTax)
|
|
746
842
|
} : {})
|
|
747
843
|
}
|
|
748
844
|
};
|
|
749
845
|
}
|
|
846
|
+
function resolveReceiptFinancials(order, summary) {
|
|
847
|
+
const totalAmount = firstPresentValue(summary.expect_amount, order.expect_amount, summary.total_amount, order.total_amount) ?? 0;
|
|
848
|
+
const rawPayProcessingFee = firstPresentValue(summary.pay_service_charge_amount, order.pay_service_charge_amount);
|
|
849
|
+
const payProcessingFee = rawPayProcessingFee ?? 0;
|
|
850
|
+
const orderPaidAmount = firstPresentValue(summary.order_paid_amount, order.order_paid_amount, sumAppliedPayments(order.payments)) ?? 0;
|
|
851
|
+
const totalRefundAmount = firstPresentValue(summary.total_refund_amount, order.total_refund_amount) ?? 0;
|
|
852
|
+
const netPaymentApplied = _decimal.default.max(new _decimal.default(toMoneyNumber(orderPaidAmount)).minus(toMoneyNumber(totalRefundAmount)), 0);
|
|
853
|
+
const fallbackCustomerPaidAmount = _decimal.default.max(sumCustomerPaidPayments(order.payments), new _decimal.default(toMoneyNumber(orderPaidAmount)).plus(toMoneyNumber(payProcessingFee)));
|
|
854
|
+
const customerPaidAmount = firstPresentValue(summary.customer_paid_amount, order.customer_paid_amount, fallbackCustomerPaidAmount) ?? 0;
|
|
855
|
+
const amountGap = firstPresentValue(summary.amount_gap, order.amount_gap);
|
|
856
|
+
return {
|
|
857
|
+
totalAmount,
|
|
858
|
+
orderPaidAmount,
|
|
859
|
+
payProcessingFee,
|
|
860
|
+
customerPaidAmount,
|
|
861
|
+
totalRefundAmount,
|
|
862
|
+
netPaymentApplied,
|
|
863
|
+
amountGap,
|
|
864
|
+
paymentStatus: resolveReceiptPaymentStatus({
|
|
865
|
+
order,
|
|
866
|
+
summary
|
|
867
|
+
}),
|
|
868
|
+
hasPayProcessingFee: isPresentId(rawPayProcessingFee)
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
function resolveReceiptPaymentStatus(params) {
|
|
872
|
+
return [params.order.payment_status, params.summary.payment_status, params.order.original_payment_status].map(status => stringify(status).trim()).find(Boolean) || '';
|
|
873
|
+
}
|
|
874
|
+
function resolveTaxTitle(params) {
|
|
875
|
+
return [params.summary.tax_title, params.order.tax_title, params.shopInfo.tax_title].map(title => getLocalizedValue(title, params.locale).trim()).find(Boolean) || 'Tax';
|
|
876
|
+
}
|
|
750
877
|
function calculateProductOriginalAmount(order) {
|
|
751
878
|
return normalizeArray(order.products).reduce((total, product) => {
|
|
752
879
|
const quantity = toNumber(product.product_quantity ?? product.quantity ?? product.num ?? 1, 1);
|
|
@@ -773,25 +900,27 @@ function normalizeCustomerDisplayValue(value) {
|
|
|
773
900
|
return text;
|
|
774
901
|
}
|
|
775
902
|
function buildDelivery(order, locale) {
|
|
776
|
-
const
|
|
777
|
-
|
|
778
|
-
const serviceTypeLabelKey =
|
|
903
|
+
const deliveryType = stringify(order.delivery_type).trim();
|
|
904
|
+
const serviceType = deliveryType || stringify(firstPresentValue(order.metadata?.service_type, order.service_type)).trim();
|
|
905
|
+
const serviceTypeLabelKey = resolveServiceTypeLabelKey(serviceType, order);
|
|
906
|
+
if (!serviceTypeLabelKey) return [];
|
|
779
907
|
const items = [{
|
|
780
908
|
item: '',
|
|
781
909
|
value: label(locale, serviceTypeLabelKey),
|
|
782
910
|
size: 2,
|
|
783
911
|
align: 'left'
|
|
784
912
|
}];
|
|
785
|
-
|
|
913
|
+
const handoverTime = firstPresentValue(order.handover_time, order.handover_at, order.pickup_time, order.pickup_at, order.scheduled_pickup_time, order.delivery_time, order.delivery_at, order.scheduled_delivery_time, order.fulfillment_time, order.fulfillment_at, order.metadata?.handover_time, order.metadata?.handover_at, order.metadata?.pickup_time, order.metadata?.pickup_at, order.metadata?.scheduled_pickup_time, order.metadata?.delivery_time, order.metadata?.delivery_at, order.metadata?.scheduled_delivery_time, order.metadata?.fulfillment_time, order.metadata?.fulfillment_at);
|
|
914
|
+
if (isPresentId(handoverTime)) {
|
|
786
915
|
items.push({
|
|
787
|
-
item: label(locale, '
|
|
788
|
-
value:
|
|
916
|
+
item: label(locale, 'handoverTime'),
|
|
917
|
+
value: formatDateTime(handoverTime, locale)
|
|
789
918
|
});
|
|
790
919
|
}
|
|
791
920
|
return items;
|
|
792
921
|
}
|
|
793
922
|
function buildAppointment(order, locale) {
|
|
794
|
-
const bookings = normalizeArray(order.bookings);
|
|
923
|
+
const bookings = sortBookings(normalizeArray(order.bookings));
|
|
795
924
|
if (bookings.length) {
|
|
796
925
|
return bookings.map(booking => {
|
|
797
926
|
const snapshot = {
|
|
@@ -819,6 +948,43 @@ function buildAppointment(order, locale) {
|
|
|
819
948
|
value: getLocalizedValue(tableName, locale)
|
|
820
949
|
}];
|
|
821
950
|
}
|
|
951
|
+
function sortBookings(bookings) {
|
|
952
|
+
return bookings.map((booking, index) => ({
|
|
953
|
+
booking,
|
|
954
|
+
index
|
|
955
|
+
})).sort((left, right) => {
|
|
956
|
+
const leftStart = bookingStartTimestamp(left.booking);
|
|
957
|
+
const rightStart = bookingStartTimestamp(right.booking);
|
|
958
|
+
if (leftStart !== rightStart) return leftStart < rightStart ? -1 : 1;
|
|
959
|
+
for (const field of ['booking_id', 'schedule_event_id']) {
|
|
960
|
+
const fieldOrder = compareOptionalValues(left.booking?.[field], right.booking?.[field]);
|
|
961
|
+
if (fieldOrder !== 0) return fieldOrder;
|
|
962
|
+
}
|
|
963
|
+
const bookingUidOrder = compareOptionalValues(firstPresentValue(left.booking?.metadata?.unique_identification_number, left.booking?.booking_uid), firstPresentValue(right.booking?.metadata?.unique_identification_number, right.booking?.booking_uid));
|
|
964
|
+
return bookingUidOrder || left.index - right.index;
|
|
965
|
+
}).map(({
|
|
966
|
+
booking
|
|
967
|
+
}) => booking);
|
|
968
|
+
}
|
|
969
|
+
function bookingStartTimestamp(booking) {
|
|
970
|
+
const startValues = [booking?.start_at, booking?.start_datetime, booking?.booking_time, isPresentId(booking?.start_date) ? `${booking.start_date} ${stringify(booking.start_time)}`.trim() : undefined];
|
|
971
|
+
for (const startValue of startValues) {
|
|
972
|
+
if (!isPresentId(startValue)) continue;
|
|
973
|
+
const timestamp = (0, _dayjs.default)(startValue).valueOf();
|
|
974
|
+
if (Number.isFinite(timestamp)) return timestamp;
|
|
975
|
+
}
|
|
976
|
+
return Number.POSITIVE_INFINITY;
|
|
977
|
+
}
|
|
978
|
+
function compareOptionalValues(left, right) {
|
|
979
|
+
const hasLeft = isPresentId(left);
|
|
980
|
+
const hasRight = isPresentId(right);
|
|
981
|
+
if (!hasLeft && !hasRight) return 0;
|
|
982
|
+
if (!hasLeft) return 1;
|
|
983
|
+
if (!hasRight) return -1;
|
|
984
|
+
return String(left).localeCompare(String(right), undefined, {
|
|
985
|
+
numeric: true
|
|
986
|
+
});
|
|
987
|
+
}
|
|
822
988
|
function buildResources(order, locale) {
|
|
823
989
|
return normalizeArray(order.resources || order.resource_list).map(resource => ({
|
|
824
990
|
id: resource.id || resource.resource_id || '',
|
|
@@ -836,13 +1002,151 @@ function buildPaymentData(params) {
|
|
|
836
1002
|
includeFundRecordBalance: false
|
|
837
1003
|
}));
|
|
838
1004
|
}
|
|
1005
|
+
function buildRefundData(params) {
|
|
1006
|
+
const payments = normalizeArray(params.order.payments);
|
|
1007
|
+
const refunds = Array.from(normalizeArray(params.order.refunds).reduce((result, refund, index) => {
|
|
1008
|
+
const identity = refundIdentity(refund, index);
|
|
1009
|
+
const candidate = {
|
|
1010
|
+
refund,
|
|
1011
|
+
index
|
|
1012
|
+
};
|
|
1013
|
+
const existing = result.get(identity);
|
|
1014
|
+
if (!existing || shouldPreferRefundCandidate(candidate, existing)) {
|
|
1015
|
+
result.set(identity, candidate);
|
|
1016
|
+
}
|
|
1017
|
+
return result;
|
|
1018
|
+
}, new Map()).values()).filter(({
|
|
1019
|
+
refund
|
|
1020
|
+
}) => isPrintableRefund(refund)).sort((left, right) => {
|
|
1021
|
+
const leftTime = refundTimestamp(left.refund);
|
|
1022
|
+
const rightTime = refundTimestamp(right.refund);
|
|
1023
|
+
if (leftTime !== rightTime) return leftTime < rightTime ? -1 : 1;
|
|
1024
|
+
return left.index - right.index;
|
|
1025
|
+
});
|
|
1026
|
+
return refunds.map(({
|
|
1027
|
+
refund
|
|
1028
|
+
}) => {
|
|
1029
|
+
const payment = resolveRefundPayment(refund, payments);
|
|
1030
|
+
const methodName = paymentMethodName(payment, params.locale) || label(params.locale, 'refund');
|
|
1031
|
+
const amount = firstPresentValue(refund.amount, refund.refund_amount, refund.total_amount) ?? 0;
|
|
1032
|
+
const items = [{
|
|
1033
|
+
item: methodName,
|
|
1034
|
+
value: formatNegativeMoney(amount, params.currencySymbol)
|
|
1035
|
+
}];
|
|
1036
|
+
const occurredAt = firstPresentValue(refund.refund_time, refund.refunded_at, refund.created_at, refund.updated_at);
|
|
1037
|
+
if (isPresentId(occurredAt)) {
|
|
1038
|
+
items.push({
|
|
1039
|
+
item: formatDateTime(occurredAt, params.locale),
|
|
1040
|
+
value: ''
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
return items;
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
function refundIdentity(refund, index) {
|
|
1047
|
+
if (isPresentId(refund.order_refund_id)) return `refund-id:${refund.order_refund_id}`;
|
|
1048
|
+
if (isPresentId(refund.refund_number)) return `refund-number:${refund.refund_number}`;
|
|
1049
|
+
return `refund-index:${index}`;
|
|
1050
|
+
}
|
|
1051
|
+
function shouldPreferRefundCandidate(candidate, existing) {
|
|
1052
|
+
const candidatePrintable = isPrintableRefund(candidate.refund);
|
|
1053
|
+
const existingPrintable = isPrintableRefund(existing.refund);
|
|
1054
|
+
if (candidatePrintable !== existingPrintable) return candidatePrintable;
|
|
1055
|
+
const candidateTime = refundFreshnessTimestamp(candidate.refund);
|
|
1056
|
+
const existingTime = refundFreshnessTimestamp(existing.refund);
|
|
1057
|
+
if (candidateTime !== existingTime) return candidateTime > existingTime;
|
|
1058
|
+
return candidate.index > existing.index;
|
|
1059
|
+
}
|
|
1060
|
+
function refundFreshnessTimestamp(refund) {
|
|
1061
|
+
const timestampValue = firstPresentValue(refund.updated_at, refund.refunded_at, refund.refund_time, refund.created_at);
|
|
1062
|
+
if (!isPresentId(timestampValue)) return Number.NEGATIVE_INFINITY;
|
|
1063
|
+
const timestamp = (0, _dayjs.default)(timestampValue).valueOf();
|
|
1064
|
+
return Number.isFinite(timestamp) ? timestamp : Number.NEGATIVE_INFINITY;
|
|
1065
|
+
}
|
|
1066
|
+
function refundTimestamp(refund) {
|
|
1067
|
+
const occurredAt = firstPresentValue(refund.refund_time, refund.refunded_at, refund.created_at, refund.updated_at);
|
|
1068
|
+
if (!isPresentId(occurredAt)) return Number.POSITIVE_INFINITY;
|
|
1069
|
+
const timestamp = (0, _dayjs.default)(occurredAt).valueOf();
|
|
1070
|
+
return Number.isFinite(timestamp) ? timestamp : Number.POSITIVE_INFINITY;
|
|
1071
|
+
}
|
|
1072
|
+
function isPrintableRefund(refund) {
|
|
1073
|
+
const status = stringify(refund.status).trim().toLowerCase();
|
|
1074
|
+
if (!status) return true;
|
|
1075
|
+
return !['pending', 'payment_pending', 'payment_processing', 'refund_processing', 'processing', 'failed', 'error', 'cancelled', 'canceled', 'voided'].includes(status);
|
|
1076
|
+
}
|
|
1077
|
+
function resolveRefundPayment(refund, payments) {
|
|
1078
|
+
if (refund.payment && typeof refund.payment === 'object' && !Array.isArray(refund.payment)) {
|
|
1079
|
+
return refund.payment;
|
|
1080
|
+
}
|
|
1081
|
+
const orderPaymentId = firstPresentValue(refund.order_payment_id, refund.payment_id);
|
|
1082
|
+
const matchedPayment = payments.find(payment => isSameId(firstPresentValue(payment.order_payment_id, payment.id), orderPaymentId));
|
|
1083
|
+
return matchedPayment || refund;
|
|
1084
|
+
}
|
|
839
1085
|
function buildWallets(params) {
|
|
840
|
-
|
|
1086
|
+
const paymentWallets = normalizeArray(params.order.payments).filter(payment => isPrintablePayment(payment) && !!getFundRecord(payment)).map(payment => buildPaymentItems({
|
|
841
1087
|
payment,
|
|
842
1088
|
locale: params.locale,
|
|
843
1089
|
currencySymbol: params.currencySymbol,
|
|
844
1090
|
includeFundRecordBalance: true
|
|
845
1091
|
}));
|
|
1092
|
+
return [...paymentWallets, ...buildVoucherAssets(params)];
|
|
1093
|
+
}
|
|
1094
|
+
function buildVoucherAssets(params) {
|
|
1095
|
+
const seenVoucherKeys = new Set();
|
|
1096
|
+
return normalizeArray(params.order.vouchers).flatMap((voucher, index) => {
|
|
1097
|
+
if (!voucher || typeof voucher !== 'object' || Array.isArray(voucher)) return [];
|
|
1098
|
+
const voucherKey = getVoucherAssetKey(voucher, index);
|
|
1099
|
+
if (seenVoucherKeys.has(voucherKey)) return [];
|
|
1100
|
+
seenVoucherKeys.add(voucherKey);
|
|
1101
|
+
const name = getVoucherAssetName(voucher, params.locale);
|
|
1102
|
+
const percent = getVoucherDiscountPercent(voucher);
|
|
1103
|
+
if (percent) {
|
|
1104
|
+
return [[{
|
|
1105
|
+
item: appendPercentToVoucherName(name, percent),
|
|
1106
|
+
value: formatVoucherDiscount(percent, params.locale)
|
|
1107
|
+
}]];
|
|
1108
|
+
}
|
|
1109
|
+
const balance = getVoucherBalance(voucher);
|
|
1110
|
+
return [[{
|
|
1111
|
+
item: name,
|
|
1112
|
+
value: ''
|
|
1113
|
+
}, {
|
|
1114
|
+
item: label(params.locale, 'balance'),
|
|
1115
|
+
value: formatMoney(balance, params.currencySymbol)
|
|
1116
|
+
}]];
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
function getVoucherAssetKey(voucher, index) {
|
|
1120
|
+
const identity = firstPresentValue(voucher.voucher_id, voucher.id, voucher.code, voucher.encoded);
|
|
1121
|
+
return identity === undefined ? `voucher-index:${index}` : `voucher:${String(identity)}`;
|
|
1122
|
+
}
|
|
1123
|
+
function getVoucherAssetName(voucher, locale) {
|
|
1124
|
+
return getLocalizedValue(voucher.product_name || voucher.name || voucher.title, locale) || stringify(voucher.encoded || voucher.code || label(locale, 'giftCard'));
|
|
1125
|
+
}
|
|
1126
|
+
function getVoucherDiscountPercent(voucher) {
|
|
1127
|
+
const discountType = stringify(voucher.metadata?.discount_card_type || voucher.discount_card_type).toLowerCase();
|
|
1128
|
+
if (discountType !== 'percent' && discountType !== 'percentage') return null;
|
|
1129
|
+
const percent = new _decimal.default(toMoneyNumber(voucher.par_value));
|
|
1130
|
+
if (!percent.isFinite() || percent.lte(0) || percent.gt(100)) return null;
|
|
1131
|
+
return percent;
|
|
1132
|
+
}
|
|
1133
|
+
function appendPercentToVoucherName(name, percent) {
|
|
1134
|
+
if (/\d+(?:\.\d+)?\s*(?:%|折)|\boff\b/i.test(name)) return name;
|
|
1135
|
+
const separator = /^[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}]/u.test(name) ? '' : ' ';
|
|
1136
|
+
return `${trimDecimal(percent)}%${separator}${name}`;
|
|
1137
|
+
}
|
|
1138
|
+
function formatVoucherDiscount(percent, locale) {
|
|
1139
|
+
const normalizedLocale = normalizeLocaleKey(locale);
|
|
1140
|
+
if (normalizedLocale === 'zh_CN' || normalizedLocale === 'zh_HK') {
|
|
1141
|
+
return `${trimDecimal(percent)}% OFF`;
|
|
1142
|
+
}
|
|
1143
|
+
if (normalizedLocale === 'pt') return `Desconto ${trimDecimal(percent)}%`;
|
|
1144
|
+
return normalizedLocale === 'en' ? `Discount ${trimDecimal(percent)}% OFF` : `${trimDecimal(percent)}% OFF`;
|
|
1145
|
+
}
|
|
1146
|
+
function getVoucherBalance(voucher) {
|
|
1147
|
+
const parValue = new _decimal.default(toMoneyNumber(voucher.par_value));
|
|
1148
|
+
const usedParValue = new _decimal.default(toMoneyNumber(voucher.used_par_value));
|
|
1149
|
+
return _decimal.default.max(parValue.minus(usedParValue), 0);
|
|
846
1150
|
}
|
|
847
1151
|
function buildPaymentItems(params) {
|
|
848
1152
|
const {
|
|
@@ -851,10 +1155,22 @@ function buildPaymentItems(params) {
|
|
|
851
1155
|
currencySymbol,
|
|
852
1156
|
includeFundRecordBalance
|
|
853
1157
|
} = params;
|
|
1158
|
+
const serviceFee = getPaymentServiceFee(payment);
|
|
854
1159
|
const items = [{
|
|
855
1160
|
item: paymentMethodName(payment, locale),
|
|
856
|
-
value: formatMoney(payment
|
|
1161
|
+
value: formatMoney(resolveReceiptPaymentAmount(payment, serviceFee), currencySymbol)
|
|
857
1162
|
}];
|
|
1163
|
+
items.push(...buildCashChangePaymentItems({
|
|
1164
|
+
payment,
|
|
1165
|
+
locale,
|
|
1166
|
+
currencySymbol
|
|
1167
|
+
}));
|
|
1168
|
+
if (serviceFee.gt(0)) {
|
|
1169
|
+
items.push({
|
|
1170
|
+
item: label(locale, 'surchargeIncluded'),
|
|
1171
|
+
value: formatMoney(serviceFee, currencySymbol)
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
858
1174
|
const fundRecord = getFundRecord(payment);
|
|
859
1175
|
if (fundRecord) {
|
|
860
1176
|
items.push(...buildFundRecordPaymentItems({
|
|
@@ -879,6 +1195,47 @@ function buildPaymentItems(params) {
|
|
|
879
1195
|
});
|
|
880
1196
|
return items;
|
|
881
1197
|
}
|
|
1198
|
+
function getPaymentServiceFee(payment) {
|
|
1199
|
+
return new _decimal.default(toMoneyNumber(payment.service_fee));
|
|
1200
|
+
}
|
|
1201
|
+
function resolveReceiptPaymentAmount(payment, serviceFee) {
|
|
1202
|
+
const amount = new _decimal.default(toMoneyNumber(payment.amount ?? payment.origin_amount));
|
|
1203
|
+
const hasAmount = payment.amount !== undefined && payment.amount !== null && payment.amount !== '';
|
|
1204
|
+
const hasOriginAmount = payment.origin_amount !== undefined && payment.origin_amount !== null && payment.origin_amount !== '';
|
|
1205
|
+
if (!hasAmount || !hasOriginAmount || serviceFee.lte(0)) return amount;
|
|
1206
|
+
const originAmount = new _decimal.default(toMoneyNumber(payment.origin_amount));
|
|
1207
|
+
return amount.eq(originAmount) ? amount.plus(serviceFee) : amount;
|
|
1208
|
+
}
|
|
1209
|
+
function buildCashChangePaymentItems(params) {
|
|
1210
|
+
const {
|
|
1211
|
+
payment,
|
|
1212
|
+
locale,
|
|
1213
|
+
currencySymbol
|
|
1214
|
+
} = params;
|
|
1215
|
+
if (!shouldDisplayCashChange(payment)) return [];
|
|
1216
|
+
return [{
|
|
1217
|
+
item: label(locale, 'cashReceived'),
|
|
1218
|
+
value: formatMoney(payment.metadata.actual_paid_amount, currencySymbol)
|
|
1219
|
+
}, {
|
|
1220
|
+
item: label(locale, 'changeDue'),
|
|
1221
|
+
value: formatMoney(payment.metadata.change_given_amount, currencySymbol)
|
|
1222
|
+
}];
|
|
1223
|
+
}
|
|
1224
|
+
function shouldDisplayCashChange(payment) {
|
|
1225
|
+
if (stringify(payment.status).toLowerCase() !== 'paid') return false;
|
|
1226
|
+
const paymentMethod = stringify(payment.code ?? payment.payment_method).toUpperCase();
|
|
1227
|
+
if (paymentMethod !== 'CASHMANUAL') return false;
|
|
1228
|
+
const actualPaidAmount = payment.metadata?.actual_paid_amount;
|
|
1229
|
+
const changeGivenAmount = payment.metadata?.change_given_amount;
|
|
1230
|
+
if (!isNumericAmount(actualPaidAmount) || !isNumericAmount(changeGivenAmount)) return false;
|
|
1231
|
+
return new _decimal.default(changeGivenAmount).toDecimalPlaces(2).gt(0);
|
|
1232
|
+
}
|
|
1233
|
+
function isNumericAmount(value) {
|
|
1234
|
+
if (typeof value === 'number') return Number.isFinite(value);
|
|
1235
|
+
if (typeof value !== 'string') return false;
|
|
1236
|
+
const normalized = value.trim();
|
|
1237
|
+
return normalized !== '' && /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i.test(normalized);
|
|
1238
|
+
}
|
|
882
1239
|
function buildFundRecordPaymentItems(params) {
|
|
883
1240
|
const {
|
|
884
1241
|
payment,
|
|
@@ -981,13 +1338,29 @@ function getLocalizedValue(value, locale) {
|
|
|
981
1338
|
const underscoredLocale = locale.replace('-', '_');
|
|
982
1339
|
return stringify(value[locale] ?? value[dashedLocale] ?? value[underscoredLocale] ?? value.original ?? value.auto ?? value.default ?? value.en ?? '');
|
|
983
1340
|
}
|
|
984
|
-
function
|
|
985
|
-
const normalized = serviceType.toLowerCase();
|
|
986
|
-
if (
|
|
987
|
-
if (
|
|
988
|
-
if (
|
|
989
|
-
if (
|
|
990
|
-
return 'dineIn';
|
|
1341
|
+
function resolveServiceTypeLabelKey(serviceType, order) {
|
|
1342
|
+
const normalized = serviceType.trim().toLowerCase().replace(/[\s-]+/g, '_');
|
|
1343
|
+
if (['', 'nil', 'none', 'unknown'].includes(normalized)) return null;
|
|
1344
|
+
if (['pickup', 'pick_up', 'self_pickup'].includes(normalized)) return 'pickUp';
|
|
1345
|
+
if (['delivery', 'shipping', 'local_delivery'].includes(normalized)) return 'delivery';
|
|
1346
|
+
if (['takeaway', 'take_away'].includes(normalized)) return 'takeAway';
|
|
1347
|
+
if (['dine_in', 'dinein'].includes(normalized)) return 'dineIn';
|
|
1348
|
+
if (['shop_service', 'shop_server'].includes(normalized)) {
|
|
1349
|
+
return resolveShopServiceLabelKey(order);
|
|
1350
|
+
}
|
|
1351
|
+
return null;
|
|
1352
|
+
}
|
|
1353
|
+
function resolveShopServiceLabelKey(order) {
|
|
1354
|
+
const rawShopServiceType = firstPresentValue(order.metadata?.shop_service_type?.server_type, order.shop_service_type?.server_type, typeof order.shop_service_type === 'string' ? order.shop_service_type : undefined);
|
|
1355
|
+
if (!isPresentId(rawShopServiceType)) return 'dineIn';
|
|
1356
|
+
const normalized = stringify(rawShopServiceType).trim().toLowerCase().replace(/[\s-]+/g, '_');
|
|
1357
|
+
if (['takeaway', 'take_away'].includes(normalized)) return 'takeAway';
|
|
1358
|
+
if (['dine_in', 'dinein'].includes(normalized)) return 'dineIn';
|
|
1359
|
+
return null;
|
|
1360
|
+
}
|
|
1361
|
+
function normalizeBooleanFlag(value) {
|
|
1362
|
+
if (value === true || value === 1 || stringify(value).trim() === '1') return 1;
|
|
1363
|
+
return 0;
|
|
991
1364
|
}
|
|
992
1365
|
function buildShopAddress(shopInfo) {
|
|
993
1366
|
return [shopInfo.address_street, shopInfo.address_detail, shopInfo.city, shopInfo.province, shopInfo.country, shopInfo.zip].filter(Boolean).join(', ');
|
|
@@ -1008,17 +1381,17 @@ function formatNegativeMoney(value, currencySymbol) {
|
|
|
1008
1381
|
const amount = new _decimal.default(toMoneyNumber(value)).abs();
|
|
1009
1382
|
return `-${currencySymbol}${amount.toFixed(2)}`;
|
|
1010
1383
|
}
|
|
1011
|
-
function
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
}
|
|
1021
|
-
function
|
|
1384
|
+
function sumAppliedPayments(payments) {
|
|
1385
|
+
return normalizeArray(payments).filter(payment => isPrintablePayment(payment)).reduce((sum, payment) => {
|
|
1386
|
+
if (isPresentId(payment.origin_amount)) {
|
|
1387
|
+
return sum.plus(toMoneyNumber(payment.origin_amount));
|
|
1388
|
+
}
|
|
1389
|
+
const amount = new _decimal.default(toMoneyNumber(payment.amount));
|
|
1390
|
+
const serviceFee = _decimal.default.max(toMoneyNumber(payment.service_fee), 0);
|
|
1391
|
+
return sum.plus(_decimal.default.max(amount.minus(serviceFee), 0));
|
|
1392
|
+
}, new _decimal.default(0));
|
|
1393
|
+
}
|
|
1394
|
+
function sumCustomerPaidPayments(payments) {
|
|
1022
1395
|
return normalizeArray(payments).filter(payment => isPrintablePayment(payment)).reduce((sum, payment) => {
|
|
1023
1396
|
return sum.plus(toMoneyNumber(payment.amount ?? payment.origin_amount));
|
|
1024
1397
|
}, new _decimal.default(0));
|
|
@@ -1026,7 +1399,7 @@ function sumPayments(payments) {
|
|
|
1026
1399
|
function isPrintablePayment(payment) {
|
|
1027
1400
|
const status = stringify(payment.status).toLowerCase();
|
|
1028
1401
|
if (!status) return true;
|
|
1029
|
-
return ['paid', 'success', 'succeeded', 'completed'].includes(status);
|
|
1402
|
+
return ['paid', 'success', 'succeeded', 'completed', 'partially_refunded', 'refunded'].includes(status);
|
|
1030
1403
|
}
|
|
1031
1404
|
function normalizeArray(value) {
|
|
1032
1405
|
return Array.isArray(value) ? value : [];
|