@pisell/pisellos 2.2.301 → 2.2.303

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 (152) hide show
  1. package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
  2. package/dist/model/strategy/adapter/dataVariant/evaluator.js +287 -101
  3. package/dist/model/strategy/adapter/dataVariant/type.d.ts +25 -0
  4. package/dist/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
  5. package/dist/model/strategy/adapter/itemRule/adapter.js +135 -35
  6. package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
  7. package/dist/model/strategy/adapter/itemRule/evaluator.js +25 -1
  8. package/dist/model/strategy/adapter/itemRule/type.d.ts +44 -0
  9. package/dist/model/strategy/adapter/itemRule/type.js +19 -1
  10. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +10 -7
  11. package/dist/modules/Discount/index.d.ts +2 -0
  12. package/dist/modules/Discount/index.js +41 -5
  13. package/dist/modules/Discount/types.d.ts +21 -0
  14. package/dist/modules/OpenData/index.d.ts +15 -2
  15. package/dist/modules/OpenData/index.js +307 -19
  16. package/dist/modules/OpenData/types.d.ts +55 -0
  17. package/dist/modules/OpenData/types.js +7 -1
  18. package/dist/modules/OpenData/utils.d.ts +21 -1
  19. package/dist/modules/OpenData/utils.js +138 -0
  20. package/dist/modules/Order/index.d.ts +50 -7
  21. package/dist/modules/Order/index.js +1690 -815
  22. package/dist/modules/Order/salesNotes.d.ts +31 -0
  23. package/dist/modules/Order/salesNotes.js +492 -0
  24. package/dist/modules/Order/types.d.ts +117 -10
  25. package/dist/modules/Order/types.js +6 -1
  26. package/dist/modules/Order/utils/virtualSettlement.d.ts +63 -0
  27. package/dist/modules/Order/utils/virtualSettlement.js +284 -0
  28. package/dist/modules/Order/utils.d.ts +5 -1
  29. package/dist/modules/Order/utils.js +138 -33
  30. package/dist/modules/Payment/walletpass.js +20 -21
  31. package/dist/modules/Product/types.d.ts +23 -0
  32. package/dist/modules/ProductList/index.d.ts +2 -1
  33. package/dist/modules/ProductList/index.js +100 -20
  34. package/dist/modules/ProductList/types.d.ts +10 -0
  35. package/dist/modules/Rules/index.d.ts +5 -0
  36. package/dist/modules/Rules/index.js +30 -14
  37. package/dist/modules/SalesSummary/index.d.ts +1 -0
  38. package/dist/modules/SalesSummary/index.js +4 -3
  39. package/dist/modules/SalesSummary/types.d.ts +1 -0
  40. package/dist/modules/SalesSummary/utils.d.ts +1 -0
  41. package/dist/modules/SalesSummary/utils.js +21 -1
  42. package/dist/plugins/request.d.ts +2 -1
  43. package/dist/plugins/request.js +4 -2
  44. package/dist/server/index.d.ts +21 -0
  45. package/dist/server/index.js +1774 -1285
  46. package/dist/server/modules/order/types.d.ts +50 -0
  47. package/dist/server/modules/order/types.js +2 -0
  48. package/dist/server/utils/small-ticket.d.ts +4 -1
  49. package/dist/server/utils/small-ticket.js +461 -96
  50. package/dist/solution/BaseSales/index.d.ts +26 -3
  51. package/dist/solution/BaseSales/index.js +1492 -873
  52. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +2 -0
  53. package/dist/solution/BaseSales/utils/parseSalesResponse.js +1 -1
  54. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  55. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +72 -9
  56. package/dist/solution/BookingByStep/index.d.ts +1 -1
  57. package/dist/solution/BookingTicket/index.d.ts +8 -3
  58. package/dist/solution/BookingTicket/index.js +558 -443
  59. package/dist/solution/BookingTicket/utils/addProductDecision.js +2 -1
  60. package/dist/solution/BookingTicket/utils/orderCustomer.js +3 -2
  61. package/dist/solution/RegisterAndLogin/config.d.ts +9 -3
  62. package/dist/solution/RegisterAndLogin/config.js +95 -40
  63. package/dist/solution/RegisterAndLogin/index.js +4 -1
  64. package/dist/solution/Sales/index.d.ts +16 -1
  65. package/dist/solution/Sales/index.js +338 -63
  66. package/dist/solution/Sales/types.d.ts +10 -0
  67. package/dist/solution/ScanOrder/index.d.ts +1 -0
  68. package/dist/solution/ScanOrder/index.js +31 -27
  69. package/dist/solution/ScanOrder/utils.d.ts +1 -0
  70. package/dist/solution/ScanOrder/utils.js +2 -0
  71. package/dist/solution/UnifiedBookingSales/index.d.ts +20 -6
  72. package/dist/solution/UnifiedBookingSales/index.js +874 -527
  73. package/dist/solution/UnifiedBookingSales/types.d.ts +21 -2
  74. package/dist/solution/VenueBooking/index.d.ts +1 -0
  75. package/dist/solution/VenueBooking/index.js +8 -4
  76. package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
  77. package/lib/model/strategy/adapter/dataVariant/evaluator.js +137 -6
  78. package/lib/model/strategy/adapter/dataVariant/type.d.ts +25 -0
  79. package/lib/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
  80. package/lib/model/strategy/adapter/itemRule/adapter.js +73 -4
  81. package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
  82. package/lib/model/strategy/adapter/itemRule/evaluator.js +23 -1
  83. package/lib/model/strategy/adapter/itemRule/type.d.ts +44 -0
  84. package/lib/model/strategy/adapter/itemRule/type.js +19 -1
  85. package/lib/model/strategy/adapter/promotion/index.js +1 -46
  86. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +4 -0
  87. package/lib/modules/Discount/index.d.ts +2 -0
  88. package/lib/modules/Discount/index.js +34 -2
  89. package/lib/modules/Discount/types.d.ts +21 -0
  90. package/lib/modules/OpenData/index.d.ts +15 -2
  91. package/lib/modules/OpenData/index.js +230 -3
  92. package/lib/modules/OpenData/types.d.ts +55 -0
  93. package/lib/modules/OpenData/types.js +9 -1
  94. package/lib/modules/OpenData/utils.d.ts +21 -1
  95. package/lib/modules/OpenData/utils.js +126 -0
  96. package/lib/modules/Order/index.d.ts +50 -7
  97. package/lib/modules/Order/index.js +704 -64
  98. package/lib/modules/Order/salesNotes.d.ts +31 -0
  99. package/lib/modules/Order/salesNotes.js +382 -0
  100. package/lib/modules/Order/types.d.ts +117 -10
  101. package/lib/modules/Order/types.js +5 -1
  102. package/lib/modules/Order/utils/virtualSettlement.d.ts +63 -0
  103. package/lib/modules/Order/utils/virtualSettlement.js +262 -0
  104. package/lib/modules/Order/utils.d.ts +5 -1
  105. package/lib/modules/Order/utils.js +127 -21
  106. package/lib/modules/Payment/walletpass.js +14 -11
  107. package/lib/modules/Product/types.d.ts +23 -0
  108. package/lib/modules/ProductList/index.d.ts +2 -1
  109. package/lib/modules/ProductList/index.js +47 -2
  110. package/lib/modules/ProductList/types.d.ts +10 -0
  111. package/lib/modules/Rules/index.d.ts +5 -0
  112. package/lib/modules/Rules/index.js +22 -12
  113. package/lib/modules/SalesSummary/index.d.ts +1 -0
  114. package/lib/modules/SalesSummary/index.js +4 -2
  115. package/lib/modules/SalesSummary/types.d.ts +1 -0
  116. package/lib/modules/SalesSummary/utils.d.ts +1 -0
  117. package/lib/modules/SalesSummary/utils.js +17 -1
  118. package/lib/plugins/request.d.ts +2 -1
  119. package/lib/plugins/request.js +3 -2
  120. package/lib/server/index.d.ts +21 -0
  121. package/lib/server/index.js +492 -108
  122. package/lib/server/modules/order/types.d.ts +50 -0
  123. package/lib/server/modules/order/types.js +1 -0
  124. package/lib/server/utils/small-ticket.d.ts +4 -1
  125. package/lib/server/utils/small-ticket.js +427 -72
  126. package/lib/solution/BaseSales/index.d.ts +26 -3
  127. package/lib/solution/BaseSales/index.js +439 -30
  128. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +2 -0
  129. package/lib/solution/BaseSales/utils/parseSalesResponse.js +1 -1
  130. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  131. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +38 -0
  132. package/lib/solution/BookingByStep/index.d.ts +1 -1
  133. package/lib/solution/BookingTicket/index.d.ts +8 -3
  134. package/lib/solution/BookingTicket/index.js +60 -15
  135. package/lib/solution/BookingTicket/utils/addProductDecision.js +1 -0
  136. package/lib/solution/BookingTicket/utils/orderCustomer.js +2 -1
  137. package/lib/solution/RegisterAndLogin/config.d.ts +9 -3
  138. package/lib/solution/RegisterAndLogin/config.js +49 -8
  139. package/lib/solution/RegisterAndLogin/index.js +4 -1
  140. package/lib/solution/Sales/index.d.ts +16 -1
  141. package/lib/solution/Sales/index.js +168 -1
  142. package/lib/solution/Sales/types.d.ts +10 -0
  143. package/lib/solution/ScanOrder/index.d.ts +1 -0
  144. package/lib/solution/ScanOrder/index.js +5 -1
  145. package/lib/solution/ScanOrder/utils.d.ts +1 -0
  146. package/lib/solution/ScanOrder/utils.js +1 -0
  147. package/lib/solution/UnifiedBookingSales/index.d.ts +20 -6
  148. package/lib/solution/UnifiedBookingSales/index.js +169 -16
  149. package/lib/solution/UnifiedBookingSales/types.d.ts +21 -2
  150. package/lib/solution/VenueBooking/index.d.ts +1 -0
  151. package/lib/solution/VenueBooking/index.js +5 -1
  152. package/package.json +1 -1
