@pisell/pisellos 2.2.260 → 2.2.262

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 (107) hide show
  1. package/dist/model/strategy/adapter/dataVariant/adapter.d.ts +1 -0
  2. package/dist/model/strategy/adapter/dataVariant/adapter.js +15 -0
  3. package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +2 -0
  4. package/dist/model/strategy/adapter/dataVariant/evaluator.js +25 -0
  5. package/dist/model/strategy/adapter/dataVariant/examples.js +1 -6
  6. package/dist/model/strategy/adapter/dataVariant/type.d.ts +2 -0
  7. package/dist/model/strategy/adapter/promotion/index.js +0 -9
  8. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +23 -13
  9. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +2 -1
  10. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +1 -1
  11. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.js +32 -1
  12. package/dist/modules/Discount/index.d.ts +5 -2
  13. package/dist/modules/Discount/index.js +30 -7
  14. package/dist/modules/Discount/types.d.ts +4 -0
  15. package/dist/modules/Order/index.d.ts +45 -2
  16. package/dist/modules/Order/index.js +1552 -926
  17. package/dist/modules/Order/types.d.ts +36 -2
  18. package/dist/modules/Order/utils/bundleDiscountHydration.d.ts +5 -0
  19. package/dist/modules/Order/utils/bundleDiscountHydration.js +144 -0
  20. package/dist/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
  21. package/dist/modules/Order/utils/orderCollectionIdentity.js +405 -0
  22. package/dist/modules/Order/utils.d.ts +8 -3
  23. package/dist/modules/Order/utils.js +136 -56
  24. package/dist/modules/Rules/index.d.ts +4 -10
  25. package/dist/modules/Rules/index.js +63 -12
  26. package/dist/modules/Rules/types.d.ts +12 -2
  27. package/dist/modules/SalesSummary/index.d.ts +7 -3
  28. package/dist/modules/SalesSummary/index.js +67 -39
  29. package/dist/modules/SalesSummary/types.d.ts +1 -0
  30. package/dist/modules/SalesSummary/utils.js +2 -1
  31. package/dist/modules/SurchargeList/index.d.ts +6 -4
  32. package/dist/modules/SurchargeList/index.js +62 -39
  33. package/dist/modules/SurchargeList/types.d.ts +6 -2
  34. package/dist/server/index.d.ts +8 -0
  35. package/dist/server/index.js +1365 -911
  36. package/dist/server/modules/order/index.d.ts +32 -7
  37. package/dist/server/modules/order/index.js +551 -464
  38. package/dist/server/modules/order/types.d.ts +4 -0
  39. package/dist/server/modules/products/index.d.ts +5 -1
  40. package/dist/server/modules/products/index.js +384 -315
  41. package/dist/server/modules/products/types.d.ts +4 -0
  42. package/dist/solution/BaseSales/index.d.ts +42 -2
  43. package/dist/solution/BaseSales/index.js +1416 -775
  44. package/dist/solution/BaseSales/types.d.ts +7 -1
  45. package/dist/solution/BaseSales/types.js +3 -2
  46. package/dist/solution/BaseSales/utils/cartPromotion.js +19 -7
  47. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -3
  48. package/dist/solution/BaseSales/utils/parseSalesResponse.js +6 -8
  49. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +20 -4
  50. package/dist/solution/BookingByStep/index.d.ts +1 -1
  51. package/dist/solution/BookingTicket/index.d.ts +8 -0
  52. package/dist/solution/BookingTicket/index.js +212 -31
  53. package/dist/solution/ShopDiscount/index.js +15 -14
  54. package/lib/model/strategy/adapter/dataVariant/adapter.d.ts +1 -0
  55. package/lib/model/strategy/adapter/dataVariant/adapter.js +10 -0
  56. package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +2 -0
  57. package/lib/model/strategy/adapter/dataVariant/evaluator.js +20 -1
  58. package/lib/model/strategy/adapter/dataVariant/examples.js +0 -2
  59. package/lib/model/strategy/adapter/dataVariant/type.d.ts +2 -0
  60. package/lib/model/strategy/adapter/promotion/index.js +0 -49
  61. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +16 -1
  62. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +1 -0
  63. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +1 -1
  64. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +23 -2
  65. package/lib/modules/Discount/index.d.ts +5 -2
  66. package/lib/modules/Discount/index.js +23 -3
  67. package/lib/modules/Discount/types.d.ts +4 -0
  68. package/lib/modules/Order/index.d.ts +45 -2
  69. package/lib/modules/Order/index.js +720 -116
  70. package/lib/modules/Order/types.d.ts +36 -2
  71. package/lib/modules/Order/utils/bundleDiscountHydration.d.ts +5 -0
  72. package/lib/modules/Order/utils/bundleDiscountHydration.js +139 -0
  73. package/lib/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
  74. package/lib/modules/Order/utils/orderCollectionIdentity.js +415 -0
  75. package/lib/modules/Order/utils.d.ts +8 -3
  76. package/lib/modules/Order/utils.js +104 -18
  77. package/lib/modules/Rules/index.d.ts +4 -10
  78. package/lib/modules/Rules/index.js +61 -9
  79. package/lib/modules/Rules/types.d.ts +12 -2
  80. package/lib/modules/SalesSummary/index.d.ts +7 -3
  81. package/lib/modules/SalesSummary/index.js +28 -11
  82. package/lib/modules/SalesSummary/types.d.ts +1 -0
  83. package/lib/modules/SalesSummary/utils.js +2 -0
  84. package/lib/modules/SurchargeList/index.d.ts +6 -4
  85. package/lib/modules/SurchargeList/index.js +41 -21
  86. package/lib/modules/SurchargeList/types.d.ts +6 -2
  87. package/lib/server/index.d.ts +8 -0
  88. package/lib/server/index.js +336 -11
  89. package/lib/server/modules/order/index.d.ts +32 -7
  90. package/lib/server/modules/order/index.js +298 -189
  91. package/lib/server/modules/order/types.d.ts +4 -0
  92. package/lib/server/modules/products/index.d.ts +5 -1
  93. package/lib/server/modules/products/index.js +21 -0
  94. package/lib/server/modules/products/types.d.ts +4 -0
  95. package/lib/solution/BaseSales/index.d.ts +42 -2
  96. package/lib/solution/BaseSales/index.js +535 -108
  97. package/lib/solution/BaseSales/types.d.ts +7 -1
  98. package/lib/solution/BaseSales/types.js +2 -1
  99. package/lib/solution/BaseSales/utils/cartPromotion.js +13 -1
  100. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -3
  101. package/lib/solution/BaseSales/utils/parseSalesResponse.js +4 -5
  102. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +14 -6
  103. package/lib/solution/BookingByStep/index.d.ts +1 -1
  104. package/lib/solution/BookingTicket/index.d.ts +8 -0
  105. package/lib/solution/BookingTicket/index.js +134 -8
  106. package/lib/solution/ShopDiscount/index.js +2 -1
  107. package/package.json +1 -1
@@ -40,11 +40,13 @@ var import_decimal = __toESM(require("decimal.js"));
40
40
  var import_lodash_es = require("lodash-es");
41
41
  var import_types2 = require("../BookingByStep/types");
42
42
  var import_utils = require("../../modules/Order/utils");
43
+ var import_orderCollectionIdentity = require("../../modules/Order/utils/orderCollectionIdentity");
43
44
  var import_dayjs = __toESM(require("dayjs"));
44
45
  __reExport(BaseSales_exports, require("./types"), module.exports);
45
46
  var import_Quotation = require("../../modules/Quotation");
46
47
  var import_transformBaseProductToOrderProduct = require("./utils/transformBaseProductToOrderProduct");
