@pisell/pisellos 2.3.28 → 2.3.29

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 (84) hide show
  1. package/dist/model/strategy/adapter/dataVariant/adapter.d.ts +50 -0
  2. package/dist/model/strategy/adapter/dataVariant/adapter.js +167 -0
  3. package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +89 -0
  4. package/dist/model/strategy/adapter/dataVariant/evaluator.js +780 -0
  5. package/dist/model/strategy/adapter/dataVariant/examples.d.ts +39 -0
  6. package/dist/model/strategy/adapter/dataVariant/examples.js +277 -0
  7. package/dist/model/strategy/adapter/dataVariant/index.d.ts +4 -0
  8. package/dist/model/strategy/adapter/dataVariant/index.js +4 -0
  9. package/dist/model/strategy/adapter/dataVariant/type.d.ts +148 -0
  10. package/dist/model/strategy/adapter/dataVariant/type.js +54 -0
  11. package/dist/model/strategy/adapter/index.d.ts +4 -0
  12. package/dist/model/strategy/adapter/index.js +5 -1
  13. package/dist/model/strategy/adapter/promotion/index.js +0 -9
  14. package/dist/modules/Discount/index.d.ts +5 -2
  15. package/dist/modules/Discount/index.js +30 -7
  16. package/dist/modules/Discount/types.d.ts +4 -0
  17. package/dist/modules/Order/index.d.ts +7 -1
  18. package/dist/modules/Order/index.js +187 -74
  19. package/dist/modules/Order/types.d.ts +2 -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 +2 -1
  23. package/dist/modules/Order/utils.js +2 -8
  24. package/dist/modules/Product/types.d.ts +22 -0
  25. package/dist/modules/ProductList/index.d.ts +1 -1
  26. package/dist/modules/ProductList/index.js +4 -2
  27. package/dist/modules/ProductList/types.d.ts +2 -0
  28. package/dist/server/index.d.ts +50 -0
  29. package/dist/server/index.js +995 -749
  30. package/dist/server/modules/order/index.d.ts +10 -4
  31. package/dist/server/modules/order/index.js +404 -399
  32. package/dist/server/modules/products/index.d.ts +26 -7
  33. package/dist/server/modules/products/index.js +167 -76
  34. package/dist/server/modules/products/types.d.ts +14 -0
  35. package/dist/solution/BaseSales/index.d.ts +9 -1
  36. package/dist/solution/BaseSales/index.js +998 -756
  37. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -3
  38. package/dist/solution/BaseSales/utils/parseSalesResponse.js +6 -8
  39. package/dist/solution/BookingByStep/index.d.ts +1 -1
  40. package/dist/solution/BookingTicket/index.d.ts +14 -2
  41. package/dist/solution/BookingTicket/types.d.ts +2 -0
  42. package/dist/solution/ShopDiscount/index.js +15 -14
  43. package/lib/model/strategy/adapter/dataVariant/adapter.d.ts +50 -0
  44. package/lib/model/strategy/adapter/dataVariant/adapter.js +149 -0
  45. package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +89 -0
  46. package/lib/model/strategy/adapter/dataVariant/evaluator.js +583 -0
  47. package/lib/model/strategy/adapter/dataVariant/examples.d.ts +39 -0
  48. package/lib/model/strategy/adapter/dataVariant/examples.js +293 -0
  49. package/lib/model/strategy/adapter/dataVariant/index.d.ts +4 -0
  50. package/lib/model/strategy/adapter/dataVariant/index.js +38 -0
  51. package/lib/model/strategy/adapter/dataVariant/type.d.ts +148 -0
  52. package/lib/model/strategy/adapter/dataVariant/type.js +31 -0
  53. package/lib/model/strategy/adapter/index.d.ts +4 -0
  54. package/lib/model/strategy/adapter/index.js +13 -2
  55. package/lib/modules/Discount/index.d.ts +5 -2
  56. package/lib/modules/Discount/index.js +23 -3
  57. package/lib/modules/Discount/types.d.ts +4 -0
  58. package/lib/modules/Order/index.d.ts +7 -1
  59. package/lib/modules/Order/index.js +104 -6
  60. package/lib/modules/Order/types.d.ts +2 -0
  61. package/lib/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
  62. package/lib/modules/Order/utils/orderCollectionIdentity.js +415 -0
  63. package/lib/modules/Order/utils.d.ts +2 -1
  64. package/lib/modules/Order/utils.js +4 -11
  65. package/lib/modules/Product/types.d.ts +22 -0
  66. package/lib/modules/ProductList/index.d.ts +1 -1
  67. package/lib/modules/ProductList/index.js +4 -2
  68. package/lib/modules/ProductList/types.d.ts +2 -0
  69. package/lib/server/index.d.ts +50 -0
  70. package/lib/server/index.js +206 -29
  71. package/lib/server/modules/order/index.d.ts +10 -4
  72. package/lib/server/modules/order/index.js +198 -139
  73. package/lib/server/modules/products/index.d.ts +26 -7
  74. package/lib/server/modules/products/index.js +114 -35
  75. package/lib/server/modules/products/types.d.ts +14 -0
  76. package/lib/solution/BaseSales/index.d.ts +9 -1
  77. package/lib/solution/BaseSales/index.js +229 -54
  78. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -3
  79. package/lib/solution/BaseSales/utils/parseSalesResponse.js +4 -5
  80. package/lib/solution/BookingByStep/index.d.ts +1 -1
  81. package/lib/solution/BookingTicket/index.d.ts +14 -2
  82. package/lib/solution/BookingTicket/types.d.ts +2 -0
  83. package/lib/solution/ShopDiscount/index.js +2 -1
  84. package/package.json +1 -1
