@pisell/pisellos 0.10.43 → 0.10.45

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/itemRule/adapter.d.ts +4 -1
  2. package/dist/model/strategy/adapter/itemRule/adapter.js +135 -35
  3. package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
  4. package/dist/model/strategy/adapter/itemRule/evaluator.js +25 -1
  5. package/dist/model/strategy/adapter/itemRule/type.d.ts +44 -0
  6. package/dist/model/strategy/adapter/itemRule/type.js +19 -1
  7. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  8. package/dist/model/strategy/adapter/walletPass/evaluator.d.ts +2 -0
  9. package/dist/model/strategy/adapter/walletPass/evaluator.js +4 -2
  10. package/dist/modules/Customer/index.js +2 -1
  11. package/dist/modules/Discount/availability.d.ts +7 -0
  12. package/dist/modules/Discount/availability.js +49 -0
  13. package/dist/modules/Discount/index.d.ts +1 -3
  14. package/dist/modules/Discount/index.js +12 -151
  15. package/dist/modules/Discount/types.d.ts +6 -0
  16. package/dist/modules/Order/index.d.ts +41 -9
  17. package/dist/modules/Order/index.js +1457 -872
  18. package/dist/modules/Order/salesNotes.d.ts +31 -0
  19. package/dist/modules/Order/salesNotes.js +492 -0
  20. package/dist/modules/Order/types.d.ts +105 -8
  21. package/dist/modules/Order/types.js +6 -1
  22. package/dist/modules/Order/utils.d.ts +4 -2
  23. package/dist/modules/Order/utils.js +224 -79
  24. package/dist/modules/Payment/cashRecommendationAlgorithm.d.ts +4 -5
  25. package/dist/modules/Payment/cashRecommendationAlgorithm.js +17 -367
  26. package/dist/modules/Product/index.d.ts +1 -1
  27. package/dist/modules/ProductList/index.d.ts +2 -1
  28. package/dist/modules/ProductList/index.js +100 -20
  29. package/dist/modules/ProductList/types.d.ts +10 -0
  30. package/dist/modules/Rules/index.js +50 -16
  31. package/dist/server/index.d.ts +7 -0
  32. package/dist/server/index.js +45 -3
  33. package/dist/server/modules/order/index.js +6 -0
  34. package/dist/server/modules/order/types.d.ts +9 -0
  35. package/dist/server/utils/small-ticket.d.ts +1 -0
  36. package/dist/server/utils/small-ticket.js +142 -14
  37. package/dist/solution/BaseSales/index.d.ts +15 -1
  38. package/dist/solution/BaseSales/index.js +1240 -877
  39. package/dist/solution/BaseSales/types.d.ts +2 -2
  40. package/dist/solution/BookingByStep/index.d.ts +1 -1
  41. package/dist/solution/BookingTicket/index.d.ts +1 -0
  42. package/dist/solution/BookingTicket/index.js +37 -16
  43. package/dist/solution/BookingTicket/utils/orderCustomer.js +3 -2
  44. package/dist/solution/RegisterAndLogin/config.d.ts +9 -3
  45. package/dist/solution/RegisterAndLogin/config.js +95 -40
  46. package/dist/solution/RegisterAndLogin/index.js +4 -1
  47. package/dist/solution/ScanOrder/index.d.ts +1 -0
  48. package/dist/solution/ScanOrder/index.js +31 -27
  49. package/dist/solution/ScanOrder/utils.d.ts +1 -0
  50. package/dist/solution/ScanOrder/utils.js +2 -0
  51. package/dist/solution/ShopDiscount/index.d.ts +1 -0
  52. package/dist/solution/ShopDiscount/index.js +59 -22
  53. package/dist/solution/ShopDiscount/utils.d.ts +4 -2
  54. package/dist/solution/ShopDiscount/utils.js +40 -21
  55. package/dist/solution/UnifiedBookingSales/index.d.ts +15 -2
  56. package/dist/solution/UnifiedBookingSales/index.js +777 -510
  57. package/dist/solution/UnifiedBookingSales/types.d.ts +14 -1
  58. package/dist/solution/VenueBooking/index.d.ts +1 -0
  59. package/dist/solution/VenueBooking/index.js +8 -4
  60. package/lib/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
  61. package/lib/model/strategy/adapter/itemRule/adapter.js +73 -4
  62. package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
  63. package/lib/model/strategy/adapter/itemRule/evaluator.js +23 -1
  64. package/lib/model/strategy/adapter/itemRule/type.d.ts +44 -0
  65. package/lib/model/strategy/adapter/itemRule/type.js +19 -1
  66. package/lib/model/strategy/adapter/walletPass/evaluator.d.ts +2 -0
  67. package/lib/model/strategy/adapter/walletPass/evaluator.js +2 -0
  68. package/lib/modules/Customer/index.js +1 -0
  69. package/lib/modules/Discount/availability.d.ts +7 -0
  70. package/lib/modules/Discount/availability.js +43 -0
  71. package/lib/modules/Discount/index.d.ts +1 -3
  72. package/lib/modules/Discount/index.js +10 -131
  73. package/lib/modules/Discount/types.d.ts +6 -0
  74. package/lib/modules/Order/index.d.ts +41 -9
  75. package/lib/modules/Order/index.js +456 -69
  76. package/lib/modules/Order/salesNotes.d.ts +31 -0
  77. package/lib/modules/Order/salesNotes.js +382 -0
  78. package/lib/modules/Order/types.d.ts +105 -8
  79. package/lib/modules/Order/types.js +5 -1
  80. package/lib/modules/Order/utils.d.ts +4 -2
  81. package/lib/modules/Order/utils.js +134 -3
  82. package/lib/modules/Payment/cashRecommendationAlgorithm.d.ts +4 -5
  83. package/lib/modules/Payment/cashRecommendationAlgorithm.js +9 -354
  84. package/lib/modules/Product/index.d.ts +1 -1
  85. package/lib/modules/ProductList/index.d.ts +2 -1
  86. package/lib/modules/ProductList/index.js +47 -2
  87. package/lib/modules/ProductList/types.d.ts +10 -0
  88. package/lib/modules/Rules/index.js +42 -5
  89. package/lib/server/index.d.ts +7 -0
  90. package/lib/server/index.js +39 -3
  91. package/lib/server/modules/order/index.js +6 -0
  92. package/lib/server/modules/order/types.d.ts +9 -0
  93. package/lib/server/utils/small-ticket.d.ts +1 -0
  94. package/lib/server/utils/small-ticket.js +136 -12
  95. package/lib/solution/BaseSales/index.d.ts +15 -1
  96. package/lib/solution/BaseSales/index.js +192 -22
  97. package/lib/solution/BaseSales/types.d.ts +2 -2
  98. package/lib/solution/BookingByStep/index.d.ts +1 -1
  99. package/lib/solution/BookingTicket/index.d.ts +1 -0
  100. package/lib/solution/BookingTicket/index.js +23 -5
  101. package/lib/solution/BookingTicket/utils/orderCustomer.js +2 -1
  102. package/lib/solution/RegisterAndLogin/config.d.ts +9 -3
  103. package/lib/solution/RegisterAndLogin/config.js +49 -8
  104. package/lib/solution/RegisterAndLogin/index.js +4 -1
  105. package/lib/solution/ScanOrder/index.d.ts +1 -0
  106. package/lib/solution/ScanOrder/index.js +5 -1
  107. package/lib/solution/ScanOrder/utils.d.ts +1 -0
  108. package/lib/solution/ScanOrder/utils.js +1 -0
  109. package/lib/solution/ShopDiscount/index.d.ts +1 -0
  110. package/lib/solution/ShopDiscount/index.js +29 -3
  111. package/lib/solution/ShopDiscount/utils.d.ts +4 -2
  112. package/lib/solution/ShopDiscount/utils.js +39 -23
  113. package/lib/solution/UnifiedBookingSales/index.d.ts +15 -2
  114. package/lib/solution/UnifiedBookingSales/index.js +125 -1
  115. package/lib/solution/UnifiedBookingSales/types.d.ts +14 -1
  116. package/lib/solution/VenueBooking/index.d.ts +1 -0
  117. package/lib/solution/VenueBooking/index.js +5 -1
  118. package/package.json +1 -1
