@pisell/pisellos 0.10.56 → 0.10.58

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 (118) hide show
  1. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  2. package/dist/modules/OpenData/index.js +2 -1
  3. package/dist/modules/Order/index.d.ts +1 -0
  4. package/dist/modules/Order/index.js +118 -59
  5. package/dist/modules/Order/utils/weighedProduct.d.ts +12 -0
  6. package/dist/modules/Order/utils/weighedProduct.js +94 -0
  7. package/dist/modules/Order/utils.d.ts +6 -4
  8. package/dist/modules/Order/utils.js +40 -16
  9. package/dist/modules/Payment/index.d.ts +0 -5
  10. package/dist/modules/Payment/index.js +35 -85
  11. package/dist/modules/ProductList/index.d.ts +3 -1
  12. package/dist/modules/ProductList/index.js +203 -95
  13. package/dist/modules/ProductList/types.d.ts +8 -0
  14. package/dist/modules/ProductList/types.js +2 -0
  15. package/dist/modules/ResourcePlanner/planner.js +10 -8
  16. package/dist/modules/Rules/index.js +16 -14
  17. package/dist/modules/Rules/types.d.ts +2 -0
  18. package/dist/server/index.js +122 -69
  19. package/dist/server/modules/floor-plan/index.js +34 -3
  20. package/dist/server/modules/payment/index.d.ts +25 -6
  21. package/dist/server/modules/payment/index.js +660 -133
  22. package/dist/server/test.json +1 -1
  23. package/dist/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
  24. package/dist/shared/receipt/customerInvoiceLanguages.js +60 -0
  25. package/dist/shared/receipt/loadCustomerInvoiceLayout.d.ts +5 -0
  26. package/dist/shared/receipt/loadCustomerInvoiceLayout.js +46 -4
  27. package/dist/shared/receipt/small-ticket.d.ts +11 -0
  28. package/dist/shared/receipt/small-ticket.js +430 -255
  29. package/dist/shared/receipt/templateVisibility.d.ts +23 -0
  30. package/dist/shared/receipt/templateVisibility.js +64 -0
  31. package/dist/solution/BaseSales/index.d.ts +4 -2
  32. package/dist/solution/BaseSales/index.js +1328 -1214
  33. package/dist/solution/BaseSales/types.d.ts +5 -1
  34. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +40 -25
  35. package/dist/solution/BaseSales/utils.js +3 -2
  36. package/dist/solution/BookingTicket/index.d.ts +4 -1
  37. package/dist/solution/BookingTicket/index.js +120 -80
  38. package/dist/solution/OrderInvoicePreview/index.d.ts +10 -0
  39. package/dist/solution/OrderInvoicePreview/index.js +85 -14
  40. package/dist/solution/RegisterAndLogin/config.js +54 -11
  41. package/dist/solution/RegisterAndLogin/index.d.ts +2 -0
  42. package/dist/solution/RegisterAndLogin/index.js +1 -1
  43. package/dist/solution/RegisterAndLogin/utils.d.ts +12 -4
  44. package/dist/solution/RegisterAndLogin/utils.js +36 -16
  45. package/dist/solution/Sales/index.d.ts +2 -0
  46. package/dist/solution/Sales/index.js +15 -1
  47. package/dist/solution/ScanOrder/utils.js +3 -2
  48. package/dist/solution/UnifiedBookingSales/index.d.ts +7 -1
  49. package/dist/solution/UnifiedBookingSales/index.js +560 -401
  50. package/dist/solution/VenueBooking/index.d.ts +15 -2
  51. package/dist/solution/VenueBooking/index.js +1062 -785
  52. package/dist/solution/VenueBooking/types.d.ts +2 -1
  53. package/dist/solution/VenueBooking/types.js +1 -0
  54. package/dist/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  55. package/dist/solution/VenueBooking/utils/dateSummary.js +7 -4
  56. package/dist/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
  57. package/dist/solution/VenueBooking/utils/smartPricing.js +273 -0
  58. package/dist/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
  59. package/dist/solution/VenueBooking/utils/timeSlot.js +6 -3
  60. package/lib/modules/OpenData/index.js +2 -1
  61. package/lib/modules/Order/index.d.ts +1 -0
  62. package/lib/modules/Order/index.js +71 -11
  63. package/lib/modules/Order/utils/weighedProduct.d.ts +12 -0
  64. package/lib/modules/Order/utils/weighedProduct.js +89 -0
  65. package/lib/modules/Order/utils.d.ts +6 -4
  66. package/lib/modules/Order/utils.js +34 -13
  67. package/lib/modules/Payment/index.d.ts +0 -5
  68. package/lib/modules/Payment/index.js +3 -28
  69. package/lib/modules/ProductList/index.d.ts +3 -1
  70. package/lib/modules/ProductList/index.js +45 -6
  71. package/lib/modules/ProductList/types.d.ts +8 -0
  72. package/lib/modules/ProductList/types.js +1 -0
  73. package/lib/modules/ResourcePlanner/planner.js +10 -8
  74. package/lib/modules/Rules/index.js +16 -14
  75. package/lib/modules/Rules/types.d.ts +2 -0
  76. package/lib/server/index.js +72 -28
  77. package/lib/server/modules/floor-plan/index.js +29 -1
  78. package/lib/server/modules/payment/index.d.ts +25 -6
  79. package/lib/server/modules/payment/index.js +350 -78
  80. package/lib/server/test.json +1 -1
  81. package/lib/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
  82. package/lib/shared/receipt/customerInvoiceLanguages.js +58 -0
  83. package/lib/shared/receipt/loadCustomerInvoiceLayout.d.ts +5 -0
  84. package/lib/shared/receipt/loadCustomerInvoiceLayout.js +42 -4
  85. package/lib/shared/receipt/small-ticket.d.ts +11 -0
  86. package/lib/shared/receipt/small-ticket.js +234 -30
  87. package/lib/shared/receipt/templateVisibility.d.ts +23 -0
  88. package/lib/shared/receipt/templateVisibility.js +63 -0
  89. package/lib/solution/BaseSales/index.d.ts +4 -2
  90. package/lib/solution/BaseSales/index.js +79 -18
  91. package/lib/solution/BaseSales/types.d.ts +5 -1
  92. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +24 -9
  93. package/lib/solution/BaseSales/utils.js +2 -1
  94. package/lib/solution/BookingTicket/index.d.ts +4 -1
  95. package/lib/solution/BookingTicket/index.js +14 -2
  96. package/lib/solution/OrderInvoicePreview/index.d.ts +10 -0
  97. package/lib/solution/OrderInvoicePreview/index.js +61 -7
  98. package/lib/solution/RegisterAndLogin/config.js +57 -11
  99. package/lib/solution/RegisterAndLogin/index.d.ts +2 -0
  100. package/lib/solution/RegisterAndLogin/index.js +9 -1
  101. package/lib/solution/RegisterAndLogin/utils.d.ts +12 -4
  102. package/lib/solution/RegisterAndLogin/utils.js +24 -17
  103. package/lib/solution/Sales/index.d.ts +2 -0
  104. package/lib/solution/Sales/index.js +10 -1
  105. package/lib/solution/ScanOrder/utils.js +2 -1
  106. package/lib/solution/UnifiedBookingSales/index.d.ts +7 -1
  107. package/lib/solution/UnifiedBookingSales/index.js +85 -7
  108. package/lib/solution/VenueBooking/index.d.ts +15 -2
  109. package/lib/solution/VenueBooking/index.js +243 -96
  110. package/lib/solution/VenueBooking/types.d.ts +2 -1
  111. package/lib/solution/VenueBooking/types.js +1 -0
  112. package/lib/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  113. package/lib/solution/VenueBooking/utils/dateSummary.js +7 -4
  114. package/lib/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
  115. package/lib/solution/VenueBooking/utils/smartPricing.js +224 -0
  116. package/lib/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
  117. package/lib/solution/VenueBooking/utils/timeSlot.js +5 -2
  118. package/package.json +1 -1