@@ -40,6 +40,7 @@ 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");
@@ -76,11 +77,18 @@ function isBaseSalesHistoricalDiscountEntry(discount) {
76
77
  (discount == null ? void 0 : discount.isEditMode) || (discount == null ? void 0 : discount.isDisabled) || (discount == null ? void 0 : discount.order_discount_id) != null
77
78
  );
78
79
  }
79
- function getBaseSalesUniqueArrayMetadataKey(key) {
80
- if (key === "products" || key === "bookings")
81
- 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";
82
90
  if (key === "payments" || key === "payment")
83
- return "unique_payment_number";
91
+ return "payment";
84
92
  return null;
85
93
  }
86
94
  function isSameBaseSalesOrderRecord(left, right) {
@@ -95,13 +103,6 @@ function isSameBaseSalesOrderRecord(left, right) {
95
103
  (value) => value !== void 0 && value !== null && value !== "" && leftIdentities.has(String(value))
96
104
  );
97
105
  }
98
- function getBaseSalesMetadataUid(item, metadataKey) {
99
- var _a;
100
- const uid = ((_a = item == null ? void 0 : item.metadata) == null ? void 0 : _a[metadataKey]) ?? (item == null ? void 0 : item[metadataKey]);
101
- if (uid === void 0 || uid === null || uid === "")
102
- return null;
103
- return String(uid);
104
- }
105
106
  function isBaseSalesBlankValue(value) {
106
107
  return value === void 0 || value === null || value === "";
107
108
  }
@@ -120,40 +121,122 @@ function mergeBaseSalesProductSnapshotFields(currentItem, loadedItem) {
120
121
  }
121
122
  return mergedItem;
122
123
  }
123
- function mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey, arrayKey) {
124
- const result = [];
125
- const indexByUid = /* @__PURE__ */ new Map();
126
- const appendOrReplaceByUid = (item) => {
127
- const clonedItem = (0, import_lodash_es.cloneDeep)(item);
128
- const uid = getBaseSalesMetadataUid(clonedItem, metadataKey);
129
- if (!uid) {
130
- result.push(clonedItem);
131
- return;
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
+ });
132
143
  }
133
- const existingIndex = indexByUid.get(uid);
134
- if (existingIndex !== void 0) {
135
- result[existingIndex] = arrayKey === "products" ? mergeBaseSalesProductSnapshotFields(result[existingIndex], clonedItem) : 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
+ );
136
192
  return;
