@pisell/pisellos 2.2.278 → 2.2.280

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 (188) hide show
  1. package/dist/modules/BaseModule.d.ts +1 -0
  2. package/dist/modules/BaseModule.js +24 -28
  3. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +7 -3
  4. package/dist/modules/BookingContext/utils/productExtend.js +5 -9
  5. package/dist/modules/BookingContext/utils/timeSlices.js +24 -3
  6. package/dist/modules/Customer/index.d.ts +4 -0
  7. package/dist/modules/Customer/index.js +91 -59
  8. package/dist/modules/Customer/types.d.ts +2 -0
  9. package/dist/modules/Discount/index.d.ts +1 -0
  10. package/dist/modules/Discount/index.js +40 -11
  11. package/dist/modules/Discount/types.d.ts +1 -0
  12. package/dist/modules/Holder/index.d.ts +48 -0
  13. package/dist/modules/Holder/index.js +640 -0
  14. package/dist/modules/Holder/types.d.ts +123 -0
  15. package/dist/modules/Holder/types.js +1 -0
  16. package/dist/modules/Holder/utils.d.ts +13 -0
  17. package/dist/modules/Holder/utils.js +34 -0
  18. package/dist/modules/OpenData/index.js +2 -2
  19. package/dist/modules/Order/index.d.ts +32 -4
  20. package/dist/modules/Order/index.js +868 -675
  21. package/dist/modules/Order/types.d.ts +22 -1
  22. package/dist/modules/Order/utils/discountProductLineIdentity.d.ts +45 -0
  23. package/dist/modules/Order/utils/discountProductLineIdentity.js +227 -0
  24. package/dist/modules/Order/utils/orderCollectionIdentity.d.ts +15 -0
  25. package/dist/modules/Order/utils/orderCollectionIdentity.js +75 -0
  26. package/dist/modules/Order/utils.d.ts +10 -0
  27. package/dist/modules/Order/utils.js +71 -34
  28. package/dist/modules/Payment/index.d.ts +4 -0
  29. package/dist/modules/Payment/index.js +14 -4
  30. package/dist/modules/Payment/walletpass.js +21 -7
  31. package/dist/modules/Product/types.d.ts +1 -0
  32. package/dist/modules/ProductList/index.js +33 -13
  33. package/dist/modules/Quotation/index.d.ts +1 -1
  34. package/dist/modules/Quotation/index.js +2 -2
  35. package/dist/modules/ResourcePlanner/index.d.ts +24 -0
  36. package/dist/modules/ResourcePlanner/index.js +181 -0
  37. package/dist/modules/ResourcePlanner/planner.d.ts +14 -0
  38. package/dist/modules/ResourcePlanner/planner.js +1069 -0
  39. package/dist/modules/ResourcePlanner/types.d.ts +227 -0
  40. package/dist/modules/ResourcePlanner/types.js +1 -0
  41. package/dist/modules/Rules/index.js +153 -56
  42. package/dist/modules/SalesSummary/index.js +12 -13
  43. package/dist/modules/ScanOrderLogger/index.d.ts +2 -0
  44. package/dist/modules/ScanOrderLogger/index.js +15 -2
  45. package/dist/modules/ScanOrderLogger/providers/feishu.js +45 -27
  46. package/dist/modules/ScanOrderLogger/types.d.ts +1 -0
  47. package/dist/modules/Schedule/index.d.ts +3 -1
  48. package/dist/modules/Schedule/index.js +21 -16
  49. package/dist/modules/Summary/utils.js +38 -13
  50. package/dist/modules/index.d.ts +2 -0
  51. package/dist/modules/index.js +3 -1
  52. package/dist/plugins/window.d.ts +1 -0
  53. package/dist/server/index.d.ts +20 -0
  54. package/dist/server/index.js +1101 -909
  55. package/dist/server/modules/order/index.d.ts +2 -0
  56. package/dist/server/modules/order/index.js +261 -96
  57. package/dist/server/modules/order/types.d.ts +1 -1
  58. package/dist/solution/BaseSales/index.d.ts +20 -1
  59. package/dist/solution/BaseSales/index.js +989 -881
  60. package/dist/solution/BaseSales/utils/cartPromotion.js +19 -1
  61. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +6 -3
  62. package/dist/solution/BaseSales/utils.js +31 -20
  63. package/dist/solution/BookingByStep/index.d.ts +17 -2
  64. package/dist/solution/BookingByStep/index.js +294 -215
  65. package/dist/solution/BookingByStep/types.d.ts +2 -1
  66. package/dist/solution/BookingByStep/types.js +3 -1
  67. package/dist/solution/BookingByStep/utils/capacity.js +17 -1
  68. package/dist/solution/BookingByStep/utils/timeslots.d.ts +3 -1
  69. package/dist/solution/BookingByStep/utils/timeslots.js +19 -12
  70. package/dist/solution/BookingTicket/index.d.ts +21 -3
  71. package/dist/solution/BookingTicket/index.js +312 -226
  72. package/dist/solution/BookingTicket/utils/scan/handleScan.d.ts +3 -1
  73. package/dist/solution/BookingTicket/utils/scan/handleScan.js +10 -2
  74. package/dist/solution/ScanOrder/index.d.ts +26 -14
  75. package/dist/solution/ScanOrder/index.js +1142 -739
  76. package/dist/solution/ScanOrder/types.d.ts +21 -1
  77. package/dist/solution/ScanOrder/utils.d.ts +8 -0
  78. package/dist/solution/ScanOrder/utils.js +97 -45
  79. package/dist/solution/ShopDiscount/index.d.ts +1 -0
  80. package/dist/solution/ShopDiscount/index.js +125 -87
  81. package/dist/solution/UnifiedBookingSales/index.d.ts +204 -0
  82. package/dist/solution/UnifiedBookingSales/index.js +2211 -0
  83. package/dist/solution/UnifiedBookingSales/types.d.ts +150 -0
  84. package/dist/solution/UnifiedBookingSales/types.js +11 -0
  85. package/dist/solution/VenueBooking/index.d.ts +39 -11
  86. package/dist/solution/VenueBooking/index.js +1167 -841
  87. package/dist/solution/VenueBooking/types.d.ts +3 -0
  88. package/dist/solution/VenueBooking/utils/resource.js +1 -0
  89. package/dist/solution/VenueBooking/utils/slotMerge.d.ts +4 -4
  90. package/dist/solution/VenueBooking/utils/slotMerge.js +10 -5
  91. package/dist/solution/index.d.ts +1 -0
  92. package/dist/solution/index.js +2 -1
  93. package/dist/types/index.d.ts +1 -0
  94. package/lib/model/strategy/adapter/promotion/index.js +0 -51
  95. package/lib/modules/BaseModule.d.ts +1 -0
  96. package/lib/modules/BaseModule.js +24 -37
  97. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +3 -0
  98. package/lib/modules/BookingContext/utils/productExtend.js +4 -3
  99. package/lib/modules/BookingContext/utils/timeSlices.js +18 -3
  100. package/lib/modules/Customer/index.d.ts +4 -0
  101. package/lib/modules/Customer/index.js +11 -0
  102. package/lib/modules/Customer/types.d.ts +2 -0
  103. package/lib/modules/Discount/index.d.ts +1 -0
  104. package/lib/modules/Discount/index.js +9 -0
  105. package/lib/modules/Discount/types.d.ts +1 -0
  106. package/lib/modules/Holder/index.d.ts +48 -0
  107. package/lib/modules/Holder/index.js +402 -0
  108. package/lib/modules/Holder/types.d.ts +123 -0
  109. package/lib/modules/Holder/types.js +17 -0
  110. package/lib/modules/Holder/utils.d.ts +13 -0
  111. package/lib/modules/Holder/utils.js +71 -0
  112. package/lib/modules/OpenData/index.js +1 -1
  113. package/lib/modules/Order/index.d.ts +32 -4
  114. package/lib/modules/Order/index.js +372 -156
  115. package/lib/modules/Order/types.d.ts +22 -1
  116. package/lib/modules/Order/utils/discountProductLineIdentity.d.ts +45 -0
  117. package/lib/modules/Order/utils/discountProductLineIdentity.js +170 -0
  118. package/lib/modules/Order/utils/orderCollectionIdentity.d.ts +15 -0
  119. package/lib/modules/Order/utils/orderCollectionIdentity.js +70 -0
  120. package/lib/modules/Order/utils.d.ts +10 -0
  121. package/lib/modules/Order/utils.js +39 -6
  122. package/lib/modules/Payment/index.d.ts +4 -0
  123. package/lib/modules/Payment/index.js +7 -0
  124. package/lib/modules/Payment/walletpass.js +12 -0
  125. package/lib/modules/Product/types.d.ts +1 -0
  126. package/lib/modules/ProductList/index.js +49 -31
  127. package/lib/modules/Quotation/index.d.ts +1 -1
  128. package/lib/modules/Quotation/index.js +2 -2
  129. package/lib/modules/ResourcePlanner/index.d.ts +24 -0
  130. package/lib/modules/ResourcePlanner/index.js +148 -0
  131. package/lib/modules/ResourcePlanner/planner.d.ts +14 -0
  132. package/lib/modules/ResourcePlanner/planner.js +933 -0
  133. package/lib/modules/ResourcePlanner/types.d.ts +227 -0
  134. package/lib/modules/ResourcePlanner/types.js +17 -0
  135. package/lib/modules/Rules/index.js +117 -25
  136. package/lib/modules/SalesSummary/index.js +6 -7
  137. package/lib/modules/ScanOrderLogger/index.d.ts +2 -0
  138. package/lib/modules/ScanOrderLogger/index.js +13 -1
  139. package/lib/modules/ScanOrderLogger/providers/feishu.js +15 -6
  140. package/lib/modules/ScanOrderLogger/types.d.ts +1 -0
  141. package/lib/modules/Schedule/index.d.ts +3 -1
  142. package/lib/modules/Schedule/index.js +10 -8
  143. package/lib/modules/Summary/utils.js +21 -1
  144. package/lib/modules/index.d.ts +2 -0
  145. package/lib/modules/index.js +5 -1
  146. package/lib/plugins/window.d.ts +1 -0
  147. package/lib/server/index.d.ts +20 -0
  148. package/lib/server/index.js +124 -19
  149. package/lib/server/modules/order/index.d.ts +2 -0
  150. package/lib/server/modules/order/index.js +75 -5
  151. package/lib/server/modules/order/types.d.ts +1 -1
  152. package/lib/solution/BaseSales/index.d.ts +20 -1
  153. package/lib/solution/BaseSales/index.js +105 -31
  154. package/lib/solution/BaseSales/utils/cartPromotion.js +18 -0
  155. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +1 -0
  156. package/lib/solution/BaseSales/utils.js +29 -18
  157. package/lib/solution/BookingByStep/index.d.ts +17 -2
  158. package/lib/solution/BookingByStep/index.js +60 -18
  159. package/lib/solution/BookingByStep/types.d.ts +2 -1
  160. package/lib/solution/BookingByStep/types.js +5 -0
  161. package/lib/solution/BookingByStep/utils/capacity.js +20 -1
  162. package/lib/solution/BookingByStep/utils/timeslots.d.ts +3 -1
  163. package/lib/solution/BookingByStep/utils/timeslots.js +19 -11
  164. package/lib/solution/BookingTicket/index.d.ts +21 -3
  165. package/lib/solution/BookingTicket/index.js +75 -16
  166. package/lib/solution/BookingTicket/utils/scan/handleScan.d.ts +3 -1
  167. package/lib/solution/BookingTicket/utils/scan/handleScan.js +2 -2
  168. package/lib/solution/ScanOrder/index.d.ts +26 -14
  169. package/lib/solution/ScanOrder/index.js +449 -182
  170. package/lib/solution/ScanOrder/types.d.ts +21 -1
  171. package/lib/solution/ScanOrder/utils.d.ts +8 -0
  172. package/lib/solution/ScanOrder/utils.js +60 -18
  173. package/lib/solution/ShopDiscount/index.d.ts +1 -0
  174. package/lib/solution/ShopDiscount/index.js +14 -0
  175. package/lib/solution/UnifiedBookingSales/index.d.ts +204 -0
  176. package/lib/solution/UnifiedBookingSales/index.js +1273 -0
  177. package/lib/solution/UnifiedBookingSales/types.d.ts +150 -0
  178. package/lib/solution/UnifiedBookingSales/types.js +33 -0
  179. package/lib/solution/VenueBooking/index.d.ts +39 -11
  180. package/lib/solution/VenueBooking/index.js +322 -110
  181. package/lib/solution/VenueBooking/types.d.ts +3 -0
  182. package/lib/solution/VenueBooking/utils/resource.js +1 -0
  183. package/lib/solution/VenueBooking/utils/slotMerge.d.ts +4 -4
  184. package/lib/solution/VenueBooking/utils/slotMerge.js +6 -4
  185. package/lib/solution/index.d.ts +1 -0
  186. package/lib/solution/index.js +3 -1
  187. package/lib/types/index.d.ts +1 -0
  188. package/package.json +1 -1