47
48
  var import_quotationPrice = require("./utils/quotationPrice");
49
+ var SERVER_ORDER_CHANGED_EVENT = "order:onOrdersChanged";
48
50
  function isBaseSalesManualProductDiscountProduct(product) {
49
51
  var _a, _b;
50
52
  return ((_a = product == null ? void 0 : product.metadata) == null ? void 0 : _a.is_manual_discount) === true || ((_b = product == null ? void 0 : product.metadata) == null ? void 0 : _b.is_manual_discount) === 1 || ((product == null ? void 0 : product.discount_list) || []).some((item) => (item == null ? void 0 : item.type) === "product");
@@ -75,54 +77,166 @@ function isBaseSalesHistoricalDiscountEntry(discount) {
75
77
  (discount == null ? void 0 : discount.isEditMode) || (discount == null ? void 0 : discount.isDisabled) || (discount == null ? void 0 : discount.order_discount_id) != null
76
78
  );
77
79
  }
78
- function getBaseSalesUniqueArrayMetadataKey(key) {
79
- if (key === "products" || key === "bookings")
80
- return "unique_identification_number";
80
+ var BASE_SALES_PERSISTENT_ID_FIELD_BY_KIND = {
81
+ product: "order_detail_id",
82
+ booking: "schedule_event_id",
83
+ payment: "order_payment_id"
84
+ };
85
+ function getBaseSalesOrderCollectionKind(key) {
86
+ if (key === "products")
87
+ return "product";
88
+ if (key === "bookings")
89
+ return "booking";
81
90
  if (key === "payments" || key === "payment")
82
- return "unique_payment_number";
91
+ return "payment";
83
92
  return null;
84
93
  }
85
- function getBaseSalesMetadataUid(item, metadataKey) {
86
- var _a;
87
- const uid = ((_a = item == null ? void 0 : item.metadata) == null ? void 0 : _a[metadataKey]) ?? (item == null ? void 0 : item[metadataKey]);
88
- if (uid === void 0 || uid === null || uid === "")
89
- return null;
90
- return String(uid);
94
+ function isSameBaseSalesOrderRecord(left, right) {
95
+ if (!left || !right || typeof left !== "object" || typeof right !== "object")
96
+ return false;
97
+ const leftIdentities = new Set(
98
+ [left.order_id, left.id, left.external_sale_number, left.order_number].filter((value) => value !== void 0 && value !== null && value !== "").map(String)
99
+ );
100
+ if (leftIdentities.size === 0)
101
+ return false;
102
+ return [right.order_id, right.id, right.external_sale_number, right.order_number].some(
103
+ (value) => value !== void 0 && value !== null && value !== "" && leftIdentities.has(String(value))
104
+ );
91
105
  }
92
- function mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey) {
93
- const result = [];
94
- const indexByUid = /* @__PURE__ */ new Map();
95
- const appendOrReplaceByUid = (item) => {
96
- const clonedItem = (0, import_lodash_es.cloneDeep)(item);
97
- const uid = getBaseSalesMetadataUid(clonedItem, metadataKey);
98
- if (!uid) {
99
- result.push(clonedItem);
100
- return;
106
+ function isBaseSalesBlankValue(value) {
107
+ return value === void 0 || value === null || value === "";
108
+ }
109
+ function mergeBaseSalesProductSnapshotFields(currentItem, loadedItem) {
110
+ var _a, _b, _c;
111
+ const mergedItem = (0, import_lodash_es.cloneDeep)(loadedItem);
112
+ if (isBaseSalesBlankValue(mergedItem.product_cover) && !isBaseSalesBlankValue(currentItem == null ? void 0 : currentItem.product_cover)) {
113
+ mergedItem.product_cover = currentItem.product_cover;
114
+ }
115
+ const currentHolderConfig = (_a = currentItem == null ? void 0 : currentItem.metadata) == null ? void 0 : _a.holder_config;
116
+ if ((((_b = mergedItem.metadata) == null ? void 0 : _b.holder_config) === void 0 || ((_c = mergedItem.metadata) == null ? void 0 : _c.holder_config) === null) && currentHolderConfig !== void 0 && currentHolderConfig !== null) {
117
+ mergedItem.metadata = {
118
+ ...mergedItem.metadata || {},
119
+ holder_config: currentHolderConfig
120
+ };
121
+ }
122
+ return mergedItem;
123
+ }
124
+ function mergeBaseSalesCollectionItem(kind, currentItem, incomingItem, uidRemaps) {
125
+ const currentReferenceUid = (0, import_orderCollectionIdentity.getOrderCollectionReferenceUid)(kind, currentItem);
126
+ const incomingReferenceUid = (0, import_orderCollectionIdentity.getOrderCollectionReferenceUid)(kind, incomingItem);
127
+ const identityMergedItem = (0, import_orderCollectionIdentity.mergeOrderCollectionItems)(
128
+ kind,
129
+ currentItem,
130
+ incomingItem
131
+ );
132
+ const mergedUid = (0, import_orderCollectionIdentity.getOrderCollectionUid)(kind, identityMergedItem);
133
+ if (mergedUid) {
134
+ for (const from of /* @__PURE__ */ new Set([currentReferenceUid, incomingReferenceUid])) {
135
+ if (!from || from === mergedUid)
136
+ continue;
137
+ uidRemaps.push({
138
+ kind,
139
+ from,
140
+ to: mergedUid,
141
+ persistentId: (0, import_orderCollectionIdentity.getOrderCollectionPersistentId)(kind, incomingItem) || (0, import_orderCollectionIdentity.getOrderCollectionPersistentId)(kind, currentItem)
142
+ });
101
143
  }
102
- const existingIndex = indexByUid.get(uid);
103
- if (existingIndex !== void 0) {
104
- result[existingIndex] = clonedItem;
144
+ }
145
+ const mergedItem = mergedUid ? (0, import_orderCollectionIdentity.setOrderCollectionUid)(kind, incomingItem, mergedUid) : (0, import_lodash_es.cloneDeep)(incomingItem);
146
+ const persistentIdField = BASE_SALES_PERSISTENT_ID_FIELD_BY_KIND[kind];
147
+ if (isBaseSalesBlankValue(mergedItem[persistentIdField]) && !isBaseSalesBlankValue(identityMergedItem[persistentIdField])) {
148
+ mergedItem[persistentIdField] = identityMergedItem[persistentIdField];
149
+ }
150
+ return kind === "product" ? mergeBaseSalesProductSnapshotFields(currentItem, mergedItem) : mergedItem;
151
+ }
152
+ function mergeBaseSalesOrderCollection(kind, currentValue, incomingValue, strategy, uidRemaps) {
153
+ const currentItems = (0, import_orderCollectionIdentity.normalizeOrderCollection)(kind, currentValue, {
154
+ ensureUid: false
155
+ }).items;
156
+ const incomingItems = (0, import_orderCollectionIdentity.normalizeOrderCollection)(kind, incomingValue, {
157
+ ensureUid: false
158
+ }).items;
159
+ if (strategy === "authoritative-incoming") {
160
+ const result2 = (0, import_lodash_es.cloneDeep)(incomingItems);
161
+ currentItems.forEach((currentItem) => {
162
+ const incomingIndex = result2.findIndex(
163
+ (incomingItem) => (0, import_orderCollectionIdentity.isSameOrderCollectionItem)(kind, currentItem, incomingItem)
164
+ );
165
+ if (incomingIndex !== -1) {
166
+ result2[incomingIndex] = mergeBaseSalesCollectionItem(
167
+ kind,
168
+ currentItem,
169
+ result2[incomingIndex],
170
+ uidRemaps
171
+ );
172
+ return;
173
+ }
174
+ if (!(0, import_orderCollectionIdentity.getOrderCollectionPersistentId)(kind, currentItem)) {
175
+ result2.push((0, import_lodash_es.cloneDeep)(currentItem));
176
+ }
177
+ });
178
+ return result2;
179
+ }
180
+ const result = (0, import_lodash_es.cloneDeep)(currentItems);
181
+ incomingItems.forEach((incomingItem) => {
182
+ const currentIndex = result.findIndex(
183
+ (currentItem) => (0, import_orderCollectionIdentity.isSameOrderCollectionItem)(kind, currentItem, incomingItem)
184
+ );
185
+ if (currentIndex !== -1) {
186
+ result[currentIndex] = mergeBaseSalesCollectionItem(
187
+ kind,
188
+ result[currentIndex],
189
+ incomingItem,
190
+ uidRemaps
191
+ );
105
192
  return;
106
193
  }
107
- indexByUid.set(uid, result.length);
108
- result.push(clonedItem);
109
- };
110
- currentValue.forEach(appendOrReplaceByUid);
111
- loadedValue.forEach(appendOrReplaceByUid);
194
+ result.push((0, import_lodash_es.cloneDeep)(incomingItem));
195
+ });
112
196
  return result;
113
197
  }
114
- function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord) {
115
- if (!currentTempOrder)
116
- return loadedRecord;
198
+ function normalizeBaseSalesRecordCollections(sourceRecord, options) {
199
+ const normalizedRecord = (0, import_orderCollectionIdentity.normalizeOrderCollections)(
200
+ (0, import_lodash_es.cloneDeep)(sourceRecord || {}),
201
+ options
202
+ ).order;
203
+ if (Array.isArray(normalizedRecord.payment)) {
204
+ normalizedRecord.payment = (0, import_orderCollectionIdentity.normalizeOrderCollection)(
205
+ "payment",
206
+ normalizedRecord.payment,
207
+ options
208
+ ).items;
209
+ }
210
+ return normalizedRecord;
211
+ }
212
+ function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord, strategy) {
213
+ const normalizedLoadedRecord = normalizeBaseSalesRecordCollections(
214
+ loadedRecord || {},
215
+ { ensureUid: false }
216
+ );
217
+ if (!currentTempOrder) {
218
+ return normalizeBaseSalesRecordCollections(normalizedLoadedRecord);
219
+ }
220
+ const normalizedCurrentTempOrder = normalizeBaseSalesRecordCollections(
221
+ currentTempOrder,
222
+ { ensureUid: false }
223
+ );
224
+ const uidRemaps = [];
117
225
  const mergedRecord = (0, import_lodash_es.mergeWith)(
118
- (0, import_lodash_es.cloneDeep)(currentTempOrder),
119
- (0, import_lodash_es.cloneDeep)(loadedRecord || {}),
226
+ normalizedCurrentTempOrder,
227
+ normalizedLoadedRecord,
120
228
  (currentValue, loadedValue, key) => {
229
+ const collectionKind = getBaseSalesOrderCollectionKind(key);
230
+ if (collectionKind && Array.isArray(loadedValue)) {
231
+ return mergeBaseSalesOrderCollection(
232
+ collectionKind,
233
+ Array.isArray(currentValue) ? currentValue : [],
234
+ loadedValue,
235
+ strategy,
236
+ uidRemaps
237
+ );
238
+ }
121
239
  if (Array.isArray(currentValue) && Array.isArray(loadedValue)) {
122
- const metadataKey = getBaseSalesUniqueArrayMetadataKey(key);
123
- if (metadataKey) {
124
- return mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey);
125
- }
126
240
  return [
127
241
  ...(0, import_lodash_es.cloneDeep)(currentValue),
128
242
  ...(0, import_lodash_es.cloneDeep)(loadedValue)
@@ -137,7 +251,9 @@ function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord) {
137
251
  }
138
252
  );
139
253
  delete mergedRecord.request_unique_idempotency_token;
140
- return mergedRecord;
254
+ return normalizeBaseSalesRecordCollections(
255
+ (0, import_orderCollectionIdentity.applyOrderCollectionUidRemaps)(mergedRecord, uidRemaps)
256
+ );
141
257
  }
142
258
  var BaseSalesImpl = class extends import_BaseModule.BaseModule {
143
259
  constructor(name, version) {
@@ -156,6 +272,16 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
156
272
  this.hasManualDiscountSelection = false;
157
273
  this.reusedSharedSubModuleNames = /* @__PURE__ */ new Set();
158
274
  this.paymentMethodsCache = [];
275
+ this.queuedAutoPaymentSync = false;
276
+ this.autoPaymentSyncFlushing = false;
277
+ this.autoPaymentSyncTimer = null;
278
+ this.salesDetailLoadInFlightCount = 0;
279
+ this.salesDetailLoadSequence = 0;
280
+ this.salesDetailHydrateQueue = Promise.resolve();
281
+ this.serverOrderChangeUnsubscribe = null;
282
+ this.serverOrderChangeHydrateInFlight = null;
283
+ this.queuedServerOrderChanges = [];
284
+ this.serverOrderChangeSyncEnabled = false;
159
285
  }
160
286
  /**
161
287
  * 子类可覆盖此方法以追加/收敛要注册的子模块。
@@ -165,10 +291,10 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
165
291
  return ["products", "order", "salesSummary", "schedule", "payment", "quotation"];
166
292
  }
167
293
  getReusableSharedSubModule(moduleName) {
168
- var _a;
294
+ var _a, _b;
169
295
  if (moduleName !== "schedule" && moduleName !== "quotation")
170
296
  return null;
171
- return ((_a = this.core) == null ? void 0 : _a.getModule(moduleName)) || null;
297
+ return ((_b = (_a = this.core) == null ? void 0 : _a.getModule) == null ? void 0 : _b.call(_a, moduleName)) || null;
172
298
  }
173
299
  isScheduleListLoaded(scheduleModule) {
174
300
  if (!scheduleModule)
@@ -220,6 +346,123 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
220
346
  });
221
347
  }
222
348
  }
349
+ isCurrentSalesOrderRecord(order) {
350
+ var _a, _b;
351
+ const currentTempOrder = (_b = (_a = this.store.order) == null ? void 0 : _a.getTempOrder) == null ? void 0 : _b.call(_a);
352
+ const currentRecords = [
353
+ currentTempOrder,
354
+ this.currentSalesDetail
355
+ ].filter(Boolean);
356
+ return currentRecords.some((record) => isSameBaseSalesOrderRecord(record, order));
357
+ }
358
+ setServerOrderChangeSyncEnabled(enabled) {
359
+ this.serverOrderChangeSyncEnabled = enabled;
360
+ if (!enabled)
361
+ this.queuedServerOrderChanges = [];
362
+ }
363
+ queueLatestServerOrderChange(order) {
364
+ const snapshot = (0, import_lodash_es.cloneDeep)(order);
365
+ const existingIndex = this.queuedServerOrderChanges.findIndex(
366
+ (queued) => isSameBaseSalesOrderRecord(queued, snapshot)
367
+ );
368
+ if (existingIndex >= 0) {
369
+ this.queuedServerOrderChanges[existingIndex] = snapshot;
370
+ return;
371
+ }
372
+ this.queuedServerOrderChanges.push(snapshot);
373
+ }
374
+ async drainQueuedServerOrderChanges() {
375
+ if (!this.serverOrderChangeSyncEnabled || this.salesDetailLoadInFlightCount > 0 || this.serverOrderChangeHydrateInFlight || this.queuedServerOrderChanges.length === 0)
376
+ return;
377
+ const changedOrders = this.queuedServerOrderChanges;
378
+ this.queuedServerOrderChanges = [];
379
+ await this.syncCurrentSalesDetailFromServerOrderChange({ changedOrders });
380
+ }
381
+ async syncCurrentSalesDetailFromServerOrderChange(payload) {
382
+ const changedOrders = Array.isArray(payload) ? payload : Array.isArray(payload == null ? void 0 : payload.changedOrders) ? payload.changedOrders : (payload == null ? void 0 : payload.data) && typeof payload.data === "object" ? [payload.data] : [];
383
+ if (!this.serverOrderChangeSyncEnabled)
384
+ return;
385
+ if (this.salesDetailLoadInFlightCount > 0) {
386
+ changedOrders.forEach(
387
+ (order) => this.queueLatestServerOrderChange(order)
388
+ );
389
+ return;
390
+ }
391
+ const changedOrder = changedOrders.find(
392
+ (order) => this.isCurrentSalesOrderRecord(order)
393
+ );
394
+ if (!changedOrder)
395
+ return;
396
+ if (this.serverOrderChangeHydrateInFlight) {
397
+ this.queueLatestServerOrderChange(changedOrder);
398
+ return;
399
+ }
400
+ if (!this.store.order)
401
+ return;
402
+ this.serverOrderChangeHydrateInFlight = (async () => {
403
+ var _a, _b;
404
+ const currentTempOrder = (_b = (_a = this.store.order).getTempOrder) == null ? void 0 : _b.call(_a);
405
+ const record = mergeSalesDetailRecordWithTempOrder(
406
+ currentTempOrder,
407
+ changedOrder,
408
+ "authoritative-incoming"
409
+ );
410
+ const sales = await this.store.order.hydrateTempOrderFromRecord(record, {
411
+ recalcOnHydrate: false
412
+ });
413
+ this.currentSalesDetail = sales;
414
+ await this.core.effects.emit(`${this.name}:onSalesOrderLoaded`, { sales });
415
+ })();
416
+ try {
417
+ await this.serverOrderChangeHydrateInFlight;
418
+ } finally {
419
+ this.serverOrderChangeHydrateInFlight = null;
420
+ await this.drainQueuedServerOrderChanges();
421
+ }
422
+ }
423
+ registerServerOrderChangeSync() {
424
+ var _a, _b;
425
+ (_a = this.serverOrderChangeUnsubscribe) == null ? void 0 : _a.call(this);
426
+ const effects = (_b = this.core) == null ? void 0 : _b.effects;
427
+ if (!effects || typeof effects.on !== "function")
428
+ return;
429
+ this.serverOrderChangeUnsubscribe = effects.on(SERVER_ORDER_CHANGED_EVENT, (payload) => {
430
+ return this.syncCurrentSalesDetailFromServerOrderChange(payload).catch((error) => {
431
+ this.logError("sync sales detail from server order change failed", {
432
+ error: error instanceof Error ? error.message : String(error)
433
+ });
434
+ });
435
+ });
436
+ }
437
+ async hydrateLatestLoadedSalesDetail(record, loadSequence) {
438
+ let hydratedSales = null;
439
+ let skippedBeforeHydrate = false;
440
+ const hydrateTask = async () => {
441
+ if (loadSequence !== this.salesDetailLoadSequence) {
442
+ skippedBeforeHydrate = true;
443
+ return;
444
+ }
445
+ if (!this.store.order)
446
+ throw new Error("order 模块未初始化");
447
+ const sales = await this.store.order.hydrateTempOrderFromRecord(record, {
448
+ recalcOnHydrate: false
449
+ });
450
+ hydratedSales = sales;
451
+ if (loadSequence !== this.salesDetailLoadSequence)
452
+ return;
453
+ this.currentSalesDetail = sales;
454
+ await this.core.effects.emit(`${this.name}:onSalesOrderLoaded`, { sales });
455
+ };
456
+ const queuedTask = this.salesDetailHydrateQueue.then(hydrateTask, hydrateTask);
457
+ this.salesDetailHydrateQueue = queuedTask.then(
458
+ () => void 0,
459
+ () => void 0
460
+ );
461
+ await queuedTask;
462
+ if (skippedBeforeHydrate)
463
+ return record;
464
+ return hydratedSales || this.currentSalesDetail || record;
465
+ }
223
466
  hydrateOrderPaymentNames(payments) {
224
467
  if (!payments.length)
225
468
  return [];
@@ -634,9 +877,13 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
634
877
  );
635
878
  }
636
879
  await this.getPaymentMethodsAsync();
880
+ this.registerServerOrderChangeSync();
637
881
  this.core.effects.emit(`${this.name}:onInited`, {});
638
882
  }
639
883
  async destroy() {
884
+ var _a;
885
+ (_a = this.serverOrderChangeUnsubscribe) == null ? void 0 : _a.call(this);
886
+ this.serverOrderChangeUnsubscribe = null;
640
887
  Object.keys(this.store).forEach((key) => {
641
888
  if (this.reusedSharedSubModuleNames.has(key))
642
889
  return;
@@ -650,6 +897,8 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
650
897
  }
651
898
  });
652
899
  this.currentSalesDetail = null;
900
+ this.queuedServerOrderChanges = [];
901
+ this.salesDetailLoadSequence += 1;
653
902
  await this.core.effects.emit(`${this.name}:onDestroy`, {});
654
903
  super.destroy();
655
904
  }
@@ -663,30 +912,47 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
663
912
  async loadSalesDetail(orderIdOrParams) {
664
913
  if (!this.store.order)
665
914
  throw new Error("order 模块未初始化");
666
- const params = typeof orderIdOrParams === "object" ? orderIdOrParams : { orderId: orderIdOrParams };
667
- const externalSaleNumber = params.externalSaleNumber || params.external_sale_number;
668
- const preloadedSalesDetail = params.preloadedSalesDetail;
669
- const lookup = params.orderId ?? externalSaleNumber ?? params.orderNumber ?? (preloadedSalesDetail == null ? void 0 : preloadedSalesDetail.order_id) ?? (preloadedSalesDetail == null ? void 0 : preloadedSalesDetail.external_sale_number) ?? (preloadedSalesDetail == null ? void 0 : preloadedSalesDetail.order_number);
670
- if (!preloadedSalesDetail && (lookup === void 0 || lookup === null || lookup === "")) {
671
- throw new Error("加载销售详情需要 orderId、externalSaleNumber 或 orderNumber");
672
- }
673
- const loadedRecord = preloadedSalesDetail ?? await this.store.order.getSalesOrderByLookup({
674
- lookup,
675
- forceRemote: params.forceRemote
676
- });
677
- if (!preloadedSalesDetail && (!loadedRecord || loadedRecord.code !== 200)) {
678
- const message = loadedRecord && (loadedRecord.message || loadedRecord.msg) || `加载销售详情失败: ${lookup}`;
679
- throw new Error(message);
680
- }
681
- const remoteRecord = preloadedSalesDetail ?? loadedRecord.data;
682
- const currentTempOrder = params.merge ? this.store.order.getTempOrder() : null;
683
- const record = params.merge ? mergeSalesDetailRecordWithTempOrder(currentTempOrder, remoteRecord) : remoteRecord;
684
- const sales = await this.store.order.hydrateTempOrderFromRecord(record, {
685
- recalcOnHydrate: false
686
- });
687
- this.currentSalesDetail = sales;
688
- await this.core.effects.emit(`${this.name}:onSalesOrderLoaded`, { sales });
689
- return sales;
915
+ const loadSequence = ++this.salesDetailLoadSequence;
916
+ this.salesDetailLoadInFlightCount += 1;
917
+ try {
918
+ const params = typeof orderIdOrParams === "object" ? orderIdOrParams : { orderId: orderIdOrParams };
919
+ const externalSaleNumber = params.externalSaleNumber || params.external_sale_number;
920
+ const preloadedSalesDetail = params.preloadedSalesDetail;
921
+ const lookup = params.orderId ?? externalSaleNumber ?? params.orderNumber ?? (preloadedSalesDetail == null ? void 0 : preloadedSalesDetail.order_id) ?? (preloadedSalesDetail == null ? void 0 : preloadedSalesDetail.external_sale_number) ?? (preloadedSalesDetail == null ? void 0 : preloadedSalesDetail.order_number);
922
+ if (!preloadedSalesDetail && (lookup === void 0 || lookup === null || lookup === "")) {
923
+ throw new Error("加载销售详情需要 orderId、externalSaleNumber 或 orderNumber");
924
+ }
925
+ const loadedRecord = preloadedSalesDetail ?? await this.store.order.getSalesOrderByLookup({
926
+ lookup,
927
+ forceRemote: params.forceRemote
928
+ });
929
+ if (!preloadedSalesDetail && (!loadedRecord || loadedRecord.code !== 200)) {
930
+ const message = loadedRecord && (loadedRecord.message || loadedRecord.msg) || `加载销售详情失败: ${lookup}`;
931
+ throw new Error(message);
932
+ }
933
+ const remoteRecord = preloadedSalesDetail ?? loadedRecord.data;
934
+ const currentTempOrder = params.merge ? this.store.order.getTempOrder() : null;
935
+ const record = params.merge ? mergeSalesDetailRecordWithTempOrder(
936
+ currentTempOrder,
937
+ remoteRecord,
938
+ "preserve-local"
939
+ ) : remoteRecord;
940
+ return await this.hydrateLatestLoadedSalesDetail(record, loadSequence);
941
+ } finally {
942
+ this.salesDetailLoadInFlightCount = Math.max(
943
+ 0,
944
+ this.salesDetailLoadInFlightCount - 1
945
+ );
946
+ if (this.salesDetailLoadInFlightCount === 0) {
947
+ try {
948
+ await this.drainQueuedServerOrderChanges();
949
+ } catch (error) {
950
+ this.logError("drain queued server order changes failed", {
951
+ error: error instanceof Error ? error.message : String(error)
952
+ });
953
+ }
954
+ }
955
+ }
690
956
  }
691
957
  /** 获取当前已加载的销售详情(只读快照)。未加载过则返回 null。 */
692
958
  getSalesOrder() {
@@ -1019,7 +1285,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1019
1285
  });
1020
1286
  }
1021
1287
  async loadDiscountConfig(params) {
1022
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t;
1288
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
1023
1289
  if (!this.store.order)
1024
1290
  throw new Error("order 模块未初始化");
1025
1291
  const tempOrder = this.store.order.ensureTempOrder();
@@ -1057,7 +1323,8 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1057
1323
  if (hasManualDiscountSelection && currentDiscountList.length) {
1058
1324
  return {
1059
1325
  productList: tempOrder.products || [],
1060
- discountList: currentDiscountList
1326
+ discountList: currentDiscountList,
1327
+ availableWalletIds: this.getAvailableWalletIds()
1061
1328
  };
1062
1329
  }
1063
1330
  let nextDiscountList = this.mergeHistoricalDiscountList(
@@ -1086,17 +1353,19 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1086
1353
  });
1087
1354
  return {
1088
1355
  productList: tempOrder.products || [],
1089
- discountList: nextDiscountList
1356
+ discountList: nextDiscountList,
1357
+ availableWalletIds: this.getAvailableWalletIds()
1090
1358
  };
1091
1359
  }
1092
1360
  if (rulesModule) {
1093
- const holders = ((_l = tempOrder.holder) == null ? void 0 : _l.form_record_id) ? [{ form_record_id: tempOrder.holder.form_record_id }] : [];
1361
+ const orderTotalAmount = Number(((_l = orderStore.summary) == null ? void 0 : _l.total_amount) || 0);
1362
+ console.log("[BaseSales.applyDiscountConfig.calcDiscount]");
1094
1363
  const result = rulesModule.calcDiscount({
1095
1364
  productList: tempOrder.products,
1096
1365
  discountList: nextDiscountList,
1097
- holders,
1098
- isFormSubject: !!((_m = tempOrder.holder) == null ? void 0 : _m.type) && tempOrder.holder.type === "form",
1099
- orderTotalAmount: Number(((_n = orderStore.summary) == null ? void 0 : _n.total_amount) || 0)
1366
+ holders: [],
1367
+ isFormSubject: (product) => (0, import_utils.resolveIsFormSubject)(tempOrder, product),
1368
+ orderTotalAmount
1100
1369
  }) || { productList: tempOrder.products, discountList: nextDiscountList };
1101
1370
  if (result.productList) {
1102
1371
  tempOrder.products = preserveManualProductDiscountProducts(
@@ -1105,8 +1374,8 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1105
1374
  );
1106
1375
  }
1107
1376
  for (const product of tempOrder.products || []) {
1108
- const productUid = (_o = product.metadata) == null ? void 0 : _o.unique_identification_number;
1109
- const runtimeOrigin = productUid ? (_r = (_q = (_p = tempOrder._extend) == null ? void 0 : _p.productsByUid) == null ? void 0 : _q[productUid]) == null ? void 0 : _r.origin : void 0;
1377
+ const productUid = (_m = product.metadata) == null ? void 0 : _m.unique_identification_number;
1378
+ const runtimeOrigin = productUid ? (_p = (_o = (_n = tempOrder._extend) == null ? void 0 : _n.productsByUid) == null ? void 0 : _o[productUid]) == null ? void 0 : _p.origin : void 0;
1110
1379
  if ((runtimeOrigin == null ? void 0 : runtimeOrigin.isManualDiscount) || isBaseSalesManualProductDiscountProduct(product))
1111
1380
  continue;
1112
1381
  const totalPerUnitDiscount = (product.discount_list || []).reduce(
@@ -1114,7 +1383,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1114
1383
  0
1115
1384
  );
1116
1385
  const optionSum = (0, import_utils.sumOptionUnitPrice)((0, import_utils.getProductSkuOptions)(product));
1117
- const sourcePrice = ((_s = product.metadata) == null ? void 0 : _s.source_product_price) ?? (((_t = product.metadata) == null ? void 0 : _t.main_product_original_price) != null ? new import_decimal.default(Number(product.metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : product.original_price ?? "0");
1386
+ const sourcePrice = ((_q = product.metadata) == null ? void 0 : _q.source_product_price) ?? (((_r = product.metadata) == null ? void 0 : _r.main_product_original_price) != null ? new import_decimal.default(Number(product.metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : product.original_price ?? "0");
1118
1387
  const newSourceSellingPrice = new import_decimal.default(Number(sourcePrice) || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
1119
1388
  const newMainSellingPrice = new import_decimal.default(Number(newSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
1120
1389
  if (product.metadata) {
@@ -1146,11 +1415,18 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1146
1415
  });
1147
1416
  return {
1148
1417
  productList: tempOrder.products || [],
1149
- discountList: nextDiscountList
1418
+ discountList: nextDiscountList,
1419
+ availableWalletIds: this.getAvailableWalletIds()
1150
1420
  };
1151
1421
  }
1422
+ getAvailableWalletIds() {
1423
+ var _a;
1424
+ if (!((_a = this.store.order) == null ? void 0 : _a.getAvailableWalletIds))
1425
+ return [];
1426
+ return this.store.order.getAvailableWalletIds();
1427
+ }
1152
1428
  async bestDiscount(cb) {
1153
- var _a, _b, _c, _d, _e;
1429
+ var _a, _b, _c;
1154
1430
  if (!this.store.order)
1155
1431
  throw new Error("order 模块未初始化");
1156
1432
  const tempOrder = this.store.order.ensureTempOrder();
@@ -1169,13 +1445,14 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1169
1445
  };
1170
1446
  await (discountModule == null ? void 0 : discountModule.setDiscountList(nextDiscountList));
1171
1447
  if (rulesModule) {
1172
- const holders = ((_c = tempOrder.holder) == null ? void 0 : _c.form_record_id) ? [{ form_record_id: tempOrder.holder.form_record_id }] : [];
1448
+ const orderTotalAmount = Number(((_c = orderStore.summary) == null ? void 0 : _c.total_amount) || 0);
1449
+ console.log("[BaseSales.bestDiscount.calcDiscount]");
1173
1450
  result = rulesModule.calcDiscount({
1174
1451
  productList: tempOrder.products,
1175
1452
  discountList: nextDiscountList,
1176
- holders,
1177
- isFormSubject: !!((_d = tempOrder.holder) == null ? void 0 : _d.type) && tempOrder.holder.type === "form",
1178
- orderTotalAmount: Number(((_e = orderStore.summary) == null ? void 0 : _e.total_amount) || 0)
1453
+ holders: [],
1454
+ isFormSubject: (product) => (0, import_utils.resolveIsFormSubject)(tempOrder, product),
1455
+ orderTotalAmount
1179
1456
  }) || result;
1180
1457
  if (result.productList) {
1181
1458
  tempOrder.products = preserveManualProductDiscountProducts(
@@ -1199,6 +1476,12 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1199
1476
  }
1200
1477
  await this.store.order.recalculateSummary({ createIfMissing: true });
1201
1478
  this.store.order.persistTempOrder();
1479
+ await this.effectsEmit("onDiscountApplied", {
1480
+ productList: tempOrder.products || [],
1481
+ discountList: nextDiscountList,
1482
+ selectedDiscountList: tempOrder.discount_list || [],
1483
+ tempOrder
1484
+ });
1202
1485
  cb == null ? void 0 : cb(result);
1203
1486
  return result;
1204
1487
  }
@@ -1207,6 +1490,30 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1207
1490
  return [];
1208
1491
  return this.store.order.getDiscountList();
1209
1492
  }
1493
+ /** 读取 Discount 模块原始券列表(未经过 bookingTime 等过滤)。 */
1494
+ getOriginalDiscountList() {
1495
+ var _a, _b;
1496
+ if (!this.store.order)
1497
+ return [];
1498
+ const discountModule = (_a = this.store.order.store) == null ? void 0 : _a.discount;
1499
+ return ((_b = discountModule == null ? void 0 : discountModule.getOriginalDiscountList) == null ? void 0 : _b.call(discountModule)) || [];
1500
+ }
1501
+ /**
1502
+ * 同步写入 Discount 模块的 discountList / originalDiscountList。
1503
+ * 供 Holder 补全等场景在 OS store 层更新 machinecode holder 字段。
1504
+ */
1505
+ async replaceDiscountStoreLists(params) {
1506
+ var _a;
1507
+ if (!this.store.order)
1508
+ throw new Error("order 模块未初始化");
1509
+ const discountModule = (_a = this.store.order.store) == null ? void 0 : _a.discount;
1510
+ if (!discountModule)
1511
+ return;
1512
+ if (params.originalDiscountList) {
1513
+ await discountModule.setOriginalDiscountList(params.originalDiscountList);
1514
+ }
1515
+ await discountModule.setDiscountList(params.discountList);
1516
+ }
1210
1517
  async scanPromotionCode(code, customerId) {
1211
1518
  try {
1212
1519
  if (!this.store.order)
@@ -1215,11 +1522,19 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1215
1522
  if (raw.isAvailable) {
1216
1523
  await this.store.order.recalculateSummary({ createIfMissing: true });
1217
1524
  this.store.order.persistTempOrder();
1525
+ const tempOrder = this.store.order.ensureTempOrder();
1526
+ await this.effectsEmit("onDiscountApplied", {
1527
+ productList: tempOrder.products || [],
1528
+ discountList: this.store.order.getDiscountList(),
1529
+ selectedDiscountList: tempOrder.discount_list || [],
1530
+ tempOrder
1531
+ });
1218
1532
  }
1219
1533
  return {
1220
1534
  isAvailable: raw.isAvailable,
1221
1535
  type: raw.type,
1222
- unavailableReason: raw.unavailableReason
1536
+ unavailableReason: raw.unavailableReason,
1537
+ scannedDiscountList: raw.scannedDiscountList
1223
1538
  };
1224
1539
  } catch (error) {
1225
1540
  throw error;
@@ -1227,7 +1542,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1227
1542
  }
1228
1543
  // TODO 需要优化,这段逻辑太长了,里面应该有些历史遗留问题
1229
1544
  async setDiscountSelected(params) {
1230
- var _a, _b, _c, _d, _e, _f, _g, _h;
1545
+ var _a, _b, _c, _d, _e, _f, _g;
1231
1546
  try {
1232
1547
  if (!this.store.order)
1233
1548
  throw new Error("order 模块未初始化");
@@ -1244,16 +1559,18 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1244
1559
  const orderStore = this.store.order.store || {};
1245
1560
  const discountModule = orderStore.discount;
1246
1561
  const rulesModule = orderStore.rules;
1247
- const holders = ((_a = tempOrder.holder) == null ? void 0 : _a.form_record_id) ? [{ form_record_id: tempOrder.holder.form_record_id }] : [];
1248
1562
  let nextDiscountList = updated;
1249
1563
  await (discountModule == null ? void 0 : discountModule.setDiscountList(updated));
1250
1564
  if (rulesModule) {
1565
+ const orderTotalAmount = Number(((_a = orderStore.summary) == null ? void 0 : _a.total_amount) || 0);
1566
+ console.log("[BaseSales.setDiscountSelected.calcDiscount]");
1251
1567
  const result = rulesModule.calcDiscount(
1252
1568
  {
1253
1569
  productList: tempOrder.products,
1254
1570
  discountList: updated,
1255
- holders,
1256
- isFormSubject: !!((_b = tempOrder.holder) == null ? void 0 : _b.type) && tempOrder.holder.type === "form"
1571
+ holders: [],
1572
+ isFormSubject: (product) => (0, import_utils.resolveIsFormSubject)(tempOrder, product),
1573
+ orderTotalAmount
1257
1574
  },
1258
1575
  {
1259
1576
  discountId: params.discountId,
@@ -1276,6 +1593,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1276
1593
  if (d.isSelected && !beforeSelectedIds.has(d.id)) {
1277
1594
  d.isSelected = false;
1278
1595
  d.isManualSelect = true;
1596
+ d.appliedProductDetails = [];
1279
1597
  }
1280
1598
  }
1281
1599
  }
@@ -1284,22 +1602,38 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1284
1602
  const selectedResourceIds = new Set(
1285
1603
  nextDiscountList.filter((d) => d.isSelected).map((d) => d.id)
1286
1604
  );
1605
+ const filterSelectedDiscountDetails = (discountList) => (discountList || []).filter((pd) => {
1606
+ var _a2;
1607
+ const rid = ((_a2 = pd.discount) == null ? void 0 : _a2.resource_id) ?? pd.id;
1608
+ return rid != null && selectedResourceIds.has(rid);
1609
+ });
1287
1610
  for (const product of tempOrder.products) {
1288
- const productUid = (_c = product.metadata) == null ? void 0 : _c.unique_identification_number;
1289
- const runtimeOrigin = productUid ? (_f = (_e = (_d = tempOrder._extend) == null ? void 0 : _d.productsByUid) == null ? void 0 : _e[productUid]) == null ? void 0 : _f.origin : void 0;
1611
+ const productUid = (_b = product.metadata) == null ? void 0 : _b.unique_identification_number;
1612
+ const runtimeOrigin = productUid ? (_e = (_d = (_c = tempOrder._extend) == null ? void 0 : _c.productsByUid) == null ? void 0 : _d[productUid]) == null ? void 0 : _e.origin : void 0;
1290
1613
  if ((runtimeOrigin == null ? void 0 : runtimeOrigin.isManualDiscount) || isBaseSalesManualProductDiscountProduct(product))
1291
1614
  continue;
1292
- product.discount_list = (product.discount_list || []).filter((pd) => {
1293
- var _a2;
1294
- const rid = ((_a2 = pd.discount) == null ? void 0 : _a2.resource_id) ?? pd.id;
1295
- return rid != null && selectedResourceIds.has(rid);
1296
- });
1615
+ product.discount_list = filterSelectedDiscountDetails(product.discount_list);
1616
+ if (Array.isArray(product.product_bundle)) {
1617
+ product.product_bundle = product.product_bundle.map((bundle) => {
1618
+ const nextBundleDiscountList = filterSelectedDiscountDetails(bundle == null ? void 0 : bundle.discount_list);
1619
+ const shouldRestoreBundlePrice = nextBundleDiscountList.length === 0;
1620
+ const restoredBundlePrice = (bundle == null ? void 0 : bundle.original_price) ?? (bundle == null ? void 0 : bundle.product_price) ?? (bundle == null ? void 0 : bundle.price);
1621
+ return {
1622
+ ...bundle,
1623
+ ...shouldRestoreBundlePrice ? {
1624
+ price: restoredBundlePrice,
1625
+ bundle_selling_price: restoredBundlePrice
1626
+ } : {},
1627
+ discount_list: nextBundleDiscountList
1628
+ };
1629
+ });
1630
+ }
1297
1631
  const totalPerUnitDiscount = (product.discount_list || []).reduce(
1298
1632
  (sum, pd) => sum + (pd.amount || 0),
1299
1633
  0
1300
1634
  );
1301
1635
  const optionSum = (0, import_utils.sumOptionUnitPrice)((0, import_utils.getProductSkuOptions)(product));
1302
- const sourcePrice = ((_g = product.metadata) == null ? void 0 : _g.source_product_price) ?? (((_h = product.metadata) == null ? void 0 : _h.main_product_original_price) != null ? new import_decimal.default(Number(product.metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : product.original_price ?? "0");
1636
+ const sourcePrice = ((_f = product.metadata) == null ? void 0 : _f.source_product_price) ?? (((_g = product.metadata) == null ? void 0 : _g.main_product_original_price) != null ? new import_decimal.default(Number(product.metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : product.original_price ?? "0");
1303
1637
  const newSourceSellingPrice = new import_decimal.default(Number(sourcePrice) || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
1304
1638
  const newMainSellingPrice = new import_decimal.default(Number(newSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
1305
1639
  if (product.metadata) {
@@ -1353,6 +1687,12 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1353
1687
  }
1354
1688
  await this.store.order.recalculateSummary({ createIfMissing: true });
1355
1689
  this.store.order.persistTempOrder();
1690
+ await this.effectsEmit("onDiscountApplied", {
1691
+ productList: tempOrder.products || [],
1692
+ discountList: result.discountList || [],
1693
+ selectedDiscountList: tempOrder.discount_list || [],
1694
+ tempOrder
1695
+ });
1356
1696
  } catch (error) {
1357
1697
  throw error;
1358
1698
  }
@@ -1382,6 +1722,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1382
1722
  ...(params == null ? void 0 : params.payments) !== void 0 ? { payments: params.payments } : {},
1383
1723
  ...inferredPaymentStatus !== void 0 ? { paymentStatus: inferredPaymentStatus } : {},
1384
1724
  ...(params == null ? void 0 : params.smallTicketDataFlag) !== void 0 ? { smallTicketDataFlag: params.smallTicketDataFlag } : {},
1725
+ ...(params == null ? void 0 : params.confirmPendingVoucherPayments) !== void 0 ? { confirmPendingVoucherPayments: params.confirmPendingVoucherPayments } : {},
1385
1726
  ...(params == null ? void 0 : params.enhancePayload) !== void 0 ? { enhancePayload: params.enhancePayload } : {}
1386
1727
  };
1387
1728
  return this.store.order.submitTempOrder(submitParams);
@@ -1401,6 +1742,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1401
1742
  ...(params == null ? void 0 : params.payments) !== void 0 ? { payments: params.payments } : {},
1402
1743
  ...inferredPaymentStatus !== void 0 ? { paymentStatus: inferredPaymentStatus } : {},
1403
1744
  ...(params == null ? void 0 : params.smallTicketDataFlag) !== void 0 ? { smallTicketDataFlag: params.smallTicketDataFlag } : {},
1745
+ ...(params == null ? void 0 : params.confirmPendingVoucherPayments) !== void 0 ? { confirmPendingVoucherPayments: params.confirmPendingVoucherPayments } : {},
1404
1746
  ...(params == null ? void 0 : params.enhancePayload) !== void 0 ? { enhancePayload: params.enhancePayload } : {}
1405
1747
  };
1406
1748
  return this.store.order.submitTempOrderAsync(submitParams);
@@ -1469,6 +1811,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1469
1811
  };
1470
1812
  const syncState = this.store.order.getOrderSyncState();
1471
1813
  if (params.submitWhenPaid && syncState === "submitting") {
1814
+ this.queueLatestAutoPaymentSync();
1472
1815
  return this.store.order.syncPaymentsToOrder(syncParams);
1473
1816
  }
1474
1817
  const payments = params.payments || [];
@@ -1480,14 +1823,28 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1480
1823
  });
1481
1824
  try {
1482
1825
  const syncResult = await this.store.order.syncPaymentsToOrder(syncParams);
1483
- await this.effectsEmit(import_types.BaseSalesHookNames.onPaymentSyncEnd, {
1826
+ const latestPayments = this.store.order.getOrderPayments();
1827
+ const amountSnapshot = this.store.order.getOrderAmountSnapshot();
1828
+ const orderSnapshot = this.store.order.getOrderSnapshot();
1829
+ const syncPayload = {
1484
1830
  ok: true,
1485
1831
  syncResult,
1486
- payments: this.store.order.getOrderPayments(),
1832
+ payments: latestPayments,
1487
1833
  params: syncParams,
1488
- amountSnapshot: this.store.order.getOrderAmountSnapshot(),
1489
- orderSnapshot: this.store.order.getOrderSnapshot()
1490
- });
1834
+ amountSnapshot,
1835
+ orderSnapshot,
1836
+ isFullyPaid: syncResult.isFullyPaid,
1837
+ isOrderFullyPaid: syncResult.isOrderFullyPaid,
1838
+ isDepositFullyPaid: syncResult.isDepositFullyPaid,
1839
+ paymentStage: syncResult.paymentStage,
1840
+ depositAmount: syncResult.depositAmount,
1841
+ orderExpectedAmount: syncResult.orderExpectedAmount
1842
+ };
1843
+ await this.effectsEmit(import_types.BaseSalesHookNames.onPaymentSyncEnd, syncPayload);
1844
+ if (syncResult.isDepositFullyPaid && !syncResult.isOrderFullyPaid) {
1845
+ await this.effectsEmit(import_types.BaseSalesHookNames.onDepositPaymentSyncEnd, syncPayload);
1846
+ }
1847
+ this.scheduleQueuedAutoPaymentSyncFlush(0);
1491
1848
  return syncResult;
1492
1849
  } catch (error) {
1493
1850
  await this.effectsEmit(import_types.BaseSalesHookNames.onPaymentSyncEnd, {
@@ -1498,6 +1855,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1498
1855
  amountSnapshot: this.store.order.getOrderAmountSnapshot(),
1499
1856
  orderSnapshot: this.store.order.getOrderSnapshot()
1500
1857
  });
1858
+ this.scheduleQueuedAutoPaymentSyncFlush(0);
1501
1859
  throw error;
1502
1860
  }
1503
1861
  }
@@ -1514,6 +1872,61 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1514
1872
  throw new Error("order 模块未初始化");
1515
1873
  return this.store.order.setOrderPayments(payments);
1516
1874
  }
1875
+ getPaymentStatusForSync(payments) {
1876
+ const order = this.store.order;
1877
+ if (!order)
1878
+ throw new Error("order 模块未初始化");
1879
+ const completion = order.getPaymentCompletion(payments);
1880
+ return completion.isOrderFullyPaid ? "paid" : "partially_paid";
1881
+ }
1882
+ queueLatestAutoPaymentSync() {
1883
+ this.queuedAutoPaymentSync = true;
1884
+ this.scheduleQueuedAutoPaymentSyncFlush();
1885
+ }
1886
+ scheduleQueuedAutoPaymentSyncFlush(delay = 100) {
1887
+ if (!this.queuedAutoPaymentSync)
1888
+ return;
1889
+ if (this.autoPaymentSyncTimer)
1890
+ return;
1891
+ this.autoPaymentSyncTimer = setTimeout(() => {
1892
+ this.autoPaymentSyncTimer = null;
1893
+ void this.flushQueuedAutoPaymentSync();
1894
+ }, delay);
1895
+ }
1896
+ async flushQueuedAutoPaymentSync() {
1897
+ if (!this.store.order)
1898
+ return;
1899
+ if (!this.queuedAutoPaymentSync || this.autoPaymentSyncFlushing)
1900
+ return;
1901
+ if (this.store.order.getOrderSyncState() === "submitting") {
1902
+ this.scheduleQueuedAutoPaymentSyncFlush();
1903
+ return;
1904
+ }
1905
+ this.autoPaymentSyncFlushing = true;
1906
+ try {
1907
+ while (this.queuedAutoPaymentSync) {
1908
+ this.queuedAutoPaymentSync = false;
1909
+ const payments = this.store.order.getOrderPayments();
1910
+ if (!payments.length)
1911
+ continue;
1912
+ await this.syncPaymentsToOrder({
1913
+ payments,
1914
+ paymentStatus: this.getPaymentStatusForSync(payments),
1915
+ submitWhenPaid: true,
1916
+ smallTicketDataFlag: 1
1917
+ });
1918
+ }
1919
+ } catch (error) {
1920
+ this.logError("queued auto sync payments failed", {
1921
+ error: error instanceof Error ? error.message : String(error)
1922
+ });
1923
+ } finally {
1924
+ this.autoPaymentSyncFlushing = false;
1925
+ if (this.queuedAutoPaymentSync) {
1926
+ this.scheduleQueuedAutoPaymentSyncFlush(0);
1927
+ }
1928
+ }
1929
+ }
1517
1930
  /** 追加单个支付项到当前订单。 */
1518
1931
  addOrderPayment(payment) {
1519
1932
  var _a;
@@ -1549,11 +1962,14 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1549
1962
  });
1550
1963
  const amountSnapshot = this.store.order.getOrderAmountSnapshot();
1551
1964
  const syncState = this.store.order.getOrderSyncState();
1552
- if (amountSnapshot && syncState !== "submitting") {
1553
- const paymentStatus = Number(amountSnapshot.amountGap || 0) <= 0 ? "paid" : "partially_paid";
1965
+ if (amountSnapshot) {
1966
+ if (syncState === "submitting") {
1967
+ this.queueLatestAutoPaymentSync();
1968
+ return payments;
1969
+ }
1554
1970
  void this.syncPaymentsToOrder({
1555
1971
  payments,
1556
- paymentStatus,
1972
+ paymentStatus: this.getPaymentStatusForSync(payments),
1557
1973
  submitWhenPaid: true,
1558
1974
  smallTicketDataFlag: 1
1559
1975
  }).catch((error) => {
@@ -1561,7 +1977,6 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1561
1977
  error: error instanceof Error ? error.message : String(error)
1562
1978
  });
1563
1979
  });
1564
- } else {
1565
1980
  }
1566
1981
  return payments;
1567
1982
  }
@@ -1578,21 +1993,33 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1578
1993
  return this.store.order.deleteOrderPayment(paymentIdentity);
1579
1994
  }
1580
1995
  /** 覆盖 wallet pass 支付项,同时保留普通支付项。 */
1581
- updateVoucherOrderPayments(payments) {
1996
+ updateVoucherOrderPayments(payments, options) {
1997
+ if (!this.store.order)
1998
+ throw new Error("order 模块未初始化");
1999
+ return this.store.order.updateVoucherOrderPayments(payments, options);
2000
+ }
2001
+ confirmPendingVoucherPayments() {
1582
2002
  if (!this.store.order)
1583
2003
  throw new Error("order 模块未初始化");
1584
- return this.store.order.updateVoucherOrderPayments(payments);
2004
+ return this.store.order.confirmPendingVoucherPayments();
2005
+ }
2006
+ discardPendingVoucherPayments() {
2007
+ if (!this.store.order)
2008
+ throw new Error("order 模块未初始化");
2009
+ return this.store.order.discardPendingVoucherPayments();
1585
2010
  }
1586
2011
  getWalletProductList() {
1587
- var _a, _b, _c;
2012
+ var _a, _b;
1588
2013
  const tempOrder = (_a = this.store.order) == null ? void 0 : _a.getTempOrder();
1589
2014
  if (!((_b = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _b.length))
1590
2015
  return [];
1591
- const products = (_c = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _c.filter((n) => n.product_id);
1592
- const walletProducts = products.map((product) => {
2016
+ const walletProducts = tempOrder == null ? void 0 : tempOrder.products.map((product) => {
1593
2017
  const metadata = product.metadata || {};
2018
+ const rawHolderId = product.holder_id ?? metadata.holder_id;
2019
+ const holderIdValue = Array.isArray(rawHolderId) ? rawHolderId[0] : rawHolderId;
2020
+ const holder_id = Number.isInteger(Number(holderIdValue)) ? Number(holderIdValue) : void 0;
1594
2021
  return {
1595
- product_id: product.product_id,
2022
+ product_id: product.product_id || 0,
1596
2023
  product_variant_id: String(product.product_variant_id ?? ""),
1597
2024
  quantity: product.num || 1,
1598
2025
  is_price_include_tax: tempOrder.is_price_include_tax,
@@ -1600,7 +2027,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1600
2027
  tax_fee: product.tax_fee,
1601
2028
  selling_price: Number(product.selling_price || 0),
1602
2029
  discount_list: product.discount_list || [],
1603
- holder_id: product.holder_id ?? metadata.holder_id,
2030
+ holder_id,
1604
2031
  original_price: product.original_price,
1605
2032
  main_product_original_price: metadata.main_product_original_price ?? product.original_price,
1606
2033
  main_product_selling_price: metadata.main_product_selling_price ?? product.selling_price,