@pisell/pisellos 2.2.260 → 2.2.261

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 (129) hide show
  1. package/dist/model/strategy/adapter/index.d.ts +0 -4
  2. package/dist/model/strategy/adapter/index.js +1 -5
  3. package/dist/model/strategy/adapter/promotion/adapter.d.ts +4 -0
  4. package/dist/model/strategy/adapter/promotion/adapter.js +23 -0
  5. package/dist/model/strategy/adapter/promotion/evaluator.d.ts +17 -0
  6. package/dist/model/strategy/adapter/promotion/evaluator.js +279 -6
  7. package/dist/model/strategy/adapter/promotion/examples.d.ts +86 -0
  8. package/dist/model/strategy/adapter/promotion/examples.js +99 -0
  9. package/dist/model/strategy/adapter/promotion/index.d.ts +1 -1
  10. package/dist/model/strategy/adapter/promotion/index.js +1 -1
  11. package/dist/model/strategy/adapter/promotion/type.d.ts +90 -2
  12. package/dist/model/strategy/adapter/promotion/type.js +45 -0
  13. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +17 -13
  14. package/dist/modules/Order/index.d.ts +33 -2
  15. package/dist/modules/Order/index.js +615 -288
  16. package/dist/modules/Order/types.d.ts +20 -2
  17. package/dist/modules/Order/utils/bundleDiscountHydration.d.ts +5 -0
  18. package/dist/modules/Order/utils/bundleDiscountHydration.js +144 -0
  19. package/dist/modules/Order/utils.d.ts +4 -0
  20. package/dist/modules/Order/utils.js +116 -29
  21. package/dist/modules/Product/types.d.ts +0 -22
  22. package/dist/modules/ProductList/index.d.ts +1 -1
  23. package/dist/modules/ProductList/index.js +2 -4
  24. package/dist/modules/ProductList/types.d.ts +0 -2
  25. package/dist/modules/Rules/index.d.ts +4 -3
  26. package/dist/modules/Rules/index.js +42 -17
  27. package/dist/modules/Rules/types.d.ts +2 -1
  28. package/dist/modules/SalesSummary/index.d.ts +7 -3
  29. package/dist/modules/SalesSummary/index.js +67 -39
  30. package/dist/modules/SalesSummary/types.d.ts +1 -0
  31. package/dist/modules/SalesSummary/utils.js +2 -1
  32. package/dist/modules/SurchargeList/index.d.ts +6 -4
  33. package/dist/modules/SurchargeList/index.js +62 -39
  34. package/dist/modules/SurchargeList/types.d.ts +6 -2
  35. package/dist/server/index.d.ts +3 -50
  36. package/dist/server/index.js +1075 -1040
  37. package/dist/server/modules/order/index.d.ts +22 -3
  38. package/dist/server/modules/order/index.js +398 -316
  39. package/dist/server/modules/products/index.d.ts +7 -26
  40. package/dist/server/modules/products/index.js +76 -166
  41. package/dist/server/modules/products/types.d.ts +0 -14
  42. package/dist/solution/BaseSales/index.d.ts +22 -2
  43. package/dist/solution/BaseSales/index.js +995 -701
  44. package/dist/solution/BaseSales/types.d.ts +1 -0
  45. package/dist/solution/BaseSales/types.js +2 -1
  46. package/dist/solution/BaseSales/utils/cartPromotion.d.ts +3 -1
  47. package/dist/solution/BaseSales/utils/cartPromotion.js +74 -29
  48. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +6 -3
  49. package/dist/solution/BookingByStep/index.d.ts +1 -1
  50. package/dist/solution/BookingTicket/index.d.ts +9 -1
  51. package/dist/solution/BookingTicket/index.js +153 -6
  52. package/dist/solution/BookingTicket/types.d.ts +0 -2
  53. package/dist/solution/ScanOrder/index.js +31 -20
  54. package/dist/solution/VenueBooking/index.js +30 -19
  55. package/lib/model/strategy/adapter/index.d.ts +0 -4
  56. package/lib/model/strategy/adapter/index.js +2 -13
  57. package/lib/model/strategy/adapter/promotion/adapter.d.ts +4 -0
  58. package/lib/model/strategy/adapter/promotion/adapter.js +20 -0
  59. package/lib/model/strategy/adapter/promotion/evaluator.d.ts +17 -0
  60. package/lib/model/strategy/adapter/promotion/evaluator.js +235 -0
  61. package/lib/model/strategy/adapter/promotion/examples.d.ts +86 -0
  62. package/lib/model/strategy/adapter/promotion/examples.js +91 -0
  63. package/lib/model/strategy/adapter/promotion/index.d.ts +1 -1
  64. package/lib/model/strategy/adapter/promotion/index.js +2 -0
  65. package/lib/model/strategy/adapter/promotion/type.d.ts +90 -2
  66. package/lib/model/strategy/adapter/promotion/type.js +2 -0
  67. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +11 -1
  68. package/lib/modules/Order/index.d.ts +33 -2
  69. package/lib/modules/Order/index.js +402 -64
  70. package/lib/modules/Order/types.d.ts +20 -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.d.ts +4 -0
  74. package/lib/modules/Order/utils.js +90 -3
  75. package/lib/modules/Product/types.d.ts +0 -22
  76. package/lib/modules/ProductList/index.d.ts +1 -1
  77. package/lib/modules/ProductList/index.js +2 -4
  78. package/lib/modules/ProductList/types.d.ts +0 -2
  79. package/lib/modules/Rules/index.d.ts +4 -3
  80. package/lib/modules/Rules/index.js +27 -7
  81. package/lib/modules/Rules/types.d.ts +2 -1
  82. package/lib/modules/SalesSummary/index.d.ts +7 -3
  83. package/lib/modules/SalesSummary/index.js +28 -11
  84. package/lib/modules/SalesSummary/types.d.ts +1 -0
  85. package/lib/modules/SalesSummary/utils.js +2 -0
  86. package/lib/modules/SurchargeList/index.d.ts +6 -4
  87. package/lib/modules/SurchargeList/index.js +41 -21
  88. package/lib/modules/SurchargeList/types.d.ts +6 -2
  89. package/lib/server/index.d.ts +3 -50
  90. package/lib/server/index.js +244 -215
  91. package/lib/server/modules/order/index.d.ts +22 -3
  92. package/lib/server/modules/order/index.js +103 -53
  93. package/lib/server/modules/products/index.d.ts +7 -26
  94. package/lib/server/modules/products/index.js +35 -113
  95. package/lib/server/modules/products/types.d.ts +0 -14
  96. package/lib/solution/BaseSales/index.d.ts +22 -2
  97. package/lib/solution/BaseSales/index.js +246 -60
  98. package/lib/solution/BaseSales/types.d.ts +1 -0
  99. package/lib/solution/BaseSales/types.js +2 -1
  100. package/lib/solution/BaseSales/utils/cartPromotion.d.ts +3 -1
  101. package/lib/solution/BaseSales/utils/cartPromotion.js +59 -16
  102. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +6 -6
  103. package/lib/solution/BookingByStep/index.d.ts +1 -1
  104. package/lib/solution/BookingTicket/index.d.ts +9 -1
  105. package/lib/solution/BookingTicket/index.js +101 -0
  106. package/lib/solution/BookingTicket/types.d.ts +0 -2
  107. package/lib/solution/ScanOrder/index.js +8 -0
  108. package/lib/solution/VenueBooking/index.js +8 -0
  109. package/package.json +1 -1
  110. package/dist/model/strategy/adapter/dataVariant/adapter.d.ts +0 -49
  111. package/dist/model/strategy/adapter/dataVariant/adapter.js +0 -152
  112. package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +0 -87
  113. package/dist/model/strategy/adapter/dataVariant/evaluator.js +0 -755
  114. package/dist/model/strategy/adapter/dataVariant/examples.d.ts +0 -39
  115. package/dist/model/strategy/adapter/dataVariant/examples.js +0 -282
  116. package/dist/model/strategy/adapter/dataVariant/index.d.ts +0 -4
  117. package/dist/model/strategy/adapter/dataVariant/index.js +0 -4
  118. package/dist/model/strategy/adapter/dataVariant/type.d.ts +0 -146
  119. package/dist/model/strategy/adapter/dataVariant/type.js +0 -54
  120. package/lib/model/strategy/adapter/dataVariant/adapter.d.ts +0 -49
  121. package/lib/model/strategy/adapter/dataVariant/adapter.js +0 -139
  122. package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +0 -87
  123. package/lib/model/strategy/adapter/dataVariant/evaluator.js +0 -564
  124. package/lib/model/strategy/adapter/dataVariant/examples.d.ts +0 -39
  125. package/lib/model/strategy/adapter/dataVariant/examples.js +0 -295
  126. package/lib/model/strategy/adapter/dataVariant/index.d.ts +0 -4
  127. package/lib/model/strategy/adapter/dataVariant/index.js +0 -38
  128. package/lib/model/strategy/adapter/dataVariant/type.d.ts +0 -146
  129. package/lib/model/strategy/adapter/dataVariant/type.js +0 -31