@@ -44,6 +44,7 @@ var import_utils3 = require("../../solution/ScanOrder/utils");
44
44
  var import_manualProductDiscount = require("./utils/manualProductDiscount");
45
45
  var import_bundleDiscountHydration = require("./utils/bundleDiscountHydration");
46
46
  var import_orderCollectionIdentity = require("./utils/orderCollectionIdentity");
47
+ var import_discountProductLineIdentity = require("./utils/discountProductLineIdentity");
47
48
  var import_Discount = require("../Discount");
48
49
  var import_Rules = require("../Rules");
49
50
  var import_types2 = require("../Rules/types");
@@ -65,8 +66,7 @@ function isSameDiscountList(left, right) {
65
66
  );
66
67
  }
67
68
  function isManualProductDiscountProduct(product) {
68
- var _a, _b;
69
- 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");
69
+ return (0, import_manualProductDiscount.hasManualProductDiscountFlag)(product == null ? void 0 : product.metadata) || ((product == null ? void 0 : product.discount_list) || []).some((item) => (item == null ? void 0 : item.type) === "product");
70
70
  }
71
71
  var ORDER_PAYMENT_STATUS_PAID = "paid";
72
72
  var ORDER_PAYMENT_STATUS_PENDING = "payment_pending";
@@ -113,6 +113,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
113
113
  super(name || "order", version);
114
114
  this.defaultName = "order";
115
115
  this.defaultVersion = "1.0.0";
116
+ this.openCache = false;
117
+ this.sessionStoragePersistEnabled = false;
118
+ this.sessionStorageRestoreRecord = null;
116
119
  // ─── 促销/赠品 ────────────────────────────────────
117
120
  /** 评估器引用;由 SalesSdkProvider 注入,未注入时 applyPromotion 静默跳过 */
118
121
  this.promotionEvaluator = null;
@@ -329,11 +332,32 @@ var OrderModule = class extends import_BaseModule.BaseModule {
329
332
  return product;
330
333
  });
331
334
  }
