@pisell/pisellos 2.2.274 → 2.2.276

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 (117) hide show
  1. package/dist/core/index.d.ts +2 -0
  2. package/dist/core/index.js +7 -0
  3. package/dist/model/strategy/adapter/promotion/adapter.d.ts +4 -0
  4. package/dist/model/strategy/adapter/promotion/adapter.js +23 -0
  5. package/dist/model/strategy/adapter/promotion/evaluator.d.ts +17 -0
  6. package/dist/model/strategy/adapter/promotion/evaluator.js +279 -6
  7. package/dist/model/strategy/adapter/promotion/examples.d.ts +86 -0
  8. package/dist/model/strategy/adapter/promotion/examples.js +99 -0
  9. package/dist/model/strategy/adapter/promotion/index.d.ts +1 -1
  10. package/dist/model/strategy/adapter/promotion/index.js +1 -1
  11. package/dist/model/strategy/adapter/promotion/type.d.ts +90 -2
  12. package/dist/model/strategy/adapter/promotion/type.js +45 -0
  13. package/dist/modules/OpenData/index.d.ts +2 -0
  14. package/dist/modules/OpenData/index.js +8 -0
  15. package/dist/modules/Order/index.d.ts +28 -8
  16. package/dist/modules/Order/index.js +907 -588
  17. package/dist/modules/Order/payment-utils.d.ts +26 -0
  18. package/dist/modules/Order/payment-utils.js +225 -0
  19. package/dist/modules/Order/types.d.ts +35 -1
  20. package/dist/modules/Order/utils/orderCollectionIdentity.js +7 -2
  21. package/dist/modules/Order/utils.js +10 -6
  22. package/dist/modules/Payment/index.d.ts +2 -0
  23. package/dist/modules/Payment/index.js +78 -49
  24. package/dist/modules/Payment/types.d.ts +104 -25
  25. package/dist/modules/Payment/types.js +17 -0
  26. package/dist/modules/Payment/walletpass.d.ts +38 -1
  27. package/dist/modules/Payment/walletpass.js +917 -114
  28. package/dist/modules/Rules/index.d.ts +3 -0
  29. package/dist/modules/Rules/index.js +100 -70
  30. package/dist/server/index.d.ts +25 -0
  31. package/dist/server/index.js +1993 -1061
  32. package/dist/server/modules/index.d.ts +1 -1
  33. package/dist/server/modules/order/index.d.ts +70 -4
  34. package/dist/server/modules/order/index.js +1816 -728
  35. package/dist/server/modules/order/types.d.ts +25 -3
  36. package/dist/server/modules/order/types.js +7 -1
  37. package/dist/solution/BaseSales/index.d.ts +104 -5
  38. package/dist/solution/BaseSales/index.js +1767 -436
  39. package/dist/solution/BaseSales/types.d.ts +55 -1
  40. package/dist/solution/BaseSales/types.js +2 -1
  41. package/dist/solution/BaseSales/utils/cartPromotion.d.ts +3 -1
  42. package/dist/solution/BaseSales/utils/cartPromotion.js +94 -32
  43. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +6 -1
  44. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +7 -4
  45. package/dist/solution/BookingByStep/index.d.ts +1 -1
  46. package/dist/solution/BookingTicket/index.d.ts +21 -5
  47. package/dist/solution/BookingTicket/index.js +139 -56
  48. package/dist/solution/BookingTicket/types.d.ts +1 -0
  49. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +8 -0
  50. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +173 -83
  51. package/dist/solution/Sales/index.d.ts +2 -0
  52. package/dist/solution/Sales/index.js +26 -4
  53. package/dist/solution/ScanOrder/index.js +31 -20
  54. package/dist/solution/VenueBooking/index.d.ts +1 -0
  55. package/dist/solution/VenueBooking/index.js +30 -19
  56. package/dist/types/index.d.ts +1 -0
  57. package/dist/utils/payment-number.d.ts +9 -0
  58. package/dist/utils/payment-number.js +69 -0
  59. package/lib/core/index.d.ts +2 -0
  60. package/lib/core/index.js +4 -0
  61. package/lib/model/strategy/adapter/promotion/adapter.d.ts +4 -0
  62. package/lib/model/strategy/adapter/promotion/adapter.js +20 -0
  63. package/lib/model/strategy/adapter/promotion/evaluator.d.ts +17 -0
  64. package/lib/model/strategy/adapter/promotion/evaluator.js +235 -0
  65. package/lib/model/strategy/adapter/promotion/examples.d.ts +86 -0
  66. package/lib/model/strategy/adapter/promotion/examples.js +91 -0
  67. package/lib/model/strategy/adapter/promotion/index.d.ts +1 -1
  68. package/lib/model/strategy/adapter/promotion/index.js +2 -0
  69. package/lib/model/strategy/adapter/promotion/type.d.ts +90 -2
  70. package/lib/model/strategy/adapter/promotion/type.js +2 -0
  71. package/lib/modules/OpenData/index.d.ts +2 -0
  72. package/lib/modules/OpenData/index.js +5 -0
  73. package/lib/modules/Order/index.d.ts +28 -8
  74. package/lib/modules/Order/index.js +252 -84
  75. package/lib/modules/Order/payment-utils.d.ts +26 -0
  76. package/lib/modules/Order/payment-utils.js +224 -0
  77. package/lib/modules/Order/types.d.ts +35 -1
  78. package/lib/modules/Order/utils/orderCollectionIdentity.js +3 -0
  79. package/lib/modules/Order/utils.js +11 -4
  80. package/lib/modules/Payment/index.d.ts +2 -0
  81. package/lib/modules/Payment/index.js +33 -12
  82. package/lib/modules/Payment/types.d.ts +104 -25
  83. package/lib/modules/Payment/types.js +1 -0
  84. package/lib/modules/Payment/walletpass.d.ts +38 -1
  85. package/lib/modules/Payment/walletpass.js +730 -21
  86. package/lib/modules/Rules/index.d.ts +3 -0
  87. package/lib/modules/Rules/index.js +38 -9
  88. package/lib/server/index.d.ts +25 -0
  89. package/lib/server/index.js +726 -31
  90. package/lib/server/modules/index.d.ts +1 -1
  91. package/lib/server/modules/order/index.d.ts +70 -4
  92. package/lib/server/modules/order/index.js +818 -69
  93. package/lib/server/modules/order/types.d.ts +25 -3
  94. package/lib/server/modules/order/types.js +1 -0
  95. package/lib/solution/BaseSales/index.d.ts +104 -5
  96. package/lib/solution/BaseSales/index.js +858 -27
  97. package/lib/solution/BaseSales/types.d.ts +55 -1
  98. package/lib/solution/BaseSales/types.js +2 -1
  99. package/lib/solution/BaseSales/utils/cartPromotion.d.ts +3 -1
  100. package/lib/solution/BaseSales/utils/cartPromotion.js +66 -12
  101. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +6 -1
  102. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +4 -3
  103. package/lib/solution/BookingByStep/index.d.ts +1 -1
  104. package/lib/solution/BookingTicket/index.d.ts +21 -5
  105. package/lib/solution/BookingTicket/index.js +64 -13
  106. package/lib/solution/BookingTicket/types.d.ts +1 -0
  107. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +8 -0
  108. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +37 -5
  109. package/lib/solution/Sales/index.d.ts +2 -0
  110. package/lib/solution/Sales/index.js +20 -6
  111. package/lib/solution/ScanOrder/index.js +8 -0
  112. package/lib/solution/VenueBooking/index.d.ts +1 -0
  113. package/lib/solution/VenueBooking/index.js +8 -0
  114. package/lib/types/index.d.ts +1 -0
  115. package/lib/utils/payment-number.d.ts +9 -0
  116. package/lib/utils/payment-number.js +64 -0
  117. package/package.json +1 -1
@@ -40,6 +40,8 @@ var import_decimal = __toESM(require("decimal.js"));
40
40
  var import_lodash_es = require("lodash-es");
41
41
  var import_types2 = require("../BookingByStep/types");
42
42
  var import_utils = require("../../modules/Order/utils");
43
+ var import_payment_utils = require("../../modules/Order/payment-utils");
44
+ var import_payment_number = require("../../utils/payment-number");
43
45
  var import_orderCollectionIdentity = require("../../modules/Order/utils/orderCollectionIdentity");
44
46
  var import_dayjs = __toESM(require("dayjs"));
45
47
  __reExport(BaseSales_exports, require("./types"), module.exports);
@@ -47,6 +49,88 @@ var import_Quotation = require("../../modules/Quotation");
47
49
  var import_transformBaseProductToOrderProduct = require("./utils/transformBaseProductToOrderProduct");
