@pisell/pisellos 2.2.257 → 2.2.259

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 (59) hide show
  1. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +17 -13
  2. package/dist/modules/Order/index.d.ts +32 -1
  3. package/dist/modules/Order/index.js +615 -288
  4. package/dist/modules/Order/types.d.ts +20 -2
  5. package/dist/modules/Order/utils/bundleDiscountHydration.d.ts +5 -0
  6. package/dist/modules/Order/utils/bundleDiscountHydration.js +144 -0
  7. package/dist/modules/Order/utils.d.ts +4 -0
  8. package/dist/modules/Order/utils.js +114 -28
  9. package/dist/modules/Rules/index.d.ts +3 -3
  10. package/dist/modules/Rules/index.js +8 -3
  11. package/dist/modules/Rules/types.d.ts +2 -1
  12. package/dist/modules/SalesSummary/index.d.ts +7 -3
  13. package/dist/modules/SalesSummary/index.js +67 -39
  14. package/dist/modules/SalesSummary/types.d.ts +1 -0
  15. package/dist/modules/SalesSummary/utils.js +2 -1
  16. package/dist/modules/SurchargeList/index.d.ts +6 -4
  17. package/dist/modules/SurchargeList/index.js +62 -39
  18. package/dist/modules/SurchargeList/types.d.ts +6 -2
  19. package/dist/server/index.d.ts +3 -0
  20. package/dist/server/index.js +1136 -855
  21. package/dist/server/modules/order/index.d.ts +22 -3
  22. package/dist/server/modules/order/index.js +398 -316
  23. package/dist/solution/BaseSales/index.d.ts +22 -2
  24. package/dist/solution/BaseSales/index.js +995 -701
  25. package/dist/solution/BaseSales/types.d.ts +1 -0
  26. package/dist/solution/BaseSales/types.js +2 -1
  27. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +2 -1
  28. package/dist/solution/BookingTicket/index.d.ts +8 -0
  29. package/dist/solution/BookingTicket/index.js +153 -6
  30. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +11 -1
  31. package/lib/modules/Order/index.d.ts +32 -1
  32. package/lib/modules/Order/index.js +402 -64
  33. package/lib/modules/Order/types.d.ts +20 -2
  34. package/lib/modules/Order/utils/bundleDiscountHydration.d.ts +5 -0
  35. package/lib/modules/Order/utils/bundleDiscountHydration.js +139 -0
  36. package/lib/modules/Order/utils.d.ts +4 -0
  37. package/lib/modules/Order/utils.js +84 -2
  38. package/lib/modules/Rules/index.d.ts +3 -3
  39. package/lib/modules/Rules/index.js +4 -3
  40. package/lib/modules/Rules/types.d.ts +2 -1
  41. package/lib/modules/SalesSummary/index.d.ts +7 -3
  42. package/lib/modules/SalesSummary/index.js +28 -11
  43. package/lib/modules/SalesSummary/types.d.ts +1 -0
  44. package/lib/modules/SalesSummary/utils.js +2 -0
  45. package/lib/modules/SurchargeList/index.d.ts +6 -4
  46. package/lib/modules/SurchargeList/index.js +41 -21
  47. package/lib/modules/SurchargeList/types.d.ts +6 -2
  48. package/lib/server/index.d.ts +3 -0
  49. package/lib/server/index.js +215 -9
  50. package/lib/server/modules/order/index.d.ts +22 -3
  51. package/lib/server/modules/order/index.js +103 -53
  52. package/lib/solution/BaseSales/index.d.ts +22 -2
  53. package/lib/solution/BaseSales/index.js +246 -60
  54. package/lib/solution/BaseSales/types.d.ts +1 -0
  55. package/lib/solution/BaseSales/types.js +2 -1
  56. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +2 -1
  57. package/lib/solution/BookingTicket/index.d.ts +8 -0
  58. package/lib/solution/BookingTicket/index.js +101 -0
  59. package/package.json +1 -1
@@ -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);
@@ -30,7 +30,7 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
30
30
  protected defaultVersion: string;
31
31
  isSolution: boolean;
32
32
  protected initializeOptions: ModuleOptions;
33
- private logger;
33
+ protected logger: any;
34
34
  protected appPlugin: AppPlugin;