335
+ syncSessionStorageOptions(otherParams) {
336
+ this.cacheId = otherParams.cacheId;
337
+ this.fatherModule = otherParams.fatherModule;
338
+ this.openCache = Boolean(
339
+ this.cacheId && otherParams.openCache !== false
340
+ );
341
+ this.sessionStoragePersistEnabled = Boolean(
342
+ this.openCache && otherParams.enableSessionStoragePersist === true
343
+ );
344
+ }
332
345
  async initialize(core, options) {
333
- var _a, _b, _c;
346
+ var _a, _b, _c, _d;
334
347
  this.core = core;
335
348
  this.store = options.store;
336
- if (!this.store.tempOrder) {
349
+ const otherParams = options.otherParams || {};
350
+ this.syncSessionStorageOptions(otherParams);
351
+ if (this.sessionStoragePersistEnabled) {
352
+ const cachedTempOrder = this.store.tempOrder;
353
+ this.sessionStorageRestoreRecord = (0, import_utils.isTempOrder)(cachedTempOrder) ? (0, import_lodash_es.cloneDeep)(cachedTempOrder) : null;
354
+ this.store.tempOrder = null;
355
+ this.store.summary = (0, import_utils.createEmptySummary)();
356
+ this.store.availableWalletIds = [];
357
+ this.store.lastOrderInfo = void 0;
358
+ this.store.syncState = void 0;
359
+ this.store.discountList = [];
360
+ } else if (!this.store.tempOrder) {
337
361
  this.store.tempOrder = null;
338
362
  }
339
363
  if (!this.store.summary) {
@@ -343,25 +367,24 @@ var OrderModule = class extends import_BaseModule.BaseModule {
343
367
  this.store.availableWalletIds = [];
344
368
  }
345
369
  this.request = this.core.getPlugin("request");
346
- this.appPlugin = this.core.getPlugin("app");
347
- if (!this.appPlugin) {
348
- throw new Error("Order 模块需要 app 插件支持");
370
+ const appPlugin = this.core.getPlugin("app");
371
+ if (!appPlugin) {
372
+ console.error("Order 模块需要 app 插件支持");
349
373
  }
350
- const app = this.appPlugin.getApp();
351
- this.logger = app.logger;
374
+ const app = (_a = appPlugin == null ? void 0 : appPlugin.getApp) == null ? void 0 : _a.call(appPlugin);
375
+ this.logger = app == null ? void 0 : app.logger;
352
376
  this.window = this.core.getPlugin("window");
353
- const otherParams = options.otherParams || {};
354
- this.cacheId = otherParams.cacheId;
355
377
  this.salesSummaryModuleName = otherParams.salesSummaryModuleName;
356
- this.rulesHooksOverride = (_a = otherParams.rules) == null ? void 0 : _a.hooks;
378
+ this.rulesHooksOverride = (_b = otherParams.rules) == null ? void 0 : _b.hooks;
357
379
  this.moduleHooksOverride = options.hooks;
358
- this.orderHooks = this.moduleHooksOverride || ((_b = otherParams.order) == null ? void 0 : _b.hooks) || ((_c = otherParams.hooks) == null ? void 0 : _c.order);
380
+ this.orderHooks = this.moduleHooksOverride || ((_c = otherParams.order) == null ? void 0 : _c.hooks) || ((_d = otherParams.hooks) == null ? void 0 : _d.order);
359
381
  this.otherParams = otherParams;
360
382
  this.registerDiscountModules(options);
361
383
  this.logInfo("OrderModule initialized successfully");
362
384
  }
363
385
  async destroy() {
364
386
  var _a, _b;
387
+ this.sessionStorageRestoreRecord = null;
365
388
  const childModules = [(_a = this.store) == null ? void 0 : _a.discount, (_b = this.store) == null ? void 0 : _b.rules];
366
389
  for (const childModule of childModules) {
367
390
  if (!childModule || typeof childModule.destroy !== "function")
@@ -391,7 +414,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
391
414
  updateOtherParams(params) {
392
415
  var _a, _b, _c;
393
416
  const otherParams = params || {};
394
- this.cacheId = otherParams.cacheId;
417
+ this.syncSessionStorageOptions(otherParams);
395
418
  this.salesSummaryModuleName = otherParams.salesSummaryModuleName;
396
419
  this.rulesHooksOverride = (_a = otherParams.rules) == null ? void 0 : _a.hooks;
397
420
  this.orderHooks = this.moduleHooksOverride || ((_b = otherParams.order) == null ? void 0 : _b.hooks) || ((_c = otherParams.hooks) == null ? void 0 : _c.order);
@@ -436,14 +459,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
436
459
  // ─── Discount: 子模块注册 ───
437
460
  registerDiscountModules(options) {
438
461
  let targetCacheData = {};
439
- if (this.cacheId && this.window) {
440
- const sessionData = this.window.sessionStorage.getItem(this.name);
441
- if (sessionData) {
442
- try {
462
+ if (!this.sessionStoragePersistEnabled && this.openCache && this.cacheId && this.window) {
463
+ try {
464
+ const sessionData = this.window.sessionStorage.getItem(this.name);
465
+ if (sessionData) {
443
466
  const data = JSON.parse(sessionData);
444
467
  targetCacheData = (data == null ? void 0 : data[this.cacheId]) || {};
445
- } catch {
446
468
  }
469
+ } catch {
447
470
  }
448
471
  }
449
472
  const discount = new import_Discount.DiscountModule(`${this.name}_discount`);
@@ -451,7 +474,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
451
474
  initialState: targetCacheData == null ? void 0 : targetCacheData[discount.name],
452
475
  otherParams: {
453
476
  fatherModule: this.name,
454
- openCache: !!this.cacheId,
477
+ // Unified 的单快照由 Order 管理;其他 Solution 保持原有 Discount 缓存语义。
478
+ openCache: this.openCache && !this.sessionStoragePersistEnabled,
455
479
  cacheId: this.cacheId
456
480
  }
457
481
  });
@@ -672,6 +696,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
672
696
  };
673
697
  })
674
698
  );
699
+ (0, import_discountProductLineIdentity.ensureUniqueProductLineUids)(tempOrder);
700
+ (0, import_discountProductLineIdentity.consolidateDiscountFreeProductLines)(tempOrder);
675
701
  }
676
702
  if (result == null ? void 0 : result.discountList) {
677
703
  OrderModule.populateSavedAmounts(
@@ -867,7 +893,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
867
893
  }
868
894
  /**
869
895
  * 控制 IndexedDB 草稿(saveDraft)是否写入。
870
- * localStorage tempOrder 持久化已废弃,此方法仅影响 saveDraft。
896
+ * 此开关仅影响 saveDraft;可选 sessionStorage 会话恢复由
897
+ * enableSessionStoragePersist 独立控制。
871
898
  *
872
899
  * @example
873
900
  * order.setEnableTempOrderPersist(false); // BigSale 弹窗:跳过 ~1s 的 dbUpdate
@@ -879,8 +906,80 @@ var OrderModule = class extends import_BaseModule.BaseModule {
879
906
  isTempOrderPersistEnabled() {
880
907
  return this.draftPersistEnabled;
881
908
  }
882
- /** @deprecated OrderModule 不再负责 tempOrder localStorage 持久化;草稿保存请使用 IndexedDB saveDraft。 */
909
+ /**
910
+ * 在 UnifiedBookingSales 显式开启会话恢复时,将完整 tempOrder 写入
911
+ * sessionStorage 的 cacheId 分桶。写入失败由 BaseModule 静默降级。
912
+ */
883
913
  persistTempOrder() {
914
+ if (!this.sessionStoragePersistEnabled || !this.store.tempOrder)
915
+ return;
916
+ this.checkSaveCache({
917
+ cacheId: this.cacheId,
918
+ fatherModule: this.fatherModule,
919
+ store: { tempOrder: this.store.tempOrder },
920
+ cacheKey: ["tempOrder"]
921
+ });
922
+ }
923
+ /**
924
+ * 终止当前模块实例的 sessionStorage 订单恢复会话。
925
+ *
926
+ * 支付跳转等终态场景需要同时删除当前 cacheId 的 tempOrder 快照,并关闭
927
+ * 本实例后续异步任务的再次写入;新模块实例初始化时会按 otherParams 重新启用。
928
+ */
929
+ clearSessionStoragePersistedTempOrder() {
930
+ var _a;
931
+ this.sessionStorageRestoreRecord = null;
932
+ if (!this.sessionStoragePersistEnabled)
933
+ return;
934
+ this.sessionStoragePersistEnabled = false;
935
+ if (!this.cacheId || !this.fatherModule || !((_a = this.window) == null ? void 0 : _a.sessionStorage)) {
936
+ return;
937
+ }
938
+ const sessionStorage = this.window.sessionStorage;
939
+ const rawCacheData = sessionStorage.getItem(this.fatherModule);
940
+ if (!rawCacheData)
941
+ return;
942
+ let parsedCacheData;
943
+ try {
944
+ parsedCacheData = JSON.parse(rawCacheData);
945
+ } catch {
946
+ return;
947
+ }
948
+ if (!parsedCacheData || typeof parsedCacheData !== "object" || Array.isArray(parsedCacheData)) {
949
+ return;
950
+ }
951
+ const cacheRoot = parsedCacheData;
952
+ const cacheBucket = cacheRoot[this.cacheId];
953
+ if (!cacheBucket || typeof cacheBucket !== "object" || Array.isArray(cacheBucket)) {
954
+ return;
955
+ }
956
+ const moduleBucket = cacheBucket[this.name];
957
+ if (!moduleBucket || typeof moduleBucket !== "object" || Array.isArray(moduleBucket)) {
958
+ return;
959
+ }
960
+ delete moduleBucket.tempOrder;
961
+ if (Object.keys(moduleBucket).length === 0) {
962
+ delete cacheBucket[this.name];
963
+ }
964
+ if (Object.keys(cacheBucket).length === 0) {
965
+ delete cacheRoot[this.cacheId];
966
+ }
967
+ sessionStorage.setItem(this.fatherModule, JSON.stringify(cacheRoot));
968
+ }
969
+ consumeSessionStorageRestore() {
970
+ const record = this.sessionStorageRestoreRecord;
971
+ this.sessionStorageRestoreRecord = null;
972
+ return record ? (0, import_lodash_es.cloneDeep)(record) : null;
973
+ }
974
+ notifyTempOrderChanged() {
975
+ if (!this.store.tempOrder)
976
+ return;
977
+ this.store.tempOrder = {
978
+ ...this.store.tempOrder,
979
+ products: [...this.store.tempOrder.products],
980
+ bookings: this.store.tempOrder.bookings ? [...this.store.tempOrder.bookings] : []
981
+ };
982
+ this.persistTempOrder();
884
983
  }
885
984
  // ─── TempOrder: 创建 & 获取 ───
886
985
  createDefaultTempOrderInstance() {
@@ -1071,7 +1170,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1071
1170
  paidAmount: netPaidAmount
1072
1171
  });
1073
1172
  const isOrderFullyPaid = orderExpectedAmount.lte(0) ? true : netPaidAmount.gte(orderExpectedAmount);
1074
- const paymentStage = this.isDepositOrder(tempOrder, depositAmount) && !isDepositFullyPaid ? "deposit" : "normal";
1173
+ const paymentStage = this.isDepositOrder(tempOrder, depositAmount) && !isDepositFullyPaid && !this.hasPaidNormalPayment(paymentList) ? "deposit" : "normal";
1075
1174
  return {
1076
1175
  isFullyPaid: isOrderFullyPaid,
1077
1176
  isOrderFullyPaid,
@@ -1092,12 +1191,22 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1092
1191
  return sum.plus(this.calculatePaymentGapAmount(paymentRecord));
1093
1192
  }, new import_decimal.default(0));
1094
1193
  }
1194
+ hasPaidNormalPayment(payments) {
1195
+ return (payments || []).some((payment) => {
1196
+ const paymentRecord = payment;
1197
+ if (!isPaidPaymentRecord(paymentRecord))
1198
+ return false;
1199
+ return paymentRecord.order_payment_type !== "deposit" && paymentRecord.type !== "deposit";
1200
+ });
1201
+ }
1095
1202
  resolveNextOrderPaymentType(tempOrder) {
1096
1203
  const depositAmount = new import_decimal.default(tempOrder.deposit_amount || "0.00");
1097
1204
  if (!this.isDepositOrder(tempOrder, depositAmount))
1098
1205
  return "normal";
1099
1206
  if (depositAmount.lte(0))
1100
1207
  return "normal";
1208
+ if (this.hasPaidNormalPayment(tempOrder.payments || []))
1209
+ return "normal";
1101
1210
  const depositPaidAmount = this.calculateDepositPaidAmount(tempOrder.payments || []);
1102
1211
  return depositPaidAmount.lt(depositAmount) ? "deposit" : "normal";
1103
1212
  }
@@ -1395,24 +1504,28 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1395
1504
  }