@@ -48,6 +48,7 @@ var ORDER_BUSINESS_WRITE_SOURCES = /* @__PURE__ */ new Set([
48
48
  "overwriteExistingOrder",
49
49
  "markOrderSyncedByExternalSaleNumber"
50
50
  ]);
51
+ var ORDER_MERGE_SELF_CHECK = false;
51
52
  var OrderModule = class extends import_BaseModule.BaseModule {
52
53
  constructor(name, version) {
53
54
  super(name, version);
@@ -56,8 +57,6 @@ var OrderModule = class extends import_BaseModule.BaseModule {
56
57
  this.pendingSyncMessages = [];
57
58
  this.isProcessingSyncBatch = false;
58
59
  this.isIdlePhase = true;
59
- // Map<resource_id, OrderId[]> 资源到订单的倒排索引
60
- this.resourceIdIndex = /* @__PURE__ */ new Map();
61
60
  this.orderSQLiteSaveQueue = Promise.resolve();
62
61
  /** 按 storageKey 记录最近一次 SQLite 写入来源与时间,用于去重 */
63
62
  this.recentSqliteWriteByStorageKey = /* @__PURE__ */ new Map();
@@ -309,12 +308,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
309
308
  };
310
309
  }
311
310
  updateCreateStore() {
312
- var _a;
313
311
  const appPlugin = this.core.getPlugin("app");
314
312
  const app = appPlugin == null ? void 0 : appPlugin.getApp();
315
313
  if (app) {
316
314
  const coreData = app.data.store.getStore().getDataByModel("core");
317
- if (!((_a = this.store.createdAtQuery) == null ? void 0 : _a.sales_time_between) && (coreData == null ? void 0 : coreData.core)) {
315
+ if (coreData == null ? void 0 : coreData.core) {
318
316
  const today = (0, import_dayjs.default)();
319
317
  if (coreData == null ? void 0 : coreData.core.operating_day_boundary) {
320
318
  const operatingDayBoundary = coreData.core.operating_day_boundary;
@@ -481,10 +479,6 @@ var OrderModule = class extends import_BaseModule.BaseModule {
481
479
  return this.store.list;
482
480
  }
483
481
  }
484
- getOrdersByResourceId(resourceId) {
485
- const ids = this.resourceIdIndex.get(String(resourceId)) || [];
486
- return ids.map((id) => this.store.map.get(id)).filter((order) => !!order);
487
- }
488
482
  normalizeOrderForMemoryList(order) {
489
483
  const externalSaleNumber = order == null ? void 0 : order.external_sale_number;
490
484
  if ((order == null ? void 0 : order.order_id) !== void 0 && (order == null ? void 0 : order.order_id) !== null && (order == null ? void 0 : order.order_id) !== "") {
@@ -617,22 +611,33 @@ var OrderModule = class extends import_BaseModule.BaseModule {
617
611
  const patchedOrders = [...pendingMap.values()];
618
612
  const mergeActions = {};
619
613
  const updatedList = [...this.store.list];
614
+ const identityKeyToIndex = /* @__PURE__ */ new Map();
615
+ for (let index = 0; index < updatedList.length; index += 1) {
616
+ for (const key of this.getOrderIdentityMatchKeys(updatedList[index])) {
617
+ if (!identityKeyToIndex.has(key))
618
+ identityKeyToIndex.set(key, index);
619
+ }
620
+ }
620
621
  for (const [storageKey, pendingOrder] of memoryPendingMap.entries()) {
621
- const matchIndex = this.findOrderIndexByIdentity(updatedList, pendingOrder);
622
- if (matchIndex < 0)
622
+ const matchIndex = this.lookupOrderIndexByIdentityKeys(
623
+ identityKeyToIndex,
624
+ this.getOrderIdentityMatchKeys(pendingOrder)
625
+ );
626
+ if (matchIndex >= 0) {
627
+ const mergedOrder = this.mergeOrderRecords(updatedList[matchIndex], pendingOrder, {
628
+ preferIncomingProducts: true
629
+ });
630
+ updatedList[matchIndex] = mergedOrder;
631
+ this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, matchIndex);
632
+ mergeActions[storageKey] = "update";
623
633
  continue;
624
- updatedList[matchIndex] = this.mergeOrderRecords(updatedList[matchIndex], pendingOrder, {
625
- preferIncomingProducts: true
626
- });
627
- pendingMap.delete(storageKey);
628
- memoryPendingMap.delete(storageKey);
629
- mergeActions[storageKey] = "update";
630
- }
631
- for (const [storageKey, order] of memoryPendingMap.entries()) {
634
+ }
635
+ const insertIndex = updatedList.length;
636
+ updatedList.push(pendingOrder);
637
+ this.registerOrderIdentityKeys(identityKeyToIndex, pendingOrder, insertIndex);
632
638
  mergeActions[storageKey] = "insert";
633
- updatedList.push(order);
634
639
  }
635
- this.store.list = this.compactOrderListByIdentity(updatedList, "upsertPendingSyncOrders.store").list;
640
+ this.store.list = this.runOrderStoreSelfCheck(updatedList, "upsertPendingSyncOrders.store");
636
641
  this.syncOrdersMap();
637
642
  await this.patchOrdersInSQLite(patchedOrders, "upsertPendingSyncOrders", mergeActions);
638
643
  this.logInfo("upsertPendingSyncOrders-结束", {
@@ -674,21 +679,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
674
679
  }
675
680
  syncOrdersMap() {
676
681
  this.store.map.clear();
677
- this.resourceIdIndex.clear();
678
682
  for (const order of this.store.list) {
679
683
  const primaryIdentity = this.getOrderMapKey(order);
680
684
  if (!primaryIdentity)
681
685
  continue;
682
686
  this.store.map.set(primaryIdentity, order);
683
- const resourceIds = this.extractResourceIds(order);
684
- for (const resourceId of resourceIds) {
685
- const key = String(resourceId);
686
- const existing = this.resourceIdIndex.get(key) || [];
687
- if (existing.some((eid) => this.getIdKey(eid) === primaryIdentity))
688
- continue;
689
- existing.push(primaryIdentity);
690
- this.resourceIdIndex.set(key, existing);
691
- }
692
687
  }
693
688
  }
694
689
  getOrderMapKey(order) {
@@ -735,24 +730,6 @@ var OrderModule = class extends import_BaseModule.BaseModule {
735
730
  }
736
731
  return keys;
737
732
  }
738
- extractResourceIds(order) {
739
- const ids = /* @__PURE__ */ new Set();
740
- const visitResources = (resources) => {
741
- if (!Array.isArray(resources))
742
- return;
743
- resources.forEach((resource) => {
744
- const rid = resource == null ? void 0 : resource.relation_id;
745
- if (rid !== void 0 && rid !== null && rid !== "")
746
- ids.add(String(rid));
747
- if (Array.isArray(resource == null ? void 0 : resource.children))
748
- visitResources(resource.children);
749
- });
750
- };
751
- if (Array.isArray(order == null ? void 0 : order.bookings)) {
752
- order.bookings.forEach((booking) => visitResources((booking == null ? void 0 : booking.resources) || []));
753
- }
754
- return [...ids];
755
- }
756
733
  getOrderDateKey(order) {
757
734
  var _a, _b, _c, _d;
758
735
  const candidates = [
@@ -971,9 +948,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
971
948
  * 将增量订单合并到 store
972
949
  */
973
950
  async mergeOrdersToStore(freshOrders, source) {
951
+ const storeOrderCountBefore = this.store.list.length;
974
952
  this.logInfo("mergeOrdersToStore-开始", {
975
953
  freshOrderCount: freshOrders.length,
976
- storeOrderCountBefore: this.store.list.length,
954
+ storeOrderCountBefore,
977
955
  source
978
956
  });
979
957
  this.logDuplicateOrders(`${source}.beforeMerge`, this.store.list);
@@ -992,19 +970,45 @@ var OrderModule = class extends import_BaseModule.BaseModule {
992
970
  const patchedOrders = [];
993
971
  const mergeActions = {};
994
972
  const updatedList = [...this.store.list];
973
+ const identityKeyToIndex = /* @__PURE__ */ new Map();
974
+ for (let index = 0; index < updatedList.length; index += 1) {
975
+ const identityKeys = this.getOrderIdentityMatchKeys(updatedList[index]);
976
+ for (const key of identityKeys) {
977
+ if (!identityKeyToIndex.has(key))
978
+ identityKeyToIndex.set(key, index);
979
+ }
980
+ }
995
981
  for (const fresh of uniqueFreshOrders) {
996
- const matchIndex = this.findOrderIndexByIdentity(updatedList, fresh);
982
+ const freshIdentityKeys = this.getOrderIdentityMatchKeys(fresh);
983
+ const matchIndex = this.lookupOrderIndexByIdentityKeys(identityKeyToIndex, freshIdentityKeys);
997
984
  const storageKey = this.getOrderStorageKey(fresh);
998
985
  const mergeKey = storageKey || (fresh.order_id !== void 0 && fresh.order_id !== null ? this.getIdKey(fresh.order_id) : "");
999
986
  if (matchIndex >= 0) {
1000
- const mergedOrder = this.mergeOrderRecords(updatedList[matchIndex], fresh);
987
+ const existingOrder = updatedList[matchIndex];
988
+ if (this.isPendingSyncOrder(existingOrder) && this.isRemoteEchoMergeSource(source)) {
989
+ this.logInfo("mergeOrdersToStore-跳过 pending 订单远端覆盖", {
990
+ source,
991
+ order_id: existingOrder.order_id ?? fresh.order_id ?? null,
992
+ external_sale_number: existingOrder.external_sale_number ?? fresh.external_sale_number ?? null,
993
+ local_payment_status: existingOrder.payment_status ?? null,
994
+ remote_payment_status: fresh.payment_status ?? null,
995
+ local_need_sync: existingOrder.need_sync ?? null,
996
+ remote_need_sync: fresh.need_sync ?? null,
997
+ reason: "protect_pending_sync_order_from_remote_echo"
998
+ });
999
+ continue;
1000
+ }
1001
+ const mergedOrder = this.mergeOrderRecords(existingOrder, fresh);
1001
1002
  updatedList[matchIndex] = mergedOrder;
1003
+ this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, matchIndex);
1002
1004
  patchedOrders.push(mergedOrder);
1003
1005
  if (mergeKey)
1004
1006
  mergeActions[mergeKey] = "update";
1005
1007
  continue;
1006
1008
  }
1009
+ const insertIndex = updatedList.length;
1007
1010
  updatedList.push(fresh);
1011
+ this.registerOrderIdentityKeys(identityKeyToIndex, fresh, insertIndex);
1008
1012
  patchedOrders.push(fresh);
1009
1013
  if (mergeKey)
1010
1014
  mergeActions[mergeKey] = "insert";
@@ -1016,7 +1020,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1016
1020
  updateCount,
1017
1021
  storeOrderCountAfter: this.store.list.length
1018
1022
  });
1019
- this.store.list = this.compactOrderListByIdentity(updatedList, `${source}.store`).list;
1023
+ this.store.list = this.runOrderStoreSelfCheck(updatedList, `${source}.store`);
1020
1024
  this.syncOrdersMap();
1021
1025
  await this.patchOrdersInSQLite(patchedOrders, source, mergeActions);
1022
1026
  this.logInfo("mergeOrdersToStore-结束", {
@@ -1027,6 +1031,53 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1027
1031
  });
1028
1032
  await this.emitOrdersChanged(patchedOrders, source);
1029
1033
  }
1034
+ /**
1035
+ * 在身份索引中查找与目标订单共享任一身份键的已存在订单下标。
1036
+ * 返回所有命中键里最小的下标,等价于原 findOrderIndexByIdentity 的「取首个匹配」语义。
1037
+ *
1038
+ * @example
1039
+ * const idx = this.lookupOrderIndexByIdentityKeys(identityKeyToIndex, freshIdentityKeys)
1040
+ */
1041
+ lookupOrderIndexByIdentityKeys(identityKeyToIndex, identityKeys) {
1042
+ let matchIndex = -1;
1043
+ for (const key of identityKeys) {
1044
+ const index = identityKeyToIndex.get(key);
1045
+ if (index === void 0)
1046
+ continue;
1047
+ if (matchIndex < 0 || index < matchIndex)
1048
+ matchIndex = index;
1049
+ }
1050
+ return matchIndex;
1051
+ }
1052
+ isRemoteEchoMergeSource(source) {
1053
+ return source === "pubsub.bodyUpsert" || source === "pubsub.httpRefresh";
1054
+ }
1055
+ /**
1056
+ * 将订单的全部身份键登记到索引并指向其在列表中的下标。
1057
+ * 合并后订单新增的身份字段(如挂单同步后拿到 order_id)也会被登记。
1058
+ *
1059
+ * @example
1060
+ * this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, matchIndex)
1061
+ */
1062
+ registerOrderIdentityKeys(identityKeyToIndex, order, index) {
1063
+ const identityKeys = this.getOrderIdentityMatchKeys(order);
1064
+ for (const key of identityKeys) {
1065
+ identityKeyToIndex.set(key, index);
1066
+ }
1067
+ }
1068
+ /**
1069
+ * 合并热路径去重兜底:默认直接返回原列表(增量索引已保证无重复)。
1070
+ * 仅当 ORDER_MERGE_SELF_CHECK 开启时,额外做一次全表压缩并在发现残留重复时告警。
1071
+ */
1072
+ runOrderStoreSelfCheck(orders, source) {
1073
+ if (!ORDER_MERGE_SELF_CHECK)
1074
+ return orders;
1075
+ const { list, removedCount } = this.compactOrderListByIdentity(orders, source);
1076
+ if (removedCount > 0) {
1077
+ this.logWarning("合并自检发现残留重复订单,已压缩", { source, removedCount });
1078
+ }
1079
+ return list;
1080
+ }
1030
1081
  normalizeOrderSyncMessage(res) {
1031
1082
  const data = (res == null ? void 0 : res.data) || res;
1032
1083
  if (!data)
@@ -1640,7 +1691,6 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1640
1691
  async clear() {
1641
1692
  this.store.list = [];
1642
1693
  this.store.map = /* @__PURE__ */ new Map();
1643
- this.resourceIdIndex.clear();
1644
1694
  if (this.dbManager) {
1645
1695
  await this.runInOrderSQLiteSaveQueue(async () => {
1646
1696
  await this.dbManager.clear(INDEXDB_STORE_NAME);
@@ -18,8 +18,7 @@ export declare class ProductsModule extends BaseModule implements Module {
18
18
  private productsPriceCache;
19
19
  private readonly CACHE_MAX_DAYS;
20
20
  private formatters;
21
- private isBuiltinFormatterRegistered;
22
- private isLegacyPriceFormatterEnabled;
21
+ private isPriceFormatterRegistered;
23
22
  private quotationPriceBridge?;
24
23
  private quotationBridgeChannel?;
25
24
  private quotationBridgeLoadedKey?;
@@ -37,8 +36,6 @@ export declare class ProductsModule extends BaseModule implements Module {
37
36
  private lastPreloadCompletedAtMs;
38
37
  /** IndexDB 写入串行队列,避免快照与 patch 并发交错 */
39
38
  private productIndexDBSaveQueue;
40
- /** 最近一次智能定价评估提取的 schedule 变价时间点(HH:mm),供 Server 订阅定时刷新使用 */
41
- private lastScheduleTimePoints;
42
39
  constructor(name?: string, version?: string);
43
40
  initialize(core: PisellCore, options: any): Promise<void>;
44
41
  /**
@@ -111,10 +108,6 @@ export declare class ProductsModule extends BaseModule implements Module {
111
108
  */
112
109
  private prepareProductsWithPrice;
113
110
  private getProductsPriceCacheKey;
114
- /**
115
- * 稳定序列化策略上下文,避免对象 key 顺序不同导致缓存 key 抖动。
116
- */
117
- private stringifyStable;
118
111
  private normalizeProductIds;
119
112
  /**
120
113
  * 按轻量范围返回商品 ID,不做 structuredClone。
@@ -129,26 +122,14 @@ export declare class ProductsModule extends BaseModule implements Module {
129
122
  */
130
123
  private applyFormatters;
131
124
  /**
132
- * 注册内置商品格式化器。
133
- *
134
- * 智能定价默认替代报价单逻辑;报价单 formatter 仅在 enableLegacyPriceFormatter=true 时启用。
125
+ * 注册内置的价格格式化器
126
+ * 这个格式化器负责将价格数据应用到商品上
135
127
  * @private
136
128
  */
137
- private registerBuiltinProductFormatters;
138
- /**
139
- * 是否启用旧报价单价格 formatter。
140
- *
141
- * 默认关闭,避免报价单逻辑覆盖智能定价结果。
142
- */
143
- private shouldEnableLegacyPriceFormatter;
144
- /**
145
- * 返回最近一次 prepareProductsWithPrice / DataVariant 评估提取的变价时间点(HH:mm)。
146
- * 供 OS Server 商品 query 订阅定时刷新使用。
147
- */
148
- getLastScheduleTimePoints(): string[];
129
+ private registerBuiltinPriceFormatter;
149
130
  /**
150
131
  * 注册商品格式化器
151
- * 格式化器会按注册顺序依次执行;legacy 启用时先兜底报价,再由智能定价覆盖。
132
+ * 格式化器会按注册顺序依次执行(内置价格格式化器始终是第一个)
152
133
  * @param formatter 格式化函数
153
134
  * @param prepend 是否插入到队列开头(默认 false,追加到末尾)
154
135
  * @example
@@ -163,8 +144,8 @@ export declare class ProductsModule extends BaseModule implements Module {
163
144
  */
164
145
  registerFormatter(formatter: ProductFormatter, prepend?: boolean): void;
165
146
  /**
166
- * 清空所有格式化器(包括内置智能定价格式化器)
167
- * @param keepBuiltin 是否保留内置智能定价格式化器(默认 true)
147
+ * 清空所有格式化器(包括内置价格格式化器)
148
+ * @param keepBuiltin 是否保留内置价格格式化器(默认 true)
168
149
  */
169
150
  clearFormatters(keepBuiltin?: boolean): void;
170
151
  /**
@@ -43,10 +43,8 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
43
43
  // 最多缓存7天
44
44
  // 商品格式化器列表
45
45
  this.formatters = [];
46
- // 是否已注册内置商品格式化器
47
- this.isBuiltinFormatterRegistered = false;
48
- // 旧报价单格式化器默认关闭,仅显式开启时作为兼容兜底注册
49
- this.isLegacyPriceFormatterEnabled = false;
46
+ // 是否已注册内置价格格式化器
47
+ this.isPriceFormatterRegistered = false;
50
48
  this.quotationBridgeLoadedKey = "";
51
49
  this.quotationScheduleCache = /* @__PURE__ */ new Map();
52
50
  this.quotationScheduleCacheSource = null;
@@ -58,8 +56,6 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
58
56
  this.lastPreloadCompletedAtMs = 0;
59
57
  /** IndexDB 写入串行队列,避免快照与 patch 并发交错 */
60
58
  this.productIndexDBSaveQueue = Promise.resolve();
61
- /** 最近一次智能定价评估提取的 schedule 变价时间点(HH:mm),供 Server 订阅定时刷新使用 */
62
- this.lastScheduleTimePoints = [];
63
59
  }
64
60
  async initialize(core, options) {
65
61
  var _a;
@@ -86,7 +82,7 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
86
82
  console.warn("[Products] IndexDB Manager 未找到");
87
83
  }
88
84
  }
89
- this.registerBuiltinProductFormatters();
85
+ this.registerBuiltinPriceFormatter();
90
86
  this.initProductDataSource();
91
87
  this.setupProductSync();
92
88
  this.logInfo("模块初始化完成", {
@@ -478,7 +474,7 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
478
474
  * @private
479
475
  */
480
476
  async prepareProductsWithPrice(schedule_date, extraContext, options) {
481
- var _a, _b, _c, _d;
477
+ var _a, _b;
482
478
  const tTotal = performance.now();
483
479
  const targetIds = options == null ? void 0 : options.productIds;
484
480
  const isIncremental = Array.isArray(targetIds);
@@ -503,28 +499,21 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
503
499
  (0, import_product.perfMark)("prepareProducts.extractIds", performance.now() - tIds, { count: ids.length });
504
500
  }
505
501
  this.logInfo("获取到商品列表", { productCount: products.length });
506
- let priceData = [];
507
- if (this.isLegacyPriceFormatterEnabled) {
508
- const tPrice = performance.now();
509
- priceData = await this.loadProductsPrice({
510
- ids,
511
- schedule_date,
512
- schedule_datetime: extraContext == null ? void 0 : extraContext.schedule_datetime,
513
- customer_id: extraContext == null ? void 0 : extraContext.customer_id
514
- });
515
- (0, import_product.perfMark)("prepareProducts.loadPrice", performance.now() - tPrice, { count: ids.length });
516
- this.logInfo("获取商品报价单价格成功", { priceDataCount: (priceData == null ? void 0 : priceData.length) ?? 0 });
517
- }
502
+ const tPrice = performance.now();
503
+ const priceData = await this.loadProductsPrice({
504
+ ids,
505
+ schedule_date,
506
+ schedule_datetime: extraContext == null ? void 0 : extraContext.schedule_datetime,
507
+ customer_id: extraContext == null ? void 0 : extraContext.customer_id
508
+ });
509
+ (0, import_product.perfMark)("prepareProducts.loadPrice", performance.now() - tPrice, { count: ids.length });
510
+ this.logInfo("获取商品报价单价格成功", { priceDataCount: (priceData == null ? void 0 : priceData.length) ?? 0 });
518
511
  const context = {
519
512
  schedule_date,
520
513
  schedule_datetime: extraContext == null ? void 0 : extraContext.schedule_datetime,
521
514
  customer_id: extraContext == null ? void 0 : extraContext.customer_id,
522
515
  priceData,
523
516
  locale: (_b = (_a = this.core) == null ? void 0 : _a.context) == null ? void 0 : _b.locale,
524
- dataVariantEvaluator: (extraContext == null ? void 0 : extraContext.dataVariantEvaluator) || ((_d = (_c = this.core) == null ? void 0 : _c.context) == null ? void 0 : _d.dataVariantEvaluator),
525
- menuList: (extraContext == null ? void 0 : extraContext.menuList) || [],
526
- scheduleList: (extraContext == null ? void 0 : extraContext.scheduleList) || [],
527
- strategy_context: extraContext == null ? void 0 : extraContext.strategy_context,
528
517
  ...extraContext
529
518
  };
530
519
  const tFormat = performance.now();
@@ -564,21 +553,7 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
564
553
  getProductsPriceCacheKey(schedule_date, extraContext, productIds) {
565
554
  const datetime = (extraContext == null ? void 0 : extraContext.schedule_datetime) || schedule_date;
566
555
  const productScope = productIds ? `:products:${productIds.join(",")}` : "";
567
- const strategyScope = this.stringifyStable((extraContext == null ? void 0 : extraContext.strategy_context) || {});
568
- return `${datetime}:customer:${(extraContext == null ? void 0 : extraContext.customer_id) ?? ""}:strategy:${strategyScope}${productScope}`;
569
- }
570
- /**
571
- * 稳定序列化策略上下文,避免对象 key 顺序不同导致缓存 key 抖动。
572
- */
573
- stringifyStable(value) {
574
- if (value == null)
575
- return "";
576
- if (Array.isArray(value))
577
- return `[${value.map((item) => this.stringifyStable(item)).join(",")}]`;
578
- if (typeof value === "object") {
579
- return `{${Object.keys(value).sort().map((key) => `${key}:${this.stringifyStable(value[key])}`).join(",")}}`;
580
- }
581
- return String(value);
556
+ return `${datetime}:customer:${(extraContext == null ? void 0 : extraContext.customer_id) ?? ""}${productScope}`;
582
557
  }
583
558
  normalizeProductIds(productIds) {
584
559
  if (!Array.isArray(productIds))
@@ -662,49 +637,21 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
662
637
  return result;
663
638
  }
664
639
  /**
665
- * 注册内置商品格式化器。
666
- *
667
- * 智能定价默认替代报价单逻辑;报价单 formatter 仅在 enableLegacyPriceFormatter=true 时启用。
640
+ * 注册内置的价格格式化器
641
+ * 这个格式化器负责将价格数据应用到商品上
668
642
  * @private
669
643
  */
670
- registerBuiltinProductFormatters() {
671
- if (this.isBuiltinFormatterRegistered) {
672
- console.warn("[ProductsModule] 内置商品格式化器已注册,跳过");
644
+ registerBuiltinPriceFormatter() {
645
+ if (this.isPriceFormatterRegistered) {
646
+ console.warn("[ProductsModule] 内置价格格式化器已注册,跳过");
673
647
  return;
674
648
  }
675
- this.isLegacyPriceFormatterEnabled = this.shouldEnableLegacyPriceFormatter();
676
- const dataVariantFormatter = (products, context) => {
677
- var _a, _b;
678
- const evaluator = context.dataVariantEvaluator || ((_b = (_a = this.core) == null ? void 0 : _a.context) == null ? void 0 : _b.dataVariantEvaluator);
679
- if (!evaluator || typeof evaluator.resolveProducts !== "function") {
680
- this.lastScheduleTimePoints = [];
681
- this.logWarning("智能定价评估器未注入,跳过 DataVariant 格式化", {
682
- productCount: products.length
683
- });
684
- return products;
685
- }
686
- const strategyContext = context.strategy_context || {};
687
- const businessData = {
688
- products,
689
- scheduleDateTime: context.schedule_datetime || context.schedule_date,
690
- scheduleList: context.scheduleList || [],
691
- menuList: context.menuList || [],
692
- customerId: context.customer_id,
693
- channel: strategyContext.channel,
694
- orderType: strategyContext.orderType || strategyContext.order_type,
695
- businessCode: strategyContext.business_code ?? strategyContext.businessCode,
696
- custom: strategyContext
697
- };
698
- const result = evaluator.resolveProducts(businessData);
699
- this.lastScheduleTimePoints = Array.isArray(result == null ? void 0 : result.scheduleTimePoints) ? [...result.scheduleTimePoints] : [];
700
- return Array.isArray(result == null ? void 0 : result.products) ? result.products : products;
701
- };
702
- const legacyPriceFormatter = (products, context) => {
649
+ const priceFormatter = (products, context) => {
703
650
  if (!context.priceData || context.priceData.length === 0) {
704
- console.log("[ProductsModule] 💰 没有价格数据,跳过 legacy 报价单价格应用");
651
+ console.log("[ProductsModule] 💰 没有价格数据,跳过价格应用");
705
652
  return products;
706
653
  }
707
- console.log(`[ProductsModule] 💰 应用 legacy 报价单价格到 ${products.length} 个商品`);
654
+ console.log(`[ProductsModule] 💰 应用价格数据到 ${products.length} 个商品`);
708
655
  return (0, import_product.applyPriceDataToProducts)(products, context.priceData);
709
656
  };
710
657
  const i18nFormatter = (products, context) => {
@@ -713,34 +660,15 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
713
660
  const detailValueFormatter = (products, context) => {
714
661
  return (0, import_product.applyDetailValueToProducts)(products, context);
715
662
  };
716
- if (this.isLegacyPriceFormatterEnabled) {
717
- this.formatters.push(legacyPriceFormatter);
718
- }
719
- this.formatters.push(dataVariantFormatter);
663
+ this.formatters.unshift(priceFormatter);
720
664
  this.formatters.push(i18nFormatter);
721
665
  this.formatters.push(detailValueFormatter);
722
- this.isBuiltinFormatterRegistered = true;
723
- console.log("[ProductsModule] ✅ 内置商品格式化器已注册(智能定价优先)");
724
- }
725
- /**
726
- * 是否启用旧报价单价格 formatter。
727
- *
728
- * 默认关闭,避免报价单逻辑覆盖智能定价结果。
729
- */
730
- shouldEnableLegacyPriceFormatter() {
731
- var _a, _b, _c;
732
- return ((_a = this.otherParams) == null ? void 0 : _a.enableLegacyPriceFormatter) === true || ((_c = (_b = this.core) == null ? void 0 : _b.context) == null ? void 0 : _c.enableLegacyPriceFormatter) === true;
733
- }
734
- /**
735
- * 返回最近一次 prepareProductsWithPrice / DataVariant 评估提取的变价时间点(HH:mm)。
736
- * 供 OS Server 商品 query 订阅定时刷新使用。
737
- */
738
- getLastScheduleTimePoints() {
739
- return [...this.lastScheduleTimePoints];
666
+ this.isPriceFormatterRegistered = true;
667
+ console.log("[ProductsModule] ✅ 内置价格格式化器已注册(第 1 个)");
740
668
  }
741
669
  /**
742
670
  * 注册商品格式化器
743
- * 格式化器会按注册顺序依次执行;legacy 启用时先兜底报价,再由智能定价覆盖。
671
+ * 格式化器会按注册顺序依次执行(内置价格格式化器始终是第一个)
744
672
  * @param formatter 格式化函数
745
673
  * @param prepend 是否插入到队列开头(默认 false,追加到末尾)
746
674
  * @example
@@ -755,7 +683,7 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
755
683
  */
756
684
  registerFormatter(formatter, prepend = false) {
757
685
  if (prepend) {
758
- const insertIndex = this.isBuiltinFormatterRegistered ? this.isLegacyPriceFormatterEnabled ? 2 : 1 : 0;
686
+ const insertIndex = this.isPriceFormatterRegistered ? 1 : 0;
759
687
  this.formatters.splice(insertIndex, 0, formatter);
760
688
  console.log(`[ProductsModule] 📌 已在位置 ${insertIndex + 1} 插入格式化器,当前共 ${this.formatters.length} 个`);
761
689
  } else {
@@ -764,17 +692,16 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
764
692
  }
765
693
  }
766
694
  /**
767
- * 清空所有格式化器(包括内置智能定价格式化器)
768
- * @param keepBuiltin 是否保留内置智能定价格式化器(默认 true)
695
+ * 清空所有格式化器(包括内置价格格式化器)
696
+ * @param keepBuiltin 是否保留内置价格格式化器(默认 true)
769
697
  */
770
698
  clearFormatters(keepBuiltin = true) {
771
- if (keepBuiltin && this.isBuiltinFormatterRegistered) {
772
- const builtinCount = this.isLegacyPriceFormatterEnabled ? 2 : 1;
773
- this.formatters = this.formatters.slice(0, builtinCount);
774
- console.log("[ProductsModule] 🧹 已清空自定义格式化器,保留内置智能定价格式化器");
699
+ if (keepBuiltin && this.isPriceFormatterRegistered) {
700
+ this.formatters = [this.formatters[0]];
701
+ console.log("[ProductsModule] 🧹 已清空自定义格式化器,保留内置价格格式化器");
775
702
  } else {
776
703
  this.formatters = [];
777
- this.isBuiltinFormatterRegistered = false;
704
+ this.isPriceFormatterRegistered = false;
778
705
  console.log("[ProductsModule] 🧹 已清空所有格式化器");
779
706
  }
780
707
  }
@@ -875,8 +802,7 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
875
802
  "resourceRelation",
876
803
  "bundleGroup.bundleItem",
877
804
  "optionGroup.optionItem",
878
- "variantGroup.variantItem",
879
- "dataVariants"
805
+ "variantGroup.variantItem"
880
806
  ],
881
807
  open_deposit: 1,
882
808
  is_append_product_description: 1,
@@ -1301,7 +1227,7 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
1301
1227
  * Server 层监听该事件后对变更商品增量执行 prepareProductsWithPrice 并更新缓存
1302
1228
  */
1303
1229
  async processProductSyncMessages() {
1304
- var _a, _b, _c, _d, _e, _f, _g;
1230
+ var _a, _b, _c, _d, _e, _f;
1305
1231
  const messages = [...this.pendingSyncMessages];
1306
1232
  this.pendingSyncMessages = [];
1307
1233
  if (messages.length === 0)
@@ -1355,10 +1281,6 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
1355
1281
  if ((_f = msg.relation_product_ids) == null ? void 0 : _f.length) {
1356
1282
  sseRefreshIds.push(...msg.relation_product_ids);
1357
1283
  }
1358
- } else if (["product_data_variant"].includes(channelKey)) {
1359
- if ((_g = msg.product_ids) == null ? void 0 : _g.length) {
1360
- sseRefreshIds.push(...msg.product_ids);
1361
- }
1362
1284
  }
1363
1285
  }
1364
1286
  const uniqueDeleteIds = [...new Set(deleteIds)];
@@ -110,8 +110,6 @@ export interface ProductSyncMessage {
110
110
  change_types?: string[];
111
111
  /** 关联商品 ID(product_collection / product_category / product_quotation 变更时携带) */
112
112
  relation_product_ids?: number[];
113
- /** 关联商品 ID(product_data_variant 变更时携带) */
114
- product_ids?: number[];
115
113
  message_uuid?: string;
116
114
  timestamp?: string;
117
115
  /** 内部标记:来源频道 key */
@@ -126,18 +124,6 @@ export interface ProductFormatterContext {
126
124
  customer_id?: number | string;
127
125
  priceData?: LoadProductsPriceData[];
128
126
  scheduleModule?: any;
129
- /** 全量餐牌列表,供智能定价 menu_match 等条件判断使用 */
130
- menuList?: any[];
131
- /** 全量日程列表,供智能定价 schedule_match 等条件判断使用 */
132
- scheduleList?: any[];
133
- /** 外部传入的策略上下文,仅承载定价条件,不参与商品集合筛选 */
134
- strategy_context?: Record<string, any>;
135
- /** 智能定价评估器,由宿主统一注入到 PisellOS context */
136
- dataVariantEvaluator?: {
137
- resolveProducts: (businessData: any) => {
138
- products: ProductData[];
139
- };
140
- };
141
127
  locale?: string;
142
128
  }
143
129
  /**