@pisell/pisellos 2.3.50 → 2.3.51

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.
@@ -568,6 +568,19 @@ export interface OrderChangedPayload {
568
568
  /** 触发来源,便于订阅者区分 pubsub / 远端覆盖 / 清空等场景 */
569
569
  source?: string;
570
570
  }
571
+ export type RemoteProductMembershipChangeSource = 'pubsub.bodyUpsert' | 'pubsub.httpRefresh';
572
+ /**
573
+ * 远端订单快照相对本地订单产生商品成员增删时的广播载荷。
574
+ * 只表达商品行成员关系变化,不包含数量、价格、备注等字段级修改。
575
+ */
576
+ export interface RemoteProductMembershipChangedPayload {
577
+ order_id: OrderId;
578
+ source: RemoteProductMembershipChangeSource;
579
+ added_product_keys: string[];
580
+ removed_product_keys: string[];
581
+ previous_product_count: number;
582
+ current_product_count: number;
583
+ }
571
584
  /**
572
585
  * OrderSyncMessage - pubsub 同步消息结构
573
586
  */
@@ -605,5 +618,6 @@ export interface OrderState {
605
618
  export declare enum OrderHooks {
606
619
  onOrdersLoaded = "order:onOrdersLoaded",
607
620
  onOrdersChanged = "order:onOrdersChanged",
621
+ onRemoteProductMembershipChanged = "order:onRemoteProductMembershipChanged",
608
622
  onOrdersSyncCompleted = "order:onOrdersSyncCompleted"
609
623
  }
@@ -135,6 +135,11 @@
135
135
  * const changedOrders = payload.changedOrders
136
136
  */
137
137
 
138
+ /**
139
+ * 远端订单快照相对本地订单产生商品成员增删时的广播载荷。
140
+ * 只表达商品行成员关系变化,不包含数量、价格、备注等字段级修改。
141
+ */
142
+
138
143
  /**
139
144
  * OrderSyncMessage - pubsub 同步消息结构
140
145
  */
@@ -149,6 +154,7 @@
149
154
  export var OrderHooks = /*#__PURE__*/function (OrderHooks) {
150
155
  OrderHooks["onOrdersLoaded"] = "order:onOrdersLoaded";
151
156
  OrderHooks["onOrdersChanged"] = "order:onOrdersChanged";
157
+ OrderHooks["onRemoteProductMembershipChanged"] = "order:onRemoteProductMembershipChanged";
152
158
  OrderHooks["onOrdersSyncCompleted"] = "order:onOrdersSyncCompleted";
153
159
  return OrderHooks;
154
160
  }({});
@@ -9,7 +9,7 @@ import { RequestPlugin, WindowPlugin } from '../../plugins';
9
9
  export * from './types';
10
10
  import { ProductList } from '../../modules/ProductList';
11
11
  import { PaymentModule } from '../../modules/Payment';
12
- import type { PaymentMethod, RoundingResult, WalletAssetId, WalletAssetsSnapshot, WalletAssetsState, WalletAssetSelectionSource, ScanWalletAssetResult } from '../../modules/Payment/types';
12
+ import type { PaymentMethod, RoundingResult, WalletAssetId, WalletAssetsBehaviorOptions, WalletAssetsSnapshot, WalletAssetsState, WalletAssetSelectionSource, ScanWalletAssetResult } from '../../modules/Payment/types';
13
13
  import type { SalesSummaryModule } from '../../modules/SalesSummary';
14
14
  import type { ScheduleModule } from '../../modules/Schedule';
15
15
  import { QuotationModule } from '../../modules/Quotation';
@@ -333,6 +333,8 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
333
333
  getWalletAssetsState(): WalletAssetsState;
334
334
  /** 导出 Shared Checkout 跨运行时恢复所需的钱包状态与搜索缓存。 */
335
335
  exportWalletAssetsSnapshot(): WalletAssetsSnapshot;
336
+ /** 配置仅影响 Wallet Assets,不改变 Promotion/Voucher 选择流程。 */
337
+ configureWalletAssetsBehavior(options: WalletAssetsBehaviorOptions): void;
336
338
  /**
337
339
  * 恢复 Shared Checkout 钱包快照,并把选择重新同步为订单 pending payment。
338
340
  */
@@ -3843,6 +3843,14 @@ export var BaseSalesImpl = /*#__PURE__*/function (_BaseModule) {
3843
3843
  return this.store.payment.wallet.exportWalletAssetsSnapshot();
3844
3844
  }
3845
3845
 
3846
+ /** 配置仅影响 Wallet Assets,不改变 Promotion/Voucher 选择流程。 */
3847
+ }, {
3848
+ key: "configureWalletAssetsBehavior",
3849
+ value: function configureWalletAssetsBehavior(options) {
3850
+ if (!this.store.payment) throw new Error('payment 模块未初始化');
3851
+ this.store.payment.wallet.configureWalletAssetsBehavior(options);
3852
+ }
3853
+
3846
3854
  /**
3847
3855
  * 恢复 Shared Checkout 钱包快照,并把选择重新同步为订单 pending payment。
3848
3856
  */
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
326
326
  date: string;
327
327
  status: string;
328
328
  week: string;
329
- weekNum: 0 | 2 | 1 | 5 | 4 | 3 | 6;
329
+ weekNum: 0 | 1 | 2 | 3 | 4 | 5 | 6;
330
330
  }[]>;