48
50
  var import_quotationPrice = require("./utils/quotationPrice");
49
51
  var SERVER_ORDER_CHANGED_EVENT = "order:onOrdersChanged";
52
+ var WALLET_PAYMENT_CODE_BY_TAG = {
53
+ product_voucher: "PRODUCTVOUCHER",
54
+ gift_card: "GIFTCARD",
55
+ point_card: "POINTCARD"
56
+ };
57
+ function getSharedWalletAssetId(asset) {
58
+ return (asset == null ? void 0 : asset.id) ?? (asset == null ? void 0 : asset.voucher_id) ?? (asset == null ? void 0 : asset.code);
59
+ }
60
+ function getSharedWalletAssetAmount(asset) {
61
+ const value = (asset == null ? void 0 : asset.edit_current_amount) ?? (asset == null ? void 0 : asset._available_max_amount) ?? ((asset == null ? void 0 : asset.tag) === "point_card" ? asset == null ? void 0 : asset.recommended_usage_amount : asset == null ? void 0 : asset.available_max_amount) ?? (asset == null ? void 0 : asset.actualDeduction) ?? (asset == null ? void 0 : asset.amount) ?? 0;
62
+ const amount = Number(value);
63
+ return Number.isFinite(amount) && amount > 0 ? amount : 0;
64
+ }
65
+ function isRejectedSalesSubmitResult(result) {
66
+ var _a, _b;
67
+ const candidates = [
68
+ result,
69
+ result == null ? void 0 : result.data,
70
+ (_a = result == null ? void 0 : result.response) == null ? void 0 : _a.data,
71
+ (_b = result == null ? void 0 : result.response) == null ? void 0 : _b.body
72
+ ];
73
+ return candidates.some((candidate) => {
74
+ if (!candidate || typeof candidate !== "object")
75
+ return false;
76
+ const responseCode = Number(candidate.code ?? candidate.statusCode);
77
+ if (Number.isFinite(responseCode) && responseCode >= 400)
78
+ return true;
79
+ if (candidate.status === false || candidate.success === false || candidate.result === false) {
80
+ return true;
81
+ }
82
+ return ["failed", "error"].includes(
83
+ String(candidate.status || "").toLowerCase()
84
+ );
85
+ });
86
+ }
87
+ function getSalesSubmitErrorMessage(result) {
88
+ var _a, _b;
89
+ return (result == null ? void 0 : result.message) || (result == null ? void 0 : result.msg) || ((_a = result == null ? void 0 : result.data) == null ? void 0 : _a.message) || ((_b = result == null ? void 0 : result.data) == null ? void 0 : _b.msg) || "Wallet 支付确认失败";
90
+ }
91
+ function toWalletFundValue(value) {
92
+ try {
93
+ return new import_decimal.default(value || 0).toDecimalPlaces(2).toFixed(2);
94
+ } catch {
95
+ return "0.00";
96
+ }
97
+ }
98
+ function subtractWalletFundValue(left, right) {
99
+ try {
100
+ return new import_decimal.default(left || 0).minus(right || 0).toDecimalPlaces(2).toFixed(2);
101
+ } catch {
102
+ return "0.00";
103
+ }
104
+ }
105
+ function getSharedWalletPassUseValue(params) {
106
+ const { asset, amount, paymentMethod } = params;
107
+ const configuredValue = Number(asset == null ? void 0 : asset.wallet_pass_use_value);
108
+ if (Number.isFinite(configuredValue) && configuredValue > 0) {
109
+ return configuredValue;
110
+ }
111
+ const isPointCard = (asset == null ? void 0 : asset.tag) === "point_card" || paymentMethod.code === "POINTCARD";
112
+ const usageUnit = asset == null ? void 0 : asset.wallet_pass_usage_unit;
113
+ if (isPointCard && (usageUnit == null ? void 0 : usageUnit.points) && (usageUnit == null ? void 0 : usageUnit.price)) {
114
+ return new import_decimal.default(amount).div(usageUnit.price).mul(usageUnit.points).toDecimalPlaces(2, import_decimal.default.ROUND_DOWN).toNumber();
115
+ }
116
+ return amount;
117
+ }
118
+ function buildSharedWalletFundRecord(params) {
119
+ const { asset, amount, paymentMethod } = params;
120
+ const isPointCard = (asset == null ? void 0 : asset.tag) === "point_card" || paymentMethod.code === "POINTCARD";
121
+ const usingBeforeValue = (asset == null ? void 0 : asset.balance_par_value) ?? (asset == null ? void 0 : asset.balance) ?? (asset == null ? void 0 : asset.using_before_value) ?? 0;
122
+ const walletPassUseValue = getSharedWalletPassUseValue(params);
123
+ const usingValue = isPointCard ? walletPassUseValue : amount;
124
+ const walletPassName = (asset == null ? void 0 : asset.wallet_pass_name) || (asset == null ? void 0 : asset.format_title) || (asset == null ? void 0 : asset.product_name) || (asset == null ? void 0 : asset.name) || paymentMethod.name;
125
+ return {
126
+ voucher_id: (asset == null ? void 0 : asset.voucher_id) ?? (asset == null ? void 0 : asset.id),
127
+ wallet_pass_name: walletPassName && typeof walletPassName === "object" ? walletPassName : { default: walletPassName || "" },
128
+ code: (asset == null ? void 0 : asset.code) || (asset == null ? void 0 : asset.tag),
129
+ encoded: asset == null ? void 0 : asset.encoded,
130
+ using_before_value: toWalletFundValue(usingBeforeValue),
131
+ using_after_value: subtractWalletFundValue(usingBeforeValue, usingValue)
132
+ };
133
+ }
50
134
  function isBaseSalesManualProductDiscountProduct(product) {
51
135
  var _a, _b;
52
136
  return ((_a = product == null ? void 0 : product.metadata) == null ? void 0 : _a.is_manual_discount) === true || ((_b = product == null ? void 0 : product.metadata) == null ? void 0 : _b.is_manual_discount) === 1 || ((product == null ? void 0 : product.discount_list) || []).some((item) => (item == null ? void 0 : item.type) === "product");
@@ -77,6 +161,11 @@ function isBaseSalesHistoricalDiscountEntry(discount) {
77
161
  (discount == null ? void 0 : discount.isEditMode) || (discount == null ? void 0 : discount.isDisabled) || (discount == null ? void 0 : discount.order_discount_id) != null
78
162
  );
79
163
  }
164
+ function getBaseSalesUniqueArrayMetadataKey(key) {
165
+ if (key === "products" || key === "bookings")
166
+ return "unique_identification_number";
167
+ return null;
168
+ }
80
169
  var BASE_SALES_PERSISTENT_ID_FIELD_BY_KIND = {
81
170
  product: "order_detail_id",
82
171
  booking: "schedule_event_id",
@@ -150,6 +239,15 @@ function mergeBaseSalesCollectionItem(kind, currentItem, incomingItem, uidRemaps
150
239
  return kind === "product" ? mergeBaseSalesProductSnapshotFields(currentItem, mergedItem) : mergedItem;
151
240
  }
152
241
  function mergeBaseSalesOrderCollection(kind, currentValue, incomingValue, strategy, uidRemaps) {
242
+ if (kind === "payment") {
243
+ return (0, import_payment_utils.mergeOrderPaymentListsByIdentity)(
244
+ currentValue,
245
+ incomingValue,
246
+ strategy === "preserve-local" ? { preserveUnmatchedExisting: true } : {
247
+ preserveUnmatchedExistingWhen: (payment) => (0, import_payment_utils.isIdentifiedPendingOrderPayment)(payment) || !(0, import_orderCollectionIdentity.getOrderCollectionPersistentId)("payment", payment)
248
+ }
249
+ );
250
+ }
153
251
  const currentItems = (0, import_orderCollectionIdentity.normalizeOrderCollection)(kind, currentValue, {
154
252
  ensureUid: false
155
253
  }).items;
@@ -209,6 +307,35 @@ function normalizeBaseSalesRecordCollections(sourceRecord, options) {
209
307
  }
210
308
  return normalizedRecord;
211
309
  }
310
+ function getBaseSalesMetadataUid(item, metadataKey) {
311
+ var _a;
312
+ const uid = ((_a = item == null ? void 0 : item.metadata) == null ? void 0 : _a[metadataKey]) ?? (item == null ? void 0 : item[metadataKey]);
313
+ if (uid === void 0 || uid === null || uid === "")
314
+ return null;
315
+ return String(uid);
316
+ }
317
+ function mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey) {
318
+ const result = [];
319
+ const indexByUid = /* @__PURE__ */ new Map();
320
+ const appendOrReplaceByUid = (item) => {
321
+ const clonedItem = (0, import_lodash_es.cloneDeep)(item);
322
+ const uid = getBaseSalesMetadataUid(clonedItem, metadataKey);
323
+ if (!uid) {
324
+ result.push(clonedItem);
325
+ return;
326
+ }
327
+ const existingIndex = indexByUid.get(uid);
328
+ if (existingIndex !== void 0) {
329
+ result[existingIndex] = clonedItem;
330
+ return;
331
+ }
332
+ indexByUid.set(uid, result.length);
333
+ result.push(clonedItem);
334
+ };
335
+ currentValue.forEach(appendOrReplaceByUid);
336
+ loadedValue.forEach(appendOrReplaceByUid);
337
+ return result;
338
+ }
212
339
  function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord, strategy) {
213
340
  const normalizedLoadedRecord = normalizeBaseSalesRecordCollections(
214
341
  loadedRecord || {},
@@ -237,6 +364,15 @@ function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord, str
237
364
  );
238
365
  }