@@ -25,6 +25,7 @@ var _decimal = _interopRequireDefault(require("decimal.js"));
25
25
  var _lodashEs = require("lodash-es");
26
26
  var _types2 = require("../BookingByStep/types");
27
27
  var _utils = require("../../modules/Order/utils");
28
+ var _virtualSettlement = require("../../modules/Order/utils/virtualSettlement");
28
29
  var _paymentUtils = require("../../modules/Order/payment-utils");
29
30
  var _paymentNumber = require("../../utils/payment-number");
30
31
  var _orderCollectionIdentity = require("../../modules/Order/utils/orderCollectionIdentity");
@@ -37,6 +38,8 @@ var _quotationPrice = require("./utils/quotationPrice");
37
38
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
38
39
  const SERVER_ORDER_CHANGED_EVENT = 'order:onOrdersChanged';
39
40
  const OS_FULFILLMENT_REF_MODE_FIELD = '_os_fulfillment_ref_mode';
41
+ const OS_INVOICE_LAYOUT_CONFIG_FIELD = '_os_invoice_layout_config';
42
+ const OS_INVOICE_TEMPLATE_SETTINGS_FIELD = '_os_invoice_template_settings';
40
43
  const WALLET_PAYMENT_CODE_BY_TAG = {
41
44
  product_voucher: 'PRODUCTVOUCHER',
42
45
  gift_card: 'GIFTCARD',
@@ -256,6 +259,22 @@ function normalizeBaseSalesRecordCollections(sourceRecord, options) {
256
259
  }
257
260
  return normalizedRecord;
258
261
  }
262
+ function isValidBaseSalesSmallTicketDataSnapshot(value) {
263
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
264
+ const localeSnapshots = Object.values(value);
265
+ return localeSnapshots.length > 0 && localeSnapshots.some(localeSnapshot => localeSnapshot !== null && typeof localeSnapshot === 'object' && !Array.isArray(localeSnapshot));
266
+ }
267
+ function mergeBaseSalesSmallTicketDataSnapshot(currentValue, loadedValue) {
268
+ if (isValidBaseSalesSmallTicketDataSnapshot(loadedValue)) {
269
+ return (0, _lodashEs.cloneDeep)(loadedValue);
270
+ }
271
+ if (isValidBaseSalesSmallTicketDataSnapshot(currentValue)) {
272
+ return (0, _lodashEs.cloneDeep)(currentValue);
273
+ }
274
+ if (loadedValue !== undefined) return (0, _lodashEs.cloneDeep)(loadedValue);
275
+ if (currentValue !== undefined) return (0, _lodashEs.cloneDeep)(currentValue);
276
+ return undefined;
277
+ }
259
278
  function getBaseSalesMetadataUid(item, metadataKey) {
260
279
  const uid = item?.metadata?.[metadataKey] ?? item?.[metadataKey];
261
280
  if (uid === undefined || uid === null || uid === '') return null;
@@ -283,7 +302,56 @@ function mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey) {
283
302
  loadedValue.forEach(appendOrReplaceByUid);
284
303
  return result;
285
304
  }
