@pisell/pisellos 2.2.302 → 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 (153) 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/model/strategy/adapter/promotion/index.js +0 -9
  11. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +10 -7
  12. package/dist/modules/Discount/index.d.ts +2 -0
  13. package/dist/modules/Discount/index.js +41 -5
  14. package/dist/modules/Discount/types.d.ts +21 -0
  15. package/dist/modules/OpenData/index.d.ts +15 -2
  16. package/dist/modules/OpenData/index.js +307 -19
  17. package/dist/modules/OpenData/types.d.ts +55 -0
  18. package/dist/modules/OpenData/types.js +7 -1
  19. package/dist/modules/OpenData/utils.d.ts +21 -1
  20. package/dist/modules/OpenData/utils.js +138 -0
  21. package/dist/modules/Order/index.d.ts +50 -7
  22. package/dist/modules/Order/index.js +1690 -815
  23. package/dist/modules/Order/salesNotes.d.ts +31 -0
  24. package/dist/modules/Order/salesNotes.js +492 -0
  25. package/dist/modules/Order/types.d.ts +117 -10
  26. package/dist/modules/Order/types.js +6 -1
  27. package/dist/modules/Order/utils/virtualSettlement.d.ts +63 -0
  28. package/dist/modules/Order/utils/virtualSettlement.js +284 -0
  29. package/dist/modules/Order/utils.d.ts +5 -1
  30. package/dist/modules/Order/utils.js +138 -33
  31. package/dist/modules/Payment/walletpass.js +20 -21
  32. package/dist/modules/Product/types.d.ts +23 -0
  33. package/dist/modules/ProductList/index.d.ts +2 -1
  34. package/dist/modules/ProductList/index.js +100 -20
  35. package/dist/modules/ProductList/types.d.ts +10 -0
  36. package/dist/modules/Rules/index.d.ts +5 -0
  37. package/dist/modules/Rules/index.js +30 -14
  38. package/dist/modules/SalesSummary/index.d.ts +1 -0
  39. package/dist/modules/SalesSummary/index.js +4 -3
  40. package/dist/modules/SalesSummary/types.d.ts +1 -0
  41. package/dist/modules/SalesSummary/utils.d.ts +1 -0
  42. package/dist/modules/SalesSummary/utils.js +21 -1
  43. package/dist/plugins/request.d.ts +2 -1
  44. package/dist/plugins/request.js +4 -2
  45. package/dist/server/index.d.ts +21 -0
  46. package/dist/server/index.js +1774 -1285
  47. package/dist/server/modules/order/types.d.ts +50 -0
  48. package/dist/server/modules/order/types.js +2 -0
  49. package/dist/server/utils/small-ticket.d.ts +4 -1
  50. package/dist/server/utils/small-ticket.js +461 -96
  51. package/dist/solution/BaseSales/index.d.ts +24 -3
  52. package/dist/solution/BaseSales/index.js +1484 -873
  53. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +2 -0
  54. package/dist/solution/BaseSales/utils/parseSalesResponse.js +1 -1
  55. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  56. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +72 -9
  57. package/dist/solution/BookingByStep/index.d.ts +1 -1
  58. package/dist/solution/BookingTicket/index.d.ts +22 -5
  59. package/dist/solution/BookingTicket/index.js +558 -443
  60. package/dist/solution/BookingTicket/utils/addProductDecision.js +2 -1
  61. package/dist/solution/BookingTicket/utils/orderCustomer.js +3 -2
  62. package/dist/solution/RegisterAndLogin/config.d.ts +9 -3
  63. package/dist/solution/RegisterAndLogin/config.js +95 -40
  64. package/dist/solution/RegisterAndLogin/index.js +4 -1
  65. package/dist/solution/Sales/index.d.ts +16 -1
  66. package/dist/solution/Sales/index.js +338 -63
  67. package/dist/solution/Sales/types.d.ts +10 -0
  68. package/dist/solution/ScanOrder/index.d.ts +1 -0
  69. package/dist/solution/ScanOrder/index.js +31 -27
  70. package/dist/solution/ScanOrder/utils.d.ts +1 -0
  71. package/dist/solution/ScanOrder/utils.js +2 -0
  72. package/dist/solution/UnifiedBookingSales/index.d.ts +20 -6
  73. package/dist/solution/UnifiedBookingSales/index.js +874 -527
  74. package/dist/solution/UnifiedBookingSales/types.d.ts +21 -2
  75. package/dist/solution/VenueBooking/index.d.ts +1 -0
  76. package/dist/solution/VenueBooking/index.js +8 -4
  77. package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
  78. package/lib/model/strategy/adapter/dataVariant/evaluator.js +137 -6
  79. package/lib/model/strategy/adapter/dataVariant/type.d.ts +25 -0
  80. package/lib/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
  81. package/lib/model/strategy/adapter/itemRule/adapter.js +73 -4
  82. package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
  83. package/lib/model/strategy/adapter/itemRule/evaluator.js +23 -1
  84. package/lib/model/strategy/adapter/itemRule/type.d.ts +44 -0
  85. package/lib/model/strategy/adapter/itemRule/type.js +19 -1
  86. package/lib/model/strategy/adapter/promotion/index.js +1 -46
  87. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +4 -0
  88. package/lib/modules/Discount/index.d.ts +2 -0
  89. package/lib/modules/Discount/index.js +34 -2
  90. package/lib/modules/Discount/types.d.ts +21 -0
  91. package/lib/modules/OpenData/index.d.ts +15 -2
  92. package/lib/modules/OpenData/index.js +230 -3
  93. package/lib/modules/OpenData/types.d.ts +55 -0
  94. package/lib/modules/OpenData/types.js +9 -1
  95. package/lib/modules/OpenData/utils.d.ts +21 -1
  96. package/lib/modules/OpenData/utils.js +126 -0
  97. package/lib/modules/Order/index.d.ts +50 -7
  98. package/lib/modules/Order/index.js +704 -64
  99. package/lib/modules/Order/salesNotes.d.ts +31 -0
  100. package/lib/modules/Order/salesNotes.js +382 -0
  101. package/lib/modules/Order/types.d.ts +117 -10
  102. package/lib/modules/Order/types.js +5 -1
  103. package/lib/modules/Order/utils/virtualSettlement.d.ts +63 -0
  104. package/lib/modules/Order/utils/virtualSettlement.js +262 -0
  105. package/lib/modules/Order/utils.d.ts +5 -1
  106. package/lib/modules/Order/utils.js +127 -21
  107. package/lib/modules/Payment/walletpass.js +14 -11
  108. package/lib/modules/Product/types.d.ts +23 -0
  109. package/lib/modules/ProductList/index.d.ts +2 -1
  110. package/lib/modules/ProductList/index.js +47 -2
  111. package/lib/modules/ProductList/types.d.ts +10 -0
  112. package/lib/modules/Rules/index.d.ts +5 -0
  113. package/lib/modules/Rules/index.js +22 -12
  114. package/lib/modules/SalesSummary/index.d.ts +1 -0
  115. package/lib/modules/SalesSummary/index.js +4 -2
  116. package/lib/modules/SalesSummary/types.d.ts +1 -0
  117. package/lib/modules/SalesSummary/utils.d.ts +1 -0
  118. package/lib/modules/SalesSummary/utils.js +17 -1
  119. package/lib/plugins/request.d.ts +2 -1
  120. package/lib/plugins/request.js +3 -2
  121. package/lib/server/index.d.ts +21 -0
  122. package/lib/server/index.js +492 -108
  123. package/lib/server/modules/order/types.d.ts +50 -0
  124. package/lib/server/modules/order/types.js +1 -0
  125. package/lib/server/utils/small-ticket.d.ts +4 -1
  126. package/lib/server/utils/small-ticket.js +427 -72
  127. package/lib/solution/BaseSales/index.d.ts +24 -3
  128. package/lib/solution/BaseSales/index.js +433 -30
  129. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +2 -0
  130. package/lib/solution/BaseSales/utils/parseSalesResponse.js +1 -1
  131. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  132. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +38 -0
  133. package/lib/solution/BookingByStep/index.d.ts +1 -1
  134. package/lib/solution/BookingTicket/index.d.ts +22 -5
  135. package/lib/solution/BookingTicket/index.js +60 -15
  136. package/lib/solution/BookingTicket/utils/addProductDecision.js +1 -0
  137. package/lib/solution/BookingTicket/utils/orderCustomer.js +2 -1
  138. package/lib/solution/RegisterAndLogin/config.d.ts +9 -3
  139. package/lib/solution/RegisterAndLogin/config.js +49 -8
  140. package/lib/solution/RegisterAndLogin/index.js +4 -1
  141. package/lib/solution/Sales/index.d.ts +16 -1
  142. package/lib/solution/Sales/index.js +168 -1
  143. package/lib/solution/Sales/types.d.ts +10 -0
  144. package/lib/solution/ScanOrder/index.d.ts +1 -0
  145. package/lib/solution/ScanOrder/index.js +5 -1
  146. package/lib/solution/ScanOrder/utils.d.ts +1 -0
  147. package/lib/solution/ScanOrder/utils.js +1 -0
  148. package/lib/solution/UnifiedBookingSales/index.d.ts +20 -6
  149. package/lib/solution/UnifiedBookingSales/index.js +169 -16
  150. package/lib/solution/UnifiedBookingSales/types.d.ts +21 -2
  151. package/lib/solution/VenueBooking/index.d.ts +1 -0
  152. package/lib/solution/VenueBooking/index.js +5 -1
  153. 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 模块未初始化');