239
366
  if (Array.isArray(currentValue) && Array.isArray(loadedValue)) {
367
+ if (key === "payments" || key === "payment") {
368
+ return (0, import_payment_utils.mergeOrderPaymentListsByIdentity)(currentValue, loadedValue, {
369
+ preserveUnmatchedExisting: true
370
+ });
371
+ }
372
+ const metadataKey = getBaseSalesUniqueArrayMetadataKey(key);
373
+ if (metadataKey) {
374
+ return mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey);
375
+ }
240
376
  return [
241
377
  ...(0, import_lodash_es.cloneDeep)(currentValue),
242
378
  ...(0, import_lodash_es.cloneDeep)(loadedValue)
@@ -255,6 +391,18 @@ function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord, str
255
391
  (0, import_orderCollectionIdentity.applyOrderCollectionUidRemaps)(mergedRecord, uidRemaps)
256
392
  );
257
393
  }
394
+ function filterPendingPaymentsFromLoadedSalesDetail(sourceRecord) {
395
+ if (!sourceRecord || typeof sourceRecord !== "object")
396
+ return sourceRecord;
397
+ const record = { ...sourceRecord };
398
+ if (Array.isArray(sourceRecord.payments)) {
399
+ record.payments = sourceRecord.payments.filter((payment) => !(0, import_payment_utils.isPendingOrderPayment)(payment));
400
+ }
401
+ if (Array.isArray(sourceRecord.payment)) {
402
+ record.payment = sourceRecord.payment.filter((payment) => !(0, import_payment_utils.isPendingOrderPayment)(payment));
403
+ }
404
+ return record;
405
+ }
258
406
  var BaseSalesImpl = class extends import_BaseModule.BaseModule {
259
407
  constructor(name, version) {
260
408
  super(name, version);
@@ -266,6 +414,11 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
266
414
  order: void 0
267
415
  };
268
416
  this.otherParams = {};
417
+ /**
418
+ * 由已在初始化阶段解析过设备短号的业务解决方案写入。
419
+ * 未设置时,支付编号仍按原逻辑实时读取设备信息。
420
+ */
421
+ this.paymentNumberDevicePrefix = null;
269
422
  // 当前缓存中已加载的最新 SalesDetail;只读 getter 走它对外暴露详情数据。
270
423
  this.currentSalesDetail = null;
271
424
  this.discountConfigCacheKey = null;
@@ -277,6 +430,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
277
430
  this.autoPaymentSyncTimer = null;
278
431
  this.salesDetailLoadInFlightCount = 0;
279
432
  this.salesDetailLoadSequence = 0;
433
+ this.walletAssetsRefreshSequence = 0;
280
434
  this.salesDetailHydrateQueue = Promise.resolve();
281
435
  this.serverOrderChangeUnsubscribe = null;
282
436
  this.serverOrderChangeHydrateInFlight = null;
@@ -829,6 +983,27 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
829
983
  const coreData = (_f = (_d = (_c = app == null ? void 0 : app.models) == null ? void 0 : _c.getStore) == null ? void 0 : (_e = _d.call(_c)).getDataByModel) == null ? void 0 : _f.call(_e, "core", "core");
830
984
  return coreData == null ? void 0 : coreData[key];
831
985
  }
986
+ /**
987
+ * 复用业务解决方案初始化时已解析的支付设备短号。
988
+ * 空值会清除缓存,使后续支付恢复实时读取设备信息的兼容路径。
989
+ */
990
+ setPaymentNumberDevicePrefix(prefix) {
991
+ const normalized = String(prefix ?? "").trim();
992
+ this.paymentNumberDevicePrefix = normalized || null;
993
+ }
994
+ getPaymentNumberDevicePrefixSync() {
995
+ if (!this.appPlugin)
996
+ return "LOCAL";
997
+ return (0, import_payment_number.resolvePaymentNumberDevicePrefixFromDeviceId)((key) => this.getAppData(key));
998
+ }
999
+ getPaymentNumberDevicePrefixAsync() {
1000
+ if (!this.appPlugin)
1001
+ return Promise.resolve("LOCAL");
1002
+ if (this.paymentNumberDevicePrefix) {
1003
+ return Promise.resolve(this.paymentNumberDevicePrefix);
1004
+ }
1005
+ return (0, import_payment_number.resolvePaymentNumberDevicePrefix)((key) => this.getAppData(key));
1006
+ }
832
1007
  syncAppDataToTempOrder(tempOrder) {
833
1008
  const isPriceIncludeTax = this.getAppData("is_price_include_tax");
834
1009
  const taxCountryCode = this.getAppData("tax_country_code");
@@ -869,6 +1044,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
869
1044
  var _a, _b;
870
1045
  this.core = core;
871
1046
  this.initializeOptions = options || {};
1047
+ this.paymentNumberDevicePrefix = null;
872
1048
  this.otherParams = options.otherParams || {};
873
1049
  this.cacheId = (_a = this.otherParams) == null ? void 0 : _a.cacheId;
874
1050
  this.reusedSharedSubModuleNames.clear();
@@ -930,8 +1106,10 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
930
1106
  }
931
1107
  });
932
1108
  this.currentSalesDetail = null;
1109
+ this.paymentNumberDevicePrefix = null;
933
1110
  this.queuedServerOrderChanges = [];
934
1111
  this.salesDetailLoadSequence += 1;
1112
+ this.walletAssetsRefreshSequence += 1;
935
1113
  await this.core.effects.emit(`${this.name}:onDestroy`, {});
936
1114
  super.destroy();
937
1115
  }
@@ -963,13 +1141,16 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
963
1141
  const message = loadedRecord && (loadedRecord.message || loadedRecord.msg) || `加载销售详情失败: ${lookup}`;
964
1142
  throw new Error(message);
965
1143
  }
966
- const remoteRecord = preloadedSalesDetail ?? loadedRecord.data;
1144
+ const remoteRecord = filterPendingPaymentsFromLoadedSalesDetail(
1145
+ preloadedSalesDetail ?? loadedRecord.data
1146
+ );
967
1147
  const currentTempOrder = params.merge ? this.store.order.getTempOrder() : null;