305
+
306
+ // checkout / realtime snapshots may reorder protocol arrays or append persistence fields.
307
+ // Compare only the Sales Note protocol fields so a matching remote echo can acknowledge dirty state.
308
+ function normalizeBaseSalesNotesForComparison(value, options) {
309
+ if (!Array.isArray(value)) return null;
310
+ const unresolvedOrderTargetUuid = String(options?.unresolvedOrderTargetUuid ?? '').trim();
311
+ return value.map(note => {
312
+ if (!note || typeof note !== 'object' || Array.isArray(note)) {
313
+ return (0, _lodashEs.cloneDeep)(note);
314
+ }
315
+ const noteRecord = note;
316
+ const relations = Array.isArray(noteRecord.note_relations) ? noteRecord.note_relations.map(relation => {
317
+ if (!relation || typeof relation !== 'object' || Array.isArray(relation)) {
318
+ return (0, _lodashEs.cloneDeep)(relation);
319
+ }
320
+ const shouldResolveOrderTarget = relation.is_primary === 0 && relation.relation_type === 'related_to' && relation.target_type === 'order' && String(relation.target_uuid ?? '').trim() === '' && unresolvedOrderTargetUuid.length > 0;
321
+ return {
322
+ uuid: relation.uuid,
323
+ relation_type: relation.relation_type,
324
+ target_type: relation.target_type,
325
+ target_uuid: shouldResolveOrderTarget ? unresolvedOrderTargetUuid : relation.target_uuid,
326
+ is_primary: relation.is_primary
327
+ };
328
+ }).sort((left, right) => String(left?.uuid ?? '').localeCompare(String(right?.uuid ?? ''))) : (0, _lodashEs.cloneDeep)(noteRecord.note_relations);
329
+ return {
330
+ uuid: noteRecord.uuid,
331
+ note_type: noteRecord.note_type,
332
+ content: {
333
+ text: (0, _lodashEs.cloneDeep)(noteRecord.content?.text)
334
+ },
335
+ importance: noteRecord.importance,
336
+ note_relations: relations
337
+ };
338
+ }).sort((left, right) => String(left?.uuid ?? '').localeCompare(String(right?.uuid ?? '')));
339
+ }
340
+ function areBaseSalesNotesEquivalent(currentValue, loadedValue, options) {
341
+ const currentNotes = normalizeBaseSalesNotesForComparison(currentValue, {
342
+ unresolvedOrderTargetUuid: options?.currentOrderTargetUuid
343
+ });
344
+ const loadedNotes = normalizeBaseSalesNotesForComparison(loadedValue);
345
+ return currentNotes !== null && loadedNotes !== null && (0, _lodashEs.isEqual)(currentNotes, loadedNotes);
346
+ }
286
347
  function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord, strategy) {
348
+ const loadedHasSalesNotes = Object.prototype.hasOwnProperty.call(loadedRecord || {}, 'notes');
349
+ const hasDirtyLocalSalesNotes = currentTempOrder?._extend?.salesNotesState?.dirty === true;
350
+ const incomingSalesNotesMatchLocal = loadedHasSalesNotes && areBaseSalesNotesEquivalent(currentTempOrder?.notes, loadedRecord.notes, {
351
+ currentOrderTargetUuid: loadedRecord?.shop_order_number || currentTempOrder?.shop_order_number
352
+ });
353
+ const shouldAwaitAuthoritativeSalesNotes = strategy === 'authoritative-incoming' && hasDirtyLocalSalesNotes && (Number(loadedRecord?.need_sync) === 1 || !incomingSalesNotesMatchLocal);
354
+ const preserveDirtyLocalSalesNotes = hasDirtyLocalSalesNotes && (strategy === 'preserve-local' || shouldAwaitAuthoritativeSalesNotes);
287
355
  const normalizedLoadedRecord = normalizeBaseSalesRecordCollections(loadedRecord || {}, {
288
356
  ensureUid: false
289
357
  });
@@ -295,6 +363,17 @@ function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord, str
295
363
  });
296
364
  const uidRemaps = [];
297
365
  const mergedRecord = (0, _lodashEs.mergeWith)(normalizedCurrentTempOrder, normalizedLoadedRecord, (currentValue, loadedValue, key) => {
366
+ if (key === 'notes') {
367
+ if (preserveDirtyLocalSalesNotes && Array.isArray(currentValue)) {
368
+ return (0, _lodashEs.cloneDeep)(currentValue);
369
+ }
370
+ if (Array.isArray(loadedValue)) return (0, _lodashEs.cloneDeep)(loadedValue);
371
+ }
372
+ // small_ticket_data 是由 Server 一次性生成的完整展示快照,不能递归进入
373
+ // locale 内部继续套用订单集合或普通数组的合并规则。
374
+ if (key === 'small_ticket_data') {
375
+ return mergeBaseSalesSmallTicketDataSnapshot(currentValue, loadedValue);
376
+ }
298
377
  const collectionKind = getBaseSalesOrderCollectionKind(key);
299
378
  if (collectionKind && Array.isArray(loadedValue)) {
300
379
  return mergeBaseSalesOrderCollection(collectionKind, Array.isArray(currentValue) ? currentValue : [], loadedValue, strategy, uidRemaps);
@@ -318,7 +397,24 @@ function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord, str
318
397
  return undefined;
319
398
  });
320
399
  delete mergedRecord.request_unique_idempotency_token;
321
- return normalizeBaseSalesRecordCollections((0, _orderCollectionIdentity.applyOrderCollectionUidRemaps)(mergedRecord, uidRemaps));
400
+ const normalizedMergedRecord = normalizeBaseSalesRecordCollections((0, _orderCollectionIdentity.applyOrderCollectionUidRemaps)(mergedRecord, uidRemaps));
401
+ normalizedMergedRecord._extend = {
402
+ ...(normalizedMergedRecord._extend || {}),
403
+ salesNotesState: preserveDirtyLocalSalesNotes ? {
404
+ loaded: true,
405
+ dirty: true
406
+ } : loadedHasSalesNotes ? {
407
+ loaded: true,
408
+ dirty: normalizedLoadedRecord._extend?.salesNotesState?.dirty === true
409
+ } : {
410
+ loaded: false,
411
+ dirty: false
412
+ }
413
+ };
414
+ if (!loadedHasSalesNotes && !preserveDirtyLocalSalesNotes) {
415
+ delete normalizedMergedRecord.notes;
416
+ }
417
+ return normalizedMergedRecord;
322
418
  }
323
419
  function filterPendingPaymentsFromLoadedSalesDetail(sourceRecord) {
324
420
  if (!sourceRecord || typeof sourceRecord !== 'object') return sourceRecord;
@@ -1042,6 +1138,11 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1042
1138
  getSubmitOrderSalesChannel() {
1043
1139
  return this.otherParams?.channel;
1044
1140
  }
1141
+
1142
+ /** Subclasses with target-scoped OpenData override this guard before reusing the cache. */
1143
+ isInvoiceOpenDataCacheCurrent() {
1144
+ return true;
1145
+ }
1045
1146
  getFulfillmentRefModeConfigs() {
1046
1147
  const candidates = [this.otherParams?.openData, this.otherParams?.dineInConfig, this.store?.openData?.getOpenData?.()];
1047
1148
  return candidates.filter(candidate => candidate && typeof candidate === 'object' && !Array.isArray(candidate));
@@ -1055,14 +1156,52 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1055
1156
  }
1056
1157
  return undefined;
1057
1158
  }