137
193
  }
138
- indexByUid.set(uid, result.length);
139
- result.push(clonedItem);
140
- };
141
- currentValue.forEach(appendOrReplaceByUid);
142
- loadedValue.forEach(appendOrReplaceByUid);
194
+ result.push((0, import_lodash_es.cloneDeep)(incomingItem));
195
+ });
143
196
  return result;
144
197
  }
145
- function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord) {
146
- if (!currentTempOrder)
147
- 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 = [];
148
225
  const mergedRecord = (0, import_lodash_es.mergeWith)(
149
- (0, import_lodash_es.cloneDeep)(currentTempOrder),
150
- (0, import_lodash_es.cloneDeep)(loadedRecord || {}),
226
+ normalizedCurrentTempOrder,
227
+ normalizedLoadedRecord,
151
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
+ }
152
239
  if (Array.isArray(currentValue) && Array.isArray(loadedValue)) {
153
- const metadataKey = getBaseSalesUniqueArrayMetadataKey(key);
154
- if (metadataKey) {
155
- return mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey, key);
156
- }
157
240
  return [
158
241
  ...(0, import_lodash_es.cloneDeep)(currentValue),
159
242
  ...(0, import_lodash_es.cloneDeep)(loadedValue)
@@ -168,7 +251,9 @@ function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord) {
168
251
  }
169
252
  );
170
253
  delete mergedRecord.request_unique_idempotency_token;
171
- return mergedRecord;
254
+ return normalizeBaseSalesRecordCollections(
255
+ (0, import_orderCollectionIdentity.applyOrderCollectionUidRemaps)(mergedRecord, uidRemaps)
256
+ );
172
257
  }