35
35
  protected store: BaseSalesState;
36
36
  protected otherParams: Record<string, any>;
@@ -46,6 +46,12 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
46
46
  protected hasManualDiscountSelection: boolean;
47
47
  private readonly reusedSharedSubModuleNames;
48
48
  private paymentMethodsCache;
49
+ private queuedAutoPaymentSync;
50
+ private autoPaymentSyncFlushing;
51
+ private autoPaymentSyncTimer;
52
+ private salesDetailLoadInFlight;
53
+ private serverOrderChangeUnsubscribe;
54
+ private serverOrderChangeHydrateInFlight;
49
55
  constructor(name?: string, version?: string);
50
56
  /**
51
57
  * 子类可覆盖此方法以追加/收敛要注册的子模块。
@@ -66,6 +72,9 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
66
72
  * 记录错误日志
67
73
  */
68
74
  private logError;
75
+ private isCurrentSalesOrderRecord;
76
+ private syncCurrentSalesDetailFromServerOrderChange;
77
+ private registerServerOrderChangeSync;
69
78
  private hydrateOrderPaymentNames;
70
79
  get payment(): PaymentModule | undefined;
71
80
  private getCurrentOrderCustomerId;
@@ -195,6 +204,7 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
195
204
  payments?: OrderPaymentSource[];
196
205
  paymentStatus?: BaseSalesPaymentStatus;
197
206
  smallTicketDataFlag?: number;
207
+ confirmPendingVoucherPayments?: boolean;
198
208
  enhancePayload?: SubmitPayloadEnhancer;
199
209
  }): Promise<T>;
200
210
  /**
@@ -207,12 +217,14 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
207
217
  payments?: OrderPaymentSource[];
208
218
  paymentStatus?: BaseSalesPaymentStatus;
209
219
  smallTicketDataFlag?: number;
220
+ confirmPendingVoucherPayments?: boolean;
210
221
  enhancePayload?: SubmitPayloadEnhancer;
211
222
  }): Promise<T>;
212
223
  submitTempOrderAsync<T = any>(params?: {
213
224
  payments?: OrderPaymentSource[];
214
225
  paymentStatus?: BaseSalesPaymentStatus;
215
226
  smallTicketDataFlag?: number;
227
+ confirmPendingVoucherPayments?: boolean;
216
228
  enhancePayload?: SubmitPayloadEnhancer;
217
229
  }): Promise<T>;
218
230
  printLocalOrderReceipt<T = any>(lookup?: BaseSalesPrintLocalOrderReceiptParams): Promise<T>;
@@ -222,6 +234,10 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
222
234
  getOrderPayments(): OrderPaymentData[];
223
235
  /** 覆盖当前订单支付项,内部由 OrderModule 清洗为 Sales 协议字段。 */
224
236
  setOrderPayments(payments: OrderPaymentSource[]): OrderPaymentData[];
237
+ private getPaymentStatusForSync;
238
+ private queueLatestAutoPaymentSync;
239
+ private scheduleQueuedAutoPaymentSyncFlush;
240
+ private flushQueuedAutoPaymentSync;
225
241
  /** 追加单个支付项到当前订单。 */
226
242
  addOrderPayment(payment: OrderPaymentSource): OrderPaymentData[];
227
243
  /** 更新当前订单中的指定支付项。 */
@@ -229,7 +245,11 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
229
245
  /** 删除当前订单中的指定支付项。 */
230
246
  deleteOrderPayment(paymentIdentity: string | number): OrderPaymentData[];
231
247
  /** 覆盖 wallet pass 支付项,同时保留普通支付项。 */
232
- updateVoucherOrderPayments(payments: OrderPaymentSource[]): OrderPaymentData[];
248
+ updateVoucherOrderPayments(payments: OrderPaymentSource[], options?: {
249
+ status?: 'paid' | 'payment_pending';
250
+ }): OrderPaymentData[];
251
+ confirmPendingVoucherPayments(): OrderPaymentData[];
252
+ discardPendingVoucherPayments(): OrderPaymentData[];
233
253
  private getWalletProductList;
234
254
  initWalletData(params?: {
235
255
  order_wait_pay_amount?: number;