968
- const record = params.merge ? mergeSalesDetailRecordWithTempOrder(
1148
+ const mergedRecord = params.merge ? mergeSalesDetailRecordWithTempOrder(
969
1149
  currentTempOrder,
970
1150
  remoteRecord,
971
1151
  "preserve-local"
972
1152
  ) : remoteRecord;
1153
+ const record = filterPendingPaymentsFromLoadedSalesDetail(mergedRecord);
973
1154
  return await this.hydrateLatestLoadedSalesDetail(record, loadSequence);
974
1155
  } finally {
975
1156
  this.salesDetailLoadInFlightCount = Math.max(
@@ -1145,6 +1326,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1145
1326
  // 重置 tempOrder 与与上一单强相关的运行态(resource/entryPaxNumber/enabledReservationRuleProducts),
1146
1327
  // 适用于从支付页通过 react-router 跳回继续下单时清理残留数据
1147
1328
  async restoreOrder() {
1329
+ var _a;
1148
1330
  try {
1149
1331
  if (!this.store.order) {
1150
1332
  throw new Error("scanOrder 解决方案需要 order 模块支持");
@@ -1153,6 +1335,12 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1153
1335
  this.currentSalesDetail = null;
1154
1336
  this.discountConfigCacheKey = null;
1155
1337
  this.hasManualDiscountSelection = false;
1338
+ const wallet = (_a = this.store.payment) == null ? void 0 : _a.wallet;
1339
+ if (wallet) {
1340
+ this.walletAssetsRefreshSequence += 1;
1341
+ wallet.clearAllCache();
1342
+ await this.publishWalletAssetsState(wallet.getWalletAssetsState());
1343
+ }
1156
1344
  await this.effectsEmit("onTempOrderReplaced", { tempOrder });
1157
1345
  if (this.syncAppDataToTempOrder(tempOrder) && this.isTempOrderPersistEnabled()) {
1158
1346
  this.store.order.persistTempOrder();
@@ -1565,6 +1753,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1565
1753
  }
1566
1754
  return {
1567
1755
  isAvailable: raw.isAvailable,
1756
+ ...raw.isAccepted !== void 0 ? { isAccepted: raw.isAccepted } : {},
1568
1757
  type: raw.type,
1569
1758
  unavailableReason: raw.unavailableReason,
1570
1759
  scannedDiscountList: raw.scannedDiscountList
@@ -1760,6 +1949,20 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1760
1949
  };
1761
1950
  return this.store.order.submitTempOrder(submitParams);
1762
1951
  }
1952
+ async saveSalesOrderDraft(params) {
1953
+ var _a, _b, _c, _d;
1954
+ if (!this.store.order) {
1955
+ throw new Error("BaseSales 解决方案需要 order 模块支持");
1956
+ }
1957
+ return this.store.order.saveTempOrderAsDraft({
1958
+ cacheId: this.cacheId,
1959
+ platform: (params == null ? void 0 : params.platform) ?? ((_a = this.otherParams) == null ? void 0 : _a.platform),
1960
+ businessCode: (params == null ? void 0 : params.businessCode) || ((_b = this.otherParams) == null ? void 0 : _b.businessCode) || ((_c = this.otherParams) == null ? void 0 : _c.business_code),
1961
+ channel: (params == null ? void 0 : params.channel) ?? this.getSubmitOrderSalesChannel(),
1962
+ type: (params == null ? void 0 : params.type) ?? ((_d = this.otherParams) == null ? void 0 : _d.type),
1963
+ ...(params == null ? void 0 : params.enhancePayload) !== void 0 ? { enhancePayload: params.enhancePayload } : {}
1964
+ });
1965
+ }
1763
1966
  async submitTempOrderAsync(params) {
1764
1967
  var _a, _b, _c, _d;
1765
1968
  if (!this.store.order) {
@@ -1960,8 +2163,29 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1960
2163
  }
1961
2164
  }
1962
2165
  }
1963
- /** 追加单个支付项到当前订单。 */
2166
+ /**
2167
+ * 同步兼容入口。无法等待 IoT 短号时,按调用当下的 device_id 或 LOCAL 生成。
2168
+ */
1964
2169
  addOrderPayment(payment) {
2170
+ const hasPaymentNumber = String(
2171
+ payment.payment_number || ""
2172
+ ).trim() !== "";
2173
+ return this.addOrderPaymentWithDevicePrefix(
2174
+ payment,
2175
+ hasPaymentNumber ? "LOCAL" : this.getPaymentNumberDevicePrefixSync()
2176
+ );
2177
+ }
2178
+ /**
2179
+ * 创建新支付项时优先使用业务解决方案初始化阶段缓存的设备短号;
2180
+ * 未缓存的通用 BaseSales 保持实时读取设备信息的兼容语义。
2181
+ */
2182
+ async addOrderPaymentAsync(payment) {
2183
+ const paymentRecord = payment;
2184
+ const hasPaymentNumber = String(paymentRecord.payment_number || "").trim() !== "";
2185
+ const devicePrefix = hasPaymentNumber ? "LOCAL" : await this.getPaymentNumberDevicePrefixAsync();
2186
+ return this.addOrderPaymentWithDevicePrefix(payment, devicePrefix);
2187
+ }
2188
+ addOrderPaymentWithDevicePrefix(payment, devicePrefix) {
1965
2189
  var _a;
1966
2190
  if (!this.store.order)
1967
2191
  throw new Error("order 模块未初始化");
@@ -1978,21 +2202,26 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1978
2202
  if (shopWalletPassId !== void 0 && shopWalletPassId !== null) {
1979
2203
  metadata.shop_wallet_pass_id = shopWalletPassId;
1980
2204
  }
1981
- if (!metadata.unique_payment_number) {
1982
- metadata.unique_payment_number = (0, import_utils.createUuidV4)();
1983
- }
2205
+ const normalizedPaymentRecord = (0, import_payment_utils.ensureOrderPaymentNumber)(
2206
+ paymentRecord,
2207
+ devicePrefix,
2208
+ import_utils.createUuidV4
2209
+ );
1984
2210
  const paymentTimestamp = (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
1985
2211
  const paymentTime = paymentRecord.payment_time ?? paymentTimestamp;
1986
2212
  const createdAt = paymentRecord.created_at ?? paymentTimestamp;
1987
2213
  const serviceCharge = paymentRecord.service_charge && typeof paymentRecord.service_charge === "object" ? paymentRecord.service_charge : null;
1988
2214
  const calculatedServiceFee = serviceCharge ? new import_decimal.default(paymentRecord.origin_amount ?? paymentRecord.amount ?? 0).times(serviceCharge.percentage || 0).plus(serviceCharge.amount || 0).toDecimalPlaces(2).toFixed(2) : void 0;
1989
2215
  const payments = this.store.order.addOrderPayment({
1990
- ...paymentRecord,
2216
+ ...normalizedPaymentRecord,
1991
2217
  ...calculatedServiceFee !== void 0 ? { service_fee: calculatedServiceFee } : {},
1992
2218
  metadata,
1993
2219
  payment_time: paymentTime,
1994
2220
  created_at: createdAt
1995
2221
  });
2222
+ if (paymentRecord.status === "payment_pending") {
2223
+ return payments;
2224
+ }
1996
2225
  const amountSnapshot = this.store.order.getOrderAmountSnapshot();
1997
2226
  const syncState = this.store.order.getOrderSyncState();
1998
2227
  if (amountSnapshot) {
@@ -2014,10 +2243,73 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
2014
2243
  return payments;
2015
2244
  }
2016
2245
  /** 更新当前订单中的指定支付项。 */
2017
- updateOrderPayment(paymentIdentity, updates) {
2246
+ async updateOrderPayment(paymentIdentity, updates, options = {}) {
2247
+ var _a, _b, _c;
2018
2248
  if (!this.store.order)
2019
2249
  throw new Error("order 模块未初始化");
2020
- return this.store.order.updateOrderPayment(paymentIdentity, updates);
2250
+ const matchMode = options.matchBy === "compat" || options.matchBy === "legacy" ? "compat" : "payment_number";
2251
+ const previousMatch = (0, import_payment_utils.resolveOrderPaymentIdentity)(
2252
+ this.store.order.getOrderPayments(),
2253
+ paymentIdentity,
2254
+ matchMode
2255
+ );
2256
+ const previousPayment = previousMatch == null ? void 0 : previousMatch.payment;
2257
+ if ((previousPayment == null ? void 0 : previousPayment.status) === "paid" && !options.applyUpdatesWhenPaid) {
2258
+ const currentPayments = this.store.order.getOrderPayments();
2259
+ let syncResult2;
2260
+ if (options.submitWhenPaid && options.forceSubmitIfPaid) {
2261
+ syncResult2 = await this.syncPaymentsToOrder({
2262
+ payments: currentPayments,
2263
+ paymentStatus: this.getPaymentStatusForSync(currentPayments),
2264
+ submitWhenPaid: true,
2265
+ smallTicketDataFlag: options.smallTicketDataFlag ?? 1
2266
+ });
2267
+ }
2268
+ return {
2269
+ updated: false,
2270
+ payment: previousPayment,
2271
+ payments: currentPayments,
2272
+ summary: ((_a = this.store.order.getOrderAmountSnapshot()) == null ? void 0 : _a.summary) || null,
2273
+ ...syncResult2 !== void 0 ? { syncResult: syncResult2 } : {}
2274
+ };
2275
+ }
2276
+ const result = await this.store.order.updateOrderPayment(paymentIdentity, updates, {
2277
+ matchBy: matchMode
2278
+ });
2279
+ let draftResult;
2280
+ let draftError;
2281
+ if (options.persistDraft !== false) {
2282
+ try {
2283
+ draftResult = await this.saveSalesOrderDraft();
2284
+ } catch (error) {
2285
+ draftError = error;
2286
+ this.logError("updateOrderPayment: 保存支付草稿失败", {
2287
+ paymentIdentity,
2288
+ error: error instanceof Error ? error.message : String(error)
2289
+ });
2290
+ if (!options.submitWhenPaid)
2291
+ throw error;
2292
+ }
2293
+ }
2294
+ const becamePaid = (previousPayment == null ? void 0 : previousPayment.status) !== "paid" && ((_b = result.payment) == null ? void 0 : _b.status) === "paid";
2295
+ const shouldSubmit = Boolean(
2296
+ options.submitWhenPaid && ((_c = result.payment) == null ? void 0 : _c.status) === "paid" && (becamePaid || options.forceSubmitIfPaid)
2297
+ );
2298
+ let syncResult;
2299
+ if (shouldSubmit) {
2300
+ syncResult = await this.syncPaymentsToOrder({
2301
+ payments: result.payments,
2302
+ paymentStatus: this.getPaymentStatusForSync(result.payments),
2303
+ submitWhenPaid: true,
2304
+ smallTicketDataFlag: options.smallTicketDataFlag ?? 1
2305
+ });
2306
+ }
2307
+ return {
2308
+ ...result,
2309
+ ...draftResult !== void 0 ? { draftResult } : {},
2310
+ ...draftError !== void 0 ? { draftError } : {},
2311
+ ...syncResult !== void 0 ? { syncResult } : {}
2312
+ };
2021
2313
  }
2022
2314
  /** 删除当前订单中的指定支付项。 */
2023
2315
  deleteOrderPayment(paymentIdentity) {
@@ -2031,10 +2323,24 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
2031
2323
  throw new Error("order 模块未初始化");
2032
2324
  return this.store.order.updateVoucherOrderPayments(payments, options);
2033
2325
  }
2326
+ async updateVoucherOrderPaymentsAsync(payments, options) {
2327
+ if (!this.store.order)
2328
+ throw new Error("order 模块未初始化");
2329
+ return this.store.order.updateVoucherOrderPaymentsAsync(payments, options);
2330
+ }
2034
2331
  confirmPendingVoucherPayments() {
2035
2332
  if (!this.store.order)
2036
2333
  throw new Error("order 模块未初始化");
2037
- return this.store.order.confirmPendingVoucherPayments();
2334
+ const payments = this.store.order.confirmPendingVoucherPayments();
2335
+ if (this.store.payment) {
2336
+ const committed = this.getCommittedWalletAssets();
2337
+ const state = this.store.payment.wallet.setCommittedWalletAssets(
2338
+ committed.ids,
2339
+ committed.assets
2340
+ );
2341
+ void this.publishWalletAssetsState(state);
2342
+ }
2343
+ return payments;
2038
2344
  }
2039
2345
  discardPendingVoucherPayments() {
2040
2346
  if (!this.store.order)
@@ -2095,24 +2401,14 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
2095
2401
  });
2096
2402
  return walletProducts;
2097
2403
  }
2098
- async initWalletData(params) {
2099
- if (!this.store.order)
2100
- throw new Error("order 模块未初始化");
2101
- if (!this.store.payment)
2102
- throw new Error("payment 模块未初始化");
2103
- const snapshot = this.store.order.getOrderSnapshot();
2404
+ buildWalletInitBusinessData(params) {
2405
+ var _a;
2406
+ const snapshot = (_a = this.store.order) == null ? void 0 : _a.getOrderSnapshot();
2104
2407
  const tempOrder = snapshot == null ? void 0 : snapshot.tempOrder;
2105
2408
  const amount = snapshot == null ? void 0 : snapshot.amount;
2106
- if (!tempOrder || !amount) {
2107
- return {
2108
- walletRecommendList: [],
2109
- userIdentificationCodes: [],
2110
- transformList: [],
2111
- noApplicableVoucher: [],
2112
- products: []
2113
- };
2114
- }
2115
- const walletBusinessData = {
2409
+ if (!tempOrder || !amount)
2410
+ return null;
2411
+ return {
2116
2412
  customer_id: tempOrder.customer_id ? Number(tempOrder.customer_id) : void 0,
2117
2413
  holder: tempOrder.holder,
2118
2414
  amountInfo: {
@@ -2126,11 +2422,29 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
2126
2422
  is_price_include_tax: tempOrder.is_price_include_tax ?? this.otherParams.is_price_include_tax ?? 1,
2127
2423
  ...snapshot.identity.orderId ? { payment_order_id: String(snapshot.identity.orderId) } : {}
2128
2424
  };
2425
+ }
2426
+ async initWalletData(params) {
2427
+ var _a;
2428
+ if (!this.store.order)
2429
+ throw new Error("order 模块未初始化");
2430
+ if (!this.store.payment)
2431
+ throw new Error("payment 模块未初始化");
2432
+ const snapshot = this.store.order.getOrderSnapshot();
2433
+ const walletBusinessData = this.buildWalletInitBusinessData(params);
2434
+ if (!walletBusinessData) {
2435
+ return {
2436
+ walletRecommendList: [],
2437
+ userIdentificationCodes: [],
2438
+ transformList: [],
2439
+ noApplicableVoucher: [],
2440
+ products: []
2441
+ };
2442
+ }
2129
2443
  const result = await this.store.payment.wallet.initializeWalletDataFromBusinessAsync(
2130
2444
  walletBusinessData
2131
2445
  );
2132
2446
  await this.core.effects.emit(`${this.name}:onWalletDataInitialized`, {
2133
- orderId: snapshot.identity.orderId,
2447
+ orderId: (_a = snapshot == null ? void 0 : snapshot.identity) == null ? void 0 : _a.orderId,
2134
2448
  customerId: walletBusinessData.customer_id,
2135
2449
  walletBusinessData: {
2136
2450
  customer_id: walletBusinessData.customer_id,
@@ -2141,6 +2455,208 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
2141
2455
  });
2142
2456
  return result;
2143
2457
  }
2458
+ getCommittedWalletAssets() {
2459
+ var _a, _b;
2460
+ const payments = ((_b = (_a = this.store.order) == null ? void 0 : _a.getOrderPayments) == null ? void 0 : _b.call(_a)) || [];
2461
+ const committed = payments.filter((payment) => {
2462
+ const voucherId = payment == null ? void 0 : payment.voucher_id;
2463
+ if (voucherId === void 0 || voucherId === null || voucherId === 0) {
2464
+ return false;
2465
+ }
2466
+ return (payment == null ? void 0 : payment.status) === "paid" || (payment == null ? void 0 : payment.isSynced) === true || (payment == null ? void 0 : payment.order_payment_id) !== void 0 && (payment == null ? void 0 : payment.order_payment_id) !== null && (payment == null ? void 0 : payment.order_payment_id) !== "";
2467
+ });
2468
+ return {
2469
+ ids: committed.map((payment) => payment.voucher_id),
2470
+ assets: committed.map((payment) => {
2471
+ var _a2;
2472
+ const fundRecord = (payment == null ? void 0 : payment.fund_record) || {};
2473
+ const walletPassName = fundRecord.wallet_pass_name;
2474
+ const title = walletPassName && typeof walletPassName === "object" ? walletPassName.default || Object.values(walletPassName)[0] : walletPassName;
2475
+ const code = String((payment == null ? void 0 : payment.code) || "").toUpperCase();
2476
+ const tag = ((_a2 = Object.entries(WALLET_PAYMENT_CODE_BY_TAG).find(
2477
+ ([, paymentCode]) => paymentCode === code
2478
+ )) == null ? void 0 : _a2[0]) || fundRecord.tag;
2479
+ return {
2480
+ id: payment.voucher_id,
2481
+ voucher_id: payment.voucher_id,
2482
+ code: fundRecord.code,
2483
+ tag,
2484
+ product_name: title || payment.name,
2485
+ name: title || payment.name,
2486
+ amount: Number(payment.amount || 0),
2487
+ _available_max_amount: Number(payment.amount || 0),
2488
+ unified_available_status: 1,
2489
+ _unified_available_status: 1,
2490
+ _committed_payment: payment
2491
+ };
2492
+ })
2493
+ };
2494
+ }
2495
+ async publishWalletAssetsState(state) {
2496
+ await this.effectsEmit(import_types.BaseSalesHookNames.onWalletAssetsStateChanged, {
2497
+ state
2498
+ });
2499
+ return state;
2500
+ }
2501
+ async syncSelectedWalletAssets(state) {
2502
+ if (!this.store.order || !this.store.payment) {
2503
+ throw new Error("订单或支付模块未初始化");
2504
+ }
2505
+ let paymentMethods = this.getPaymentMethods();
2506
+ if (!paymentMethods.length && state.selectedItems.length) {
2507
+ paymentMethods = await this.getPaymentMethodsAsync();
2508
+ }
2509
+ const methodByCode = new Map(
2510
+ paymentMethods.map((method) => [String(method.code || "").toUpperCase(), method])
2511
+ );
2512
+ const preparePayments = this.store.payment.wallet.formatWalletPassList2PreparePayments(
2513
+ state.selectedItems
2514
+ );
2515
+ const selectedAssetById = new Map(
2516
+ state.selectedItems.map((asset) => [
2517
+ String(getSharedWalletAssetId(asset)),
2518
+ asset
2519
+ ])
2520
+ );
2521
+ const voucherPayments = preparePayments.flatMap((item) => {
2522
+ const asset = selectedAssetById.get(String(item.voucher_id));
2523
+ const paymentCode = WALLET_PAYMENT_CODE_BY_TAG[String(item.tag || (asset == null ? void 0 : asset.tag) || "")] || String(item.tag || (asset == null ? void 0 : asset.tag) || "").toUpperCase();
2524
+ const paymentMethod = methodByCode.get(paymentCode);
2525
+ const formattedAmount = Number(item.amount);
2526
+ const amount = Number.isFinite(formattedAmount) && formattedAmount > 0 ? formattedAmount : getSharedWalletAssetAmount(asset);
2527
+ if (!asset || !paymentMethod || !Number.isFinite(amount) || amount <= 0) {
2528
+ return [];
2529
+ }
2530
+ const walletPassUseValue = getSharedWalletPassUseValue({
2531
+ asset,
2532
+ amount,
2533
+ paymentMethod
2534
+ });
2535
+ return [
2536
+ {
2537
+ amount: amount.toFixed(2),
2538
+ code: paymentMethod.code,
2539
+ custom_payment_id: paymentMethod.id,
2540
+ name: paymentMethod.name,
2541
+ type: paymentMethod.type,
2542
+ voucher_id: item.voucher_id,
2543
+ wallet_pass_usage_unit: item.wallet_pass_usage_unit,
2544
+ wallet_pass_use_value: walletPassUseValue,
2545
+ fund_record: buildSharedWalletFundRecord({
2546
+ asset,
2547
+ amount,
2548
+ paymentMethod
2549
+ })
2550
+ }
2551
+ ];
2552
+ });
2553
+ const payments = this.updateVoucherOrderPayments(voucherPayments, {
2554
+ status: "payment_pending"
2555
+ });
2556
+ await this.store.order.recalculateSummary({ createIfMissing: true });
2557
+ return payments;
2558
+ }
2559
+ /** 读取购物车与 Shared Checkout 共用的钱包资产状态。 */
2560
+ getWalletAssetsState() {
2561
+ if (!this.store.payment)
2562
+ throw new Error("payment 模块未初始化");
2563
+ return this.store.payment.wallet.getWalletAssetsState();
2564
+ }
2565
+ /** 导出 Shared Checkout 跨运行时恢复所需的钱包状态与搜索缓存。 */
2566
+ exportWalletAssetsSnapshot() {
2567
+ if (!this.store.payment)
2568
+ throw new Error("payment 模块未初始化");
2569
+ return this.store.payment.wallet.exportWalletAssetsSnapshot();
2570
+ }
2571
+ /** 配置仅影响 Wallet Assets,不改变 Promotion/Voucher 选择流程。 */
2572
+ configureWalletAssetsBehavior(options) {
2573
+ if (!this.store.payment)
2574
+ throw new Error("payment 模块未初始化");
2575
+ this.store.payment.wallet.configureWalletAssetsBehavior(options);
2576
+ }
2577
+ /**
2578
+ * 恢复 Shared Checkout 钱包快照,并把选择重新同步为订单 pending payment。
2579
+ */
2580
+ async importWalletAssetsSnapshot(snapshot) {
2581
+ if (!this.store.payment)
2582
+ throw new Error("payment 模块未初始化");
2583
+ const state = this.store.payment.wallet.importWalletAssetsSnapshot(snapshot);
2584
+ await this.syncSelectedWalletAssets(state);
2585
+ return this.publishWalletAssetsState(state);
2586
+ }
2587
+ /**
2588
+ * 基于当前订单快照刷新钱包资产。商品变化保留并重验选择;客户变化强制清空。
2589
+ */
2590
+ async refreshWalletAssets(params) {
2591
+ if (!this.store.order)
2592
+ throw new Error("order 模块未初始化");
2593
+ if (!this.store.payment)
2594
+ throw new Error("payment 模块未初始化");
2595
+ const refreshSequence = ++this.walletAssetsRefreshSequence;
2596
+ const wallet = this.store.payment.wallet;
2597
+ const businessData = this.buildWalletInitBusinessData(params);
2598
+ if (!businessData) {
2599
+ wallet.clearAllCache();
2600
+ const emptyState = wallet.getWalletAssetsState();
2601
+ this.updateVoucherOrderPayments([], { status: "payment_pending" });
2602
+ return this.publishWalletAssetsState(emptyState);
2603
+ }
2604
+ const previousState = wallet.getWalletAssetsState();
2605
+ const hasPreviousWalletContext = previousState.status !== "idle" || previousState.items.length > 0 || previousState.selectedIds.length > 0 || previousState.customerId !== void 0;
2606
+ const customerChanged = hasPreviousWalletContext && String(previousState.customerId ?? "") !== String(businessData.customer_id ?? "");
2607
+ if (customerChanged) {
2608
+ const clearedState = wallet.clearWalletAssetSelection();
2609
+ this.updateVoucherOrderPayments([], { status: "payment_pending" });
2610
+ await this.publishWalletAssetsState(clearedState);
2611
+ }
2612
+ const refreshTask = wallet.refreshWalletAssetsFromBusinessAsync(
2613
+ businessData,
2614
+ {
2615
+ preserveSelection: (params == null ? void 0 : params.preserveSelection) !== false && !customerChanged
2616
+ }
2617
+ );
2618
+ await this.publishWalletAssetsState(wallet.getWalletAssetsState());
2619
+ let state = await refreshTask;
2620
+ if (refreshSequence !== this.walletAssetsRefreshSequence) {
2621
+ return wallet.getWalletAssetsState();
2622
+ }
2623
+ if (state.status !== "error") {
2624
+ const committed = this.getCommittedWalletAssets();
2625
+ state = wallet.setCommittedWalletAssets(committed.ids, committed.assets);
2626
+ }
2627
+ await this.syncSelectedWalletAssets(state);
2628
+ return this.publishWalletAssetsState(state);
2629
+ }
2630
+ /** 选择或取消单张钱包资产,并立即同步 pending wallet payments。 */
2631
+ async selectWalletAsset(params) {
2632
+ if (!this.store.payment)
2633
+ throw new Error("payment 模块未初始化");
2634
+ const state = this.store.payment.wallet.selectWalletAsset(params.assetId, {
2635
+ selected: params.selected,
2636
+ source: params.source
2637
+ });
2638
+ await this.syncSelectedWalletAssets(state);
2639
+ return this.publishWalletAssetsState(state);
2640
+ }
2641
+ /** 扫码精确查券;仅可用资产会被自动选中。 */
2642
+ async scanWalletAsset(code) {
2643
+ if (!this.store.payment)
2644
+ throw new Error("payment 模块未初始化");
2645
+ const result = await this.store.payment.wallet.scanWalletAssetAsync(code);
2646
+ if (result.type === "normalCode") {
2647
+ await this.syncSelectedWalletAssets(result.state);
2648
+ await this.publishWalletAssetsState(result.state);
2649
+ }
2650
+ return result;
2651
+ }
2652
+ /** 清空全部未确认钱包选择,已支付钱包项由 Order 模块继续保留。 */
2653
+ async clearWalletAssetSelection() {
2654
+ if (!this.store.payment)
2655
+ throw new Error("payment 模块未初始化");
2656
+ const state = this.store.payment.wallet.clearWalletAssetSelection();
2657
+ await this.syncSelectedWalletAssets(state);
2658
+ return this.publishWalletAssetsState(state);
2659
+ }
2144
2660
  /**
2145
2661
  * 更新当前订单客户字段。
2146
2662
  *
@@ -2177,6 +2693,321 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
2177
2693
  getPaymentMethods() {
2178
2694
  return [...this.paymentMethodsCache];
2179
2695
  }
2696
+ findCashPaymentMethod(paymentMethods) {
2697
+ return paymentMethods.find((method) => {
2698
+ const identifiers = [method == null ? void 0 : method.code, method == null ? void 0 : method.type, method == null ? void 0 : method.tag].map(
2699
+ (value) => String(value || "").toUpperCase()
2700
+ );
2701
+ return identifiers.includes("CASHMANUAL") && (method == null ? void 0 : method.enabled) !== false && (method == null ? void 0 : method.enable) !== false;
2702
+ });
2703
+ }
2704
+ getPendingWalletPaymentAmount(payments = ((_b) => (_b = ((_a) => (_a = this.store.order) == null ? void 0 : _a.getOrderPayments)()) == null ? void 0 : _b.call(_a))() || []) {
2705
+ return payments.reduce((total, payment) => {
2706
+ if ((payment == null ? void 0 : payment.status) !== "payment_pending" || (payment == null ? void 0 : payment.voucher_id) === void 0 || Number(payment.voucher_id) === 0) {
2707
+ return total;
2708
+ }
2709
+ try {
2710
+ return total.plus(payment.amount || 0).plus(payment.rounding_amount || 0);
2711
+ } catch {
2712
+ return total;
2713
+ }
2714
+ }, new import_decimal.default(0));
2715
+ }
2716
+ /** 读取现金 action 所需的支付方式、待付金额和快捷金额。 */
2717
+ async getCashPaymentConfig() {
2718
+ var _a, _b, _c, _d, _e, _f;
2719
+ if (!this.store.payment)
2720
+ throw new Error("payment 模块未初始化");
2721
+ let paymentMethods = this.getPaymentMethods();
2722
+ let paymentMethod = this.findCashPaymentMethod(paymentMethods);
2723
+ if (!paymentMethod) {
2724
+ paymentMethods = await this.getPaymentMethodsAsync();
2725
+ paymentMethod = this.findCashPaymentMethod(paymentMethods);
2726
+ }
2727
+ const amountSnapshot = (_b = (_a = this.store.order) == null ? void 0 : _a.getOrderAmountSnapshot) == null ? void 0 : _b.call(_a);
2728
+ const pendingWalletAmount = this.getPendingWalletPaymentAmount();
2729
+ const amountDue = import_decimal.default.max(
2730
+ new import_decimal.default((amountSnapshot == null ? void 0 : amountSnapshot.amountGap) || 0).minus(pendingWalletAmount),
2731
+ 0
2732
+ ).toDecimalPlaces(2).toNumber();
2733
+ const currency = ((_e = (_d = (_c = this.store.order) == null ? void 0 : _c.getTempOrder) == null ? void 0 : _d.call(_c)) == null ? void 0 : _e.currency_code) || ((_f = this.otherParams) == null ? void 0 : _f.currency) || "USD";
2734
+ const recommendedAmounts = amountDue > 0 ? this.store.payment.cash.getRecommendedAmount(amountDue, currency) : [];
2735
+ return {
2736
+ available: Boolean(paymentMethod && amountDue > 0),
2737
+ paymentMethod,
2738
+ amountDue,
2739
+ recommendedAmounts
2740
+ };
2741
+ }
2742
+ /**
2743
+ * 确认足额覆盖订单的 pending Wallet 支付并提交订单。
2744
+ *
2745
+ * Order 模块在构造提交参数时将 pending voucher 转为 paid;只有提交成功后
2746
+ * 才同步 Wallet committed 状态。失败时恢复调用前 payments,允许用户重试。
2747
+ */
2748
+ async confirmWalletPayment() {
2749
+ var _a, _b, _c, _d, _e;
2750
+ if (!this.store.order)
2751
+ throw new Error("order 模块未初始化");
2752
+ const beforePayments = (0, import_lodash_es.cloneDeep)(this.store.order.getOrderPayments());
2753
+ const pendingWalletAmount = this.getPendingWalletPaymentAmount(beforePayments);
2754
+ if (pendingWalletAmount.lte(0)) {
2755
+ throw new Error("当前订单没有待确认的 Wallet 支付");
2756
+ }
2757
+ const amountSnapshot = (_b = (_a = this.store.order).getOrderAmountSnapshot) == null ? void 0 : _b.call(_a);
2758
+ const effectiveAmountDue = import_decimal.default.max(
2759
+ new import_decimal.default((amountSnapshot == null ? void 0 : amountSnapshot.amountGap) || 0).minus(pendingWalletAmount),
2760
+ 0
2761
+ );
2762
+ if (effectiveAmountDue.gt(0.01)) {
2763
+ throw new Error("Wallet 支付尚未覆盖全部待支付金额");
2764
+ }
2765
+ const beforePaymentStatus = (_c = this.store.order.getTempOrder()) == null ? void 0 : _c.payment_status;
2766
+ let submitResult;
2767
+ try {
2768
+ submitResult = await this.submitSalesOrder({
2769
+ smallTicketDataFlag: 1,
2770
+ confirmPendingVoucherPayments: true
2771
+ });
2772
+ if (isRejectedSalesSubmitResult(submitResult)) {
2773
+ throw new Error(getSalesSubmitErrorMessage(submitResult));
2774
+ }
2775
+ } catch (error) {
2776
+ this.store.order.setOrderPayments(beforePayments);
2777
+ const restoredTempOrder = this.store.order.getTempOrder();
2778
+ if (restoredTempOrder && beforePaymentStatus !== void 0) {
2779
+ restoredTempOrder.payment_status = beforePaymentStatus;
2780
+ this.store.order.persistTempOrder();
2781
+ }
2782
+ await this.store.order.recalculateSummary({ createIfMissing: true });
2783
+ throw error;
2784
+ }
2785
+ if (this.store.payment) {
2786
+ try {
2787
+ const committed = this.getCommittedWalletAssets();
2788
+ const walletState = this.store.payment.wallet.setCommittedWalletAssets(
2789
+ committed.ids,
2790
+ committed.assets
2791
+ );
2792
+ await this.publishWalletAssetsState(walletState);
2793
+ } catch (error) {
2794
+ this.logWarning("confirmWalletPayment: Wallet committed 状态同步失败", {
2795
+ error: error instanceof Error ? error.message : String(error)
2796
+ });
2797
+ }
2798
+ }
2799
+ const latestAmountSnapshot = (_e = (_d = this.store.order).getOrderAmountSnapshot) == null ? void 0 : _e.call(_d);
2800
+ return {
2801
+ submitResult,
2802
+ payments: this.store.order.getOrderPayments(),
2803
+ isOrderFullyPaid: new import_decimal.default(
2804
+ (latestAmountSnapshot == null ? void 0 : latestAmountSnapshot.amountGap) || 0
2805
+ ).lte(0)
2806
+ };
2807
+ }
2808
+ /**
2809
+ * 购物车现金直付:写入现金记录并等待支付同步完成。
2810
+ * 同步失败会恢复调用前 payments(包含 Wallet pending 状态)。
2811
+ */
2812
+ async payCash(params) {
2813
+ var _a, _b, _c, _d, _e, _f;
2814
+ if (!this.store.order)
2815
+ throw new Error("order 模块未初始化");
2816
+ const amount = Number(params.amount || 0);
2817
+ if (!Number.isFinite(amount) || amount <= 0) {
2818
+ throw new Error("现金支付金额必须大于 0");
2819
+ }
2820
+ const config = await this.getCashPaymentConfig();
2821
+ const paymentMethod = config.paymentMethod;
2822
+ if (!paymentMethod)
2823
+ throw new Error("未找到可用的 CASHMANUAL 支付方式");
2824
+ if (config.amountDue <= 0)
2825
+ throw new Error("当前订单没有待支付金额");
2826
+ const roundingAmount = Number(params.roundingAmount || 0);
2827
+ const effectivePaymentAmount = new import_decimal.default(amount).minus(roundingAmount);
2828
+ if (effectivePaymentAmount.gt(new import_decimal.default(config.amountDue).plus(0.01))) {
2829
+ throw new Error("现金支付金额超过当前待支付金额");
2830
+ }
2831
+ const beforePayments = (0, import_lodash_es.cloneDeep)(this.store.order.getOrderPayments());
2832
+ const beforePaymentStatus = (_a = this.store.order.getTempOrder()) == null ? void 0 : _a.payment_status;
2833
+ const uniquePaymentNumber = (0, import_utils.createUuidV4)();
2834
+ const paymentTimestamp = (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
2835
+ const actualPaidAmount = Number(params.actualPaidAmount ?? amount);
2836
+ const changeAmount = Number(params.changeAmount || 0);
2837
+ const shopWalletPassId = (_b = this.otherParams) == null ? void 0 : _b.shop_wallet_pass_id;
2838
+ if (!Number.isFinite(actualPaidAmount) || actualPaidAmount + 0.01 < amount) {
2839
+ throw new Error("顾客实收现金不能小于支付金额");
2840
+ }
2841
+ (_f = (_e = (_d = (_c = this.window) == null ? void 0 : _c.interaction) == null ? void 0 : _d.utils) == null ? void 0 : _e.postMessageToApp) == null ? void 0 : _f.call(_e, {
2842
+ module: "till",
2843
+ key: "open_till",
2844
+ data: { type: "cash" }
2845
+ });
2846
+ const payments = this.store.order.addOrderPayment({
2847
+ amount: amount.toFixed(2),
2848
+ code: paymentMethod.code,
2849
+ custom_payment_id: paymentMethod.id,
2850
+ name: paymentMethod.name,
2851
+ custom_payment_type: paymentMethod.type,
2852
+ voucher_id: 0,
2853
+ rounding_amount: roundingAmount.toFixed(2),
2854
+ metadata: {
2855
+ unique_payment_number: uniquePaymentNumber,
2856
+ ...shopWalletPassId !== void 0 && shopWalletPassId !== null ? { shop_wallet_pass_id: shopWalletPassId } : {},
2857
+ actual_paid_amount: Number.isFinite(actualPaidAmount) ? actualPaidAmount : amount,
2858
+ change_given_amount: Number.isFinite(changeAmount) ? changeAmount : 0
2859
+ },
2860
+ payment_time: paymentTimestamp,
2861
+ created_at: paymentTimestamp
2862
+ });
2863
+ const payment = payments.find(
2864
+ (item) => {
2865
+ var _a2;
2866
+ return ((_a2 = item == null ? void 0 : item.metadata) == null ? void 0 : _a2.unique_payment_number) === uniquePaymentNumber;
2867
+ }
2868
+ );
2869
+ try {
2870
+ const syncResult = await this.syncPaymentsToOrder({
2871
+ payments,
2872
+ submitWhenPaid: true,
2873
+ smallTicketDataFlag: 1,
2874
+ confirmPendingVoucherPayments: true
2875
+ });
2876
+ if (this.store.payment) {
2877
+ const committed = this.getCommittedWalletAssets();
2878
+ const walletState = this.store.payment.wallet.setCommittedWalletAssets(
2879
+ committed.ids,
2880
+ committed.assets
2881
+ );
2882
+ await this.publishWalletAssetsState(walletState);
2883
+ }
2884
+ return {
2885
+ payment: payment || {},
2886
+ payments: this.store.order.getOrderPayments(),
2887
+ syncResult,
2888
+ isOrderFullyPaid: syncResult.isOrderFullyPaid
2889
+ };
2890
+ } catch (error) {
2891
+ this.store.order.setOrderPayments(beforePayments);
2892
+ const restoredTempOrder = this.store.order.getTempOrder();
2893
+ if (restoredTempOrder && beforePaymentStatus !== void 0) {
2894
+ restoredTempOrder.payment_status = beforePaymentStatus;
2895
+ this.store.order.persistTempOrder();
2896
+ }
2897
+ await this.store.order.recalculateSummary({ createIfMissing: true });
2898
+ throw error;
2899
+ }
2900
+ }
2901
+ /**
2902
+ * 提交一次已由支付设备确认成功的非 Wallet 支付。
2903
+ *
2904
+ * 与 addOrderPayment 不同,本入口不会启动后台 fire-and-forget 同步;调用方会等待
2905
+ * 本次 payment、当前 pending Wallet 以及订单提交共同完成。任何同步失败都会恢复
2906
+ * 调用前的 payments 与 payment_status,便于 UI 安全解锁并重试。
2907
+ */
2908
+ async commitPaymentMethodPayment(params) {
2909
+ var _a, _b, _c, _d;
2910
+ if (!this.store.order)
2911
+ throw new Error("order 模块未初始化");
2912
+ const amount = Number(params.amount || 0);
2913
+ if (!Number.isFinite(amount) || amount <= 0) {
2914
+ throw new Error("支付金额必须大于 0");
2915
+ }
2916
+ let paymentMethods = this.getPaymentMethods();
2917
+ const findPaymentMethod = () => {
2918
+ const methodCode = String(params.paymentMethodCode || "").toUpperCase();
2919
+ return paymentMethods.find((method) => {
2920
+ const idMatched = params.paymentMethodId !== void 0 && String(method.id) === String(params.paymentMethodId);
2921
+ const codeMatched = Boolean(methodCode) && String(method.code || "").toUpperCase() === methodCode;
2922
+ return (idMatched || codeMatched) && method.enabled !== false && method.enable !== false;
2923
+ });
2924
+ };
2925
+ let paymentMethod = findPaymentMethod();
2926
+ if (!paymentMethod) {
2927
+ paymentMethods = await this.getPaymentMethodsAsync();
2928
+ paymentMethod = findPaymentMethod();
2929
+ }
2930
+ if (!paymentMethod) {
2931
+ throw new Error(
2932
+ `未找到可用的支付方式:${params.paymentMethodCode || params.paymentMethodId || ""}`
2933
+ );
2934
+ }
2935
+ const amountSnapshot = (_b = (_a = this.store.order).getOrderAmountSnapshot) == null ? void 0 : _b.call(_a);
2936
+ const pendingWalletAmount = this.getPendingWalletPaymentAmount();
2937
+ const amountDue = import_decimal.default.max(
2938
+ new import_decimal.default((amountSnapshot == null ? void 0 : amountSnapshot.amountGap) || 0).minus(pendingWalletAmount),
2939
+ 0
2940
+ );
2941
+ if (amountDue.lte(0))
2942
+ throw new Error("当前订单没有待支付金额");
2943
+ if (new import_decimal.default(amount).gt(amountDue.plus(0.01))) {
2944
+ throw new Error("支付金额超过当前待支付金额");
2945
+ }
2946
+ const beforePayments = (0, import_lodash_es.cloneDeep)(this.store.order.getOrderPayments());
2947
+ const beforePaymentStatus = (_c = this.store.order.getTempOrder()) == null ? void 0 : _c.payment_status;
2948
+ const paymentTimestamp = (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
2949
+ const metadata = {
2950
+ ...params.metadata || {},
2951
+ unique_payment_number: ((_d = params.metadata) == null ? void 0 : _d.unique_payment_number) || (0, import_utils.createUuidV4)()
2952
+ };
2953
+ const serviceCharge = params.serviceCharge ? {
2954
+ amount: String(params.serviceCharge.amount || 0),
2955
+ percentage: String(params.serviceCharge.percentage || 0)
2956
+ } : void 0;
2957
+ const serviceFee = serviceCharge ? new import_decimal.default(params.originAmount ?? amount).times(serviceCharge.percentage || 0).plus(serviceCharge.amount || 0).toDecimalPlaces(2).toFixed(2) : void 0;
2958
+ const payments = this.store.order.addOrderPayment({
2959
+ ...params.paymentData || {},
2960
+ amount: amount.toFixed(2),
2961
+ ...params.originAmount !== void 0 ? { origin_amount: Number(params.originAmount).toFixed(2) } : {},
2962
+ code: paymentMethod.code,
2963
+ custom_payment_id: paymentMethod.id,
2964
+ name: paymentMethod.name,
2965
+ custom_payment_type: paymentMethod.type,
2966
+ voucher_id: 0,
2967
+ ...serviceCharge ? { service_charge: serviceCharge } : {},
2968
+ ...serviceFee !== void 0 ? { service_fee: serviceFee } : {},
2969
+ metadata,
2970
+ payment_time: paymentTimestamp,
2971
+ created_at: paymentTimestamp
2972
+ });
2973
+ const payment = payments.find(
2974
+ (item) => {
2975
+ var _a2;
2976
+ return ((_a2 = item == null ? void 0 : item.metadata) == null ? void 0 : _a2.unique_payment_number) === metadata.unique_payment_number;
2977
+ }
2978
+ );
2979
+ try {
2980
+ const syncResult = await this.syncPaymentsToOrder({
2981
+ payments,
2982
+ submitWhenPaid: true,
2983
+ smallTicketDataFlag: 1,
2984
+ confirmPendingVoucherPayments: true
2985
+ });
2986
+ if (this.store.payment) {
2987
+ const committed = this.getCommittedWalletAssets();
2988
+ const walletState = this.store.payment.wallet.setCommittedWalletAssets(
2989
+ committed.ids,
2990
+ committed.assets
2991
+ );
2992
+ await this.publishWalletAssetsState(walletState);
2993
+ }
2994
+ return {
2995
+ payment: payment || {},
2996
+ payments: this.store.order.getOrderPayments(),
2997
+ syncResult,
2998
+ isOrderFullyPaid: syncResult.isOrderFullyPaid
2999
+ };
3000
+ } catch (error) {
3001
+ this.store.order.setOrderPayments(beforePayments);
3002
+ const restoredTempOrder = this.store.order.getTempOrder();
3003
+ if (restoredTempOrder && beforePaymentStatus !== void 0) {
3004
+ restoredTempOrder.payment_status = beforePaymentStatus;
3005
+ this.store.order.persistTempOrder();
3006
+ }
3007
+ await this.store.order.recalculateSummary({ createIfMissing: true });
3008
+ throw error;
3009
+ }
3010
+ }
2180
3011
  /**
2181
3012
  * 按当前店铺的现金舍入配置计算金额,供现金支付 UI 使用。
2182
3013
  *