1396
1505
  }
1397
1506
  calculateSummaryAmountGap(params) {
1398
- const { tempOrder, summary, orderPaidAmount } = params;
1507
+ const { tempOrder, summary, orderPaidAmount, payments } = params;
1399
1508
  const refundAmount = this.getSummaryRefundAmount(summary);
1400
1509
  const netOrderPaidAmount = import_decimal.default.max(orderPaidAmount.minus(refundAmount), 0);
1401
1510
  const targetAmount = this.calculatePaymentTargetAmount(
1402
1511
  tempOrder,
1403
1512
  summary,
1404
- netOrderPaidAmount
1513
+ netOrderPaidAmount,
1514
+ payments
1405
1515
  );
1406
1516
  return targetAmount.minus(netOrderPaidAmount).toFixed(2);
1407
1517
  }
1408
1518
  getSummaryRefundAmount(summary) {
1409
1519
  return import_decimal.default.max(new import_decimal.default((summary == null ? void 0 : summary.total_refund_amount) || 0), 0);
1410
1520
  }
1411
- calculatePaymentTargetAmount(tempOrder, summary, paidAmount = new import_decimal.default(0)) {
1521
+ calculatePaymentTargetAmount(tempOrder, summary, paidAmount = new import_decimal.default(0), payments = tempOrder.payments || []) {
1412
1522
  const depositAmount = this.getDepositAmount(tempOrder, summary);
1413
1523
  if (!this.isDepositOrder(tempOrder, depositAmount)) {
1414
1524
  return this.getOrderExpectedAmount(summary);
1415
1525
  }
1526
+ if (this.hasPaidNormalPayment(payments)) {
1527
+ return this.getOrderExpectedAmount(summary);
1528
+ }
1416
1529
  if (this.isDepositCovered({ tempOrder, summary, paidAmount })) {
1417
1530
  return this.getOrderExpectedAmount(summary);
1418
1531
  }
@@ -1592,19 +1705,21 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1592
1705
  return snapshot;
1593
1706
  }
1594
1707
  isSnapshotPayableAmountUnchanged(tempOrder, snapshot, snapshotSummary) {
1595
- const currentPaidPaymentSummary = this.calculatePaidPaymentSummary(tempOrder.payments || []);
1708
+ const currentPayments = tempOrder.payments || [];
1709
+ const currentPaidPaymentSummary = this.calculatePaidPaymentSummary(currentPayments);
1596
1710
  const currentAmountGap = this.calculateSummaryAmountGap({
1597
1711
  tempOrder,
1598
1712
  summary: snapshotSummary,
1599
- orderPaidAmount: currentPaidPaymentSummary.gapPaidAmount
1713
+ orderPaidAmount: currentPaidPaymentSummary.gapPaidAmount,
1714
+ payments: currentPayments
1600
1715
  });
1601
- const snapshotPaidPaymentSummary = this.calculatePaidPaymentSummary(
1602
- Array.isArray(snapshot.payments) ? snapshot.payments : []
1603
- );
1716
+ const snapshotPayments = Array.isArray(snapshot.payments) ? snapshot.payments : [];
1717
+ const snapshotPaidPaymentSummary = this.calculatePaidPaymentSummary(snapshotPayments);
1604
1718
  const snapshotAmountGap = this.calculateSummaryAmountGap({
1605
1719
  tempOrder,
1606
1720
  summary: snapshotSummary,
1607
- orderPaidAmount: snapshotPaidPaymentSummary.gapPaidAmount
1721
+ orderPaidAmount: snapshotPaidPaymentSummary.gapPaidAmount,
1722
+ payments: snapshotPayments
1608
1723
  });
1609
1724
  return currentAmountGap === snapshotAmountGap;
1610
1725
  }
@@ -1646,6 +1761,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1646
1761
  const isPayableAmountUnchanged = this.isSnapshotPayableAmountUnchanged(tempOrder, snapshot, summary);
1647
1762
  if (!isPayableAmountUnchanged)
1648
1763
  return null;
1764
+ const currentPaidPaymentSummary = this.calculatePaidPaymentSummary(tempOrder.payments || []);
1765
+ summary.amount_gap = this.calculateSummaryAmountGap({
1766
+ tempOrder,
1767
+ summary,
1768
+ orderPaidAmount: currentPaidPaymentSummary.gapPaidAmount
1769
+ });
1649
1770
  if (Array.isArray(snapshot.products)) {
1650
1771
  tempOrder.products = (0, import_lodash_es.cloneDeep)(snapshot.products);
1651
1772
  }
@@ -1725,6 +1846,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1725
1846
  restoreOrder() {
1726
1847
  var _a, _b;
1727
1848
  this.logInfo("restoreOrder start", {});
1849
+ this.sessionStorageRestoreRecord = null;
1728
1850
  const freshTempOrder = this.createDefaultTempOrderInstance();
1729
1851
  this.ensureExternalSaleNumber(freshTempOrder);
1730
1852
  this.store.tempOrder = freshTempOrder;
@@ -1743,6 +1865,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1743
1865
  if (!(0, import_utils.isTempOrder)(tempOrder)) {
1744
1866
  throw new Error("无效的 tempOrder 数据");
1745
1867
  }
1868
+ this.sessionStorageRestoreRecord = null;
1746
1869
  const nextTempOrder = this.normalizeTempOrderForRuntime(
1747
1870
  (0, import_lodash_es.cloneDeep)(tempOrder),
1748
1871
  { ensureIdentity: false }
@@ -1870,6 +1993,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1870
1993
  tempOrder.products = (tempOrder.products || []).map(
1871
1994
  (product) => this.sanitizeOrderProductForTempOrder(product)
1872
1995
  );
1996
+ (0, import_discountProductLineIdentity.ensureUniqueProductLineUids)(tempOrder);
1873
1997
  }
1874
1998
  ensureExtend(tempOrder) {
1875
1999
  if (!tempOrder._extend || typeof tempOrder._extend !== "object") {
@@ -1880,6 +2004,23 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1880
2004
  }
1881
2005
  return tempOrder._extend;
1882
2006
  }
2007
+ repairDuplicateProductLineIdentities(tempOrder) {
2008
+ var _a;
2009
+ const result = (0, import_orderCollectionIdentity.repairDuplicateProductLineIdentities)(
2010
+ tempOrder.products,
2011
+ (_a = tempOrder._extend) == null ? void 0 : _a.productsByUid
2012
+ );
2013
+ if (!result.repairs.length)
2014
+ return;
2015
+ tempOrder.products = result.products;
2016
+ if (result.productsByUid) {
2017
+ this.ensureExtend(tempOrder).productsByUid = result.productsByUid;
2018
+ }
2019
+ this.logWarning("Repaired duplicate product line identities", {
2020
+ repairCount: result.repairs.length,
2021
+ repairs: result.repairs
2022
+ });
2023
+ }
1883
2024
  captureProductRuntime(tempOrder, rawProduct, normalizedProduct, existedUid) {
1884
2025
  var _a;
1885
2026
  const uid = existedUid || this.getProductUid(normalizedProduct);
@@ -2525,6 +2666,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2525
2666
  delete tempOrder._extend.customerSnapshot;
2526
2667
  this.store.availableWalletIds = [];
2527
2668
  this.clearCustomerBoundDiscounts(tempOrder);
2669
+ this.applyDiscount();
2528
2670
  this.persistTempOrder();
2529
2671
  this.saveDraftInBackground();
2530
2672
  this.core.effects.emit(import_types.OrderHooks.OnOrderCustomerChange, null);
@@ -2830,21 +2972,29 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2830
2972
  devicePrefix
2831
2973
  });
2832
2974
  }
