@pisell/pisellos 0.10.28 → 0.10.30

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