@@ -36,7 +36,7 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
36
36
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
37
37
  import { BaseModule } from "../BaseModule";
38
38
  import { UnavailableReason } from "./types";
39
- import { uniqueById, getDiscountAmount, getDiscountListAmountTotal, getDiscountListAmount, filterDiscountListByBookingTime } from "../../solution/ShopDiscount/utils";
39
+ import { uniqueById, getDiscountAmount, getDiscountListAmountTotal, getDiscountListAmount, filterDiscountListByBookingTime, getDiscountTimeUnavailableReason } from "../../solution/ShopDiscount/utils";
40
40
  import { getProductOriginTotalPrice, getProductTotalPrice } from "../Cart/utils";
41
41
  import Decimal from 'decimal.js';
42
42
  import { isBoolean } from 'lodash-es';
@@ -44,6 +44,7 @@ import dayjs from 'dayjs';
44
44
  import { isOrderLevelFixedAmountDiscount } from "../../solution/ShopDiscount/utils";
45
45
  import { calculateOrderLevelDiscountAllocation } from "../../solution/ShopDiscount/utils";
46
46
  import { compareEntitlementPassPriority, getRemainingEntitlementUses, isEntitlementPass, isFullCoveragePass, resolveEntitlementQuota } from "../Discount/entitlementPass";
47
+ import { getDiscountUsageBlockReason, getDiscountUsageLimitFailKey } from "../Discount/availability";
47
48
  export var RulesModule = /*#__PURE__*/function (_BaseModule) {
48
49
  _inherits(RulesModule, _BaseModule);
49
50
  var _super = _createSuper(RulesModule);
@@ -402,7 +403,12 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
402
403
  if (discount.isEditMode) {
403
404
  editModeDiscount.push(discount);
404
405
  } else {
405
- addModeDiscount.push(discount);
406
+ // 试算不能把 config / 不可用原因写回原有选券;每次重新计算以清除旧原因。
407
+ addModeDiscount.push(_objectSpread(_objectSpread({}, discount), {}, {
408
+ usageLimitFailKey: getDiscountUsageLimitFailKey(discount),
409
+ reason: undefined,
410
+ reasonCode: getDiscountUsageBlockReason(discount)
411
+ }));
406
412
  }
407
413
  });
408
414
 
@@ -664,12 +670,19 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
664
670
 
665
671
  // 🔥 为每个折扣卡/商品券执行策略检查并附加config
666
672
  var evaluator = this.getWalletPassEvaluator();