@@ -1453,6 +1641,14 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1453
1641
  if (!this.store.order) throw new Error('order 模块未初始化');
1454
1642
  return this.store.order.updateTempOrderDepositAmount(amount);
1455
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
+ }
1456
1652
  updateTempOrderContactsInfo(contactsInfo) {
1457
1653
  if (!this.store.order) throw new Error('order 模块未初始化');
1458
1654
  return this.store.order.updateTempOrderContactsInfo(contactsInfo);
@@ -1556,6 +1752,24 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1556
1752
  throw error;
1557
1753
  }
1558
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
+ }
1559
1773
  getOrderProducts() {
1560
1774
  if (!this.store.order) throw new Error('order 模块未初始化');
1561
1775
  const products = this.store.order.getOrderProducts();
@@ -1681,9 +1895,14 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1681
1895
  const hasManualDiscountSelection = this.hasManualDiscountSelection || currentDiscountList.some(discount => discount.isManualSelect);
1682
1896
  const discountAction = params?.action || (orderId ? 'edit' : 'create');
1683
1897
  const discountConfigCacheKey = [customerId, discountAction, Number(orderId) || 0].join(':');
1684
- 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)))];
1685
1904
  if (customerId && customerId !== 1) {
1686
- if (this.discountConfigCacheKey === discountConfigCacheKey) {
1905
+ if (!params?.force && this.discountConfigCacheKey === discountConfigCacheKey) {
1687
1906
  preparedDiscountList = originalDiscountList;
1688
1907
  } else {
1689
1908
  preparedDiscountList = await this.store.order.loadDiscountConfig({
@@ -1696,11 +1915,24 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1696
1915
  await discountModule?.setOriginalDiscountList?.(preparedDiscountList);
1697
1916
  }
1698
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
+ }
1699
1930
  if (hasManualDiscountSelection && currentDiscountList.length) {
1700
1931
  return {
1701
1932
  productList: tempOrder.products || [],
1702
1933
  discountList: currentDiscountList,
1703
- availableWalletIds: this.getAvailableWalletIds()
1934
+ availableWalletIds: this.getAvailableWalletIds(),
1935
+ virtualCurrencyList: this.store.order.getVirtualCurrencyList()
1704
1936
  };
1705
1937
  }
1706
1938
  let nextDiscountList = this.mergeHistoricalDiscountList(preparedDiscountList || discountModule?.getDiscountList?.() || [], tempOrder.products || []);
@@ -1726,7 +1958,8 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1726
1958
  return {
1727
1959
  productList: tempOrder.products || [],
1728
1960
  discountList: nextDiscountList,
1729
- availableWalletIds: this.getAvailableWalletIds()
1961
+ availableWalletIds: this.getAvailableWalletIds(),
1962
+ virtualCurrencyList: this.store.order.getVirtualCurrencyList()
1730
1963
  };
1731
1964
  }
1732
1965
  if (rulesModule) {
@@ -1782,16 +2015,29 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1782
2015
  return {
1783
2016
  productList: tempOrder.products || [],
1784
2017
  discountList: nextDiscountList,
1785
- availableWalletIds: this.getAvailableWalletIds()
2018
+ availableWalletIds: this.getAvailableWalletIds(),
2019
+ virtualCurrencyList: this.store.order.getVirtualCurrencyList()
1786
2020
  };
1787
2021
  }
1788
2022
  getAvailableWalletIds() {
1789
2023
  if (!this.store.order?.getAvailableWalletIds) return [];
1790
2024
  return this.store.order.getAvailableWalletIds();
1791
2025
  }
2026
+ getVirtualCurrencyList() {
2027
+ if (!this.store.order?.getVirtualCurrencyList) return [];
2028
+ return this.store.order.getVirtualCurrencyList();
2029
+ }
1792
2030
  async bestDiscount(cb) {
1793
2031
  if (!this.store.order) throw new Error('order 模块未初始化');
1794
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
+ }
1795
2041
  const orderStore = this.store.order.store || {};
1796
2042
  const discountModule = orderStore.discount;
1797
2043
  const rulesModule = orderStore.rules;
@@ -1899,6 +2145,17 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1899
2145
  async setDiscountSelected(params) {
1900
2146
  try {
1901
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
+ }
1902
2159
  const list = this.store.order.getDiscountList();
1903
2160
  const updated = list.map(d => d.id === params.discountId && !isBaseSalesHistoricalDiscountEntry(d) ? {
1904
2161
  ...d,
@@ -2037,6 +2294,101 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2037
2294
  // Deprecated compatibility alias. New BaseSales callers should use submitSalesOrder.
2038
2295
  return this.submitSalesOrder(params);
2039
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
+ }
2040
2392
 
2041
2393
  /**
2042
2394
  * 提交当前 Sales 订单。
@@ -2048,10 +2400,11 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2048
2400
  if (!this.store.order) {
2049
2401
  throw new Error('BaseSales 解决方案需要 order 模块支持');
2050
2402
  }
2403
+ const virtualSettlement = await this.buildVirtualSettlementSubmitData();
2051
2404
  // this.store.order.persistTempOrder();
2052
2405
  const inferredPaymentStatus = this.getSubmitPaymentStatus(params?.paymentStatus);
2053
2406
  const smallTicketDataFlag = params?.smallTicketDataFlag ?? this.getDefaultCheckoutSmallTicketDataFlag();
2054
- const enhancePayload = this.buildSubmitPayloadEnhancerWithFulfillmentRefMode(params?.enhancePayload);
2407
+ const enhancePayload = this.buildSubmitPayloadEnhancerWithOpenDataConfig(params?.enhancePayload);
2055
2408
  const submitParams = {
2056
2409
  cacheId: this.cacheId,
2057
2410
  platform: this.otherParams?.platform,
@@ -2059,7 +2412,9 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2059
2412
  channel: this.getSubmitOrderSalesChannel(),
2060
2413
  type: this.otherParams?.type,
2061
2414
  request_unique_idempotency_token: this.store.order.generateIdempotencyToken(),
2062
- ...(params?.payments !== undefined ? {
2415
+ ...(virtualSettlement ? {
2416
+ payments: virtualSettlement.payments
2417
+ } : params?.payments !== undefined ? {
2063
2418
  payments: params.payments
2064
2419
  } : {}),
2065
2420
  ...(inferredPaymentStatus !== undefined ? {
@@ -2068,10 +2423,32 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2068
2423
  ...(smallTicketDataFlag !== undefined ? {
2069
2424
  smallTicketDataFlag
2070
2425
  } : {}),
2071
- ...(params?.confirmPendingVoucherPayments !== undefined ? {
2426
+ ...(virtualSettlement ? {
2427
+ confirmPendingVoucherPayments: false
2428
+ } : params?.confirmPendingVoucherPayments !== undefined ? {
2072
2429
  confirmPendingVoucherPayments: params.confirmPendingVoucherPayments
2073
2430
  } : {}),
2074
- ...(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 ? {
2075
2452
  enhancePayload
2076
2453
  } : {})
2077
2454
  };
@@ -2098,7 +2475,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2098
2475
  }
2099
2476
  const inferredPaymentStatus = this.getSubmitPaymentStatus(params?.paymentStatus);
2100
2477
  const smallTicketDataFlag = params?.smallTicketDataFlag ?? this.getDefaultCheckoutSmallTicketDataFlag();
2101
- const enhancePayload = this.buildSubmitPayloadEnhancerWithFulfillmentRefMode(params?.enhancePayload);
2478
+ const enhancePayload = this.buildSubmitPayloadEnhancerWithOpenDataConfig(params?.enhancePayload);
2102
2479
  const submitParams = {
2103
2480
  cacheId: this.cacheId,
2104
2481
  platform: this.otherParams?.platform,
@@ -2169,7 +2546,18 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2169
2546
  channel: context.channel,
2170
2547
  type: context.type
2171
2548
  });
2172
- 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, {
2173
2561
  osServer: true,
2174
2562
  customToast: () => {}
2175
2563
  });
@@ -2192,7 +2580,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2192
2580
  if (!this.store.order) throw new Error('order 模块未初始化');
2193
2581
  const businessCode = params.businessCode ?? this.otherParams?.businessCode ?? this.otherParams?.business_code;
2194
2582
  const channel = params.channel ?? this.getSubmitOrderSalesChannel();
2195
- const enhancePayload = this.buildSubmitPayloadEnhancerWithFulfillmentRefMode(params.enhancePayload);
2583
+ const enhancePayload = this.buildSubmitPayloadEnhancerWithOpenDataConfig(params.enhancePayload);
2196
2584
  const syncParams = {
2197
2585
  ...params,
2198
2586
  checkoutSyncTaskEnabled: this.shouldUseCheckoutSyncTask(),
@@ -2483,7 +2871,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2483
2871
  if (this.store.payment) {
2484
2872
  const committed = this.getCommittedWalletAssets();
2485
2873
  const state = this.store.payment.wallet.setCommittedWalletAssets(committed.ids, committed.assets);
2486
- void this.publishWalletAssetsState(state);
2874
+ void this.publishWalletAssetsState(state, 'local');
2487
2875
  }
2488
2876
  return payments;
2489
2877
  }
@@ -2629,9 +3017,10 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2629
3017
  })
2630
3018
  };
2631
3019
  }
2632
- async publishWalletAssetsState(state) {
3020
+ async publishWalletAssetsState(state, changeSource = 'derived') {
2633
3021
  await this.effectsEmit(_types.BaseSalesHookNames.onWalletAssetsStateChanged, {
2634
- state
3022
+ state,
3023
+ changeSource
2635
3024
  });
2636
3025
  return state;
2637
3026
  }
@@ -2764,7 +3153,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2764
3153
  source: params.source
2765
3154
  });
2766
3155
  await this.syncSelectedWalletAssets(state);
2767
- return this.publishWalletAssetsState(state);
3156
+ return this.publishWalletAssetsState(state, 'local');
2768
3157
  }
2769
3158
 
2770
3159
  /** 更新已选钱包资产的手动使用金额,并同步 pending payment。 */
@@ -2772,7 +3161,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2772
3161
  if (!this.store.payment) throw new Error('payment 模块未初始化');
2773
3162
  const state = this.store.payment.wallet.updateWalletAssetAmount(params.assetId, params.amount);
2774
3163
  await this.syncSelectedWalletAssets(state);
2775
- return this.publishWalletAssetsState(state);
3164
+ return this.publishWalletAssetsState(state, 'local');
2776
3165
  }
2777
3166
 
2778
3167
  /** 扫码精确查券;仅可用资产会被自动选中。 */
@@ -2787,7 +3176,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2787
3176
  const result = await wallet.scanWalletAssetAsync(code);
2788
3177
  if (result.type === 'normalCode') {
2789
3178
  await this.syncSelectedWalletAssets(result.state);
2790
- await this.publishWalletAssetsState(result.state);
3179
+ await this.publishWalletAssetsState(result.state, 'local');
2791
3180
  }
2792
3181
  return result;
2793
3182
  }
@@ -2797,7 +3186,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2797
3186
  if (!this.store.payment) throw new Error('payment 模块未初始化');
2798
3187
  const state = this.store.payment.wallet.clearWalletAssetSelection();
2799
3188
  await this.syncSelectedWalletAssets(state);
2800
- return this.publishWalletAssetsState(state);
3189
+ return this.publishWalletAssetsState(state, 'local');
2801
3190
  }
2802
3191
 
2803
3192
  /**
@@ -2893,10 +3282,24 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2893
3282
  if (!this.store.order) throw new Error('order 模块未初始化');
2894
3283
  const beforePayments = (0, _lodashEs.cloneDeep)(this.store.order.getOrderPayments());
2895
3284
  const pendingWalletAmount = this.getPendingWalletPaymentAmount(beforePayments);
3285
+ const amountSnapshot = this.store.order.getOrderAmountSnapshot?.();
2896
3286
  if (pendingWalletAmount.lte(0)) {
2897
- 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
+ };
2898
3302
  }
2899
- const amountSnapshot = this.store.order.getOrderAmountSnapshot?.();
2900
3303
  const effectiveAmountDue = _decimal.default.max(new _decimal.default(amountSnapshot?.amountGap || 0).minus(pendingWalletAmount), 0);
2901
3304
  if (effectiveAmountDue.gt(0.01)) {
2902
3305
  throw new Error('Wallet 支付尚未覆盖全部待支付金额');
@@ -2927,7 +3330,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2927
3330
  try {
2928
3331
  const committed = this.getCommittedWalletAssets();
2929
3332
  const walletState = this.store.payment.wallet.setCommittedWalletAssets(committed.ids, committed.assets);
2930
- await this.publishWalletAssetsState(walletState);
3333
+ await this.publishWalletAssetsState(walletState, 'local');
2931
3334
  } catch (error) {
2932
3335
  this.logWarning('confirmWalletPayment: Wallet committed 状态同步失败', {
2933
3336
  error: error instanceof Error ? error.message : String(error)
@@ -3011,7 +3414,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
3011
3414
  if (this.store.payment) {
3012
3415
  const committed = this.getCommittedWalletAssets();
3013
3416
  const walletState = this.store.payment.wallet.setCommittedWalletAssets(committed.ids, committed.assets);
3014
- await this.publishWalletAssetsState(walletState);
3417
+ await this.publishWalletAssetsState(walletState, 'local');
3015
3418
  }
3016
3419
  return {
3017
3420
  payment: payment || {},
@@ -3117,7 +3520,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
3117
3520
  if (this.store.payment) {
3118
3521
  const committed = this.getCommittedWalletAssets();
3119
3522
  const walletState = this.store.payment.wallet.setCommittedWalletAssets(committed.ids, committed.assets);
3120
- await this.publishWalletAssetsState(walletState);
3523
+ await this.publishWalletAssetsState(walletState, 'local');
3121
3524
  }
3122
3525
  return {
3123
3526
  payment: payment || {},