173
258
  var BaseSalesImpl = class extends import_BaseModule.BaseModule {
174
259
  constructor(name, version) {
@@ -190,9 +275,12 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
190
275
  this.queuedAutoPaymentSync = false;
191
276
  this.autoPaymentSyncFlushing = false;
192
277
  this.autoPaymentSyncTimer = null;
193
- this.salesDetailLoadInFlight = false;
278
+ this.salesDetailLoadInFlightCount = 0;
279
+ this.salesDetailLoadSequence = 0;
280
+ this.salesDetailHydrateQueue = Promise.resolve();
194
281
  this.serverOrderChangeUnsubscribe = null;
195
282
  this.serverOrderChangeHydrateInFlight = null;
283
+ this.queuedServerOrderChanges = [];
196
284
  this.serverOrderChangeSyncEnabled = false;
197
285
  }
198
286
  /**
@@ -269,22 +357,56 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
269
357
  }
270
358
  setServerOrderChangeSyncEnabled(enabled) {
271
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 });
272
380
  }
273
381
  async syncCurrentSalesDetailFromServerOrderChange(payload) {
274
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] : [];
275
- if (!this.serverOrderChangeSyncEnabled || this.salesDetailLoadInFlight || this.serverOrderChangeHydrateInFlight)
383
+ if (!this.serverOrderChangeSyncEnabled)
276
384
  return;
385
+ if (this.salesDetailLoadInFlightCount > 0) {
386
+ changedOrders.forEach(
387
+ (order) => this.queueLatestServerOrderChange(order)
388
+ );
389
+ return;
390
+ }
277
391
  const changedOrder = changedOrders.find(
278
392
  (order) => this.isCurrentSalesOrderRecord(order)
279
393
  );
280
394
  if (!changedOrder)
281
395
  return;
396
+ if (this.serverOrderChangeHydrateInFlight) {
397
+ this.queueLatestServerOrderChange(changedOrder);
398
+ return;
399
+ }
282
400
  if (!this.store.order)
283
401
  return;
284
402
  this.serverOrderChangeHydrateInFlight = (async () => {
285
403
  var _a, _b;
286
404
  const currentTempOrder = (_b = (_a = this.store.order).getTempOrder) == null ? void 0 : _b.call(_a);
287
- const record = mergeSalesDetailRecordWithTempOrder(currentTempOrder, changedOrder);
405
+ const record = mergeSalesDetailRecordWithTempOrder(
406
+ currentTempOrder,
407
+ changedOrder,
408
+ "authoritative-incoming"
409
+ );
288
410
  const sales = await this.store.order.hydrateTempOrderFromRecord(record, {
289
411
  recalcOnHydrate: false
290
412
  });
@@ -295,6 +417,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
295
417
  await this.serverOrderChangeHydrateInFlight;
296
418
  } finally {
297
419
  this.serverOrderChangeHydrateInFlight = null;
420
+ await this.drainQueuedServerOrderChanges();
298
421
  }
299
422
  }
300
423
  registerServerOrderChangeSync() {
@@ -304,13 +427,42 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
304
427
  if (!effects || typeof effects.on !== "function")
305
428
  return;
306
429
  this.serverOrderChangeUnsubscribe = effects.on(SERVER_ORDER_CHANGED_EVENT, (payload) => {
307
- void this.syncCurrentSalesDetailFromServerOrderChange(payload).catch((error) => {
430
+ return this.syncCurrentSalesDetailFromServerOrderChange(payload).catch((error) => {
308
431
  this.logError("sync sales detail from server order change failed", {
309
432
  error: error instanceof Error ? error.message : String(error)
310
433
  });
311
434
  });
312
435
  });
313
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
+ }
314
466
  hydrateOrderPaymentNames(payments) {
315
467
  if (!payments.length)
316
468
  return [];
@@ -745,6 +897,8 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
745
897
  }
746
898
  });
747
899
  this.currentSalesDetail = null;
900
+ this.queuedServerOrderChanges = [];
901
+ this.salesDetailLoadSequence += 1;
748
902
  await this.core.effects.emit(`${this.name}:onDestroy`, {});
749
903
  super.destroy();
750
904
  }
@@ -758,7 +912,8 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
758
912
  async loadSalesDetail(orderIdOrParams) {
759
913
  if (!this.store.order)
760
914
  throw new Error("order 模块未初始化");
761
- this.salesDetailLoadInFlight = true;
915
+ const loadSequence = ++this.salesDetailLoadSequence;
916
+ this.salesDetailLoadInFlightCount += 1;
762
917
  try {
763
918
  const params = typeof orderIdOrParams === "object" ? orderIdOrParams : { orderId: orderIdOrParams };
764
919
  const externalSaleNumber = params.externalSaleNumber || params.external_sale_number;
@@ -777,15 +932,26 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
777
932
  }
778
933
  const remoteRecord = preloadedSalesDetail ?? loadedRecord.data;
779
934
  const currentTempOrder = params.merge ? this.store.order.getTempOrder() : null;
780
- const record = params.merge ? mergeSalesDetailRecordWithTempOrder(currentTempOrder, remoteRecord) : remoteRecord;
781
- const sales = await this.store.order.hydrateTempOrderFromRecord(record, {
782
- recalcOnHydrate: false
783
- });
784
- this.currentSalesDetail = sales;
785
- await this.core.effects.emit(`${this.name}:onSalesOrderLoaded`, { sales });
786
- return sales;
935
+ const record = params.merge ? mergeSalesDetailRecordWithTempOrder(
936
+ currentTempOrder,
937
+ remoteRecord,
938
+ "preserve-local"
939
+ ) : remoteRecord;
940
+ return await this.hydrateLatestLoadedSalesDetail(record, loadSequence);
787
941
  } finally {
788
- this.salesDetailLoadInFlight = false;
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
+ }
789
955
  }
790
956
  }
791
957
  /** 获取当前已加载的销售详情(只读快照)。未加载过则返回 null。 */
@@ -1157,7 +1323,8 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1157
1323
  if (hasManualDiscountSelection && currentDiscountList.length) {
1158
1324
  return {
1159
1325
  productList: tempOrder.products || [],
1160
- discountList: currentDiscountList
1326
+ discountList: currentDiscountList,
1327
+ availableWalletIds: this.getAvailableWalletIds()
1161
1328
  };
1162
1329
  }
1163
1330
  let nextDiscountList = this.mergeHistoricalDiscountList(
@@ -1186,7 +1353,8 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1186
1353
  });