331
331
  submitTimeSlot(timeSlots: TimeSliceItem): void;
332
332
  private getScheduleDataByIds;
@@ -326,7 +326,7 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
326
326
  * 获取当前的客户搜索条件
327
327
  * @returns 当前搜索条件
328
328
  */
329
- getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "skip" | "num">;
329
+ getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "num" | "skip">;
330
330
  /**
331
331
  * 获取客户列表状态(包含滚动加载相关状态)
332
332
  * @returns 客户状态
@@ -487,7 +487,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
487
487
  generateIdempotencyToken(): string;
488
488
  syncPaymentsToOrder<T = any>(params: SyncPaymentsToOrderParams): Promise<SyncPaymentsToOrderResult<T>>;
489
489
  createOrder(params: CommitOrderParams['query']): {
490
- type: "appointment_booking" | "virtual";
490
+ type: "virtual" | "appointment_booking";
491
491
  platform: string;
492
492
  sales_channel: string;
493
493
  order_sales_channel: string;
@@ -397,12 +397,18 @@ export interface WalletAssetsState {
397
397
  export interface WalletAssetsSnapshot {
398
398
  state: WalletAssetsState;
399
399
  searchResults: SearchIdentificationCodeItem[];
400
+ /** 已搜索但尚未满足订单条件、等待首次可用后自动选中的 Wallet Asset code。 */
401
+ pendingAutoSelectSearchCodes?: string[];
400
402
  walletParams: WalletDeductionRecommendParams | null;
401
403
  calculationContext: {
402
404
  orderTotalAmount: number;
403
405
  products: any[];
404
406
  };
405
407
  }