1058
- buildSubmitPayloadEnhancerWithFulfillmentRefMode(enhancePayload) {
1159
+ getCachedInvoiceLayoutConfig() {
1160
+ const openDataModule = this.store?.openData;
1161
+ if (typeof openDataModule?.getInvoiceLayoutConfig !== 'function') return undefined;
1162
+ if (!this.isInvoiceOpenDataCacheCurrent()) return undefined;
1163
+ try {
1164
+ return openDataModule.getInvoiceLayoutConfig();
1165
+ } catch (error) {
1166
+ this.logWarning('读取 Invoice OpenData 布局失败,提交时不注入布局配置', {
1167
+ error: error instanceof Error ? error.message : String(error)
1168
+ });
1169
+ return undefined;
1170
+ }
1171
+ }
1172
+ getCachedInvoiceTemplateSettings() {
1173
+ const openDataModule = this.store?.openData;
1174
+ if (typeof openDataModule?.getInvoiceTemplateSettings !== 'function') return undefined;
1175
+ if (!this.isInvoiceOpenDataCacheCurrent()) return undefined;
1176
+ try {
1177
+ return openDataModule.getInvoiceTemplateSettings();
1178
+ } catch (error) {
1179
+ this.logWarning('读取 Invoice OpenData 模板配置失败,提交时不注入模板配置', {
1180
+ error: error instanceof Error ? error.message : String(error)
1181
+ });
1182
+ return undefined;
1183
+ }
1184
+ }
1185
+ buildSubmitPayloadEnhancerWithOpenDataConfig(enhancePayload) {
1059
1186
  const fulfillmentRefMode = this.getFulfillmentRefMode();
1060
- if (!fulfillmentRefMode) return enhancePayload;
1187
+ const invoiceLayoutConfig = this.getCachedInvoiceLayoutConfig();
1188
+ const invoiceTemplateSettings = this.getCachedInvoiceTemplateSettings();
1189
+ if (!fulfillmentRefMode && !invoiceLayoutConfig && !invoiceTemplateSettings) {
1190
+ return enhancePayload;
1191
+ }
1061
1192
  return (payload, ctx) => {
1062
1193
  const enhancedPayload = enhancePayload ? enhancePayload(payload, ctx) : payload;
1063
1194
  return {
1064
1195
  ...enhancedPayload,
1065
- [OS_FULFILLMENT_REF_MODE_FIELD]: fulfillmentRefMode
1196
+ ...(fulfillmentRefMode ? {
1197
+ [OS_FULFILLMENT_REF_MODE_FIELD]: fulfillmentRefMode
1198
+ } : {}),
1199
+ ...(invoiceLayoutConfig ? {
1200
+ [OS_INVOICE_LAYOUT_CONFIG_FIELD]: (0, _lodashEs.cloneDeep)(invoiceLayoutConfig)
1201
+ } : {}),
1202
+ ...(invoiceTemplateSettings ? {
1203
+ [OS_INVOICE_TEMPLATE_SETTINGS_FIELD]: (0, _lodashEs.cloneDeep)(invoiceTemplateSettings)
1204
+ } : {})
1066
1205
  };
1067
1206
  };
1068
1207
  }
@@ -1181,11 +1320,24 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1181
1320
  }
1182
1321
  return (0, _paymentNumber.resolvePaymentNumberDevicePrefix)(key => this.getAppData(key));
1183
1322
  }
1323
+ isMultiCurrencySettlementEnabled() {
1324
+ return this.otherParams?.enableMultiCurrencySettlement === true;
1325
+ }
1326
+ isActiveVirtualSettlementOrder(tempOrder) {
1327
+ return this.isMultiCurrencySettlementEnabled() && (0, _virtualSettlement.isVirtualSettlementOrder)(tempOrder);
1328
+ }
1329
+ isHistoricalVirtualSettlementOrder(tempOrder) {
1330
+ return tempOrder?.metadata?.currency_settlement_config?.settlement_type === 'virtual_currency';
1331
+ }
1184
1332
  syncAppDataToTempOrder(tempOrder) {
1185
1333
  const isPriceIncludeTax = this.getAppData('is_price_include_tax');
1186
1334
  const taxCountryCode = this.getAppData('tax_country_code');
1187
1335
  const currencyCode = this.getAppData('shop_currency_code');
1188
1336
  const currencySymbol = this.getAppData('shop_symbol');
1337
+ // 历史虚拟币订单不依赖交易开关;普通 POS 不从商品行残留快照推断订单币种。
1338
+ const isHistoricalVirtualSettlement = this.isHistoricalVirtualSettlementOrder(tempOrder);
1339
+ const isVirtualSettlement = this.isActiveVirtualSettlementOrder(tempOrder) || isHistoricalVirtualSettlement;
1340
+ const shouldManageLegalCurrencySnapshot = this.isMultiCurrencySettlementEnabled() || isHistoricalVirtualSettlement;
1189
1341
  let isChanged = false;
1190
1342
  if (isPriceIncludeTax !== undefined) {
1191
1343
  const nextIsPriceIncludeTax = Number(isPriceIncludeTax);
@@ -1201,14 +1353,26 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1201
1353
  isChanged = true;
1202
1354
  }
1203
1355
  }