1187
1354
  return {
1188
1355
  productList: tempOrder.products || [],
1189
- discountList: nextDiscountList
1356
+ discountList: nextDiscountList,
1357
+ availableWalletIds: this.getAvailableWalletIds()
1190
1358
  };
1191
1359
  }
1192
1360
  if (rulesModule) {
@@ -1247,9 +1415,16 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1247
1415
  });
1248
1416
  return {
1249
1417
  productList: tempOrder.products || [],
1250
- discountList: nextDiscountList
1418
+ discountList: nextDiscountList,
1419
+ availableWalletIds: this.getAvailableWalletIds()
1251
1420
  };
1252
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
+ }
1253
1428
  async bestDiscount(cb) {
1254
1429
  var _a, _b, _c;
1255
1430
  if (!this.store.order)
@@ -2,7 +2,7 @@
2
2
  * 把 `/order/sales/{id}` 响应(OrderData)解析为 ISalesDetail。
3
3
  *
4
4
  * - 纯函数:不依赖任何运行时模块/插件,便于单测与 view-model 适配
5
- * - products 保留 tempOrder / 后端详情原字段,仅做浅拷贝,避免丢失 product_sku 等协议字段
5
+ * - products 保留 tempOrder / 后端详情原字段,仅规范化集合身份并浅拷贝,避免丢失 product_sku 等协议字段
6
6
  * - bookings 平铺保留服务端原顺序,同时输出 byProductUid 反查表与 rootBooking
7
7
  * - header 收敛"非数组顶层字段",便于 ticketBooking view-model 直接消费
8
8
  *
@@ -130,7 +130,7 @@ export interface ISalesDetail {
130
130
  customer: ISalesDetailCustomer | null;
131
131
  /** 服务端 summary(仅输出) */
132
132
  summary: Record<string, any>;
133
- /** 原始响应快照,方便 UI 兜底使用 */
133
+ /** 规范化后的响应快照,方便 UI 兜底使用 */
134
134
  raw: Record<string, any>;
135
135
  }
136
136
  /**
@@ -138,7 +138,7 @@ export interface ISalesDetail {
138
138
  *
139
139
  * 注意:
140
140
  * - 入参允许是 `{ data: OrderData }` 或直接 `OrderData`,自动识别。
141
- * - products 保留原字段;字段补齐由 OrderModule hydrate 负责。
141
+ * - products/bookings/payments 在此补齐集合身份;其余 runtime 字段由 OrderModule hydrate 负责。
142
142
  * - 不做远程请求;不修改入参;返回新对象。
143
143
  */
144
144
  export declare function parseSalesResponse(input: Record<string, any> | null | undefined): ISalesDetail;
@@ -22,6 +22,7 @@ __export(parseSalesResponse_exports, {
22
22
  parseSalesResponse: () => parseSalesResponse
23
23
  });
24
24
  module.exports = __toCommonJS(parseSalesResponse_exports);
25
+ var import_orderCollectionIdentity = require("../../../modules/Order/utils/orderCollectionIdentity");
25
26
  var HEADER_KEYS = [
26
27
  "order_id",
27
28
  "order_number",
@@ -121,14 +122,12 @@ function indexBookingsByProductUid(bookings) {
121
122
  return result;
122
123
  }
123
124
  function parseSalesResponse(input) {
124
- const raw = input && typeof input === "object" && input.data && input.order_id == null ? input.data : input || {};
125
+ const sourceRaw = input && typeof input === "object" && input.data && input.order_id == null ? input.data : input || {};
126
+ const raw = (0, import_orderCollectionIdentity.normalizeOrderCollections)(sourceRaw).order;
125
127
  const productsRaw = Array.isArray(raw == null ? void 0 : raw.products) ? raw.products : [];
126
- const products = productsRaw.map((p, index) => {
128
+ const products = productsRaw.map((p) => {
127
129
  const row = { ...p || {} };
128
130
  const metadata = row.metadata && typeof row.metadata === "object" ? { ...row.metadata } : {};
129
- if (!metadata.unique_identification_number) {
130
- metadata.unique_identification_number = `sales-product-${row.product_id ?? "unknown"}-${row.product_variant_id ?? 0}-${index}`;
131
- }
132
131
  delete metadata.price_schema_version;
133
132
  delete row.identity_key;
134
133
  return { ...row, metadata };
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
311
311
  date: string;
312
312
  status: string;
313
313
  week: string;
314
- weekNum: 0 | 2 | 1 | 6 | 3 | 4 | 5;
314
+ weekNum: 0 | 1 | 2 | 3 | 4 | 5 | 6;
315
315
  }[]>;
316
316
  submitTimeSlot(timeSlots: TimeSliceItem): void;
317
317
  private getScheduleDataByIds;
@@ -322,7 +322,7 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
322
322
  * 获取当前的客户搜索条件
323
323
  * @returns 当前搜索条件
324
324
  */
325
- getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "num" | "skip">;
325
+ getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "skip" | "num">;
326
326
  /**
327
327
  * 获取客户列表状态(包含滚动加载相关状态)
328
328
  * @returns 客户状态
@@ -441,7 +441,19 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
441
441
  * 加车两阶段主决策(规格弹窗 / 资源编辑 / 直接加车)。
442
442
  * 与 ticketBooking `handleSelectProduct` + `handleBooking4Service` 等价。
443
443
  */
444
- decideAddProduct(item: any, options?: Partial<AddProductDecideContext>): import("./utils/addProductDecision").AddProductDecision;
444
+ decideAddProduct(item: any, options?: Partial<AddProductDecideContext>): {
445
+ action: "reloadCatalog";
446
+ } | {
447
+ action: "add";
448
+ cacheItem: any;
449
+ } | {
450
+ action: "requiresDetail";
451
+ payload: AddProductRequiresDetailPayload;
452
+ } | {
453
+ action: "requiresBookingEdit";
454
+ cacheItem: any;
455
+ payload: import("./utils/addProductDecision").AddProductRequiresBookingEditPayload;
456
+ };
445
457
  /** 规格弹窗 callback 后的第二段决策。 */
446
458
  decideAfterDetail(cacheItem: any, options?: Partial<AddProductDecideContext>): import("./utils/addProductDecision").AddProductDecision;
447
459
  /**
@@ -83,6 +83,8 @@ export interface ILoadProductsParams {
83
83
  extension_type?: string[];
84
84
  /** 商品发布状态 */
85
85
  status?: string;
86
+ /** 智能定价条件上下文,仅影响策略命中,不参与商品集合筛选 */
87
+ strategy_context?: Record<string, any>;
86
88
  }
87
89
  /**
88
90
  * 加载商品详情的参数
@@ -505,7 +505,7 @@ var ShopDiscountImpl = class extends import_BaseModule.BaseModule {
505
505
  try {
506
506
  const orderId = this.store.orderId;
507
507
  const customerId = params.customerId || ((_a = this.getCustomer()) == null ? void 0 : _a.id);
508
- const goodPassList = await ((_b = this.store.discount) == null ? void 0 : _b.loadPrepareConfig({
508
+ const prepareConfigResult = await ((_b = this.store.discount) == null ? void 0 : _b.loadPrepareConfig({
509
509
  customer_id: customerId,
510
510
  action: orderId ? "edit" : "create",
511
511
  with_good_pass: 1,
@@ -514,6 +514,7 @@ var ShopDiscountImpl = class extends import_BaseModule.BaseModule {
514
514
  request_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
515
515
  ...orderId ? { order_id: orderId } : {}
516
516
  }));
517
+ const goodPassList = (prepareConfigResult == null ? void 0 : prepareConfigResult.discountList) || [];
517
518
  const scanDiscount = (_c = this.getDiscountList()) == null ? void 0 : _c.filter(
518
519
  (item) => item.isScan
519
520
  );
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "2.3.28",
4
+ "version": "2.3.29",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",