408
+ export interface WalletAssetsBehaviorOptions {
409
+ /** 搜索到 Wallet Asset 后,当前或后续首次可用时是否自动选中。 */
410
+ autoSelectAfterSearch?: boolean;
411
+ }
406
412
  export interface RefreshWalletAssetsOptions {
407
413
  /** 商品/金额变化默认保留并重验选择;客户变化由实现层强制清空。 */
408
414
  preserveSelection?: boolean;
@@ -472,6 +478,8 @@ export interface WalletPassPayment {
472
478
  refreshWalletAssetsFromBusinessAsync: (businessData: WalletInitBusinessData, options?: RefreshWalletAssetsOptions) => Promise<WalletAssetsState>;
473
479
  /** 获取共享钱包资产状态快照。 */
474
480
  getWalletAssetsState: () => WalletAssetsState;
481
+ /** 配置仅影响 Wallet Assets 的交互行为。 */
482
+ configureWalletAssetsBehavior: (options: WalletAssetsBehaviorOptions) => void;
475
483
  /** 导出供 Shared Checkout 跨运行时传递的 Wallet Assets 快照。 */
476
484
  exportWalletAssetsSnapshot: () => WalletAssetsSnapshot;
477
485
  /** 恢复 Shared Checkout 传回的 Wallet Assets 快照。 */
@@ -1,4 +1,4 @@
1
- import { WalletPassPayment, WalletDeductionRecommendParams, WalletRecommendItem, UserIdentificationCodeParams, UserIdentificationCodeItem, SearchIdentificationCodeParams, SearchIdentificationCodeItem, SearchIdentificationCodeResult, WalletInitBusinessData, WalletAssetId, WalletAssetsSnapshot, WalletAssetsState, RefreshWalletAssetsOptions, SelectWalletAssetOptions, ScanWalletAssetResult } from './types';
1
+ import { WalletPassPayment, WalletDeductionRecommendParams, WalletRecommendItem, UserIdentificationCodeParams, UserIdentificationCodeItem, SearchIdentificationCodeParams, SearchIdentificationCodeItem, SearchIdentificationCodeResult, WalletInitBusinessData, WalletAssetId, WalletAssetsBehaviorOptions, WalletAssetsSnapshot, WalletAssetsState, RefreshWalletAssetsOptions, SelectWalletAssetOptions, ScanWalletAssetResult } from './types';
2
2
  import type { PaymentModule } from './index';
3
3
  /**
4
4
  * 钱包支付实现
@@ -12,8 +12,11 @@ export declare class WalletPassPaymentImpl implements WalletPassPayment {
12
12
  private walletInitData;
13
13
  private walletAssetsState;
14
14
  private walletAssetsRequestSequence;
15
+ private walletAssetsBehavior;
16
+ private pendingAutoSelectSearchCodes;
15
17
  private walletAssetsCalculationContext;
16
18
  constructor(paymentModule: PaymentModule);
19
+ configureWalletAssetsBehavior(options: WalletAssetsBehaviorOptions): void;
17
20
  /**
18
21
  * 发送事件的辅助方法
19
22
  * 支持使用WalletPassHooks或PaymentHooks
@@ -28,6 +31,9 @@ export declare class WalletPassPaymentImpl implements WalletPassPayment {
28
31
  * 接口暂时缺失某个扫码 code 时继续保留旧值,避免列表闪空。
29
32
  */
30
33
  private syncSearchedWalletAssets;
34
+ private isPendingAutoSelectAsset;
35
+ private clearPendingAutoSelectForAsset;
36
+ private queuePendingAutoSelectForAssets;
31
37
  /**
32
38
  * 生成钱包API默认参数
33
39
  * 根据业务数据生成标准的钱包API参数,并存储在模块中
@@ -46,6 +46,12 @@ function matchesWalletAssetCode(asset, normalizedCode) {
46
46
  (identifier) => String(identifier ?? "").trim() === normalizedCode
47
47
  );
48
48
  }
49
+ function normalizeWalletAssetCode(code) {
50
+ return String(code ?? "").trim().toUpperCase();
51
+ }
52
+ function getWalletAssetCodeKeys(asset) {
53
+ return [asset == null ? void 0 : asset.code, asset == null ? void 0 : asset.encoded].map(normalizeWalletAssetCode).filter(Boolean);
54
+ }
49
55
  function isWalletAssetAvailable(asset) {
50
56
  if (!asset)
51
57
  return false;
@@ -107,11 +113,23 @@ var WalletPassPaymentImpl = class {
107
113
  this.walletInitData = null;
108
114
  this.walletAssetsState = createInitialWalletAssetsState();
109
115
  this.walletAssetsRequestSequence = 0;
116
+ this.walletAssetsBehavior = {
117
+ autoSelectAfterSearch: true
118
+ };
119
+ this.pendingAutoSelectSearchCodes = /* @__PURE__ */ new Set();
110
120
  this.walletAssetsCalculationContext = {
111
121
  orderTotalAmount: 0,
112
122
  products: []
113
123
  };
114
124
  }
125
+ configureWalletAssetsBehavior(options) {
126
+ if (options.autoSelectAfterSearch === void 0)
127
+ return;
128
+ this.walletAssetsBehavior.autoSelectAfterSearch = options.autoSelectAfterSearch;
129
+ if (!options.autoSelectAfterSearch) {
130
+ this.pendingAutoSelectSearchCodes.clear();
131
+ }
132
+ }
115
133
  /**
116
134
  * 发送事件的辅助方法
117
135
  * 支持使用WalletPassHooks或PaymentHooks
@@ -250,6 +268,25 @@ var WalletPassPaymentImpl = class {
250
268
  refreshedAssets
251
269
  );
252
270
  }
271
+ isPendingAutoSelectAsset(asset) {
272
+ return getWalletAssetCodeKeys(asset).some(
273
+ (code) => this.pendingAutoSelectSearchCodes.has(code)
274
+ );
275
+ }
276
+ clearPendingAutoSelectForAsset(asset) {
277
+ getWalletAssetCodeKeys(asset).forEach((code) => {
278
+ this.pendingAutoSelectSearchCodes.delete(code);
279
+ });
280
+ }
281
+ queuePendingAutoSelectForAssets(assets) {
282
+ if (!this.walletAssetsBehavior.autoSelectAfterSearch)
283
+ return;
284
+ assets.forEach((asset) => {
285
+ getWalletAssetCodeKeys(asset).forEach((code) => {
286
+ this.pendingAutoSelectSearchCodes.add(code);
287
+ });
288
+ });
289
+ }
253
290
  /**
254
291
  * 生成钱包API默认参数
255
292
  * 根据业务数据生成标准的钱包API参数,并存储在模块中
@@ -777,7 +814,12 @@ var WalletPassPaymentImpl = class {
777
814
  );
778
815
  const selectedIds = preserveSelection ? [...this.walletAssetsState.selectedIds] : [];
779
816
  const selectionSources = preserveSelection ? { ...this.walletAssetsState.selectionSources } : {};
817
+ const scanSelectedAssets = preserveSelection ? this.walletAssetsState.selectedItems.filter((asset) => {
818
+ const assetId = getWalletAssetId(asset);
819
+ return assetId !== void 0 && assetId !== null && selectionSources[String(assetId)] === "scan";
820
+ }) : [];
780
821
  if (!((_a = businessData.products) == null ? void 0 : _a.length)) {
822
+ this.queuePendingAutoSelectForAssets(scanSelectedAssets);
781
823
  this.generateWalletParams(businessData);
782
824
  const restoredSearchedAssets = this.searchResults.filter(isWalletPaymentAsset).map((item) => ({
783
825
  ...item,
@@ -882,11 +924,43 @@ var WalletPassPaymentImpl = class {
882
924
  }));
883
925
  const latestSelectedIds = preserveSelection ? authoritativeSelectedIds : [];
884
926
  const latestSelectionSources = preserveSelection ? { ...this.walletAssetsState.selectionSources } : {};
885
- return this.recalculateWalletAssets(
927
+ const pendingAutoSelectAssets = this.walletAssetsBehavior.autoSelectAfterSearch ? items.filter(
928
+ (asset) => this.isPendingAutoSelectAsset(asset) && isWalletAssetAvailable(asset)
929
+ ) : [];
930
+ const requestedKeySet = new Set(
931
+ latestSelectedIds.map((id) => String(id))
932
+ );
933
+ pendingAutoSelectAssets.forEach((asset) => {
934
+ const assetId = getWalletAssetId(asset);
935
+ if (assetId === void 0 || assetId === null)
936
+ return;
937
+ const assetKey = String(assetId);
938
+ if (!requestedKeySet.has(assetKey)) {
939
+ requestedKeySet.add(assetKey);
940
+ latestSelectedIds.push(assetId);
941
+ }
942
+ latestSelectionSources[assetKey] = "scan";
943
+ });
944
+ const nextState = this.recalculateWalletAssets(
886
945
  items,
887
946
  latestSelectedIds,
888
947
  latestSelectionSources
889
948
  );
949
+ const selectedKeySet = new Set(
950
+ nextState.selectedIds.map((id) => String(id))
951
+ );
952
+ pendingAutoSelectAssets.forEach((asset) => {
953
+ const assetId = getWalletAssetId(asset);
954
+ if (assetId !== void 0 && assetId !== null && selectedKeySet.has(String(assetId))) {
955
+ this.clearPendingAutoSelectForAsset(asset);
956
+ }
957
+ });
958
+ const droppedScanSelectedAssets = scanSelectedAssets.filter((asset) => {
959
+ const assetId = getWalletAssetId(asset);
960
+ return assetId !== void 0 && assetId !== null && !selectedKeySet.has(String(assetId));
961
+ });
962
+ this.queuePendingAutoSelectForAssets(droppedScanSelectedAssets);
963
+ return nextState;
890
964
  } catch (error) {
891
965
  if (requestSequence !== this.walletAssetsRequestSequence) {
892
966
  return this.getWalletAssetsState();
@@ -926,6 +1000,9 @@ var WalletPassPaymentImpl = class {
926
1000
  return {
927
1001
  state: this.getWalletAssetsState(),
928
1002
  searchResults: [...this.searchResults],
1003
+ pendingAutoSelectSearchCodes: [
1004
+ ...this.pendingAutoSelectSearchCodes
1005
+ ],
929
1006
  walletParams: this.walletParams ? { ...this.walletParams } : null,
930
1007
  calculationContext: {
931
1008
  orderTotalAmount: this.walletAssetsCalculationContext.orderTotalAmount,
@@ -939,6 +1016,9 @@ var WalletPassPaymentImpl = class {
939
1016
  return this.getWalletAssetsState();
940
1017
  this.walletAssetsRequestSequence += 1;
941
1018
  this.searchResults = Array.isArray(snapshot.searchResults) ? [...snapshot.searchResults] : [];
1019
+ this.pendingAutoSelectSearchCodes = this.walletAssetsBehavior.autoSelectAfterSearch && Array.isArray(snapshot.pendingAutoSelectSearchCodes) ? new Set(
1020
+ snapshot.pendingAutoSelectSearchCodes.map(normalizeWalletAssetCode).filter(Boolean)
1021
+ ) : /* @__PURE__ */ new Set();
942
1022
  this.walletParams = snapshot.walletParams ? { ...snapshot.walletParams } : null;
943
1023
  this.walletAssetsCalculationContext = {
944
1024
  orderTotalAmount: Number(
@@ -957,6 +1037,9 @@ var WalletPassPaymentImpl = class {
957
1037
  }
958
1038
  selectWalletAsset(assetId, options) {
959
1039
  const assetKey = String(assetId);
1040
+ const asset = this.walletAssetsState.items.find(
1041
+ (item) => getWalletAssetKey(item) === assetKey
1042
+ );
960
1043
  const committedKeys = new Set(
961
1044
  this.walletAssetsState.committedIds.map((id) => String(id))
962
1045
  );
@@ -968,20 +1051,23 @@ var WalletPassPaymentImpl = class {
968
1051
  const selectionSources = { ...this.walletAssetsState.selectionSources };
969
1052
  delete selectionSources[assetKey];
970
1053
  if (options.selected) {
971
- const asset = this.walletAssetsState.items.find(
972
- (item) => getWalletAssetKey(item) === assetKey
973
- );
974
1054
  if (!asset || !isWalletAssetAvailable(asset)) {
975
1055
  return this.getWalletAssetsState();
976
1056
  }
977
1057
  selectedIds.push(assetId);
978
1058
  selectionSources[assetKey] = options.source || "manual";
1059
+ } else if (asset) {
1060
+ this.clearPendingAutoSelectForAsset(asset);
979
1061
  }
980
- return this.recalculateWalletAssets(
1062
+ const nextState = this.recalculateWalletAssets(
981
1063
  this.walletAssetsState.items,
982
1064
  selectedIds,
983
1065
  selectionSources
984
1066
  );
1067
+ if (options.selected && asset && nextState.selectedIds.some((id) => String(id) === assetKey)) {
1068
+ this.clearPendingAutoSelectForAsset(asset);
1069
+ }
1070
+ return nextState;
985
1071
  }
986
1072
  async scanWalletAssetAsync(code) {
987
1073
  const normalizedCode = String(code || "").trim();
@@ -1024,24 +1110,34 @@ var WalletPassPaymentImpl = class {
1024
1110
  };
1025
1111
  }
1026
1112
  const items = mergeWalletAssets(this.walletAssetsState.items, [asset]);
1027
- this.recalculateWalletAssets(
1113
+ const recalculatedState = this.recalculateWalletAssets(
1028
1114
  items,
1029
1115
  this.walletAssetsState.selectedIds,
1030
1116
  this.walletAssetsState.selectionSources
1031
1117
  );
1032
1118
  const assetId = getWalletAssetId(asset);
1033
- const selected = assetId !== void 0 && isWalletAssetAvailable(asset) ? this.selectWalletAsset(assetId, {
1119
+ const selected = this.walletAssetsBehavior.autoSelectAfterSearch && assetId !== void 0 && isWalletAssetAvailable(asset) ? this.selectWalletAsset(assetId, {
1034
1120
  selected: true,
1035
1121
  source: "scan"
1036
- }) : this.getWalletAssetsState();
1122
+ }) : recalculatedState;
1123
+ const isSelected = assetId !== void 0 && selected.selectedIds.some((id) => String(id) === String(assetId));
1124
+ if (isSelected) {
1125
+ this.clearPendingAutoSelectForAsset(asset);
1126
+ } else if (this.walletAssetsBehavior.autoSelectAfterSearch) {
1127
+ this.pendingAutoSelectSearchCodes.add(
1128
+ normalizeWalletAssetCode(normalizedCode)
1129
+ );
1130
+ this.queuePendingAutoSelectForAssets([asset]);
1131
+ }
1037
1132
  return {
1038
1133
  type: result.type,
1039
1134
  asset,
1040
- selected: assetId !== void 0 && selected.selectedIds.some((id) => String(id) === String(assetId)),
1135
+ selected: isSelected,
1041
1136
  state: selected
1042
1137
  };
1043
1138
  }
1044
1139
  clearWalletAssetSelection() {
1140
+ this.pendingAutoSelectSearchCodes.clear();
1045
1141
  return this.recalculateWalletAssets(
1046
1142
  this.walletAssetsState.items,
1047
1143
  [],
@@ -1156,6 +1252,7 @@ var WalletPassPaymentImpl = class {
1156
1252
  */
1157
1253
  clearSearchResults() {
1158
1254
  this.searchResults = [];
1255
+ this.pendingAutoSelectSearchCodes.clear();
1159
1256
  this.paymentModule.logInfo("[WalletPass] 搜索结果缓存已清除");
1160
1257
  }
1161
1258
  /**
@@ -1178,6 +1275,7 @@ var WalletPassPaymentImpl = class {
1178
1275
  this.walletRecommendList = [];
1179
1276
  this.userIdentificationCodes = [];
1180
1277
  this.searchResults = [];
1278
+ this.pendingAutoSelectSearchCodes.clear();
1181
1279
  this.walletParams = null;
1182
1280
  this.walletInitData = null;
1183
1281
  this.walletAssetsRequestSequence += 1;
@@ -14,7 +14,7 @@ export { QuotationHooks } from './quotation/types';
14
14
  export { ScheduleModuleEx } from './schedule';
15
15
  export type { ScheduleState, ScheduleItem } from './schedule/types';
16
16
  export { OrderModule } from './order';
17
- export type { OrderState, OrderData, OrderId, OrderSummary, OrderBookingItem, OrderProductLineItem, OrderPaymentItem, OrderSurchargeItem, OrderProductDiscountItem, OrderWithoutBookings, BookingData, OrderFilters, BookingFilters, OrderFilterResult, OrderFilterRejectDetail, OrderFilterRejectedEntry, BookingFilterResult, OrderModulePagedResult, } from './order/types';
17
+ export type { OrderState, OrderData, OrderId, OrderSummary, OrderBookingItem, OrderProductLineItem, OrderPaymentItem, OrderSurchargeItem, OrderProductDiscountItem, OrderWithoutBookings, BookingData, OrderFilters, BookingFilters, OrderFilterResult, OrderFilterRejectDetail, OrderFilterRejectedEntry, BookingFilterResult, OrderModulePagedResult, RemoteProductMembershipChangedPayload, RemoteProductMembershipChangeSource, } from './order/types';
18
18
  export { OrderHooks } from './order/types';
19
19
  export { PaymentServerModule } from './payment';
20
20
  export type { PaymentMethod, PaymentMethodsChangedEventData, PaymentServerState } from './payment/types';
@@ -30,6 +30,10 @@ export declare class OrderModule extends BaseModule implements Module {
30
30
  * await this.emitOrdersChanged([freshOrder], 'pubsub.bodyUpsert')
31
31
  */
32
32
  private emitOrdersChanged;
33
+ /**
34
+ * 广播远端商品成员增删。监听器异常必须与订单落库和原有订单广播隔离。
35
+ */
36
+ private emitRemoteProductMembershipChanges;
33
37
  initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
34
38
  /**
35
39
  * 记录信息日志
@@ -231,6 +235,18 @@ export declare class OrderModule extends BaseModule implements Module {
231
235
  */
232
236
  private lookupOrderIndexByIdentityKeys;
233
237
  private isRemoteEchoMergeSource;
238
+ private getProductMembershipKey;
239
+ private doProductsHaveStableMembershipIdentity;
240
+ /**
241
+ * 冲突提示关注逻辑商品行,而不是服务端 checkout 过程中可能被重建的 detail 记录。
242
+ * 通用集合合并仍以 order_detail_id 为事实主键;这里只允许相同稳定 UID 跨 detail id 对齐,
243
+ * 避免本机 checkout 回声被误判成“一删一增”。
244
+ */
245
+ private isSameProductMembershipItem;
246
+ /**
247
+ * 对比合并前后的商品成员集合。商品字段修改与数组重排不会产生 diff。
248
+ */
249
+ private getRemoteProductMembershipChange;
234
250
  /**
235
251
  * 将订单的全部身份键登记到索引并指向其在列表中的下标。
236
252
  * 合并后订单新增的身份字段(如挂单同步后拿到 order_id)也会被登记。