1204
- if (currencyCode !== undefined) {
1356
+ tempOrder.metadata = tempOrder.metadata || {};
1357
+ if (shouldManageLegalCurrencySnapshot) {
1358
+ const legalCurrencySnapshot = {
1359
+ currency_code: String(currencyCode ?? tempOrder.metadata.legal_currency_snapshot?.currency_code ?? tempOrder.currency_code ?? ''),
1360
+ currency_symbol: String(currencySymbol ?? tempOrder.metadata.legal_currency_snapshot?.currency_symbol ?? tempOrder.currency_symbol ?? ''),
1361
+ currency_format: String(tempOrder.metadata.legal_currency_snapshot?.currency_format || (isVirtualSettlement ? 'symbol_first' : tempOrder.currency_format) || 'symbol_first')
1362
+ };
1363
+ if (JSON.stringify(tempOrder.metadata.legal_currency_snapshot || {}) !== JSON.stringify(legalCurrencySnapshot)) {
1364
+ tempOrder.metadata.legal_currency_snapshot = legalCurrencySnapshot;
1365
+ isChanged = true;
1366
+ }
1367
+ }
1368
+ if (!isVirtualSettlement && currencyCode !== undefined) {
1205
1369
  const nextCurrencyCode = String(currencyCode || '');
1206
1370
  if (tempOrder.currency_code !== nextCurrencyCode) {
1207
1371
  tempOrder.currency_code = nextCurrencyCode;
1208
1372
  isChanged = true;
1209
1373
  }
1210
1374
  }
1211
- if (currencySymbol !== undefined) {
1375
+ if (!isVirtualSettlement && currencySymbol !== undefined) {
1212
1376
  const nextCurrencySymbol = String(currencySymbol || '');
1213
1377
  if (tempOrder.currency_symbol !== nextCurrencySymbol) {
1214
1378
  tempOrder.currency_symbol = nextCurrencySymbol;
@@ -1426,6 +1590,30 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1426
1590
  if (!this.store.order) return '';
1427
1591
  return this.store.order.getTempOrderNote();
1428
1592
  }
1593
+ getSalesNotes() {
1594
+ if (!this.store.order) return [];
1595
+ return this.store.order.getSalesNotes();
1596
+ }
1597
+ createSalesNotesMutationSnapshot() {
1598
+ if (!this.store.order) throw new Error('order 模块未初始化');
1599
+ return this.store.order.createSalesNotesMutationSnapshot();
1600
+ }
1601
+ restoreSalesNotesMutationSnapshot(snapshot) {
1602
+ if (!this.store.order) throw new Error('order 模块未初始化');
1603
+ this.store.order.restoreSalesNotesMutationSnapshot(snapshot);
1604
+ }
1605
+ async setSalesNote(input) {
1606
+ if (!this.store.order) throw new Error('order 模块未初始化');
1607
+ return this.store.order.setSalesNote(input);
1608
+ }
1609
+ async removeSalesNote(uuid) {
1610
+ if (!this.store.order) throw new Error('order 模块未初始化');
1611
+ await this.store.order.removeSalesNote(uuid);
1612
+ }
1613
+ async clearSalesNotes() {
1614
+ if (!this.store.order) throw new Error('order 模块未初始化');
1615
+ await this.store.order.clearSalesNotes();
1616
+ }
1429
1617
  updateTempOrderNote(note, sync = false) {
1430
1618
  try {
1431
1619
  if (!this.store.order) throw new Error('order 模块未初始化');
@@ -1439,6 +1627,12 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1439
1627
  if (!this.store.order) throw new Error('order 模块未初始化');
1440
1628
  this.store.order.syncTempOrderNoteToRemote(orderId, note);
1441
1629
  }
1630
+
1631
+ /** 存储用户自定义取餐标识到当前 tempOrder.buzzer。 */
1632
+ setPickupRef(buzzer) {
1633
+ if (!this.store.order) throw new Error('order 模块未初始化');
1634
+ return this.store.order.updateTempOrderBuzzer(buzzer);
1635
+ }
1442
1636
  updateTempOrderShopDiscount(amount) {
1443
1637
  if (!this.store.order) throw new Error('order 模块未初始化');
1444
1638
  return this.store.order.updateTempOrderShopDiscount(amount);
@@ -1447,6 +1641,14 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1447
1641
  if (!this.store.order) throw new Error('order 模块未初始化');
1448
1642
  return this.store.order.updateTempOrderDepositAmount(amount);
1449
1643
  }
1644
+ setPickupReferenceMode(mode) {
1645
+ if (!this.store.order) throw new Error('order 模块未初始化');
1646
+ return this.store.order.updateTempOrderPickupReferenceMode(mode);
1647
+ }
1648
+ setServiceType(serviceType) {
1649
+ if (!this.store.order) throw new Error('order 模块未初始化');
1650
+ return this.store.order.updateTempOrderServiceType(serviceType);
1651
+ }
1450
1652
  updateTempOrderContactsInfo(contactsInfo) {
1451
1653
  if (!this.store.order) throw new Error('order 模块未初始化');
1452
1654
  return this.store.order.updateTempOrderContactsInfo(contactsInfo);
@@ -1550,6 +1752,24 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1550
1752
  throw error;
1551
1753
  }
1552
1754
  }
1755
+
1756
+ /** 切换法币 / WalletPass 单位时清空商品、折扣与支付状态,保留客户。 */
1757
+ async clearOrderForSettlementSwitch() {
1758
+ if (!this.store.order) throw new Error('order 模块未初始化');
1759
+ const tempOrder = await this.store.order.clearOrderForSettlementSwitch();
1760
+ if (this.currentSalesDetail) {
1761
+ this.currentSalesDetail = {
1762
+ ...this.currentSalesDetail,
1763
+ products: [],
1764
+ bookings: [],
1765
+ rootBooking: null,
1766
+ bookingsByProductUid: {},
1767
+ discount_list: [],
1768
+ payments: []
1769
+ };
1770
+ }
1771
+ return tempOrder;
1772
+ }
1553
1773
  getOrderProducts() {
1554
1774
  if (!this.store.order) throw new Error('order 模块未初始化');
1555
1775
  const products = this.store.order.getOrderProducts();
@@ -1675,9 +1895,14 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1675
1895
  const hasManualDiscountSelection = this.hasManualDiscountSelection || currentDiscountList.some(discount => discount.isManualSelect);
1676
1896
  const discountAction = params?.action || (orderId ? 'edit' : 'create');
1677
1897
  const discountConfigCacheKey = [customerId, discountAction, Number(orderId) || 0].join(':');
1678
- let preparedDiscountList = [];
1898
+
1899
+ // Walk-In 不请求 prepare config;当前搜索/扫码券必须继续参与本次重算。
1900
+ // current 优先于 original,保留搜索后的最新选择与可用状态。
1901
+ const searchedDiscountList = currentDiscountList.filter(discount => discount.isScan);
1902
+ const searchedDiscountIds = new Set(searchedDiscountList.map(discount => String(discount.id)));
1903
+ let preparedDiscountList = [...searchedDiscountList, ...originalDiscountList.filter(discount => !searchedDiscountIds.has(String(discount.id)))];
1679
1904
  if (customerId && customerId !== 1) {
1680
- if (this.discountConfigCacheKey === discountConfigCacheKey) {
1905
+ if (!params?.force && this.discountConfigCacheKey === discountConfigCacheKey) {
1681
1906
  preparedDiscountList = originalDiscountList;
1682
1907
  } else {
1683
1908
  preparedDiscountList = await this.store.order.loadDiscountConfig({
@@ -1690,11 +1915,24 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1690
1915
  await discountModule?.setOriginalDiscountList?.(preparedDiscountList);
1691
1916
  }
1692
1917
  }
1918
+ if (this.isActiveVirtualSettlementOrder(tempOrder)) {
1919
+ await discountModule?.setOriginalDiscountList?.([]);
1920
+ await discountModule?.setDiscountList?.([]);
1921
+ tempOrder.discount_list = [];
1922
+ tempOrder.shop_discount = '0.00';
1923
+ return {
1924
+ productList: tempOrder.products || [],
1925
+ discountList: [],
1926
+ availableWalletIds: this.getAvailableWalletIds(),
1927
+ virtualCurrencyList: this.store.order.getVirtualCurrencyList()
1928
+ };
1929
+ }
1693
1930
  if (hasManualDiscountSelection && currentDiscountList.length) {
1694
1931
  return {
1695
1932
  productList: tempOrder.products || [],
1696
1933
  discountList: currentDiscountList,
1697
- availableWalletIds: this.getAvailableWalletIds()
1934
+ availableWalletIds: this.getAvailableWalletIds(),
1935
+ virtualCurrencyList: this.store.order.getVirtualCurrencyList()
1698
1936
  };
1699
1937
  }
1700
1938
  let nextDiscountList = this.mergeHistoricalDiscountList(preparedDiscountList || discountModule?.getDiscountList?.() || [], tempOrder.products || []);
@@ -1720,7 +1958,8 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1720
1958
  return {
1721
1959
  productList: tempOrder.products || [],
1722
1960
  discountList: nextDiscountList,
1723
- availableWalletIds: this.getAvailableWalletIds()
1961
+ availableWalletIds: this.getAvailableWalletIds(),
1962
+ virtualCurrencyList: this.store.order.getVirtualCurrencyList()
1724
1963
  };
1725
1964
  }
1726
1965
  if (rulesModule) {
@@ -1776,16 +2015,29 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1776
2015
  return {
1777
2016
  productList: tempOrder.products || [],
1778
2017
  discountList: nextDiscountList,
1779
- availableWalletIds: this.getAvailableWalletIds()
2018
+ availableWalletIds: this.getAvailableWalletIds(),
2019
+ virtualCurrencyList: this.store.order.getVirtualCurrencyList()
1780
2020
  };
1781
2021
  }
1782
2022
  getAvailableWalletIds() {
1783
2023
  if (!this.store.order?.getAvailableWalletIds) return [];
1784
2024
  return this.store.order.getAvailableWalletIds();
1785
2025
  }
2026
+ getVirtualCurrencyList() {
2027
+ if (!this.store.order?.getVirtualCurrencyList) return [];
2028
+ return this.store.order.getVirtualCurrencyList();
2029
+ }
1786
2030
  async bestDiscount(cb) {
1787
2031
  if (!this.store.order) throw new Error('order 模块未初始化');
1788
2032
  const tempOrder = this.store.order.ensureTempOrder();
2033
+ if (this.isActiveVirtualSettlementOrder(tempOrder)) {
2034
+ const result = {
2035
+ productList: tempOrder.products || [],
2036
+ discountList: []
2037
+ };
2038
+ cb?.(result);
2039
+ return result;
2040
+ }
1789
2041
  const orderStore = this.store.order.store || {};
1790
2042
  const discountModule = orderStore.discount;
1791
2043
  const rulesModule = orderStore.rules;
@@ -1893,6 +2145,17 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1893
2145
  async setDiscountSelected(params) {
1894
2146
  try {
1895
2147
  if (!this.store.order) throw new Error('order 模块未初始化');
2148
+ const currentOrder = this.store.order.ensureTempOrder();
2149
+ if (this.isActiveVirtualSettlementOrder(currentOrder)) {
2150
+ currentOrder.discount_list = [];
2151
+ currentOrder.shop_discount = '0.00';
2152
+ await this.store.order.store?.discount?.setDiscountList?.([]);
2153
+ await this.store.order.recalculateSummary({
2154
+ createIfMissing: true
2155
+ });
2156
+ this.store.order.persistTempOrder();
2157
+ return;
2158
+ }
1896
2159
  const list = this.store.order.getDiscountList();
1897
2160
  const updated = list.map(d => d.id === params.discountId && !isBaseSalesHistoricalDiscountEntry(d) ? {
1898
2161
  ...d,
@@ -2031,6 +2294,101 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2031
2294
  // Deprecated compatibility alias. New BaseSales callers should use submitSalesOrder.
2032
2295
  return this.submitSalesOrder(params);
2033
2296
  }
2297
+ async buildVirtualSettlementSubmitData() {
2298
+ if (!this.store.order) return null;
2299
+ const tempOrder = this.store.order.getTempOrder();
2300
+ if (!this.isActiveVirtualSettlementOrder(tempOrder)) return null;
2301
+ const snapshot = (0, _virtualSettlement.getTempOrderSettlementSnapshot)(tempOrder);
2302
+ const currencyProductId = Number(tempOrder?.metadata?.currency_settlement_config?.settlement_ids?.[0] ?? snapshot?.currency_product_id);
2303
+ if (!snapshot || !Number.isFinite(currencyProductId) || currencyProductId <= 0) {
2304
+ throw new Error('Virtual currency settlement configuration is invalid.');
2305
+ }
2306
+ const summary = await this.store.order.recalculateSummary({
2307
+ createIfMissing: true
2308
+ });
2309
+ const amount = new _decimal.default(summary?.total_amount || 0).toDecimalPlaces(2);
2310
+ const customerId = Number(tempOrder?.customer_id || 0);
2311
+ if (amount.gt(0) && customerId > 0 && customerId !== 1) {
2312
+ await this.store.order.loadDiscountConfig({
2313
+ customerId,
2314
+ action: tempOrder?.order_id ? 'edit' : 'create',
2315
+ orderId: Number(tempOrder?.order_id) || undefined,
2316
+ apply: false
2317
+ });
2318
+ }
2319
+ const asset = this.store.order.getVirtualCurrencyList().find(item => Number(item?.product_id) === currencyProductId);
2320
+ const currencyCode = String(tempOrder?.currency_code || '');
2321
+ const currencySymbol = String(tempOrder?.currency_symbol || '');
2322
+ const currencyFormat = String(tempOrder?.currency_format || 'symbol_first');
2323
+ if (amount.lte(0)) {
2324
+ return {
2325
+ payments: [],
2326
+ snapshot,
2327
+ currencyProductId,
2328
+ currencyCode,
2329
+ currencySymbol,
2330
+ currencyFormat
2331
+ };
2332
+ }
2333
+ if (!asset) {
2334
+ throw new Error('No matching virtual currency card is available.');
2335
+ }
2336
+ const balance = new _decimal.default(asset.balance || 0);
2337
+ if (balance.lt(amount)) {
2338
+ throw new Error('Insufficient virtual currency balance.');
2339
+ }
2340
+ const amountText = amount.toFixed(2);
2341
+ const paymentNumber = `LOCAL_${(0, _utils.createUuidV4)()}`;
2342
+ let payment;
2343
+ if (this.store.order.isOnlineStorePlatform()) {
2344
+ payment = {
2345
+ payment_number: paymentNumber,
2346
+ amount: amount.toNumber(),
2347
+ metadata: {
2348
+ unique_payment_number: (0, _utils.createUuidV4)()
2349
+ },
2350
+ tag: asset.tag,
2351
+ voucher_id: asset.id,
2352
+ wallet_pass_usage_unit: {
2353
+ price: 1,
2354
+ points: 1
2355
+ },
2356
+ wallet_pass_use_value: amountText
2357
+ };
2358
+ } else {
2359
+ const paymentMethods = await this.getPaymentMethodsAsync();
2360
+ const paymentMethod = paymentMethods.find(method => String(method.code || '').toUpperCase() === 'PRODUCTVOUCHER');
2361
+ if (!paymentMethod) {
2362
+ throw new Error('PRODUCTVOUCHER payment method is unavailable.');
2363
+ }
2364
+ payment = {
2365
+ payment_number: paymentNumber,
2366
+ amount: amountText,
2367
+ origin_amount: amountText,
2368
+ code: paymentMethod.code,
2369
+ custom_payment_id: paymentMethod.id,
2370
+ custom_payment_type: paymentMethod.custom_payment_type ?? paymentMethod.type,
2371
+ name: paymentMethod.name,
2372
+ type: 'normal',
2373
+ voucher_id: asset.id,
2374
+ order_payment_type: 'normal',
2375
+ wallet_pass_usage_unit: {
2376
+ price: 1,
2377
+ points: 1
2378
+ },
2379
+ wallet_pass_use_value: amountText,
2380
+ metadata: {}
2381
+ };
2382
+ }
2383
+ return {
2384
+ payments: [payment],
2385
+ snapshot,
2386
+ currencyProductId,
2387
+ currencyCode,
2388
+ currencySymbol,
2389
+ currencyFormat
2390
+ };
2391
+ }
2034
2392
 
2035
2393
  /**
2036
2394
  * 提交当前 Sales 订单。
@@ -2042,10 +2400,11 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2042
2400
  if (!this.store.order) {
2043
2401
  throw new Error('BaseSales 解决方案需要 order 模块支持');
2044
2402
  }
2403
+ const virtualSettlement = await this.buildVirtualSettlementSubmitData();
2045
2404
  // this.store.order.persistTempOrder();
2046
2405
  const inferredPaymentStatus = this.getSubmitPaymentStatus(params?.paymentStatus);
2047
2406
  const smallTicketDataFlag = params?.smallTicketDataFlag ?? this.getDefaultCheckoutSmallTicketDataFlag();
2048
- const enhancePayload = this.buildSubmitPayloadEnhancerWithFulfillmentRefMode(params?.enhancePayload);
2407
+ const enhancePayload = this.buildSubmitPayloadEnhancerWithOpenDataConfig(params?.enhancePayload);
2049
2408
  const submitParams = {
2050
2409
  cacheId: this.cacheId,
2051
2410
  platform: this.otherParams?.platform,
@@ -2053,7 +2412,9 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2053
2412
  channel: this.getSubmitOrderSalesChannel(),
2054
2413
  type: this.otherParams?.type,
2055
2414
  request_unique_idempotency_token: this.store.order.generateIdempotencyToken(),
2056
- ...(params?.payments !== undefined ? {
2415
+ ...(virtualSettlement ? {
2416
+ payments: virtualSettlement.payments
2417
+ } : params?.payments !== undefined ? {
2057
2418
  payments: params.payments
2058
2419
  } : {}),
2059
2420
  ...(inferredPaymentStatus !== undefined ? {
@@ -2062,10 +2423,32 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2062
2423
  ...(smallTicketDataFlag !== undefined ? {
2063
2424
  smallTicketDataFlag
2064
2425
  } : {}),
2065
- ...(params?.confirmPendingVoucherPayments !== undefined ? {
2426
+ ...(virtualSettlement ? {
2427
+ confirmPendingVoucherPayments: false
2428
+ } : params?.confirmPendingVoucherPayments !== undefined ? {
2066
2429
  confirmPendingVoucherPayments: params.confirmPendingVoucherPayments
2067
2430
  } : {}),
2068
- ...(enhancePayload !== undefined ? {
2431
+ ...(virtualSettlement ? {
2432
+ enhancePayload: (payload, ctx) => {
2433
+ const callerPayload = enhancePayload ? enhancePayload(payload, ctx) : payload;
2434
+ const currencySettlementConfig = callerPayload.metadata?.currency_settlement_config || {};
2435
+ return {
2436
+ ...callerPayload,
2437
+ metadata: {
2438
+ ...(callerPayload.metadata || {}),
2439
+ currency_settlement_config: {
2440
+ ...currencySettlementConfig,
2441
+ settlement_type: 'virtual_currency',
2442
+ settlement_ids: [virtualSettlement.currencyProductId],
2443
+ currency_display_snapshot: (0, _lodashEs.cloneDeep)(currencySettlementConfig.currency_display_snapshot ?? (0, _virtualSettlement.buildCurrencyDisplaySnapshot)(virtualSettlement.snapshot))
2444
+ }
2445
+ },
2446
+ currency_code: virtualSettlement.currencyCode,
2447
+ currency_symbol: virtualSettlement.currencySymbol,
2448
+ currency_format: virtualSettlement.currencyFormat
2449
+ };
2450
+ }
2451
+ } : enhancePayload !== undefined ? {
2069
2452
  enhancePayload
2070
2453
  } : {})
2071
2454
  };
@@ -2092,7 +2475,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2092
2475
  }
2093
2476
  const inferredPaymentStatus = this.getSubmitPaymentStatus(params?.paymentStatus);
2094
2477
  const smallTicketDataFlag = params?.smallTicketDataFlag ?? this.getDefaultCheckoutSmallTicketDataFlag();
2095
- const enhancePayload = this.buildSubmitPayloadEnhancerWithFulfillmentRefMode(params?.enhancePayload);
2478
+ const enhancePayload = this.buildSubmitPayloadEnhancerWithOpenDataConfig(params?.enhancePayload);
2096
2479
  const submitParams = {
2097
2480
  cacheId: this.cacheId,
2098
2481
  platform: this.otherParams?.platform,
@@ -2163,7 +2546,18 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2163
2546
  channel: context.channel,
2164
2547
  type: context.type
2165
2548
  });
2166
- const response = await this.request.post('/local/print-order', payload, {
2549
+ const invoiceLayoutConfig = this.getCachedInvoiceLayoutConfig();
2550
+ const invoiceTemplateSettings = this.getCachedInvoiceTemplateSettings();
2551
+ const printPayload = {
2552
+ ...payload,
2553
+ ...(invoiceLayoutConfig ? {
2554
+ invoice: (0, _lodashEs.cloneDeep)(invoiceLayoutConfig)
2555
+ } : {}),
2556
+ ...(invoiceTemplateSettings ? {
2557
+ template_settings: (0, _lodashEs.cloneDeep)(invoiceTemplateSettings)
2558
+ } : {})
2559
+ };
2560
+ const response = await this.request.post('/local/print-order', printPayload, {
2167
2561
  osServer: true,
2168
2562
  customToast: () => {}
2169
2563
  });
@@ -2186,7 +2580,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2186
2580
  if (!this.store.order) throw new Error('order 模块未初始化');
2187
2581
  const businessCode = params.businessCode ?? this.otherParams?.businessCode ?? this.otherParams?.business_code;
2188
2582
  const channel = params.channel ?? this.getSubmitOrderSalesChannel();
2189
- const enhancePayload = this.buildSubmitPayloadEnhancerWithFulfillmentRefMode(params.enhancePayload);
2583
+ const enhancePayload = this.buildSubmitPayloadEnhancerWithOpenDataConfig(params.enhancePayload);
2190
2584
  const syncParams = {
2191
2585
  ...params,
2192
2586
  checkoutSyncTaskEnabled: this.shouldUseCheckoutSyncTask(),
@@ -2477,7 +2871,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2477
2871
  if (this.store.payment) {
2478
2872
  const committed = this.getCommittedWalletAssets();
2479
2873
  const state = this.store.payment.wallet.setCommittedWalletAssets(committed.ids, committed.assets);
2480
- void this.publishWalletAssetsState(state);
2874
+ void this.publishWalletAssetsState(state, 'local');
2481
2875
  }
2482
2876
  return payments;
2483
2877
  }
@@ -2623,9 +3017,10 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2623
3017
  })
2624
3018
  };
2625
3019
  }
2626
- async publishWalletAssetsState(state) {
3020
+ async publishWalletAssetsState(state, changeSource = 'derived') {
2627
3021
  await this.effectsEmit(_types.BaseSalesHookNames.onWalletAssetsStateChanged, {
2628
- state
3022
+ state,
3023
+ changeSource
2629
3024
  });
2630
3025
  return state;
2631
3026
  }
@@ -2758,7 +3153,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2758
3153
  source: params.source
2759
3154
  });
2760
3155
  await this.syncSelectedWalletAssets(state);
2761
- return this.publishWalletAssetsState(state);
3156
+ return this.publishWalletAssetsState(state, 'local');
2762
3157
  }
2763
3158
 
2764
3159
  /** 更新已选钱包资产的手动使用金额,并同步 pending payment。 */
@@ -2766,7 +3161,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2766
3161
  if (!this.store.payment) throw new Error('payment 模块未初始化');
2767
3162
  const state = this.store.payment.wallet.updateWalletAssetAmount(params.assetId, params.amount);
2768
3163
  await this.syncSelectedWalletAssets(state);
2769
- return this.publishWalletAssetsState(state);
3164
+ return this.publishWalletAssetsState(state, 'local');
2770
3165
  }
2771
3166
 
2772
3167
  /** 扫码精确查券;仅可用资产会被自动选中。 */
@@ -2781,7 +3176,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2781
3176
  const result = await wallet.scanWalletAssetAsync(code);
2782
3177
  if (result.type === 'normalCode') {
2783
3178
  await this.syncSelectedWalletAssets(result.state);
2784
- await this.publishWalletAssetsState(result.state);
3179
+ await this.publishWalletAssetsState(result.state, 'local');
2785
3180
  }
2786
3181
  return result;
2787
3182
  }
@@ -2791,7 +3186,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2791
3186
  if (!this.store.payment) throw new Error('payment 模块未初始化');
2792
3187
  const state = this.store.payment.wallet.clearWalletAssetSelection();
2793
3188
  await this.syncSelectedWalletAssets(state);
2794
- return this.publishWalletAssetsState(state);
3189
+ return this.publishWalletAssetsState(state, 'local');
2795
3190
  }
2796
3191
 
2797
3192
  /**
@@ -2887,10 +3282,24 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2887
3282
  if (!this.store.order) throw new Error('order 模块未初始化');
2888
3283
  const beforePayments = (0, _lodashEs.cloneDeep)(this.store.order.getOrderPayments());
2889
3284
  const pendingWalletAmount = this.getPendingWalletPaymentAmount(beforePayments);
3285
+ const amountSnapshot = this.store.order.getOrderAmountSnapshot?.();
2890
3286
  if (pendingWalletAmount.lte(0)) {
2891
- throw new Error('当前订单没有待确认的 Wallet 支付');
3287
+ this.logWarning('confirmWalletPayment: 未发现待确认 Wallet 支付,跳过 Wallet 确认并按普通订单提交', {
3288
+ amountGap: amountSnapshot?.amountGap
3289
+ });
3290
+ const submitResult = await this.submitSalesOrder({
3291
+ smallTicketDataFlag: 1
3292
+ });
3293
+ if (isRejectedSalesSubmitResult(submitResult)) {
3294
+ throw new Error(getSalesSubmitErrorMessage(submitResult, '订单提交失败'));
3295
+ }
3296
+ const latestAmountSnapshot = this.store.order.getOrderAmountSnapshot?.();
3297
+ return {
3298
+ submitResult,
3299
+ payments: this.store.order.getOrderPayments(),
3300
+ isOrderFullyPaid: new _decimal.default(latestAmountSnapshot?.amountGap || 0).lte(0)
3301
+ };
2892
3302
  }
2893
- const amountSnapshot = this.store.order.getOrderAmountSnapshot?.();
2894
3303
  const effectiveAmountDue = _decimal.default.max(new _decimal.default(amountSnapshot?.amountGap || 0).minus(pendingWalletAmount), 0);
2895
3304
  if (effectiveAmountDue.gt(0.01)) {
2896
3305
  throw new Error('Wallet 支付尚未覆盖全部待支付金额');
@@ -2921,7 +3330,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2921
3330
  try {
2922
3331
  const committed = this.getCommittedWalletAssets();
2923
3332
  const walletState = this.store.payment.wallet.setCommittedWalletAssets(committed.ids, committed.assets);
2924
- await this.publishWalletAssetsState(walletState);
3333
+ await this.publishWalletAssetsState(walletState, 'local');
2925
3334
  } catch (error) {
2926
3335
  this.logWarning('confirmWalletPayment: Wallet committed 状态同步失败', {
2927
3336
  error: error instanceof Error ? error.message : String(error)
@@ -3005,7 +3414,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
3005
3414
  if (this.store.payment) {
3006
3415
  const committed = this.getCommittedWalletAssets();
3007
3416
  const walletState = this.store.payment.wallet.setCommittedWalletAssets(committed.ids, committed.assets);
3008
- await this.publishWalletAssetsState(walletState);
3417
+ await this.publishWalletAssetsState(walletState, 'local');
3009
3418
  }
3010
3419
  return {
3011
3420
  payment: payment || {},
@@ -3111,7 +3520,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
3111
3520
  if (this.store.payment) {
3112
3521
  const committed = this.getCommittedWalletAssets();
3113
3522
  const walletState = this.store.payment.wallet.setCommittedWalletAssets(committed.ids, committed.assets);
3114
- await this.publishWalletAssetsState(walletState);
3523
+ await this.publishWalletAssetsState(walletState, 'local');
3115
3524
  }
3116
3525
  return {
3117
3526
  payment: payment || {},