673
+ addModeDiscount.forEach(function (discount) {
674
+ if (discount.reasonCode) discount.config = {
675
+ isAvailable: false
676
+ };
677
+ });
667
678
  if (evaluator) {
668
679
  addModeDiscount.forEach(function (discount) {
680
+ // 即使没有匹配的动态策略,服务端状态和次数限制也不能被覆盖为可用。
681
+ if (discount.reasonCode) return;
669
682
  var discountType = discount.tag || discount.type || '';
670
683
  // 对两类全额抵扣卡和折扣卡执行附加策略检查。
671
684
  if (['entitlement_pass', 'good_pass', 'discount_card', 'product_discount_card'].includes(discountType)) {
672
- var _discount$limited_rel, _discount$limited_rel2;
685
+ var _discount$unified_ava, _discount$limited_rel, _discount$limited_rel2;
673
686
  var entitlementQuota = isEntitlementPass(discount) ? resolveEntitlementQuota(discount) : null;
674
687
  if (isEntitlementPass(discount) && !entitlementQuota) {
675
688
  discount.config = {
@@ -685,7 +698,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
685
698
  balance: (entitlementQuota === null || entitlementQuota === void 0 ? void 0 : entitlementQuota.type) === 'unlimited' ? Number.MAX_SAFE_INTEGER : (entitlementQuota === null || entitlementQuota === void 0 ? void 0 : entitlementQuota.type) === 'limited' ? entitlementQuota.balance : Number(discount.balance || 0),
686
699
  type: discountType,
687
700
  product_id: discount.product_id,
688
- unified_available_status: 1,
701
+ unified_available_status: (_discount$unified_ava = discount.unified_available_status) !== null && _discount$unified_ava !== void 0 ? _discount$unified_ava : 1,
689
702
  available_product_type: (_discount$limited_rel = discount.limited_relation_product_data) === null || _discount$limited_rel === void 0 ? void 0 : _discount$limited_rel.type,
690
703
  available_product_ids: (_discount$limited_rel2 = discount.limited_relation_product_data) === null || _discount$limited_rel2 === void 0 ? void 0 : _discount$limited_rel2.product_ids
691
704
  };
@@ -718,6 +731,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
718
731
  discount.config = {
719
732
  isAvailable: false
720
733
  };
734
+ discount.reason = result.reason;
735
+ discount.reasonCode = result.reasonCode || 'not_meet_the_required_conditions';
721
736
  }
722
737
  }
723
738
  });
@@ -894,6 +909,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
894
909
 
895
910
  // 记录每个优惠券适用的商品详细信息
896
911
  var discountApplicableProducts = new Map();
912
+ var discountTimeReasons = new Map();
913
+ var discountHolderMismatch = new Set();
897
914
 
898
915
  // 初始化每个优惠券的适用性和可抵扣商品
899
916
  addModeDiscount.forEach(function (discount) {
@@ -913,7 +930,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
913
930
 
914
931
  // 辅助函数:检查商品是否对某个折扣卡可用
915
932
  var checkItemApplicableForDiscount = function checkItemApplicableForDiscount(flatItem, discount) {
916
- var _product, _product2, _product3, _flatItem$bundleItem, _flatItem$bundleItem2, _product4;
933
+ var _discount$config2, _product, _product2, _product3, _flatItem$bundleItem, _flatItem$bundleItem2, _product4;
934
+ if (((_discount$config2 = discount.config) === null || _discount$config2 === void 0 ? void 0 : _discount$config2.isAvailable) === false) return false;
917
935
  var product;
918
936
  if (flatItem.type === 'main') {
919
937
  product = flatItem.product;
@@ -1121,7 +1139,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1121
1139
  }
1122
1140
  var isItemRewardProductDiscount = _this4.isItemRewardProductDiscount(product);
1123
1141
  addModeDiscount.forEach(function (discount) {
1124
- var _product5, _product6, _product7, _product8, _flatItem$bundleItem3, _flatItem$bundleItem4, _discount$config2;
1142
+ var _product5, _product6, _product7, _product8, _flatItem$bundleItem3, _flatItem$bundleItem4, _discount$config3;
1125
1143
  var limitedData = discount === null || discount === void 0 ? void 0 : discount.limited_relation_product_data;
1126
1144
  // 拿到discount配置的holder信息 product信息 product.holder 加在 isLimitedProduct
1127
1145
  var _tempVar = (flatItem === null || flatItem === void 0 ? void 0 : flatItem.type) === 'bundle' ? flatItem === null || flatItem === void 0 ? void 0 : flatItem.parentProduct : flatItem === null || flatItem === void 0 ? void 0 : flatItem.product;
@@ -1129,10 +1147,11 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1129
1147
  isNeedHolder: resolveIsFormSubject(_tempVar) && !(_tempVar !== null && _tempVar !== void 0 && _tempVar.isNormalProduct),
1130
1148
  holder_id: (_tempVar === null || _tempVar === void 0 ? void 0 : _tempVar.holder_id) || product.holder_id
1131
1149
  }, holders);
1132
- var timeLimit = true;
1133
- timeLimit = !!filterDiscountListByBookingTime([discount], (((_product5 = product) === null || _product5 === void 0 ? void 0 : _product5.startDate) || dayjs()).format('YYYY-MM-DD HH:mm:ss')).length;
1150
+ var timeReason = getDiscountTimeUnavailableReason(discount, (((_product5 = product) === null || _product5 === void 0 ? void 0 : _product5.startDate) || dayjs()).format('YYYY-MM-DD HH:mm:ss'));
1151
+ var timeLimit = !timeReason;
1134
1152
  // 是符合折扣的商品
1135
- var isLimitedProduct = (limitedData.type === 'product_all' && limitedData.filter !== 1 || limitedData.type === 'product_all' && limitedData.filter === 1 && !limitedData.exclude_product_ids.includes(product.id) || limitedData.product_ids && limitedData.product_ids.includes(product.id)) && isHolderMatch;
1153
+ var isProductInScope = limitedData.type === 'product_all' && limitedData.filter !== 1 || limitedData.type === 'product_all' && limitedData.filter === 1 && !limitedData.exclude_product_ids.includes(product.id) || limitedData.product_ids && limitedData.product_ids.includes(product.id);
1154
+ var isLimitedProduct = isProductInScope && isHolderMatch;
1136
1155
 
1137
1156
  // 编辑的商品 使用了优惠券不可用
1138
1157
  var isAvailableProduct = flatItem.type === 'main' ? !((_product6 = product) !== null && _product6 !== void 0 && _product6.booking_id && (_product7 = product) !== null && _product7 !== void 0 && (_product7 = _product7.discount_list) !== null && _product7 !== void 0 && _product7.length && (_product8 = product) !== null && _product8 !== void 0 && (_product8 = _product8.discount_list) !== null && _product8 !== void 0 && _product8.every(function (discount) {
@@ -1143,9 +1162,15 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1143
1162
 
1144
1163
  // 套餐是否可用判断
1145
1164
  var isBundleAvailable = _this4.checkPackageSubItemUsageRules(discount, flatItem);
1165
+ if (isProductInScope && isBundleAvailable && !isItemRewardProductDiscount) {
1166
+ var timeReasons = discountTimeReasons.get(discount.id) || [];
1167
+ timeReasons.push(timeReason);
1168
+ discountTimeReasons.set(discount.id, timeReasons);
1169
+ if (!isHolderMatch && timeLimit) discountHolderMismatch.add(discount.id);
1170
+ }
1146
1171
 
1147
1172
  // 判断优惠券是否适用于该商品
1148
- if (isAvailableProduct && !isItemRewardProductDiscount && isLimitedProduct && timeLimit && isBundleAvailable && (_discount$config2 = discount.config) !== null && _discount$config2 !== void 0 && _discount$config2.isAvailable && (!isEntitlementPass(discount) || getRemainingEntitlementUses(discount, 0, 1) > 0)) {
1173
+ if (isAvailableProduct && !isItemRewardProductDiscount && isLimitedProduct && timeLimit && isBundleAvailable && (_discount$config3 = discount.config) !== null && _discount$config3 !== void 0 && _discount$config3.isAvailable && (!isEntitlementPass(discount) || getRemainingEntitlementUses(discount, 0, 1) > 0)) {
1149
1174
  var _discountApplicabilit, _discount$metadata4, _discount$metadata5;
1150
1175
  // 记录此优惠券适用的商品
1151
1176
  (_discountApplicabilit = discountApplicability.get(discount.id)) === null || _discountApplicabilit === void 0 || _discountApplicabilit.push(product.id);
@@ -1301,9 +1326,9 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1301
1326
  if (!discount.isSelected) return false;
1302
1327
  }
1303
1328
  if (['entitlement_pass', 'good_pass', 'discount_card', 'product_discount_card'].includes(discountType) && !isReapplyEditModeDiscountForProduct) {
1304
- var _discount$config3;
1329
+ var _discount$config4;
1305
1330
  // 如果策略检查后没有config,说明不可用
1306
- if (discount.config === undefined || !(discount !== null && discount !== void 0 && (_discount$config3 = discount.config) !== null && _discount$config3 !== void 0 && _discount$config3.isAvailable)) {
1331
+ if (discount.config === undefined || !(discount !== null && discount !== void 0 && (_discount$config4 = discount.config) !== null && _discount$config4 !== void 0 && _discount$config4.isAvailable)) {
1307
1332
  return false;
1308
1333
  }
1309
1334
  }
@@ -1328,8 +1353,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1328
1353
 
1329
1354
  // 🔥 检查 maxUsagePerOrder 限制:同一 product_id 的商品券使用数量不能超过配置值
1330
1355
  if (isFullCoveragePass(discount)) {
1331
- var _discount$config4;
1332
- var maxUsagePerOrder = (_discount$config4 = discount.config) === null || _discount$config4 === void 0 ? void 0 : _discount$config4.maxUsagePerOrder;
1356
+ var _discount$config5;
1357
+ var maxUsagePerOrder = (_discount$config5 = discount.config) === null || _discount$config5 === void 0 ? void 0 : _discount$config5.maxUsagePerOrder;
1333
1358
  if (maxUsagePerOrder && maxUsagePerOrder > 0) {
1334
1359
  var currentUsedCount = usedProductIdCounts.get(discount.product_id) || 0;
1335
1360
  if (currentUsedCount >= maxUsagePerOrder) {
@@ -2351,10 +2376,17 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
2351
2376
 
2352
2377
  // 根据是否有适用商品决定isAvailable
2353
2378
  var isAvailable = applicableProducts.length > 0;
2379
+ var timeReasons = discountTimeReasons.get(discount.id) || [];
2380
+ var timeReason = timeReasons.length ? timeReasons.every(Boolean) ? timeReasons[0] : undefined : getDiscountTimeUnavailableReason(discount, dayjs().format('YYYY-MM-DD HH:mm:ss'));
2381
+ var reasonCode = isAvailable ? undefined : getDiscountUsageBlockReason(discount) || timeReason || discount.reasonCode || (discountHolderMismatch.has(discount.id) ? 'holder_not_matched' : 'product_not_applicable');
2382
+ var availabilityReason = {
2383
+ reasonCode: reasonCode,
2384
+ reason: reasonCode && reasonCode === discount.reasonCode ? discount.reason : undefined
2385
+ };
2354
2386
 
2355
2387
  // 如果此优惠券被明确设置为不选中,保持其状态,但正确设置isAvailable
2356
2388
  if (typeof discount.isSelected === 'boolean' && discount.isSelected === false && discount.isManualSelect) {
2357
- return _objectSpread(_objectSpread({}, discount), {}, {
2389
+ return _objectSpread(_objectSpread(_objectSpread({}, discount), availabilityReason), {}, {
2358
2390
  isSelected: false,
2359
2391
  isAvailable: isAvailable,
2360
2392
  // 正确设置可用性
@@ -2367,6 +2399,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
2367
2399
  }
2368
2400
  if (isDiscountUsed(discount)) {
2369
2401
  return _objectSpread(_objectSpread({}, discount), {}, {
2402
+ reason: undefined,
2403
+ reasonCode: undefined,
2370
2404
  isSelected: true,
2371
2405
  isManualSelect: options !== null && options !== void 0 && options.scan ? false : discount.isManualSelect,
2372
2406
  // 标记为可用,因为它已被应用
@@ -2387,7 +2421,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
2387
2421
  } else if (!appliedProductDetails.length && !committedAppliedProductDetails.length) {
2388
2422
  isSelected = false;
2389
2423
  }
2390
- return _objectSpread(_objectSpread({}, discount), {}, {
2424
+ return _objectSpread(_objectSpread(_objectSpread({}, discount), availabilityReason), {}, {
2391
2425
  // 如果有适用的商品,标记为可用
2392
2426
  isAvailable: isAvailable,
2393
2427
  isSelected: isSelected,
@@ -421,6 +421,7 @@ declare class Server {
421
421
  private shouldUseLocalOrderQuery;
422
422
  /**
423
423
  * 预约查询是否走本地:
424
+ * - 日历周/月/资源视图通过 compact_fields 显式标识,始终走远端;
424
425
  * - 当 sales_time_between 的开始和结束都不是今天时,走远端;
425
426
  * - 其余情况走本地。
426
427
  */
@@ -524,6 +525,12 @@ declare class Server {
524
525
  private stringifyCheckoutResourceIdentifier;
525
526
  private normalizeCheckoutSubmitData;
526
527
  private ensureCheckoutOrderNumbers;
528
+ /**
529
+ * Notes 允许在本地草稿阶段暂存空订单目标;checkout 的统一出口负责用最终
530
+ * shop_order_number 完成绑定并校验,保证后端请求、pending、设备任务和打印
531
+ * 都使用同一份完整快照。
532
+ */
533
+ private finalizeCheckoutSalesNotes;
527
534
  private dispatchCheckoutSyncTask;
528
535
  private dispatchPrintOtherReceiptTask;
529
536
  private buildPrintOtherReceiptIdempotencyKey;
@@ -43,6 +43,7 @@ import { filterBookingsFromOrders, sortBookings } from "./modules/order/utils/fi
43
43
  import { buildSmallTicketData, hasSmallTicketData } from "./utils/small-ticket";
44
44
  import { BaseSalesImpl } from "../solution/BaseSales";
45
45
  import { getOrderPaymentIdentityKeys, isIdentifiedPendingOrderPayment, isPendingOrderPayment, mergeOrderPaymentListsByIdentity } from "../modules/Order/payment-utils";
46
+ import { finalizeSalesNotesForCheckout } from "../modules/Order/salesNotes";
46
47
  import { normalizeOrderCollections } from "../modules/Order/utils/orderCollectionIdentity";
47
48
  import { stripOsPrivatePayloadFields } from "../utils/os-private-payload";
48
49
  import { getDefaultInvoiceLayoutConfig, getDefaultInvoiceTemplateSettings, normalizeRawInvoiceTemplateSettings, resolveInvoiceReceiptLocales } from "../modules/OpenData";
@@ -4369,12 +4370,14 @@ var Server = /*#__PURE__*/function () {
4369
4370
 
4370
4371
  /**
4371
4372
  * 预约查询是否走本地:
4373
+ * - 日历周/月/资源视图通过 compact_fields 显式标识,始终走远端;
4372
4374
  * - 当 sales_time_between 的开始和结束都不是今天时,走远端;
4373
4375
  * - 其余情况走本地。
4374
4376
  */
4375
4377
  }, {
4376
4378
  key: "shouldUseLocalBookingQuery",
4377
4379
  value: function shouldUseLocalBookingQuery(data) {
4380
+ if ((data === null || data === void 0 ? void 0 : data.compact_fields) === true) return false;
4378
4381
  var range = data === null || data === void 0 ? void 0 : data.sales_time_between;
4379
4382
  if (!Array.isArray(range) || range.length < 2) return true;
4380
4383
  return !this.isRangeBothNotToday(range[0], range[1]);
@@ -5868,7 +5871,7 @@ var Server = /*#__PURE__*/function () {
5868
5871
  _context57.next = 7;
5869
5872
  break;
5870
5873
  }
5871
- return _context57.abrupt("return", next);
5874
+ return _context57.abrupt("return", this.finalizeCheckoutSalesNotes(next, title));
5872
5875
  case 7:
5873
5876
  idGenerator = this.getIdGeneratorPlugin();
5874
5877
  if (idGenerator) {
@@ -5879,7 +5882,7 @@ var Server = /*#__PURE__*/function () {
5879
5882
  needsShopOrderNumber: needsShopOrderNumber,
5880
5883
  needsShopFullOrderNumber: needsShopFullOrderNumber
5881
5884
  });
5882
- return _context57.abrupt("return", next);
5885
+ return _context57.abrupt("return", this.finalizeCheckoutSalesNotes(next, title));
5883
5886
  case 11:
5884
5887
  _context57.prev = 11;
5885
5888
  if (!(needsShopOrderNumber && idGenerator.generateShopOrderNumber)) {
@@ -5917,7 +5920,7 @@ var Server = /*#__PURE__*/function () {
5917
5920
  error: _context57.t0 instanceof Error ? _context57.t0.message : String(_context57.t0)
5918
5921
  });
5919
5922
  case 26:
5920
- return _context57.abrupt("return", next);
5923
+ return _context57.abrupt("return", this.finalizeCheckoutSalesNotes(next, title));
5921
5924
  case 27:
5922
5925
  case "end":
5923
5926
  return _context57.stop();
@@ -5929,6 +5932,45 @@ var Server = /*#__PURE__*/function () {
5929
5932
  }
5930
5933
  return ensureCheckoutOrderNumbers;
5931
5934
  }()
5935
+ /**
5936
+ * Notes 允许在本地草稿阶段暂存空订单目标;checkout 的统一出口负责用最终
5937
+ * shop_order_number 完成绑定并校验,保证后端请求、pending、设备任务和打印
5938
+ * 都使用同一份完整快照。
5939
+ */
5940
+ }, {
5941
+ key: "finalizeCheckoutSalesNotes",
5942
+ value: function finalizeCheckoutSalesNotes(data, title) {
5943
+ var _data$shop_order_numb;
5944
+ if (!data || _typeof(data) !== 'object') return data;
5945
+ if (!Object.prototype.hasOwnProperty.call(data, 'notes')) return data;
5946
+ if (data.notes === undefined || data.notes === null) return data;
5947
+ if (!Array.isArray(data.notes)) {
5948
+ throw new Error('[Order Notes] checkout notes 必须为数组');
5949
+ }
5950
+ if (data.notes.length === 0) return data;
5951
+ var productTargetUuids = (Array.isArray(data.products) ? data.products : []).map(function (product) {
5952
+ var _product$metadata$uni, _product$metadata;
5953
+ return (_product$metadata$uni = product === null || product === void 0 || (_product$metadata = product.metadata) === null || _product$metadata === void 0 ? void 0 : _product$metadata.unique_identification_number) !== null && _product$metadata$uni !== void 0 ? _product$metadata$uni : product === null || product === void 0 ? void 0 : product.unique_identification_number;
5954
+ }).filter(function (targetUuid) {
5955
+ return targetUuid !== undefined && targetUuid !== null && String(targetUuid).trim().length > 0;
5956
+ }).map(function (targetUuid) {
5957
+ return String(targetUuid);
5958
+ });
5959
+ var shopOrderNumber = String((_data$shop_order_numb = data.shop_order_number) !== null && _data$shop_order_numb !== void 0 ? _data$shop_order_numb : '').trim();
5960
+ var notes = finalizeSalesNotesForCheckout({
5961
+ notes: data.notes,
5962
+ shopOrderNumber: shopOrderNumber,
5963
+ productTargetUuids: productTargetUuids
5964
+ });
5965
+ this.logInfo("".concat(title, ": checkout Notes \u5DF2\u7ED1\u5B9A\u8BA2\u5355\u53F7"), {
5966
+ shop_order_number: shopOrderNumber,
5967
+ note_count: notes.length
5968
+ });
5969
+ return _objectSpread(_objectSpread({}, data), {}, {
5970
+ shop_order_number: shopOrderNumber,
5971
+ notes: notes
5972
+ });
5973
+ }
5932
5974
  }, {
5933
5975
  key: "dispatchCheckoutSyncTask",
5934
5976
  value: function () {
@@ -3249,6 +3249,12 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
3249
3249
  mergedRecord[_field] = cloneDeep(incomingRecord[_field]);
3250
3250
  }
3251
3251
 
3252
+ // order_meta_list 是一次性生成的完整业务快照。incoming 明确携带时
3253
+ // 必须整体覆盖(包括 null / 空对象 / 空数组);省略时才保留 existing。
3254
+ if (Object.prototype.hasOwnProperty.call(incomingRecord, 'order_meta_list')) {
3255
+ mergedRecord.order_meta_list = cloneDeep(incomingRecord.order_meta_list);
3256
+ }
3257
+
3252
3258
  // 子项数组遵循完整快照语义:incoming 自有且为数组(包括 [])时权威替换;
3253
3259
  // 字段缺席或不是数组时视为稀疏 patch,继续保留 existing。
3254
3260
  for (var _i6 = 0, _ORDER_AUTHORITATIVE_2 = ORDER_AUTHORITATIVE_COLLECTION_FIELDS; _i6 < _ORDER_AUTHORITATIVE_2.length; _i6++) {
@@ -456,6 +456,15 @@ export interface OrderData {
456
456
  par_value: string;
457
457
  used_par_value: string;
458
458
  }>;
459
+ virtual_currency_snapshot?: Array<{
460
+ id: number | string;
461
+ tag: 'virtual_currency';
462
+ product_id?: number | string;
463
+ product_name: string;
464
+ par_value: string;
465
+ used_par_value: string;
466
+ name: Record<string, string>;
467
+ }>;
459
468
  };
460
469
  /**
461
470
  * 金额汇总(仅输出)。
@@ -45,6 +45,7 @@ export interface SmallTicketProduct {
45
45
  product_uid?: string | number;
46
46
  booking_uid?: string | number;
47
47
  product_note?: string;
48
+ allergy?: string;
48
49
  options?: Array<{
49
50
  name: string;
50
51
  num?: number;
@@ -319,6 +319,7 @@ function buildBaseData(params) {
319
319
  }
320
320
  function buildProducts(order, locale, productMap) {
321
321
  var products = Array.isArray(order.products) ? order.products : [];
322
+ var allergyByProductUid = buildProductAllergyMap(order, locale);
322
323
  return products.map(function (rawProduct) {
323
324
  var _ref, _ref2, _product$product_quan, _ref3, _ref4, _ref5, _product$original_pri, _ref6, _ref7, _product$selling_pric, _product$product_id, _product$metadata, _product$metadata2;
324
325
  var product = restoreReceiptDiscountHierarchy(rawProduct);
@@ -360,10 +361,11 @@ function buildProducts(order, locale, productMap) {
360
361
  originalPrice: originalPrice
361
362
  });
362
363
  var productNote = resolveProductNote(product, locale);
364
+ var allergy = isPresentId(productUid) ? allergyByProductUid.get(String(productUid).trim()) || '' : '';
363
365
  var basePrice = resolveProductBasePrice(product);
364
366
  var resolvedCombinations = Array.isArray(product.combinations) && product.combinations.length ? normalizeExistingCombinations(product.combinations, locale, currencySymbol) : combinations;
365
367
  var shouldIncludeBasePrice = options.length > 0 || resolvedCombinations.length > 0 || hasProductDiscount(product, extensionList);
366
- return _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
368
+ return _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
367
369
  product_title: productTitle,
368
370
  product_quantity: quantity,
369
371
  selling_price: formatMoney(sellingPrice, currencySymbol),
@@ -385,6 +387,8 @@ function buildProducts(order, locale, productMap) {
385
387
  booking_uid: bookingUid
386
388
  } : {}), productNote ? {
387
389
  product_note: productNote
390
+ } : {}), allergy ? {
391
+ allergy: allergy
388
392
  } : {}), options.length ? {
389
393
  options: options
390
394
  } : {}), resolvedVariant ? {
@@ -810,6 +814,25 @@ function resolveProductNote(product, locale) {
810
814
  if (productNote) return productNote;
811
815
  return getLocalizedValue(product.note, locale).trim();
812
816
  }
817
+ function buildProductAllergyMap(order, locale) {
818
+ var allergyByProductUid = new Map();
819
+ for (var _i = 0, _normalizeArray = normalizeArray(order.notes); _i < _normalizeArray.length; _i++) {
820
+ var _note$content, _relation$target_uuid;
821
+ var note = _normalizeArray[_i];
822
+ if (!note || _typeof(note) !== 'object' || Array.isArray(note) || String(note.note_type || '').trim() !== 'allergy') {
823
+ continue;
824
+ }
825
+ var content = getLocalizedValue((_note$content = note.content) === null || _note$content === void 0 ? void 0 : _note$content.text, locale).trim();
826
+ if (!content) continue;
827
+ var relation = normalizeArray(note.note_relations).find(function (item) {
828
+ return item && _typeof(item) === 'object' && !Array.isArray(item) && item.relation_type === 'about' && item.target_type === 'order_detail' && Number(item.is_primary) === 1;
829
+ });
830
+ var productUid = String((_relation$target_uuid = relation === null || relation === void 0 ? void 0 : relation.target_uuid) !== null && _relation$target_uuid !== void 0 ? _relation$target_uuid : '').trim();
831
+ if (!productUid || allergyByProductUid.has(productUid)) continue;
832
+ allergyByProductUid.set(productUid, content);
833
+ }
834
+ return allergyByProductUid;
835
+ }
813
836
  function resolveBundleProductTitle(params) {
814
837
  var _ref29, _ref30, _bundle$bundle_produc;
815
838
  var bundle = params.bundle,
@@ -1043,9 +1066,9 @@ function buildFees(params) {
1043
1066
  currencySymbol = params.currencySymbol,
1044
1067
  financials = params.financials;
1045
1068
  var fees = [];
1046
- for (var _i = 0, _normalizeArray = normalizeArray(order.surcharges || summary.surcharges); _i < _normalizeArray.length; _i++) {
1069
+ for (var _i2 = 0, _normalizeArray2 = normalizeArray(order.surcharges || summary.surcharges); _i2 < _normalizeArray2.length; _i2++) {
1047
1070
  var _ref48, _surcharge$amount;
1048
- var surcharge = _normalizeArray[_i];
1071
+ var surcharge = _normalizeArray2[_i2];
1049
1072
  var value = (_ref48 = (_surcharge$amount = surcharge.amount) !== null && _surcharge$amount !== void 0 ? _surcharge$amount : surcharge.value) !== null && _ref48 !== void 0 ? _ref48 : surcharge.total_amount;
1050
1073
  if (!isNonZero(value)) continue;
1051
1074
  fees.push({
@@ -1266,8 +1289,8 @@ function firstValidBookingDate() {
1266
1289
  for (var _len2 = arguments.length, values = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
1267
1290
  values[_key2] = arguments[_key2];
1268
1291
  }
1269
- for (var _i2 = 0, _values = values; _i2 < _values.length; _i2++) {
1270
- var value = _values[_i2];
1292
+ for (var _i3 = 0, _values = values; _i3 < _values.length; _i3++) {
1293
+ var value = _values[_i3];
1271
1294
  if (!isPresentId(value)) continue;
1272
1295
  var parsed = dayjs(value);
1273
1296
  if (parsed.isValid()) return parsed;
@@ -1324,9 +1347,9 @@ function sortBookings(bookings) {
1324
1347
  var leftStart = bookingStartTimestamp(left.booking);
1325
1348
  var rightStart = bookingStartTimestamp(right.booking);
1326
1349
  if (leftStart !== rightStart) return leftStart < rightStart ? -1 : 1;
1327
- for (var _i3 = 0, _arr = ['booking_id', 'schedule_event_id']; _i3 < _arr.length; _i3++) {
1350
+ for (var _i4 = 0, _arr = ['booking_id', 'schedule_event_id']; _i4 < _arr.length; _i4++) {
1328
1351
  var _left$booking, _right$booking;
1329
- var field = _arr[_i3];
1352
+ var field = _arr[_i4];
1330
1353
  var fieldOrder = compareOptionalValues((_left$booking = left.booking) === null || _left$booking === void 0 ? void 0 : _left$booking[field], (_right$booking = right.booking) === null || _right$booking === void 0 ? void 0 : _right$booking[field]);
1331
1354
  if (fieldOrder !== 0) return fieldOrder;
1332
1355
  }
@@ -1339,8 +1362,8 @@ function sortBookings(bookings) {
1339
1362
  }
1340
1363
  function bookingStartTimestamp(booking) {
1341
1364
  var startValues = [booking === null || booking === void 0 ? void 0 : booking.start_at, booking === null || booking === void 0 ? void 0 : booking.start_datetime, booking === null || booking === void 0 ? void 0 : booking.booking_time, isPresentId(booking === null || booking === void 0 ? void 0 : booking.start_date) ? "".concat(booking.start_date, " ").concat(stringify(booking.start_time)).trim() : undefined];
1342
- for (var _i4 = 0, _startValues = startValues; _i4 < _startValues.length; _i4++) {
1343
- var startValue = _startValues[_i4];
1365
+ for (var _i5 = 0, _startValues = startValues; _i5 < _startValues.length; _i5++) {
1366
+ var startValue = _startValues[_i5];
1344
1367
  if (!isPresentId(startValue)) continue;
1345
1368
  var timestamp = dayjs(startValue).valueOf();
1346
1369
  if (Number.isFinite(timestamp)) return timestamp;
@@ -1466,17 +1489,20 @@ function resolveRefundPayment(refund, payments) {
1466
1489
  return matchedPayment || refund;
1467
1490
  }
1468
1491
  function buildWallets(params) {
1492
+ var virtualCurrencySnapshots = collectVirtualCurrencySnapshots(params.order);
1469
1493
  var displayedWalletPayments = normalizeArray(params.order.payments).filter(function (payment) {
1470
1494
  return isPrintablePayment(payment) && !!getFundRecord(payment);
1471
1495
  });
1472
1496
  var paymentWallets = displayedWalletPayments.map(function (payment) {
1497
+ var virtualCurrencySnapshot = findVirtualCurrencySnapshotForPayment(payment, virtualCurrencySnapshots.byId);
1473
1498
  return buildPaymentItems({
1474
1499
  payment: payment,
1475
1500
  locale: params.locale,
1476
1501
  currencySymbol: params.currencySymbol,
1477
1502
  includeFundRecordBalance: true,
1478
1503
  includeFundRecordUsage: false,
1479
- includePaymentAmount: false
1504
+ includePaymentAmount: false,
1505
+ virtualCurrencyUnit: virtualCurrencySnapshot ? getVirtualCurrencySnapshotUnit(virtualCurrencySnapshot, params.locale) : undefined
1480
1506
  });
1481
1507
  });
1482
1508
  var displayedWalletPassIds = collectDisplayedWalletPassIds(displayedWalletPayments);
@@ -1484,6 +1510,11 @@ function buildWallets(params) {
1484
1510
  order: params.order,
1485
1511
  locale: params.locale,
1486
1512
  displayedWalletPassIds: displayedWalletPassIds
1513
+ })), _toConsumableArray(buildVirtualCurrencySnapshotAssets({
1514
+ snapshots: virtualCurrencySnapshots.items,
1515
+ order: params.order,
1516
+ locale: params.locale,
1517
+ displayedWalletPassIds: displayedWalletPassIds
1487
1518
  })));
1488
1519
  }
1489
1520
  function collectDisplayedWalletPassIds(payments) {
@@ -1531,6 +1562,91 @@ function buildPointCardSnapshotAssets(params) {
1531
1562
  return [rows];
1532
1563
  });
1533
1564
  }
1565
+ function collectVirtualCurrencySnapshots(order) {
1566
+ var _order$order_meta_lis;
1567
+ var items = [];
1568
+ var byId = new Map();
1569
+ var snapshots = (_order$order_meta_lis = order.order_meta_list) === null || _order$order_meta_lis === void 0 ? void 0 : _order$order_meta_lis.virtual_currency_snapshot;
1570
+ if (!Array.isArray(snapshots)) return {
1571
+ items: items,
1572
+ byId: byId
1573
+ };
1574
+ snapshots.forEach(function (snapshot) {
1575
+ if (!snapshot || _typeof(snapshot) !== 'object' || Array.isArray(snapshot)) return;
1576
+ var virtualCurrency = snapshot;
1577
+ if (stringify(virtualCurrency.tag).trim().toLowerCase() !== 'virtual_currency') return;
1578
+ var id = normalizeWalletPassId(virtualCurrency.id);
1579
+ if (!id || byId.has(id)) return;
1580
+ byId.set(id, virtualCurrency);
1581
+ items.push(virtualCurrency);
1582
+ });
1583
+ return {
1584
+ items: items,
1585
+ byId: byId
1586
+ };
1587
+ }
1588
+ function findVirtualCurrencySnapshotForPayment(payment, snapshotsById) {
1589
+ var fundRecord = getFundRecord(payment);
1590
+ for (var _i6 = 0, _arr2 = [fundRecord === null || fundRecord === void 0 ? void 0 : fundRecord.voucher_id, payment.voucher_id]; _i6 < _arr2.length; _i6++) {
1591
+ var value = _arr2[_i6];
1592
+ var id = normalizeWalletPassId(value);
1593
+ if (!id) continue;
1594
+ var snapshot = snapshotsById.get(id);
1595
+ if (snapshot) return snapshot;
1596
+ }
1597
+ return undefined;
1598
+ }
1599
+ function buildVirtualCurrencySnapshotAssets(params) {
1600
+ var snapshotTime = firstPresentValue(params.order.updated_at, params.order.created_at);
1601
+ return params.snapshots.flatMap(function (virtualCurrency) {
1602
+ var id = normalizeWalletPassId(virtualCurrency.id);
1603
+ if (!id || params.displayedWalletPassIds.has(id)) return [];
1604
+ var rows = [{
1605
+ item: stringify(virtualCurrency.product_name).trim(),
1606
+ value: ''
1607
+ }];
1608
+ var balance = getVirtualCurrencySnapshotBalance(virtualCurrency);
1609
+ if (balance) {
1610
+ rows.push({
1611
+ item: label(params.locale, 'balance'),
1612
+ value: formatVirtualCurrencyBalance(balance, getVirtualCurrencySnapshotUnit(virtualCurrency, params.locale))
1613
+ });
1614
+ }
1615
+ if (isPresentId(snapshotTime)) {
1616
+ rows.push({
1617
+ item: formatDateTime(snapshotTime, params.locale),
1618
+ value: ''
1619
+ });
1620
+ }
1621
+ return [rows];
1622
+ });
1623
+ }
1624
+ function getVirtualCurrencySnapshotBalance(snapshot) {
1625
+ if (!isNumericAmount(snapshot.par_value) || !isNumericAmount(snapshot.used_par_value)) {
1626
+ return null;
1627
+ }
1628
+ return Decimal.max(new Decimal(snapshot.par_value).minus(new Decimal(snapshot.used_par_value)), 0);
1629
+ }
1630
+ function getVirtualCurrencySnapshotUnit(snapshot, locale) {
1631
+ return getNonEmptyLocalizedValue(snapshot.name, locale);
1632
+ }
1633
+ function getNonEmptyLocalizedValue(value, locale) {
1634
+ if (value === undefined || value === null) return '';
1635
+ if (_typeof(value) !== 'object' || Array.isArray(value)) return stringify(value).trim();
1636
+ var dashedLocale = locale.replace('_', '-');
1637
+ var underscoredLocale = locale.replace('-', '_');
1638
+ for (var _i7 = 0, _arr3 = [value[locale], value[dashedLocale], value[underscoredLocale], value.original, value.auto, value.default, value.en]; _i7 < _arr3.length; _i7++) {
1639
+ var candidate = _arr3[_i7];
1640
+ var text = stringify(candidate).trim();
1641
+ if (text) return text;
1642
+ }
1643
+ return '';
1644
+ }
1645
+ function formatVirtualCurrencyBalance(value, unit) {
1646
+ var amount = trimDecimal(value);
1647
+ var normalizedUnit = unit.trim();
1648
+ return normalizedUnit ? "".concat(amount, " ").concat(normalizedUnit) : amount;
1649
+ }
1534
1650
  function normalizeWalletPassId(value) {
1535
1651
  if (typeof value === 'number') return Number.isFinite(value) ? String(value) : null;
1536
1652
  if (typeof value !== 'string') return null;
@@ -1583,8 +1699,9 @@ function buildVoucherAssets(params) {
1583
1699
  }].concat(_toConsumableArray(timeRow ? [timeRow] : []))];
1584
1700
  });
1585
1701
  }
1702
+ var TICKET_VOUCHER_TAGS = new Set(['ticket', 'product_package_ticket', 'appointment_ticket', 'session_ticket']);
1586
1703
  function isTicketVoucher(voucher) {
1587
- return stringify(voucher.tag).trim().toLowerCase() === 'ticket';
1704
+ return TICKET_VOUCHER_TAGS.has(stringify(voucher.tag).trim().toLowerCase());
1588
1705
  }
1589
1706
  function getVoucherValidity(voucher, locale) {
1590
1707
  var _voucher$metadata, _voucher$metadata2, _voucher$metadata3, _voucher$metadata4, _voucher$metadata5, _voucher$metadata6, _voucher$metadata7, _voucher$metadata8, _voucher$metadata9, _voucher$metadata10, _voucher$start_time, _voucher$metadata11, _voucher$end_time, _voucher$metadata12;
@@ -1700,7 +1817,8 @@ function buildPaymentItems(params) {
1700
1817
  currencySymbol = params.currencySymbol,
1701
1818
  includeFundRecordBalance = params.includeFundRecordBalance,
1702
1819
  includeFundRecordUsage = params.includeFundRecordUsage,
1703
- includePaymentAmount = params.includePaymentAmount;
1820
+ includePaymentAmount = params.includePaymentAmount,
1821
+ virtualCurrencyUnit = params.virtualCurrencyUnit;
1704
1822
  var serviceFee = getPaymentServiceFee(payment);
1705
1823
  var items = [{
1706
1824
  item: paymentMethodName(payment, locale),
@@ -1725,7 +1843,8 @@ function buildPaymentItems(params) {
1725
1843
  locale: locale,
1726
1844
  currencySymbol: currencySymbol,
1727
1845
  includeBalance: includeFundRecordBalance,
1728
- includeUsage: includeFundRecordUsage
1846
+ includeUsage: includeFundRecordUsage,
1847
+ virtualCurrencyUnit: virtualCurrencyUnit
1729
1848
  })));
1730
1849
  } else {
1731
1850
  var _ref59, _payment$remaining_am, _payment$metadata;
@@ -1790,7 +1909,8 @@ function buildFundRecordPaymentItems(params) {
1790
1909
  locale = params.locale,
1791
1910
  currencySymbol = params.currencySymbol,
1792
1911
  includeBalance = params.includeBalance,
1793
- includeUsage = params.includeUsage;
1912
+ includeUsage = params.includeUsage,
1913
+ virtualCurrencyUnit = params.virtualCurrencyUnit;
1794
1914
  var items = [];
1795
1915
  var usingBeforeValue = fundRecord.using_before_value;
1796
1916
  var usingAfterValue = fundRecord.using_after_value;
@@ -1811,6 +1931,14 @@ function buildFundRecordPaymentItems(params) {
1811
1931
  return items;
1812
1932
  }
1813
1933
  if (includeBalance && usingAfterValue !== undefined && usingAfterValue !== null) {
1934
+ if (virtualCurrencyUnit !== undefined) {
1935
+ if (!isNumericAmount(usingAfterValue)) return items;
1936
+ items.push({
1937
+ item: label(locale, 'balance'),
1938
+ value: formatVirtualCurrencyBalance(new Decimal(usingAfterValue), virtualCurrencyUnit)
1939
+ });
1940
+ return items;
1941
+ }
1814
1942
  items.push({
1815
1943
  item: label(locale, 'balance'),
1816
1944
  value: formatMoney(usingAfterValue, currencySymbol)