@@ -8,8 +8,49 @@ exports.hasSmallTicketData = hasSmallTicketData;
8
8
  var _dayjs = _interopRequireDefault(require("dayjs"));
9
9
  var _decimal = _interopRequireDefault(require("decimal.js"));
10
10
  var _pickupTiming = require("../../modules/Order/pickupTiming");
11
+ var _templateVisibility = require("./templateVisibility");
11
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
13
  const DEFAULT_LOCALES = ['en', 'zh_CN'];
14
+
15
+ // Attach provenance to a private copy BEFORE any locale-dependent filtering.
16
+ // Symbols survive the existing spread-based normalization, never enter JSON,
17
+ // and leave both the caller's snapshot and the default native contract intact.
18
+ const RECEIPT_SOURCE = Symbol('customerReceiptSource');
19
+ function copyReceiptSource(value, path = 'order') {
20
+ if (Array.isArray(value)) return value.map((item, index) => copyReceiptSource(item, `${path}/${index}`));
21
+ if (!value || typeof value !== 'object' || Object.getPrototypeOf(value) !== Object.prototype) return value;
22
+ const id = value.metadata?.unique_identification_number ?? value.product_uid ?? value.booking_uid ?? value.order_payment_id ?? value.payment_number ?? value.order_refund_id ?? value.refund_number ?? value.id;
23
+ const source = Object.fromEntries(Object.entries(value).map(([key, item]) => [key, copyReceiptSource(item, `${path}/${key}`)]));
24
+ // Retain the original occurrence even when a catalogue ID appears twice.
25
+ return {
26
+ ...source,
27
+ [RECEIPT_SOURCE]: `${path}${id != null ? `@${encodeURIComponent(String(id))}` : ''}`
28
+ };
29
+ }
30
+ function receiptKey(source, kind, valueKind = 'shared') {
31
+ const key = source?.[RECEIPT_SOURCE];
32
+ return typeof key === 'string' ? {
33
+ receipt_key: `${key}#${kind}`,
34
+ receipt_value_kind: valueKind
35
+ } : {};
36
+ }
37
+ function receiptSourceIndex(source, index) {
38
+ return source?.[RECEIPT_SOURCE] ? {
39
+ receipt_source_index: index
40
+ } : {};
41
+ }
42
+ function removePrivateReceiptSource(value) {
43
+ if (!value || typeof value !== 'object') return;
44
+ delete value[RECEIPT_SOURCE];
45
+ Object.values(value).forEach(removePrivateReceiptSource);
46
+ }
47
+ function receiptTimeKey(source, kind) {
48
+ const identity = receiptKey(source, kind);
49
+ return identity.receipt_key ? {
50
+ ...identity,
51
+ receipt_item_kind: 'shared'
52
+ } : {};
53
+ }
13
54
  const SERVICE_TYPE_LABEL_KEYS = {
14
55
  takeaway: 'takeAway',
15
56
  pick_up: 'pickUp',
@@ -247,19 +288,23 @@ const LABELS = {
247
288
  }
248
289
  };