2833
- async shouldMergeProductToOrder(params) {
2975
+ normalizeShouldMergeProductResult(result) {
2976
+ if (typeof result === "boolean")
2977
+ return result;
2978
+ if (result && typeof result === "object" && typeof result.shouldMerge === "boolean") {
2979
+ return result.shouldMerge;
2980
+ }
2981
+ return true;
2982
+ }
2983
+ shouldMergeProductToOrder(params) {
2834
2984
  var _a;
2835
2985
  const onBeforeMergeProductToOrder = (_a = this.orderHooks) == null ? void 0 : _a.onBeforeMergeProductToOrder;
2836
2986
  if (!onBeforeMergeProductToOrder)
2837
2987
  return true;
2838
- const result = await onBeforeMergeProductToOrder({
2988
+ const result = onBeforeMergeProductToOrder({
2839
2989
  ...params,
2840
2990
  defaultShouldMerge: true
2841
2991
  });
2842
- if (typeof result === "boolean")
2843
- return result;
2844
- if (result && typeof result === "object" && typeof result.shouldMerge === "boolean") {
2845
- return result.shouldMerge;
2992
+ if (result && typeof result === "object" && typeof result.then === "function") {
2993
+ return Promise.resolve(result).then(
2994
+ (resolved) => this.normalizeShouldMergeProductResult(resolved)
2995
+ );
2846
2996
  }
2847
- return true;
2997
+ return this.normalizeShouldMergeProductResult(result);
2848
2998
  }
2849
2999
  hasOrderProductLineNote(product) {
2850
3000
  return typeof (product == null ? void 0 : product.note) === "string" && product.note.trim().length > 0;
@@ -2887,10 +3037,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2887
3037
  * 带 booking 且 num>1 时由 `addProductToOrder` 拆成多次本方法调用(每次 num=1)。
2888
3038
  *
2889
3039
  * @example
2890
- * await this.appendProductLineToTempOrder(tempOrder, { product_id: 1, num: 1 }, booking);
3040
+ * const pending = this.appendProductLineToTempOrder(
3041
+ * tempOrder,
3042
+ * { product_id: 1, num: 1 },
3043
+ * booking,
3044
+ * );
3045
+ * if (pending) await pending;
2891
3046
  */
2892
- async appendProductLineToTempOrder(tempOrder, product, booking, options) {
2893
- var _a, _b, _c, _d, _e, _f, _g;
3047
+ appendProductLineToTempOrder(tempOrder, product, booking, options) {
3048
+ var _a, _b, _c, _d, _e, _f;
2894
3049
  const linked = booking ? this.createLinkedProductAndBooking({ product, booking }) : null;
2895
3050
  const productToAdd = (linked == null ? void 0 : linked.product) || product;
2896
3051
  const incomingFingerprint = (0, import_utils3.buildProductLineFingerprint)(
@@ -2921,15 +3076,18 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2921
3076
  normalizedIncoming
2922
3077
  );
2923
3078
  const hasIncomingProductNote = this.hasOrderProductLineNote(normalizedIncoming);
3079
+ const hasIncomingManualProductDiscount = isManualProductDiscountProduct(normalizedIncoming);
2924
3080
  const hasIncomingBookingUid = this.hasLinkedBookingUid(productToAdd) || this.hasLinkedBookingUid(normalizedIncoming);
2925
3081
  const isIncomingCustomItem = ((_e = (_d = productToAdd.metadata) == null ? void 0 : _d.origin) == null ? void 0 : _e.isCustomItem) === true || ((_f = productToAdd._origin) == null ? void 0 : _f.isCustomItem) === true;
2926
- const shouldForceNewLine = !!booking || hasIncomingProductNote || hasIncomingBookingUid || isIncomingCustomItem || isWeighingProduct;
3082
+ const shouldForceNewLine = !!booking || hasIncomingProductNote || hasIncomingManualProductDiscount || hasIncomingBookingUid || isIncomingCustomItem || isWeighingProduct;
2927
3083
  const matchedIndex = hasIncomingGoodPass || shouldForceNewLine ? -1 : tempOrder.products.findIndex((item) => {
2928
3084
  var _a2;
2929
3085
  if (this.hasGoodPassDiscount(item))
2930
3086
  return false;
2931
3087
  if (this.hasOrderProductLineNote(item))
2932
3088
  return false;
3089
+ if (isManualProductDiscountProduct(item))
3090
+ return false;
2933
3091
  if (item.order_detail_id !== void 0 && item.order_detail_id !== null)
2934
3092
  return false;
2935
3093
  if ((_a2 = item.metadata) == null ? void 0 : _a2.is_edit_for_runtime)
@@ -2949,7 +3107,90 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2949
3107
  (0, import_utils.getProductSkuOptions)(matchedProduct),
2950
3108
  matchedProduct.product_bundle
2951
3109
  ) : "";
2952
- const shouldMerge = matchedProduct ? await this.shouldMergeProductToOrder({
3110
+ const commitProductLine = (shouldMerge2) => {
3111
+ var _a2;
3112
+ if (matchedIndex === -1 || !matchedProduct || !shouldMerge2) {
3113
+ this.captureProductRuntime(
3114
+ tempOrder,
3115
+ productToAdd,
3116
+ normalizedIncoming
3117
+ );
3118
+ if (linked) {
3119
+ normalizedIncoming.booking_uid = linked.bookingUid;
3120
+ normalizedIncoming.metadata = {
3121
+ ...normalizedIncoming.metadata || {},
3122
+ booking_uid: linked.bookingUid
3123
+ };
3124
+ }
3125
+ const insertAtIndex = options == null ? void 0 : options.insertAtIndex;
3126
+ if (Number.isInteger(insertAtIndex) && Number(insertAtIndex) >= 0 && Number(insertAtIndex) < tempOrder.products.length) {
3127
+ tempOrder.products = [
3128
+ ...tempOrder.products.slice(0, insertAtIndex),
3129
+ normalizedIncoming,
3130
+ ...tempOrder.products.slice(insertAtIndex)
3131
+ ];
3132
+ } else {
3133
+ tempOrder.products = [...tempOrder.products, normalizedIncoming];
3134
+ }
3135
+ } else {
3136
+ const targetProduct = matchedProduct;
3137
+ const targetUid = (_a2 = targetProduct.metadata) == null ? void 0 : _a2.unique_identification_number;
3138
+ const normalizedProduct = (0, import_utils.mergeOrderProductDisplayFields)(
3139
+ targetProduct,
3140
+ (0, import_utils3.normalizeOrderProduct)({
3141
+ ...productToAdd,
3142
+ metadata: {
3143
+ ...productToAdd.metadata || {},
3144
+ unique_identification_number: targetUid
3145
+ }
3146
+ })
3147
+ );
3148
+ normalizedProduct.discount_list = (0, import_utils.normalizeOrderProductDiscountList)(
3149
+ normalizedProduct.discount_list
3150
+ );
3151
+ const nextNum = (0, import_utils3.getSafeProductNum)(targetProduct.num + normalizedProduct.num);
3152
+ tempOrder.products[matchedIndex] = {
3153
+ ...targetProduct,
3154
+ ...normalizedProduct,
3155
+ discount_list: normalizedProduct.discount_list,
3156
+ metadata: {
3157
+ ...targetProduct.metadata || {},
3158
+ ...normalizedProduct.metadata || {},
3159
+ unique_identification_number: targetUid
3160
+ },
3161
+ product_sku: {
3162
+ ...targetProduct.product_sku || { option: [] },
3163
+ ...normalizedProduct.product_sku || { option: [] },
3164
+ option: (0, import_utils.getProductSkuOptions)(normalizedProduct)
3165
+ },
3166
+ note: targetProduct.note,
3167
+ order_detail_id: targetProduct.order_detail_id,
3168
+ num: nextNum
3169
+ };
3170
+ this.captureProductRuntime(
3171
+ tempOrder,
3172
+ productToAdd,
3173
+ tempOrder.products[matchedIndex],
3174
+ targetUid
3175
+ );
3176
+ if (matchedIndex !== tempOrder.products.length - 1) {
3177
+ const mergedProduct = tempOrder.products[matchedIndex];
3178
+ tempOrder.products = [
3179
+ ...tempOrder.products.slice(0, matchedIndex),
3180
+ ...tempOrder.products.slice(matchedIndex + 1),
3181
+ mergedProduct
3182
+ ];
3183
+ }
3184
+ }
3185
+ if (linked) {
3186
+ tempOrder.bookings = [...tempOrder.bookings || [], linked.booking];
3187
+ }
3188
+ };
3189
+ if (!matchedProduct) {
3190
+ commitProductLine(false);
3191
+ return;
3192
+ }
3193
+ const shouldMerge = this.shouldMergeProductToOrder({
2953
3194
  incomingProduct: productToAdd,
2954
3195
  normalizedIncoming,
2955
3196
  matchedProduct,
@@ -2958,100 +3199,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2958
3199
  existedFingerprint,
2959
3200
  tempOrder,
2960
3201
  booking
2961
- }) : false;
2962
- if (matchedIndex === -1 || !matchedProduct || !shouldMerge) {
2963
- this.captureProductRuntime(
2964
- tempOrder,
2965
- productToAdd,
2966
- normalizedIncoming
2967
- );
2968
- if (linked) {
2969
- normalizedIncoming.booking_uid = linked.bookingUid;
2970
- normalizedIncoming.metadata = {
2971
- ...normalizedIncoming.metadata || {},
2972
- booking_uid: linked.bookingUid
2973
- };
2974
- }
2975
- const insertAtIndex = options == null ? void 0 : options.insertAtIndex;
2976
- if (Number.isInteger(insertAtIndex) && Number(insertAtIndex) >= 0 && Number(insertAtIndex) < tempOrder.products.length) {
2977
- tempOrder.products = [
2978
- ...tempOrder.products.slice(0, insertAtIndex),
2979
- normalizedIncoming,
2980
- ...tempOrder.products.slice(insertAtIndex)
2981
- ];
2982
- } else {
2983
- tempOrder.products = [...tempOrder.products, normalizedIncoming];
2984
- }
2985
- } else {
2986
- const targetProduct = matchedProduct;
2987
- const targetUid = (_g = targetProduct.metadata) == null ? void 0 : _g.unique_identification_number;
2988
- const normalizedProduct = (0, import_utils.mergeOrderProductDisplayFields)(
2989
- targetProduct,
2990
- (0, import_utils3.normalizeOrderProduct)({
2991
- ...productToAdd,
2992
- metadata: {
2993
- ...productToAdd.metadata || {},
2994
- unique_identification_number: targetUid
2995
- }
2996
- })
2997
- );
2998
- normalizedProduct.discount_list = (0, import_utils.normalizeOrderProductDiscountList)(
2999
- normalizedProduct.discount_list
3000
- );
3001
- const nextNum = (0, import_utils3.getSafeProductNum)(targetProduct.num + normalizedProduct.num);
3002
- const targetIsManualProductDiscount = isManualProductDiscountProduct(targetProduct);
3003
- const nextDiscountList = targetIsManualProductDiscount ? (0, import_utils.normalizeOrderProductDiscountList)(
3004
- (0, import_manualProductDiscount.syncManualProductDiscountProductNum)(
3005
- targetProduct.discount_list,
3006
- nextNum
3007
- )
3008
- ) : normalizedProduct.discount_list;
3009
- tempOrder.products[matchedIndex] = {
3010
- ...targetProduct,
3011
- ...normalizedProduct,
3012
- discount_list: nextDiscountList,
3013
- metadata: {
3014
- ...targetProduct.metadata || {},
3015
- ...normalizedProduct.metadata || {},
3016
- unique_identification_number: targetUid
3017
- },
3018
- product_sku: {
3019
- ...targetProduct.product_sku || { option: [] },
3020
- ...normalizedProduct.product_sku || { option: [] },
3021
- option: (0, import_utils.getProductSkuOptions)(normalizedProduct)
3022
- },
3023
- ...targetIsManualProductDiscount ? {
3024
- selling_price: targetProduct.selling_price,
3025
- original_price: targetProduct.original_price,
3026
- payment_price: targetProduct.payment_price,
3027
- metadata: {
3028
- ...normalizedProduct.metadata || {},
3029
- ...targetProduct.metadata || {},
3030
- unique_identification_number: targetUid
3031
- }
3032
- } : {},
3033
- note: targetProduct.note,
3034
- order_detail_id: targetProduct.order_detail_id,
3035
- num: nextNum
3036
- };
3037
- this.captureProductRuntime(
3038
- tempOrder,
3039
- productToAdd,
3040
- tempOrder.products[matchedIndex],
3041
- targetUid
3042
- );
3043
- if (matchedIndex !== tempOrder.products.length - 1) {
3044
- const mergedProduct = tempOrder.products[matchedIndex];
3045
- tempOrder.products = [
3046
- ...tempOrder.products.slice(0, matchedIndex),
3047
- ...tempOrder.products.slice(matchedIndex + 1),
3048
- mergedProduct
3049
- ];
3050
- }
3051
- }
3052
- if (linked) {
3053
- tempOrder.bookings = [...tempOrder.bookings || [], linked.booking];
3202
+ });
3203
+ if (shouldMerge && typeof shouldMerge === "object" && typeof shouldMerge.then === "function") {
3204
+ return Promise.resolve(shouldMerge).then(commitProductLine);
3054
3205
  }
3206
+ commitProductLine(shouldMerge);
3055
3207
  }
3056
3208
  /**
3057
3209
  * 添加商品行。带 booking 时强制独立行;num>1 时拆成多条 num=1 的 product+booking(对齐 BookingByStep / ticketBooking addService)。
@@ -3079,12 +3231,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3079
3231
  const singleLine = (0, import_lodash_es.cloneDeep)(productRecord);
3080
3232
  singleLine.num = 1;
3081
3233
  delete singleLine.product_quantity;
3082
- await this.appendProductLineToTempOrder(
3234
+ const appendResult2 = this.appendProductLineToTempOrder(
3083
3235
  tempOrder,
3084
3236
  singleLine,
3085
3237
  (0, import_lodash_es.cloneDeep)(booking),
3086
3238
  { insertAtIndex }
3087
3239
  );
3240
+ if (appendResult2)
3241
+ await appendResult2;
3088
3242
  if (insertAtIndex !== void 0)
3089
3243
  insertAtIndex += 1;
3090
3244
  }
@@ -3092,12 +3246,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3092
3246
  return tempOrder.products;
3093
3247
  }
3094
3248
  }
3095
- await this.appendProductLineToTempOrder(
3249
+ const appendResult = this.appendProductLineToTempOrder(
3096
3250
  tempOrder,
3097
3251
  product,
3098
3252
  booking,
3099
3253
  { insertAtIndex }
3100
3254
  );
3255
+ if (appendResult)
3256
+ await appendResult;
3101
3257
  await this.finalizeProductOrderMutation(tempOrder);
3102
3258
  this.logInfo("addProductToOrder success", {
3103
3259
  product_id: product.product_id,
@@ -3132,16 +3288,24 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3132
3288
  const singleLine = (0, import_lodash_es.cloneDeep)(productRecord);
3133
3289
  singleLine.num = 1;
3134
3290
  delete singleLine.product_quantity;
3135
- await this.appendProductLineToTempOrder(
3291
+ const appendResult2 = this.appendProductLineToTempOrder(
3136
3292
  tempOrder,
3137
3293
  singleLine,
3138
3294
  (0, import_lodash_es.cloneDeep)(booking)
3139
3295
  );
3296
+ if (appendResult2)
3297
+ await appendResult2;
3140
3298
  }
3141
3299
  continue;
3142
3300
  }
3143
3301
  }
3144
- await this.appendProductLineToTempOrder(tempOrder, product, booking);
3302
+ const appendResult = this.appendProductLineToTempOrder(
3303
+ tempOrder,
3304
+ product,
3305
+ booking
3306
+ );
3307
+ if (appendResult)
3308
+ await appendResult;
3145
3309
  }
3146
3310
  await this.finalizeProductOrderMutation(tempOrder, options);
3147
3311
  this.logInfo("addProductsToOrder success", {
@@ -3471,6 +3635,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3471
3635
  product_bundle
3472
3636
  } = params;
3473
3637
  const tempOrder = this.ensureTempOrder();
3638
+ this.repairDuplicateProductLineIdentities(tempOrder);
3474
3639
  const identityLookup = {
3475
3640
  product_id,
3476
3641
  product_variant_id
@@ -3581,6 +3746,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3581
3746
  async removeProductsFromOrder(identities, options) {
3582
3747
  var _a, _b, _c, _d;
3583
3748
  const tempOrder = this.ensureTempOrder();
3749
+ this.repairDuplicateProductLineIdentities(tempOrder);
3584
3750
  if (!identities.length) {
3585
3751
  return tempOrder.products;
3586
3752
  }
@@ -3988,7 +4154,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3988
4154
  tempOrder,
3989
4155
  effectivePayments
3990
4156
  );
3991
- const submitResult = await this.submitTempOrder({
4157
+ const submitParams = {
3992
4158
  payments: effectivePayments,
3993
4159
  paymentStatus,
3994
4160
  smallTicketDataFlag: params.smallTicketDataFlag,
@@ -4002,7 +4168,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4002
4168
  };
4003
4169
  return nextPayload;
4004
4170
  }
4005
- });
4171
+ };
4172
+ const submitResult = params.checkoutSyncTaskEnabled === false ? await this.submitTempOrderAsync(submitParams) : await this.submitTempOrder(submitParams);
4006
4173
  return { ...completion, submitResult };
4007
4174
  }
4008
4175
  createOrder(params) {
@@ -4019,11 +4186,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4019
4186
  is_deposit: 0,
4020
4187
  relation_products: [],
4021
4188
  relation_forms: [],
4189
+ business_code: params == null ? void 0 : params.business_code,
4022
4190
  ...(params == null ? void 0 : params.extraData) || {}
4023
4191
  };
4024
4192
  let is_deposit = 0;
4025
4193
  if (params.cartItems.length > 0) {
4026
4194
  params.cartItems.forEach((item) => {
4195
+ var _a2;
4027
4196
  if (!item._origin.duration) {
4028
4197
  const { duration, durationType } = (0, import_utils.generateDuration)(item);
4029
4198
  item._origin.duration = duration;
@@ -4032,6 +4201,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4032
4201
  item._origin.sub_type = (0, import_utils.normalizeBookingSubType)(item._origin);
4033
4202
  const discountList = (0, import_utils.getAllDiscountList)(item);
4034
4203
  item._origin.product.discount_list = discountList;
4204
+ if ((_a2 = params == null ? void 0 : params.extraData) == null ? void 0 : _a2.is_add_holder_info) {
4205
+ (0, import_utils.ensureCartItemOriginHolder)(item, this.window);
4206
+ }
4035
4207
  if ((0, import_utils2.isNormalProduct)(item._origin)) {
4036
4208
  order.relation_products.push(item._origin.product);
4037
4209
  const relationForms = item._origin.relation_forms || [];
@@ -4311,24 +4483,39 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4311
4483
  * 例如数组字段、商品行唯一值、价格 metadata、summary 派生状态和 _extend。
4312
4484
  */
4313
4485
  async hydrateTempOrderFromRecord(record, options) {
4314
- var _a, _b, _c;
4486
+ var _a, _b, _c, _d, _e, _f;
4315
4487
  const sourceRaw = record && typeof record === "object" && record.data && record.order_id == null ? record.data : record || {};
4488
+ const duplicateProductIdentityRepair = (0, import_orderCollectionIdentity.repairDuplicateProductLineIdentities)(
4489
+ Array.isArray(sourceRaw.products) ? sourceRaw.products : [],
4490
+ (_a = sourceRaw._extend) == null ? void 0 : _a.productsByUid
4491
+ );
4492
+ const duplicateIdentityReadySource = duplicateProductIdentityRepair.repairs.length ? {
4493
+ ...sourceRaw,
4494
+ products: duplicateProductIdentityRepair.products,
4495
+ ...duplicateProductIdentityRepair.productsByUid ? {
4496
+ _extend: {
4497
+ ...sourceRaw._extend || {},
4498
+ productsByUid: duplicateProductIdentityRepair.productsByUid
4499
+ }
4500
+ } : {}
4501
+ } : sourceRaw;
4316
4502
  const identityReadySource = this.seedAnonymousBookingUidsFromProducts(
4317
- sourceRaw
4503
+ duplicateIdentityReadySource
4318
4504
  );
4319
4505
  const normalizedCollections = (0, import_orderCollectionIdentity.normalizeOrderCollections)(identityReadySource);
4320
4506
  const raw = normalizedCollections.order;
4321
- const hasIdentityChanges = Object.values(normalizedCollections.stats).some(
4507
+ const hasIdentityChanges = duplicateProductIdentityRepair.repairs.length > 0 || Object.values(normalizedCollections.stats).some(
4322
4508
  (stats) => stats.backfilledUidCount > 0 || stats.collapsedDuplicateCount > 0 || stats.uidConflictCount > 0 || stats.anonymousRowCount > 0
4323
4509
  );
4324
4510
  if (hasIdentityChanges) {
4325
4511
  const identityLogMetadata = {
4326
4512
  collections: normalizedCollections.stats,
4327
- uidRemapCount: normalizedCollections.uidRemaps.length
4513
+ uidRemapCount: normalizedCollections.uidRemaps.length,
4514
+ duplicateProductUidRepairCount: duplicateProductIdentityRepair.repairs.length
4328
4515
  };
4329
4516
  const hasIdentityWarnings = Object.values(normalizedCollections.stats).some(
4330
4517
  (stats) => stats.uidConflictCount > 0 || stats.anonymousRowCount > 0
4331
- );
4518
+ ) || duplicateProductIdentityRepair.repairs.length > 0;
4332
4519
  if (hasIdentityWarnings) {
4333
4520
  this.logWarning(
4334
4521
  "Normalized hydrated order collection identities",
@@ -4341,8 +4528,37 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4341
4528
  );
4342
4529
  }
4343
4530
  }
4344
- const nextTempOrder = this.normalizeTempOrderForRuntime(raw, { makeEditMark: true });
4345
- const sourceLastOrderInfo = raw.lastOrderInfo || raw;
4531
+ const isSessionStorageHydrate = (options == null ? void 0 : options.source) === "sessionStorage";
4532
+ const nextTempOrder = this.normalizeTempOrderForRuntime(raw, {
4533
+ makeEditMark: !isSessionStorageHydrate
4534
+ });
4535
+ this.store.tempOrder = nextTempOrder;
4536
+ if (isSessionStorageHydrate) {
4537
+ const restoredSessionDiscounts = Array.isArray(raw.discount_list) ? (0, import_lodash_es.cloneDeep)(raw.discount_list) : [];
4538
+ const nextExtend = { ...nextTempOrder._extend || {} };
4539
+ delete nextExtend.originalSalesSnapshot;
4540
+ nextTempOrder._extend = nextExtend;
4541
+ nextTempOrder.products.forEach((product) => {
4542
+ if (product.metadata) {
4543
+ delete product.metadata.is_edit_for_runtime;
4544
+ }
4545
+ });
4546
+ nextTempOrder.discount_list = restoredSessionDiscounts;
4547
+ this.store.summary = (0, import_utils.createEmptySummary)();
4548
+ this.store.lastOrderInfo = void 0;
4549
+ await ((_b = this.store.discount) == null ? void 0 : _b.setOriginalDiscountList(
4550
+ (0, import_lodash_es.cloneDeep)(restoredSessionDiscounts)
4551
+ ));
4552
+ await ((_c = this.store.discount) == null ? void 0 : _c.setDiscountList(
4553
+ (0, import_lodash_es.cloneDeep)(restoredSessionDiscounts)
4554
+ ));
4555
+ if (options == null ? void 0 : options.recalcOnHydrate) {
4556
+ await this.recalculateSummary({ createIfMissing: false });
4557
+ }
4558
+ this.persistTempOrder();
4559
+ return nextTempOrder;
4560
+ }
4561
+ const sourceLastOrderInfo = sourceRaw.lastOrderInfo || sourceRaw;
4346
4562
  const isDraftOrder = Number(nextTempOrder.is_draft_order || 0) === 1;
4347
4563
  const syntheticIdentityOptions = {
4348
4564
  isDraftOrder,
@@ -4350,7 +4566,6 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4350
4566
  };
4351
4567
  const rawSummary = raw.summary && typeof raw.summary === "object" ? raw.summary : {};
4352
4568
  const summarySurcharges = Array.isArray(rawSummary.surcharges) ? rawSummary.surcharges.map((s) => ({ ...s || {} })) : (0, import_lodash_es.cloneDeep)(nextTempOrder.surcharges || []);
4353
- this.store.tempOrder = nextTempOrder;
4354
4569
  this.store.summary = {
4355
4570
  ...(0, import_utils.createEmptySummary)(),
4356
4571
  ...rawSummary,
@@ -4377,7 +4592,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4377
4592
  this.store.syncState = "local";
4378
4593
  }
4379
4594
  const hydratedEditDiscounts = this.collectHydratedEditDiscounts(nextTempOrder.products);
4380
- const currentDiscounts = typeof ((_a = this.store.discount) == null ? void 0 : _a.getDiscountList) === "function" ? this.store.discount.getDiscountList() || [] : [];
4595
+ const currentDiscounts = typeof ((_d = this.store.discount) == null ? void 0 : _d.getDiscountList) === "function" ? this.store.discount.getDiscountList() || [] : [];
4381
4596
  const currentScanDiscounts = currentDiscounts.filter((discount) => discount == null ? void 0 : discount.isScan);
4382
4597
  const hydratedDiscountIds = new Set(
4383
4598
  hydratedEditDiscounts.map((discount) => discount == null ? void 0 : discount.id)
@@ -4395,8 +4610,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4395
4610
  nextTempOrder.products,
4396
4611
  nextDiscounts
4397
4612
  );
4398
- await ((_b = this.store.discount) == null ? void 0 : _b.setOriginalDiscountList(nextDiscounts));
4399
- await ((_c = this.store.discount) == null ? void 0 : _c.setDiscountList(nextDiscounts));
4613
+ await ((_e = this.store.discount) == null ? void 0 : _e.setOriginalDiscountList(nextDiscounts));
4614
+ await ((_f = this.store.discount) == null ? void 0 : _f.setDiscountList(nextDiscounts));
4400
4615
  }
4401
4616
  if (options == null ? void 0 : options.recalcOnHydrate) {
4402
4617
  await this.recalculateSummary({ createIfMissing: false });
@@ -4689,8 +4904,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4689
4904
  delete row[`product_${"option"}_item`];
4690
4905
  if (!Array.isArray(row.product_bundle))
4691
4906
  row.product_bundle = [];
4692
- if (!row.metadata || typeof row.metadata !== "object")
4693
- row.metadata = {};
4907
+ row.metadata = row.metadata && typeof row.metadata === "object" ? { ...row.metadata } : {};
4908
+ delete row.bundle_edit;
4909
+ delete row.metadata.bundle_edit;
4694
4910
  if (row.booking_uid && !row.metadata.booking_uid) {
4695
4911
  row.metadata.booking_uid = row.booking_uid;
4696
4912
  }