249
290
  function buildSmallTicketData(params) {
250
- const order = params.order || {};
291
+ const order = params.includeReceiptKeys ? copyReceiptSource(params.order || {}) : params.order || {};
251
292
  const shopInfo = params.shopInfo || {};
252
293
  const locales = resolveLocales(shopInfo, params.locales);
253
294
  const productMap = params.productMap || {};
254
- return locales.reduce((data, locale) => {
295
+ const visibility = (0, _templateVisibility.resolveInvoiceDataVisibility)(params.templateSettings);
296
+ const result = locales.reduce((data, locale) => {
255
297
  data[locale] = buildLocaleData({
256
298
  order,
257
299
  shopInfo,
258
300
  locale,
259
- productMap
301
+ productMap,
302
+ visibility
260
303
  });
261
304
  return data;
262
305
  }, {});
306
+ if (params.includeReceiptKeys) removePrivateReceiptSource(result);
307
+ return result;
263
308
  }
264
309
  function hasSmallTicketData(value) {
265
310
  return !!value && typeof value === 'object' && Object.keys(value).length > 0;
@@ -269,13 +314,14 @@ function buildLocaleData(params) {
269
314
  order,
270
315
  shopInfo,
271
316
  locale,
272
- productMap
317
+ productMap,
318
+ visibility
273
319
  } = params;
274
320
  const products = buildProducts(order, locale, productMap);
275
321
  const summary = getSummary(order);
276
322
  const currencySymbol = getCurrencySymbol(order, shopInfo);
277
323
  const financials = resolveReceiptFinancials(order, summary);
278
- const delivery = buildDelivery(order, locale);
324
+ const delivery = buildDelivery(order, locale, visibility.handover);
279
325
  return {
280
326
  base_data: buildBaseData({
281
327
  order,
@@ -294,7 +340,7 @@ function buildLocaleData(params) {
294
340
  currencySymbol,
295
341
  financials
296
342
  }),
297
- customer: buildCustomer(order, locale),
343
+ customer: buildCustomer(order, locale, visibility.customer),
298
344
  appointment: buildAppointment(order, locale),
299
345
  ...(delivery.length ? {
300
346
  delivery
@@ -305,12 +351,18 @@ function buildLocaleData(params) {
305
351
  locale,
306
352
  currencySymbol
307
353
  }),
308
- wallets: buildWallets({
354
+ wallets: visibility.card.show ? buildWallets({
309
355
  order,
310
356
  locale,
311
- currencySymbol
312
- }),
313
- tickets: Array.isArray(order.tickets) ? order.tickets : [],
357
+ currencySymbol,
358
+ passTypes: visibility.card.passTypes
359
+ }) : [],
360
+ // Native printers fall back to tickets when wallets is empty. Legacy rows
361
+ // have no trustworthy asset tags, so they cannot bypass a card whitelist.
362
+ tickets: visibility.card.show && visibility.card.passTypes === null && Array.isArray(order.tickets) ? order.tickets.map(group => Array.isArray(group) ? group.map(row => row && typeof row === 'object' ? {
363
+ ...row,
364
+ ...receiptKey(row, 'ticket')
365
+ } : row) : group) : [],
314
366
  source_shop: [],
315
367
  refund_data: buildRefundData({
316
368
  order,
@@ -354,7 +406,7 @@ function buildBaseData(params) {
354
406
  function buildProducts(order, locale, productMap) {
355
407
  const products = Array.isArray(order.products) ? order.products : [];
356
408
  const allergyByProductUid = buildProductAllergyMap(order, locale);
357
- return products.map(rawProduct => {
409
+ return products.map((rawProduct, sourceIndex) => {
358
410
  const product = restoreReceiptDiscountHierarchy(rawProduct);
359
411
  const quantity = toNumber(product.product_quantity ?? product.quantity ?? product.num ?? 1, 1);
360
412
  const originalPrice = product.original_price ?? product.selling_price ?? product.payment_price ?? product.price ?? 0;
@@ -399,6 +451,10 @@ function buildProducts(order, locale, productMap) {
399
451
  const resolvedCombinations = Array.isArray(product.combinations) && product.combinations.length ? normalizeExistingCombinations(product.combinations, locale, currencySymbol) : combinations;
400
452
  const shouldIncludeBasePrice = options.length > 0 || resolvedCombinations.length > 0 || hasProductDiscount(product, extensionList);
401
453
  return {
454
+ ...receiptKey(rawProduct, 'product'),
455
+ ...(rawProduct[RECEIPT_SOURCE] ? {
456
+ receipt_source_index: sourceIndex
457
+ } : {}),
402
458
  product_title: productTitle,
403
459
  product_quantity: quantity,
404
460
  selling_price: formatMoney(sellingPrice, currencySymbol),
@@ -542,6 +598,7 @@ function normalizeProductDiscounts(params) {
542
598
  const totalAmount = new _decimal.default(toMoneyNumber(amount)).mul(isAggregatedBundleDiscount || isEntitlementPass ? 1 : quantity);
543
599
  const formattedAmount = isMarkup ? formatMoney(totalAmount.abs(), currencySymbol) : formatNegativeMoney(totalAmount, currencySymbol);
544
600
  return {
601
+ ...receiptKey(discount, 'discount'),
545
602
  item: title,
546
603
  value: formattedAmount,
547
604
  isMarkup
@@ -581,6 +638,7 @@ function buildProductExtensionList(params) {
581
638
  locale,
582
639
  currencySymbol
583
640
  }), ...(quantity > 1 ? [{
641
+ ...receiptTimeKey(product, 'quantity-price'),
584
642
  item: buildProductQuantityPriceText({
585
643
  quantity,
586
644
  currencySymbol,
@@ -588,7 +646,10 @@ function buildProductExtensionList(params) {
588
646
  }),
589
647
  value: ''
590
648
  }] : [])];
591
- const productExtensionList = extensionList.length ? extensionList : normalizeArray(product.extension_list);
649
+ const productExtensionList = extensionList.length ? extensionList : normalizeArray(product.extension_list).map(row => ({
650
+ ...row,
651
+ ...receiptKey(row, 'extension')
652
+ }));
592
653
  return [...productExtensionList, ...discountList];
593
654
  }
594
655
  function buildProductOpenWeightRows(params) {
@@ -605,10 +666,12 @@ function buildProductOpenWeightRows(params) {
605
666
  const rows = [];
606
667
  if (hasTare) {
607
668
  rows.push({
669
+ ...receiptKey(product, 'gross'),
608
670
  item: `${manualFlag}${label(locale, 'gross')}: ${productSku.weight ?? 0}${unit}`,
609
671
  value: ''
610
672
  });
611
673
  rows.push({
674
+ ...receiptKey(product, 'tare'),
612
675
  item: `${label(locale, 'tare')}: ${productSku.tare_weight}${unit}`,
613
676
  value: ''
614
677
  });
@@ -617,6 +680,7 @@ function buildProductOpenWeightRows(params) {
617
680
  const unitPrice = productSku.unit_price ?? 0;
618
681
  const netItem = `${netWeight} ${unit} NET @ ${currencySymbol}${unitPrice}/${unit}`;
619
682
  rows.push({
683
+ ...receiptTimeKey(product, 'net-weight'),
620
684
  item: hasTare ? netItem : `${manualFlag}${netItem}`,
621
685
  value: ''
622
686
  });
@@ -672,7 +736,7 @@ function normalizeProductOptions(params) {
672
736
  parentProduct
673
737
  } = params;
674
738
  const rawOptions = Array.isArray(params.options) ? params.options : Array.isArray(product.options) ? product.options : Array.isArray(product.product_sku?.option) ? product.product_sku.option : [];
675
- return rawOptions.map(option => {
739
+ return rawOptions.map((option, sourceIndex) => {
676
740
  const price = option.original_price ?? option.add_price ?? option.price;
677
741
  const quantity = toNumber(option.num ?? option.quantity ?? 1, 1);
678
742
  const value = option.value ?? option.option ?? option.item;
@@ -682,6 +746,8 @@ function normalizeProductOptions(params) {
682
746
  locale
683
747
  });
684
748
  return {
749
+ ...receiptKey(option, 'option'),
750
+ ...receiptSourceIndex(option, sourceIndex),
685
751
  name,
686
752
  ...(option.num !== undefined || option.quantity !== undefined ? {
687
753
  num: quantity
@@ -705,7 +771,7 @@ function normalizeProductCombinations(params) {
705
771
  parentProduct
706
772
  } = params;
707
773
  const bundles = Array.isArray(product.product_bundle) ? product.product_bundle : [];
708
- return bundles.map(bundle => {
774
+ return bundles.map((bundle, sourceIndex) => {
709
775
  const combinationsOptions = normalizeProductOptions({
710
776
  product: {},
711
777
  locale,
@@ -735,6 +801,8 @@ function normalizeProductCombinations(params) {
735
801
  });
736
802
  const shouldIncludeBasePrice = combinationsOptions.length > 0 || nestedCombinations.length > 0 || hasProductDiscount(bundle, extensionList);
737
803
  return {
804
+ ...receiptKey(bundle, 'combination'),
805
+ ...receiptSourceIndex(bundle, sourceIndex),
738
806
  product_title: baseTitle,
739
807
  product_quantity: quantity,
740
808
  price: formattedPrice,
@@ -762,7 +830,7 @@ function normalizeProductCombinations(params) {
762
830
  });
763
831
  }
764
832
  function normalizeExistingCombinations(combinations, locale, currencySymbol) {
765
- return combinations.map(combination => {
833
+ return combinations.map((combination, sourceIndex) => {
766
834
  if (!combination || typeof combination !== 'object' || Array.isArray(combination)) {
767
835
  return combination;
768
836
  }
@@ -799,6 +867,8 @@ function normalizeExistingCombinations(combinations, locale, currencySymbol) {
799
867
  const shouldIncludeBasePrice = normalizedOptions.length > 0 || nestedCombinations.length > 0 || hasProductDiscount(combination, extensionList);
800
868
  return {
801
869
  ...snapshot,
870
+ ...receiptKey(combination, 'combination'),
871
+ ...receiptSourceIndex(combination, sourceIndex),
802
872
  ...(productTitle ? {
803
873
  product_title: productTitle
804
874
  } : {}),
@@ -953,7 +1023,7 @@ function resolveVariantItem(group, itemPositionId) {
953
1023
  }
954
1024
  function getProductTitleSource(source, locale) {
955
1025
  if (!source || typeof source !== 'object') return '';
956
- return resolveTitleValue(source.product_title, locale) || resolveTitleValue(source.title_i18n, locale) || resolveTitleValue(source.title, locale) || resolveTitleValue(source.name, locale);
1026
+ return resolveTitleValue(source.product_title, locale) || resolveTitleValue(source.title_i18n, locale) || resolveTitleValue(source.title, locale) || resolveTitleValue(source.name_i18n, locale) || resolveTitleValue(source.name, locale);
957
1027
  }
958
1028
  function getBundleProductTitleSource(source, locale) {
959
1029
  if (!source || typeof source !== 'object') return '';
@@ -1072,6 +1142,7 @@ function buildFees(params) {
1072
1142
  const value = surcharge.amount ?? surcharge.value ?? surcharge.total_amount;
1073
1143
  if (!isNonZero(value)) continue;
1074
1144
  fees.push({
1145
+ ...receiptKey(surcharge, 'surcharge'),
1075
1146
  item: getLocalizedValue(surcharge.name || surcharge.title || surcharge.item, locale),
1076
1147
  value: formatMoney(value, currencySymbol)
1077
1148
  });
@@ -1079,6 +1150,7 @@ function buildFees(params) {
1079
1150
  const discountAmount = firstPresentValue(order.shop_discount, summary.discount_amount, order.discount_amount);
1080
1151
  if (isNonZero(discountAmount)) {
1081
1152
  fees.push({
1153
+ ...receiptKey(order, 'order-discount'),
1082
1154
  item: label(locale, 'orderDiscount'),
1083
1155
  value: formatNegativeMoney(discountAmount, currencySymbol)
1084
1156
  });
@@ -1095,6 +1167,7 @@ function buildFees(params) {
1095
1167
  const payProcessingFee = financials.payProcessingFee;
1096
1168
  if (isNonZero(payProcessingFee)) {
1097
1169
  fees.push({
1170
+ ...receiptKey(order, 'payment-processing-fee'),
1098
1171
  item: label(locale, 'payProcessingFee'),
1099
1172
  value: formatMoney(payProcessingFee, currencySymbol)
1100
1173
  });
@@ -1174,17 +1247,22 @@ function calculateProductOriginalAmount(order) {
1174
1247
  return total.plus(new _decimal.default(toMoneyNumber(originalPrice)).mul(quantity));
1175
1248
  }, new _decimal.default(0));
1176
1249
  }
1177
- function buildCustomer(order, locale) {
1250
+ function buildCustomer(order, locale, visibility) {
1251
+ if (!visibility.show) return [];
1252
+ const fields = [visibility.name, visibility.phone, visibility.email];
1178
1253
  return [{
1254
+ ...receiptKey(order, 'customer.contactName'),
1179
1255
  item: label(locale, 'contactName'),
1180
1256
  value: normalizeCustomerDisplayValue(order.customer_name || order.customer?.name || order.customer?.display_name)
1181
1257
  }, {
1258
+ ...receiptKey(order, 'customer.contactMobile'),
1182
1259
  item: label(locale, 'contactMobile'),
1183
1260
  value: stringify(order.phone || order.customer?.phone)
1184
1261
  }, {
1262
+ ...receiptKey(order, 'customer.email'),
1185
1263
  item: label(locale, 'email'),
1186
1264
  value: stringify(order.email || order.customer?.email)
1187
- }];
1265
+ }].filter((_row, index) => fields[index]);
1188
1266
  }
1189
1267
  function normalizeCustomerDisplayValue(value) {
1190
1268
  const text = stringify(value).trim();
@@ -1192,19 +1270,23 @@ function normalizeCustomerDisplayValue(value) {
1192
1270
  if (text.toLowerCase() === 'select a customer') return 'Walk-In';
1193
1271
  return text;
1194
1272
  }
1195
- function buildDelivery(order, locale) {
1273
+ function buildDelivery(order, locale, visibility) {
1274
+ if (!visibility.show) return [];
1196
1275
  const serviceType = stringify(order.metadata?.shop_service_data?.service_type).trim();
1197
1276
  const serviceTypeLabelKey = resolveServiceTypeLabelKey(serviceType);
1198
1277
  if (!serviceTypeLabelKey) return [];
1199
- const items = [{
1278
+ const items = visibility.method ? [{
1279
+ ...receiptKey(order, 'service-type'),
1200
1280
  item: label(locale, serviceTypeLabelKey),
1201
1281
  value: '',
1202
1282
  size: 2
1203
- }];
1283
+ }] : [];
1284
+ if (!visibility.fulfillmentTime) return items;
1204
1285
  if (serviceType === 'pick_up') {
1205
1286
  const pickupTime = formatPickupBookingStart(order.bookings, locale);
1206
1287
  if (pickupTime) {
1207
1288
  items.push({
1289
+ ...receiptTimeKey(order, 'pickup-time'),
1208
1290
  item: pickupTime,
1209
1291
  value: '',
1210
1292
  size: 2
@@ -1215,6 +1297,7 @@ function buildDelivery(order, locale) {
1215
1297
  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);
1216
1298
  if (isPresentId(handoverTime)) {
1217
1299
  items.push({
1300
+ ...receiptKey(order, 'handover-time'),
1218
1301
  item: label(locale, 'handoverTime'),
1219
1302
  value: formatDateTime(handoverTime, locale)
1220
1303
  });
@@ -1254,6 +1337,7 @@ function buildAppointment(order, locale) {
1254
1337
  const tableName = order.table_name || order.metadata?.table_name || order.metadata?.table?.name || order.form_data?.table_name;
1255
1338
  if (!tableName) return [];
1256
1339
  return [{
1340
+ ...receiptKey(order, 'table', 'text'),
1257
1341
  item: label(locale, 'table'),
1258
1342
  value: getLocalizedValue(tableName, locale)
1259
1343
  }];
@@ -1289,18 +1373,22 @@ function buildAppointmentRows(params) {
1289
1373
  const resourceText = formatBookingResources(resolveBookingResourcesForReceipt(booking, allResources, bookingCount), locale);
1290
1374
  const holder = getLocalizedValue(booking.holder?.name ?? booking.metadata?.holder?.name, locale).trim();
1291
1375
  return [{
1376
+ ...receiptKey(booking, 'booking-id'),
1292
1377
  item: label(locale, 'bookingId'),
1293
1378
  value: bookingId,
1294
1379
  ...association
1295
1380
  }, {
1381
+ ...receiptKey(booking, 'booking-time', 'shared'),
1296
1382
  item: label(locale, 'bookingDateTime'),
1297
1383
  value: bookingTime,
1298
1384
  ...association
1299
1385
  }, {
1386
+ ...receiptKey(booking, 'booking-resource', 'text'),
1300
1387
  item: label(locale, 'bookingResource'),
1301
1388
  value: resourceText,
1302
1389
  ...association
1303
1390
  }, {
1391
+ ...receiptKey(booking, 'booking-holder', 'text'),
1304
1392
  item: label(locale, 'bookingHolder'),
1305
1393
  value: holder,
1306
1394
  ...association
@@ -1386,6 +1474,7 @@ function compareOptionalValues(left, right) {
1386
1474
  }
1387
1475
  function buildResources(order, locale) {
1388
1476
  return normalizeArray(order.resources || order.resource_list).map(resource => ({
1477
+ ...receiptKey(resource, 'resource', 'text'),
1389
1478
  id: resource.id || resource.resource_id || '',
1390
1479
  code: '',
1391
1480
  title: getLocalizedValue(resource.title || resource.name, locale),
@@ -1431,12 +1520,14 @@ function buildRefundData(params) {
1431
1520
  const methodName = paymentMethodName(payment, params.locale) || label(params.locale, 'refund');
1432
1521
  const amount = firstPresentValue(refund.amount, refund.refund_amount, refund.total_amount) ?? 0;
1433
1522
  const items = [{
1523
+ ...receiptKey(refund, 'refund'),
1434
1524
  item: methodName,
1435
1525
  value: formatNegativeMoney(amount, params.currencySymbol)
1436
1526
  }];
1437
1527
  const occurredAt = firstPresentValue(refund.refund_time, refund.refunded_at, refund.created_at, refund.updated_at);
1438
1528
  if (isPresentId(occurredAt)) {
1439
1529
  items.push({
1530
+ ...receiptTimeKey(refund, 'refund-time'),
1440
1531
  item: formatDateTime(occurredAt, params.locale),
1441
1532
  value: ''
1442
1533
  });
@@ -1483,9 +1574,77 @@ function resolveRefundPayment(refund, payments) {
1483
1574
  const matchedPayment = payments.find(payment => isSameId(firstPresentValue(payment.order_payment_id, payment.id), orderPaymentId));
1484
1575
  return matchedPayment || refund;
1485
1576
  }
1577
+ function getPaymentWalletAssetIdentity(payment) {
1578
+ const record = getFundRecord(payment);
1579
+ return {
1580
+ id: firstNormalizedWalletAssetId(record?.voucher_id, payment.voucher_id),
1581
+ codes: normalizeWalletAssetCodes(record?.code, record?.encoded)
1582
+ };
1583
+ }
1584
+ function getProductWalletAssetTag(record) {
1585
+ // Rules normalizes product_discount_card to type=discount_card. That
1586
+ // ambiguous alias cannot establish the original asset tag for a whitelist.
1587
+ for (const tag of [record.tag, record.discount?.tag]) {
1588
+ if (typeof tag === 'string' && tag) return tag;
1589
+ }
1590
+ for (const type of [record.type, record.discount?.type]) {
1591
+ if (typeof type === 'string' && type !== 'discount_card' && PRODUCT_WALLET_DISCOUNT_TYPES.has(type)) return type;
1592
+ }
1593
+ return undefined;
1594
+ }
1595
+ function createWalletAssetFilter(order, passTypes) {
1596
+ if (passTypes === null) return () => true;
1597
+ const assets = [];
1598
+ const remember = (identity, tag) => {
1599
+ if (typeof tag === 'string' && tag && (identity.id || identity.codes.length)) assets.push({
1600
+ identity,
1601
+ tag
1602
+ });
1603
+ };
1604
+ for (const asset of [...normalizeArray(order.vouchers), ...normalizeArray(order.order_meta_list?.point_cards_snapshot), ...normalizeArray(order.order_meta_list?.virtual_currency_snapshot)]) {
1605
+ if (asset && typeof asset === 'object') remember(getVoucherAssetIdentity(asset), asset.tag);
1606
+ }
1607
+ // Some order snapshots retain the original selected assets at the root.
1608
+ // Only their explicit tag is authoritative; do not infer it from type.
1609
+ for (const record of normalizeArray(order.discount_list)) {
1610
+ if (!record || typeof record !== 'object') continue;
1611
+ remember({
1612
+ id: getProductWalletDiscountAssetId(record),
1613
+ codes: getProductWalletDiscountCodes(record)
1614
+ }, record.tag ?? record.discount?.tag);
1615
+ }
1616
+ const visit = product => {
1617
+ if (!product || typeof product !== 'object') return;
1618
+ for (const record of normalizeArray(product.discount_list)) {
1619
+ if (!record || typeof record !== 'object') continue;
1620
+ remember({
1621
+ id: getProductWalletDiscountAssetId(record),
1622
+ codes: getProductWalletDiscountCodes(record)
1623
+ }, getProductWalletAssetTag(record));
1624
+ }
1625
+ for (const key of ['combinations', 'product_bundle', 'bundle']) normalizeArray(product[key]).forEach(visit);
1626
+ };
1627
+ normalizeArray(order.products).forEach(product => {
1628
+ if (product && typeof product === 'object') visit(restoreReceiptDiscountHierarchy(product));
1629
+ });
1630
+ return (identity, tag, resolvePaymentSource = false) => {
1631
+ const directTag = typeof tag === 'string' && tag ? tag : undefined;
1632
+ if (directTag && !resolvePaymentSource) return passTypes.has(directTag);
1633
+ const exactMatches = identity.id ? assets.filter(asset => asset.identity.id === identity.id) : [];
1634
+ // A known asset ID is stronger than an unrelated code-only snapshot.
1635
+ const matches = exactMatches.length ? exactMatches : assets.filter(asset => isSameWalletAssetIdentity(asset.identity, identity));
1636
+ const tags = new Set(matches.map(asset => asset.tag));
1637
+ if (!tags.size) return !!directTag && passTypes.has(directTag);
1638
+ // A conflicting fund record is not reliable evidence for a payment's tag.
1639
+ // It must not claim the identity ahead of the original typed asset.
1640
+ if (tags.size !== 1 || directTag && !tags.has(directTag)) return false;
1641
+ return passTypes.has(matches[0].tag);
1642
+ };
1643
+ }
1486
1644
  function buildWallets(params) {
1487
- const virtualCurrencySnapshots = collectVirtualCurrencySnapshots(params.order);
1488
- const displayedWalletPayments = normalizeArray(params.order.payments).filter(payment => isPrintablePayment(payment) && !!getFundRecord(payment));
1645
+ const allowAsset = createWalletAssetFilter(params.order, params.passTypes);
1646
+ const virtualCurrencySnapshots = collectVirtualCurrencySnapshots(params.order, allowAsset);
1647
+ const displayedWalletPayments = normalizeArray(params.order.payments).filter(payment => isPrintablePayment(payment) && !!getFundRecord(payment) && allowAsset(getPaymentWalletAssetIdentity(payment), getFundRecord(payment)?.tag, true));
1489
1648
  const paymentWallets = displayedWalletPayments.map(payment => {
1490
1649
  const virtualCurrencySnapshot = findVirtualCurrencySnapshotForPayment(payment, virtualCurrencySnapshots.byId);
1491
1650
  return buildPaymentItems({
@@ -1501,20 +1660,24 @@ function buildWallets(params) {
1501
1660
  const displayedWalletAssetIdentities = collectDisplayedWalletAssetIdentities(displayedWalletPayments);
1502
1661
  const voucherWallets = buildVoucherAssets({
1503
1662
  ...params,
1663
+ allowAsset,
1504
1664
  displayedWalletAssetIdentities
1505
1665
  });
1506
1666
  const productDiscountWallets = buildProductDiscountAssets({
1507
1667
  ...params,
1668
+ allowAsset,
1508
1669
  displayedWalletAssetIdentities
1509
1670
  });
1510
1671
  return [...paymentWallets, ...voucherWallets, ...productDiscountWallets, ...buildPointCardSnapshotAssets({
1511
1672
  order: params.order,
1512
1673
  locale: params.locale,
1674
+ allowAsset,
1513
1675
  displayedWalletAssetIdentities
1514
1676
  }), ...buildVirtualCurrencySnapshotAssets({
1515
1677
  snapshots: virtualCurrencySnapshots.items,
1516
1678
  order: params.order,
1517
1679
  locale: params.locale,
1680
+ allowAsset,
1518
1681
  displayedWalletAssetIdentities
1519
1682
  })];
1520
1683
  }
@@ -1543,7 +1706,7 @@ function collectDisplayedWalletAssetIdentities(payments) {
1543
1706
  const PRODUCT_WALLET_DISCOUNT_TYPES = new Set(['good_pass', 'discount_card', 'product_discount_card', 'entitlement_pass']);
1544
1707
  function buildProductDiscountAssets(params) {
1545
1708
  const fallbackAssetTime = firstPresentValue(params.order.updated_at, params.order.created_at);
1546
- return collectProductWalletDiscountAssets(params.order).flatMap(asset => {
1709
+ return collectProductWalletDiscountAssets(params.order, params.allowAsset).flatMap(asset => {
1547
1710
  if (!claimWalletAssetIdentity(params.displayedWalletAssetIdentities, {
1548
1711
  id: asset.id,
1549
1712
  codes: asset.codes
@@ -1551,15 +1714,18 @@ function buildProductDiscountAssets(params) {
1551
1714
  const name = getProductWalletDiscountName(asset, params.locale);
1552
1715
  const assetTime = getProductWalletDiscountTime(asset) ?? fallbackAssetTime;
1553
1716
  const timeRow = isPresentId(assetTime) ? {
1717
+ ...receiptTimeKey(asset.records[0], 'asset-time'),
1554
1718
  item: formatDateTime(assetTime, params.locale),
1555
1719
  value: ''
1556
1720
  } : null;
1557
1721
  if (asset.type === 'entitlement_pass') {
1558
1722
  const remaining = getProductEntitlementBalance(asset);
1559
1723
  return [[{
1724
+ ...receiptKey(asset.records[0], 'asset-name'),
1560
1725
  item: name,
1561
1726
  value: ''
1562
1727
  }, ...(remaining ? [{
1728
+ ...receiptKey(asset.records[0], 'entitlementRemaining'),
1563
1729
  item: label(params.locale, 'entitlementRemaining'),
1564
1730
  value: formatEntitlementUses(remaining, params.locale)
1565
1731
  }] : []), ...(timeRow ? [timeRow] : [])]];
@@ -1567,30 +1733,33 @@ function buildProductDiscountAssets(params) {
1567
1733
  const percent = getProductWalletDiscountPercent(asset);
1568
1734
  if (percent) {
1569
1735
  return [[{
1736
+ ...receiptKey(asset.records[0], 'asset-discount'),
1570
1737
  item: appendPercentToVoucherName(name, percent),
1571
1738
  value: formatVoucherDiscount(percent, params.locale)
1572
1739
  }, ...(timeRow ? [timeRow] : [])]];
1573
1740
  }
1574
1741
  const balance = getProductWalletMoneyBalance(asset);
1575
1742
  return [[{
1743
+ ...receiptKey(asset.records[0], 'asset-name'),
1576
1744
  item: name,
1577
1745
  value: ''
1578
1746
  }, ...(balance ? [{
1747
+ ...receiptKey(asset.records[0], 'balance'),
1579
1748
  item: label(params.locale, 'balance'),
1580
1749
  value: formatMoney(balance, params.currencySymbol)
1581
1750
  }] : []), ...(timeRow ? [timeRow] : [])]];
1582
1751
  });
1583
1752
  }
1584
- function collectProductWalletDiscountAssets(order) {
1753
+ function collectProductWalletDiscountAssets(order, allowAsset) {
1585
1754
  const assets = [];
1586
1755
  const assetsById = new Map();
1587
1756
  normalizeArray(order.products).forEach(rawProduct => {
1588
1757
  if (!rawProduct || typeof rawProduct !== 'object') return;
1589
- visitProductWalletDiscounts(restoreReceiptDiscountHierarchy(rawProduct), assets, assetsById);
1758
+ visitProductWalletDiscounts(restoreReceiptDiscountHierarchy(rawProduct), assets, assetsById, allowAsset);
1590
1759
  });
1591
1760
  return assets;
1592
1761
  }
1593
- function visitProductWalletDiscounts(product, assets, assetsById) {
1762
+ function visitProductWalletDiscounts(product, assets, assetsById, allowAsset) {
1594
1763
  normalizeArray(product.discount_list).forEach(record => {
1595
1764
  if (!record || typeof record !== 'object' || Array.isArray(record)) return;
1596
1765
  const type = getProductWalletDiscountType(record);
@@ -1598,6 +1767,10 @@ function visitProductWalletDiscounts(product, assets, assetsById) {
1598
1767
  const id = getProductWalletDiscountAssetId(record);
1599
1768
  if (!id) return;
1600
1769
  const codes = getProductWalletDiscountCodes(record);
1770
+ if (allowAsset && !allowAsset({
1771
+ id,
1772
+ codes
1773
+ }, getProductWalletAssetTag(record))) return;
1601
1774
  const existing = assetsById.get(id);
1602
1775
  if (existing) {
1603
1776
  existing.records.push(record);
@@ -1616,7 +1789,7 @@ function visitProductWalletDiscounts(product, assets, assetsById) {
1616
1789
  for (const childKey of ['combinations', 'product_bundle', 'bundle']) {
1617
1790
  normalizeArray(product[childKey]).forEach(child => {
1618
1791
  if (!child || typeof child !== 'object' || Array.isArray(child)) return;
1619
- visitProductWalletDiscounts(child, assets, assetsById);
1792
+ visitProductWalletDiscounts(child, assets, assetsById, allowAsset);
1620
1793
  });
1621
1794
  }
1622
1795
  }
@@ -1732,23 +1905,27 @@ function buildPointCardSnapshotAssets(params) {
1732
1905
  const pointCard = snapshot;
1733
1906
  if (stringify(pointCard.tag).trim().toLowerCase() !== 'point_card') return [];
1734
1907
  const assetId = normalizeWalletPassId(pointCard.id);
1908
+ if (!params.allowAsset(getVoucherAssetIdentity(pointCard), pointCard.tag)) return [];
1735
1909
  if (!assetId || !claimWalletAssetIdentity(params.displayedWalletAssetIdentities, {
1736
1910
  id: assetId,
1737
1911
  codes: []
1738
1912
  })) return [];
1739
1913
  const rows = [{
1914
+ ...receiptKey(pointCard, 'asset-name'),
1740
1915
  item: appendMaskedCardCode(stringify(pointCard.product_name).trim() || label(params.locale, 'pointCard'), pointCard.code),
1741
1916
  value: ''
1742
1917
  }];
1743
1918
  const remainingPoints = getPointCardSnapshotRemainingPoints(pointCard);
1744
1919
  if (remainingPoints) {
1745
1920
  rows.push({
1921
+ ...receiptKey(pointCard, 'remainingPoints'),
1746
1922
  item: label(params.locale, 'remainingPoints'),
1747
1923
  value: trimDecimal(remainingPoints)
1748
1924
  });
1749
1925
  }
1750
1926
  if (isPresentId(snapshotTime)) {
1751
1927
  rows.push({
1928
+ ...receiptTimeKey(pointCard, 'asset-time'),
1752
1929
  item: formatDateTime(snapshotTime, params.locale),
1753
1930
  value: ''
1754
1931
  });
@@ -1756,7 +1933,7 @@ function buildPointCardSnapshotAssets(params) {
1756
1933
  return [rows];
1757
1934
  });
1758
1935
  }
1759
- function collectVirtualCurrencySnapshots(order) {
1936
+ function collectVirtualCurrencySnapshots(order, allowAsset) {
1760
1937
  const items = [];
1761
1938
  const byId = new Map();
1762
1939
  const snapshots = order.order_meta_list?.virtual_currency_snapshot;
@@ -1768,6 +1945,7 @@ function collectVirtualCurrencySnapshots(order) {
1768
1945
  if (!snapshot || typeof snapshot !== 'object' || Array.isArray(snapshot)) return;
1769
1946
  const virtualCurrency = snapshot;
1770
1947
  if (stringify(virtualCurrency.tag).trim().toLowerCase() !== 'virtual_currency') return;
1948
+ if (!allowAsset(getVoucherAssetIdentity(virtualCurrency), virtualCurrency.tag)) return;
1771
1949
  const id = normalizeWalletPassId(virtualCurrency.id);
1772
1950
  if (!id || byId.has(id)) return;
1773
1951
  byId.set(id, virtualCurrency);
@@ -1792,23 +1970,27 @@ function buildVirtualCurrencySnapshotAssets(params) {
1792
1970
  const snapshotTime = firstPresentValue(params.order.updated_at, params.order.created_at);
1793
1971
  return params.snapshots.flatMap(virtualCurrency => {
1794
1972
  const assetId = normalizeWalletPassId(virtualCurrency.id);
1973
+ if (!params.allowAsset(getVoucherAssetIdentity(virtualCurrency), virtualCurrency.tag)) return [];
1795
1974
  if (!assetId || !claimWalletAssetIdentity(params.displayedWalletAssetIdentities, {
1796
1975
  id: assetId,
1797
1976
  codes: []
1798
1977
  })) return [];
1799
1978
  const rows = [{
1979
+ ...receiptKey(virtualCurrency, 'asset-name'),
1800
1980
  item: stringify(virtualCurrency.product_name).trim(),
1801
1981
  value: ''
1802
1982
  }];
1803
1983
  const balance = getVirtualCurrencySnapshotBalance(virtualCurrency);
1804
1984
  if (balance) {
1805
1985
  rows.push({
1986
+ ...receiptKey(virtualCurrency, 'balance'),
1806
1987
  item: label(params.locale, 'balance'),
1807
1988
  value: formatVirtualCurrencyBalance(balance, getVirtualCurrencySnapshotUnit(virtualCurrency, params.locale))
1808
1989
  });
1809
1990
  }
1810
1991
  if (isPresentId(snapshotTime)) {
1811
1992
  rows.push({
1993
+ ...receiptTimeKey(virtualCurrency, 'asset-time'),
1812
1994
  item: formatDateTime(snapshotTime, params.locale),
1813
1995
  value: ''
1814
1996
  });
@@ -1899,19 +2081,23 @@ function buildVoucherAssets(params) {
1899
2081
  const fallbackAssetTime = firstPresentValue(params.order.updated_at, params.order.created_at);
1900
2082
  return normalizeArray(params.order.vouchers).flatMap(voucher => {
1901
2083
  if (!voucher || typeof voucher !== 'object' || Array.isArray(voucher)) return [];
2084
+ if (!params.allowAsset(getVoucherAssetIdentity(voucher), voucher.tag)) return [];
1902
2085
  if (!claimWalletAssetIdentity(params.displayedWalletAssetIdentities, getVoucherAssetIdentity(voucher))) return [];
1903
2086
  const name = getVoucherAssetName(voucher, params.locale);
1904
2087
  const assetTime = firstPresentValue(voucher.updated_at, voucher.created_at, voucher.collection_time, fallbackAssetTime);
1905
2088
  const timeRow = isPresentId(assetTime) ? {
2089
+ ...receiptTimeKey(voucher, 'asset-time'),
1906
2090
  item: formatDateTime(assetTime, params.locale),
1907
2091
  value: ''
1908
2092
  } : null;
1909
2093
  if (isEntitlementVoucher(voucher)) {
1910
2094
  const remaining = getEntitlementBalance(voucher.metadata?.balance, voucher.balance);
1911
2095
  return [[{
2096
+ ...receiptKey(voucher, 'asset-name'),
1912
2097
  item: name,
1913
2098
  value: ''
1914
2099
  }, ...(remaining ? [{
2100
+ ...receiptKey(voucher, 'entitlementRemaining'),
1915
2101
  item: label(params.locale, 'entitlementRemaining'),
1916
2102
  value: formatEntitlementUses(remaining, params.locale)
1917
2103
  }] : []), ...(timeRow ? [timeRow] : [])]];
@@ -1919,9 +2105,11 @@ function buildVoucherAssets(params) {
1919
2105
  if (isTicketVoucher(voucher)) {
1920
2106
  const validity = getVoucherValidity(voucher, params.locale);
1921
2107
  return [[{
2108
+ ...receiptKey(voucher, 'asset-name'),
1922
2109
  item: name,
1923
2110
  value: ''
1924
2111
  }, ...(validity ? [{
2112
+ ...receiptKey(voucher, 'validity'),
1925
2113
  item: label(params.locale, 'validity'),
1926
2114
  value: validity
1927
2115
  }] : [])]];
@@ -1929,15 +2117,18 @@ function buildVoucherAssets(params) {
1929
2117
  const percent = getVoucherDiscountPercent(voucher);
1930
2118
  if (percent) {
1931
2119
  return [[{
2120
+ ...receiptKey(voucher, 'asset-discount'),
1932
2121
  item: appendPercentToVoucherName(name, percent),
1933
2122
  value: formatVoucherDiscount(percent, params.locale)
1934
2123
  }, ...(timeRow ? [timeRow] : [])]];
1935
2124
  }
1936
2125
  const balance = getVoucherBalance(voucher);
1937
2126
  return [[{
2127
+ ...receiptKey(voucher, 'asset-name'),
1938
2128
  item: name,
1939
2129
  value: ''
1940
2130
  }, {
2131
+ ...receiptKey(voucher, 'balance'),
1941
2132
  item: label(params.locale, 'balance'),
1942
2133
  value: formatMoney(balance, params.currencySymbol)
1943
2134
  }, ...(timeRow ? [timeRow] : [])]];
@@ -2071,6 +2262,7 @@ function buildPaymentItems(params) {
2071
2262
  } = params;
2072
2263
  const serviceFee = getPaymentServiceFee(payment);
2073
2264
  const items = [{
2265
+ ...receiptKey(payment, 'payment'),
2074
2266
  item: paymentMethodName(payment, locale),
2075
2267
  value: includePaymentAmount ? formatMoney(resolveReceiptPaymentAmount(payment, serviceFee), currencySymbol) : ''
2076
2268
  }];
@@ -2081,6 +2273,7 @@ function buildPaymentItems(params) {
2081
2273
  }));
2082
2274
  if (serviceFee.gt(0)) {
2083
2275
  items.push({
2276
+ ...receiptKey(payment, 'surchargeIncluded'),
2084
2277
  item: label(locale, 'surchargeIncluded'),
2085
2278
  value: formatMoney(serviceFee, currencySymbol)
2086
2279
  });
@@ -2100,16 +2293,21 @@ function buildPaymentItems(params) {
2100
2293
  const remainingAmount = payment.remaining_amount ?? payment.balance ?? payment.metadata?.remaining_amount;
2101
2294
  if (remainingAmount !== undefined && remainingAmount !== null) {
2102
2295
  items.push({
2296
+ ...receiptKey(payment, 'remainingAmount'),
2103
2297
  item: label(locale, 'remainingAmount'),
2104
2298
  value: formatMoney(remainingAmount, currencySymbol)
2105
2299
  });
2106
2300
  }
2107
2301
  }
2108
2302
  items.push({
2303
+ ...receiptTimeKey(payment, 'payment-time'),
2109
2304
  item: formatDateTime(payment.paid_at || payment.created_at || payment.updated_at || new Date(), locale),
2110
2305
  value: ''
2111
2306
  });
2112
- return items;
2307
+ return items.map(item => item.receipt_key ? {
2308
+ ...item,
2309
+ receipt_key: `${item.receipt_key}/${includeFundRecordBalance ? 'wallet' : 'history'}`
2310
+ } : item);
2113
2311
  }
2114
2312
  function getPaymentServiceFee(payment) {
2115
2313
  return new _decimal.default(toMoneyNumber(payment.service_fee));
@@ -2130,9 +2328,11 @@ function buildCashChangePaymentItems(params) {
2130
2328
  } = params;
2131
2329
  if (!shouldDisplayCashChange(payment)) return [];
2132
2330
  return [{
2331
+ ...receiptKey(payment, 'cashReceived'),
2133
2332
  item: label(locale, 'cashReceived'),
2134
2333
  value: formatMoney(payment.metadata.actual_paid_amount, currencySymbol)
2135
2334
  }, {
2335
+ ...receiptKey(payment, 'changeDue'),
2136
2336
  item: label(locale, 'changeDue'),
2137
2337
  value: formatMoney(payment.metadata.change_given_amount, currencySymbol)
2138
2338
  }];
@@ -2169,12 +2369,14 @@ function buildFundRecordPaymentItems(params) {
2169
2369
  const usedPoints = new _decimal.default(toMoneyNumber(usingBeforeValue)).minus(toMoneyNumber(usingAfterValue));
2170
2370
  if (includeUsage) {
2171
2371
  items.push({
2372
+ ...receiptKey(payment, 'redeemPoints'),
2172
2373
  item: label(locale, 'redeemPoints'),
2173
2374
  value: trimDecimal(usedPoints)
2174
2375
  });
2175
2376
  }
2176
2377
  if (includeBalance) {
2177
2378
  items.push({
2379
+ ...receiptKey(payment, 'remainingPoints'),
2178
2380
  item: label(locale, 'remainingPoints'),
2179
2381
  value: trimDecimal(new _decimal.default(toMoneyNumber(usingAfterValue)))
2180
2382
  });
@@ -2185,12 +2387,14 @@ function buildFundRecordPaymentItems(params) {
2185
2387
  if (virtualCurrencyUnit !== undefined) {
2186
2388
  if (!isNumericAmount(usingAfterValue)) return items;
2187
2389
  items.push({
2390
+ ...receiptKey(payment, 'balance'),
2188
2391
  item: label(locale, 'balance'),
2189
2392
  value: formatVirtualCurrencyBalance(new _decimal.default(usingAfterValue), virtualCurrencyUnit)
2190
2393
  });
2191
2394
  return items;
2192
2395
  }
2193
2396
  items.push({
2397
+ ...receiptKey(payment, 'balance'),
2194
2398
  item: label(locale, 'balance'),
2195
2399
  value: formatMoney(usingAfterValue, currencySymbol)
2196
2400
  });