@pisell/pisellos 2.3.18 → 2.3.19

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.
@@ -441,7 +441,19 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
441
441
  * 加车两阶段主决策(规格弹窗 / 资源编辑 / 直接加车)。
442
442
  * 与 ticketBooking `handleSelectProduct` + `handleBooking4Service` 等价。
443
443
  */
444
- decideAddProduct(item: any, options?: Partial<AddProductDecideContext>): import("./utils/addProductDecision").AddProductDecision;
444
+ decideAddProduct(item: any, options?: Partial<AddProductDecideContext>): {
445
+ action: "reloadCatalog";
446
+ } | {
447
+ action: "add";
448
+ cacheItem: any;
449
+ } | {
450
+ action: "requiresDetail";
451
+ payload: AddProductRequiresDetailPayload;
452
+ } | {
453
+ action: "requiresBookingEdit";
454
+ cacheItem: any;
455
+ payload: import("./utils/addProductDecision").AddProductRequiresBookingEditPayload;
456
+ };
445
457
  /** 规格弹窗 callback 后的第二段决策。 */
446
458
  decideAfterDetail(cacheItem: any, options?: Partial<AddProductDecideContext>): import("./utils/addProductDecision").AddProductDecision;
447
459
  /**
@@ -84,7 +84,9 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
84
84
  unavailableReasonKey?: string | null;
85
85
  scannedDiscountList?: Discount[];
86
86
  }>;
87
- applyDiscount(): void;
87
+ applyDiscount(options?: {
88
+ reapplyBookingDiscountProductUids?: string[];
89
+ }): void;
88
90
  /**
89
91
  * 注入促销评估器。
90
92
  *
@@ -107,7 +107,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
107
107
  this.draftPersistEnabled = true;
108
108
  }
109
109
  collectHydratedEditDiscounts(products) {
110
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
110
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
111
111
  const discountMap = /* @__PURE__ */ new Map();
112
112
  for (const product of (0, import_bundleDiscountHydration.expandHydratedProductsForDiscountCollection)(products)) {
113
113
  for (const item of (product == null ? void 0 : product.discount_list) || []) {
@@ -137,6 +137,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
137
137
  existed.amount = Number(existed.amount || 0) + amount;
138
138
  existed.used_par_value = String(Number(existed.used_par_value || 0) + amount);
139
139
  existed.balance = String(Number(existed.balance || 0) + amount);
140
+ const productIds = Array.isArray((_f = existed.limited_relation_product_data) == null ? void 0 : _f.product_ids) ? existed.limited_relation_product_data.product_ids : [];
141
+ if ((product == null ? void 0 : product.product_id) !== void 0 && (product == null ? void 0 : product.product_id) !== null && !productIds.includes(product.product_id)) {
142
+ existed.limited_relation_product_data = {
143
+ ...existed.limited_relation_product_data || {},
144
+ product_ids: [...productIds, product.product_id]
145
+ };
146
+ }
140
147
  existed.applicableProductDetails = [
141
148
  ...existed.applicableProductDetails || [],
142
149
  detail
@@ -153,9 +160,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
153
160
  encoded: "",
154
161
  code: "",
155
162
  tag: type,
156
- product_id: ((_f = item == null ? void 0 : item.discount) == null ? void 0 : _f.discount_product_id) ?? (product == null ? void 0 : product.product_id) ?? 0,
163
+ product_id: ((_g = item == null ? void 0 : item.discount) == null ? void 0 : _g.discount_product_id) ?? (product == null ? void 0 : product.product_id) ?? 0,
157
164
  relation_type: "",
158
- par_value: String(((_g = item == null ? void 0 : item.discount) == null ? void 0 : _g.original_amount) ?? (item == null ? void 0 : item.amount) ?? "0"),
165
+ par_value: String(((_h = item == null ? void 0 : item.discount) == null ? void 0 : _h.original_amount) ?? (item == null ? void 0 : item.amount) ?? "0"),
159
166
  used_par_value: String((item == null ? void 0 : item.amount) ?? "0"),
160
167
  limit_status: "enable",
161
168
  limited_relation_product_data: {
@@ -185,8 +192,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
185
192
  discount: {
186
193
  ...(item == null ? void 0 : item.discount) || {},
187
194
  resource_id: key,
188
- discount_product_id: ((_h = item == null ? void 0 : item.discount) == null ? void 0 : _h.discount_product_id) ?? (product == null ? void 0 : product.product_id) ?? 0,
189
- discount_calculation_mode: ((_i = item == null ? void 0 : item.discount) == null ? void 0 : _i.discount_calculation_mode) ?? "item_level"
195
+ discount_product_id: ((_i = item == null ? void 0 : item.discount) == null ? void 0 : _i.discount_product_id) ?? (product == null ? void 0 : product.product_id) ?? 0,
196
+ discount_calculation_mode: ((_j = item == null ? void 0 : item.discount) == null ? void 0 : _j.discount_calculation_mode) ?? "item_level"
190
197
  },
191
198
  applicableProductDetails: [detail],
192
199
  appliedProductDetails: [detail]
@@ -539,7 +546,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
539
546
  unavailableReason
540
547
  };
541
548
  }
542
- applyDiscount() {
549
+ applyDiscount(options) {
543
550
  var _a, _b, _c, _d;
544
551
  const tempOrder = this.store.tempOrder;
545
552
  if (!tempOrder)
@@ -560,6 +567,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
560
567
  holders,
561
568
  isFormSubject: (product) => (0, import_utils.resolveIsFormSubject)(tempOrder, product),
562
569
  orderTotalAmount: Number(((_c = this.store.summary) == null ? void 0 : _c.total_amount) || 0)
570
+ }, {
571
+ reapplyBookingDiscountProductUids: options == null ? void 0 : options.reapplyBookingDiscountProductUids
563
572
  });
564
573
  if (result == null ? void 0 : result.productList) {
565
574
  const previousProductsByUid = (0, import_utils.indexOrderProductsByUid)(tempOrder.products);
@@ -2974,7 +2983,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2974
2983
  });
2975
2984
  }
2976
2985
  applyOrderProductUpdateToTempOrder(tempOrder, params) {
2977
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
2986
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
2978
2987
  const {
2979
2988
  product_id,
2980
2989
  product_variant_id,
@@ -3128,12 +3137,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3128
3137
  tempOrder.products[productIndex],
3129
3138
  (_q = tempOrder.products[productIndex].metadata) == null ? void 0 : _q.unique_identification_number
3130
3139
  );
3140
+ return (_r = tempOrder.products[productIndex].metadata) == null ? void 0 : _r.unique_identification_number;
3131
3141
  }
3132
3142
  async updateOrderProduct(params) {
3133
3143
  const tempOrder = this.ensureTempOrder();
3134
- this.applyOrderProductUpdateToTempOrder(tempOrder, params);
3144
+ const updatedProductUid = this.applyOrderProductUpdateToTempOrder(tempOrder, params);
3135
3145
  await this.applyPromotion();
3136
- this.applyDiscount();
3146
+ this.applyDiscount({
3147
+ reapplyBookingDiscountProductUids: params.allow_booking_discount_reapply && updatedProductUid ? [String(updatedProductUid)] : void 0
3148
+ });
3137
3149
  this.sanitizeTempOrderProducts(tempOrder);
3138
3150
  await this.recalculateSummary({ createIfMissing: true });
3139
3151
  this.persistTempOrder();
@@ -340,6 +340,19 @@ export interface UpdateOrderProductParams {
340
340
  * });
341
341
  */
342
342
  allow_booking_reprice?: boolean;
343
+ /**
344
+ * Change time 重报价后,允许当前预约商品行重新应用已选编辑态折扣卡。
345
+ *
346
+ * @example
347
+ * await order.updateOrderProduct({
348
+ * product_id: 1,
349
+ * product_variant_id: 0,
350
+ * updates: { discount_list: [] },
351
+ * booking: { duration: 2 },
352
+ * allow_booking_discount_reapply: true,
353
+ * });
354
+ */
355
+ allow_booking_discount_reapply?: boolean;
343
356
  }
344
357
  /** 仅更新购物车行数量;行定位语义与 updateOrderProduct / removeProductFromOrder 保持一致 */
345
358
  export interface UpdateOrderProductQuantityParams extends OrderProductIdentity {
@@ -49,5 +49,5 @@ export declare class Product extends BaseModule implements Module {
49
49
  getCategories(): ProductCategory[];
50
50
  setOtherParams(key: string, value: any): void;
51
51
  getOtherParams(): any;
52
- getProductType(): "duration" | "session" | "normal";
52
+ getProductType(): "normal" | "duration" | "session";
53
53
  }
@@ -1,8 +1,7 @@
1
1
  import { Module, PisellCore, ModuleOptions } from '../../types';
2
2
  import { BaseModule } from '../BaseModule';
3
- import { Rules, RulesModuleAPI, DiscountResult, RulesFormSubject, UnavailableReason } from './types';
3
+ import { Rules, RulesModuleAPI, DiscountResult, RulesFormSubject, RulesCalcDiscountOptions, UnavailableReason } from './types';
4
4
  import { Discount } from '../Discount/types';
5
- import { SetDiscountSelectedParams } from '../../solution/ShopDiscount/types';
6
5
  import { WindowPlugin } from '../../plugins';
7
6
  export declare class RulesModule extends BaseModule implements Module, RulesModuleAPI {
8
7
  protected defaultName: string;
@@ -45,12 +44,7 @@ export declare class RulesModule extends BaseModule implements Module, RulesModu
45
44
  }[];
46
45
  isFormSubject: RulesFormSubject;
47
46
  orderTotalAmount: number;
48
- }, options?: {
49
- isSelected?: boolean;
50
- discountId?: number;
51
- selectedList?: SetDiscountSelectedParams[];
52
- scan?: boolean;
53
- }): DiscountResult;
47
+ }, options?: RulesCalcDiscountOptions): DiscountResult;
54
48
  /**
55
49
  * 检查优惠是否符合 PackageSubItemUsageRules 配置
56
50
  * @param discount 优惠券
@@ -209,6 +209,36 @@ var RulesModule = class extends import_BaseModule.BaseModule {
209
209
  var _a;
210
210
  const resolveIsFormSubject = (product) => typeof isFormSubject === "function" ? Boolean(isFormSubject(product)) : Boolean(isFormSubject);
211
211
  const isEditModeAddNewProduct = productList.find((n) => n.booking_id) && productList.find((n) => !n.booking_id);
212
+ const reapplyBookingDiscountProductUids = new Set(
213
+ ((options == null ? void 0 : options.reapplyBookingDiscountProductUids) || []).filter((uid) => uid !== void 0 && uid !== null && uid !== "").map(String)
214
+ );
215
+ const getOriginProductUid = (originProduct) => {
216
+ var _a2;
217
+ const uid = ((_a2 = originProduct == null ? void 0 : originProduct.metadata) == null ? void 0 : _a2.unique_identification_number) ?? (originProduct == null ? void 0 : originProduct.unique_identification_number);
218
+ if (uid === void 0 || uid === null || uid === "")
219
+ return void 0;
220
+ return String(uid);
221
+ };
222
+ const shouldReapplyBookingDiscount = (originProduct, selectedDiscount) => {
223
+ if (!selectedDiscount)
224
+ return false;
225
+ const uid = getOriginProductUid(originProduct);
226
+ if (!uid || !reapplyBookingDiscountProductUids.has(uid))
227
+ return false;
228
+ const discountType = selectedDiscount.tag || selectedDiscount.type;
229
+ return selectedDiscount.isEditMode === true && selectedDiscount.isSelected === true && ["good_pass", "discount_card", "product_discount_card"].includes(discountType);
230
+ };
231
+ const resolveReapplyEditModeDiscountPercent = (originProduct, selectedDiscount) => {
232
+ var _a2;
233
+ if (!shouldReapplyBookingDiscount(originProduct, selectedDiscount))
234
+ return void 0;
235
+ const discountType = (selectedDiscount == null ? void 0 : selectedDiscount.tag) || (selectedDiscount == null ? void 0 : selectedDiscount.type);
236
+ if (discountType !== "discount_card" && discountType !== "product_discount_card") {
237
+ return void 0;
238
+ }
239
+ const percent = Number((_a2 = selectedDiscount.discount) == null ? void 0 : _a2.percent);
240
+ return Number.isFinite(percent) ? percent : void 0;
241
+ };
212
242
  const editModeDiscount = [];
213
243
  const addModeDiscount = [];
214
244
  discountList.forEach((discount) => {
@@ -232,9 +262,6 @@ var RulesModule = class extends import_BaseModule.BaseModule {
232
262
  }
233
263
  });
234
264
  }
235
- const filteredDiscountList = addModeDiscount.filter((discount) => {
236
- return !discount.isManualSelect;
237
- });
238
265
  const hasDiscountInput = editModeDiscount.length > 0 || addModeDiscount.length > 0 || Boolean(options == null ? void 0 : options.discountId) || Boolean((_a = options == null ? void 0 : options.selectedList) == null ? void 0 : _a.length) || Boolean(options == null ? void 0 : options.scan);
239
266
  if (!hasDiscountInput) {
240
267
  return {
@@ -242,6 +269,14 @@ var RulesModule = class extends import_BaseModule.BaseModule {
242
269
  productList
243
270
  };
244
271
  }
272
+ const canUseEditModeDiscountForReapply = (discount) => {
273
+ const discountType = discount.tag || discount.type;
274
+ return reapplyBookingDiscountProductUids.size > 0 && discount.isEditMode === true && discount.isSelected === true && ["good_pass", "discount_card", "product_discount_card"].includes(discountType);
275
+ };
276
+ const filteredDiscountList = [
277
+ ...addModeDiscount.filter((discount) => !discount.isManualSelect),
278
+ ...editModeDiscount.filter(canUseEditModeDiscountForReapply)
279
+ ];
245
280
  const flattenProductsWithBundle = (productList2) => {
246
281
  const flattened = [];
247
282
  productList2.forEach((originProduct) => {
@@ -737,9 +772,18 @@ var RulesModule = class extends import_BaseModule.BaseModule {
737
772
  const applicableDiscounts = sortedDiscountList.filter((discount) => {
738
773
  var _a3, _b2, _c2, _d2;
739
774
  const discountType = discount.tag || discount.type;
775
+ const currentOriginUid = getOriginProductUid(originProduct);
776
+ const isReapplyEditModeDiscountForProduct = discount.isEditMode && reapplyBookingDiscountProductUids.size > 0 && currentOriginUid && reapplyBookingDiscountProductUids.has(String(currentOriginUid)) && discount.isSelected === true;
777
+ if (discount.isEditMode && reapplyBookingDiscountProductUids.size > 0) {
778
+ const uid = currentOriginUid;
779
+ if (!uid || !reapplyBookingDiscountProductUids.has(uid))
780
+ return false;
781
+ if (!discount.isSelected)
782
+ return false;
783
+ }
740
784
  if (["good_pass", "discount_card", "product_discount_card"].includes(
741
785
  discountType
742
- )) {
786
+ ) && !isReapplyEditModeDiscountForProduct) {
743
787
  if (discount.config === void 0 || !((_a3 = discount == null ? void 0 : discount.config) == null ? void 0 : _a3.isAvailable)) {
744
788
  return false;
745
789
  }
@@ -955,7 +999,8 @@ var RulesModule = class extends import_BaseModule.BaseModule {
955
999
  }
956
1000
  return;
957
1001
  }
958
- if (applicableDiscounts.length && product.booking_id && typeof selectedDiscount.isManualSelect === "undefined" && !(options == null ? void 0 : options.scan) && !isEditModeAddNewProduct) {
1002
+ const shouldReapplyBookingDiscountForProduct = shouldReapplyBookingDiscount(originProduct, selectedDiscount);
1003
+ if (applicableDiscounts.length && product.booking_id && typeof selectedDiscount.isManualSelect === "undefined" && !(options == null ? void 0 : options.scan) && !isEditModeAddNewProduct && !shouldReapplyBookingDiscountForProduct) {
959
1004
  return;
960
1005
  }
961
1006
  const isNeedSplit = (selectedDiscount.tag || selectedDiscount.type) === "good_pass";
@@ -1011,10 +1056,16 @@ var RulesModule = class extends import_BaseModule.BaseModule {
1011
1056
  let productDiscountDifference;
1012
1057
  let discountedOptions = product.options;
1013
1058
  let optionDiscountAmount = 0;
1059
+ let reapplyDiscountPercent;
1014
1060
  if (isOrderLevel && productAllocation) {
1015
1061
  amount = productAllocation.discountAmount;
1016
1062
  productDiscountDifference = productAllocation.difference;
1017
1063
  mainProductSellingPrice = Math.max(new import_decimal.default(product.price).minus(amount).toNumber(), 0);
1064
+ } else if (resolveReapplyEditModeDiscountPercent(originProduct, selectedDiscount2) !== void 0) {
1065
+ const percent = resolveReapplyEditModeDiscountPercent(originProduct, selectedDiscount2);
1066
+ reapplyDiscountPercent = new import_decimal.default(percent).toFixed(2);
1067
+ mainProductSellingPrice = new import_decimal.default(product.price || 0).mul(new import_decimal.default(100).minus(percent)).div(100).toDecimalPlaces(2).toNumber();
1068
+ amount = new import_decimal.default(product.price).minus(mainProductSellingPrice).toNumber();
1018
1069
  } else {
1019
1070
  mainProductSellingPrice = (0, import_utils.getDiscountAmount)(
1020
1071
  selectedDiscount2,
@@ -1049,7 +1100,7 @@ var RulesModule = class extends import_BaseModule.BaseModule {
1049
1100
  title: selectedDiscount2.format_title,
1050
1101
  original_amount: product.price,
1051
1102
  product_id: originProduct.id || originProduct.product_id,
1052
- percent: selectedDiscount2.par_value,
1103
+ percent: reapplyDiscountPercent ?? selectedDiscount2.par_value,
1053
1104
  discount_product_id: selectedDiscount2.product_id
1054
1105
  },
1055
1106
  // 前端使用的num数量,为了计算优惠金额
@@ -1,4 +1,5 @@
1
1
  import { Discount } from '../Discount/types';
2
+ import { SetDiscountSelectedParams } from '../../solution/ShopDiscount/types';
2
3
  export declare enum UnavailableReason {
3
4
  TimeLimit = "time_limit",
4
5
  ProductNotApplicable = "product_not_applicable",
@@ -23,6 +24,14 @@ export interface DiscountResult {
23
24
  discountList: any[];
24
25
  }
25
26
  export type RulesFormSubject = boolean | ((product: any) => boolean);
27
+ export interface RulesCalcDiscountOptions {
28
+ isSelected?: boolean;
29
+ discountId?: number;
30
+ selectedList?: SetDiscountSelectedParams[];
31
+ scan?: boolean;
32
+ /** Change time 重报价目标行:允许已选编辑态折扣卡重新应用到这些 booking 商品。 */
33
+ reapplyBookingDiscountProductUids?: string[];
34
+ }
26
35
  export interface RulesModuleAPI {
27
36
  setRulesList: (rulesList: Rules[]) => Promise<void>;
28
37
  clear: () => Promise<void>;
@@ -34,7 +43,7 @@ export interface RulesModuleAPI {
34
43
  }[];
35
44
  isFormSubject: RulesFormSubject;
36
45
  orderTotalAmount: number;
37
- }) => DiscountResult;
46
+ }, options?: RulesCalcDiscountOptions) => DiscountResult;
38
47
  }
39
48
  type ProductDetail = {
40
49
  isClient?: boolean;
@@ -308,12 +308,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
308
308
  };
309
309
  }
310
310
  updateCreateStore() {
311
- var _a;
312
311
  const appPlugin = this.core.getPlugin("app");
313
312
  const app = appPlugin == null ? void 0 : appPlugin.getApp();
314
313
  if (app) {
315
314
  const coreData = app.data.store.getStore().getDataByModel("core");
316
- 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) {
317
316
  const today = (0, import_dayjs.default)();
318
317
  if (coreData == null ? void 0 : coreData.core.operating_day_boundary) {
319
318
  const operatingDayBoundary = coreData.core.operating_day_boundary;
@@ -49,6 +49,9 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
49
49
  private queuedAutoPaymentSync;
50
50
  private autoPaymentSyncFlushing;
51
51
  private autoPaymentSyncTimer;
52
+ private salesDetailLoadInFlight;
53
+ private serverOrderChangeUnsubscribe;
54
+ private serverOrderChangeHydrateInFlight;
52
55
  constructor(name?: string, version?: string);
53
56
  /**
54
57
  * 子类可覆盖此方法以追加/收敛要注册的子模块。
@@ -69,6 +72,9 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
69
72
  * 记录错误日志
70
73
  */
71
74
  private logError;
75
+ private isCurrentSalesOrderRecord;
76
+ private syncCurrentSalesDetailFromServerOrderChange;
77
+ private registerServerOrderChangeSync;
72
78
  private hydrateOrderPaymentNames;
73
79
  get payment(): PaymentModule | undefined;
74
80
  private getCurrentOrderCustomerId;
@@ -45,6 +45,7 @@ __reExport(BaseSales_exports, require("./types"), module.exports);
45
45
  var import_Quotation = require("../../modules/Quotation");
46
46
  var import_transformBaseProductToOrderProduct = require("./utils/transformBaseProductToOrderProduct");
47
47
  var import_quotationPrice = require("./utils/quotationPrice");
48
+ var SERVER_ORDER_CHANGED_EVENT = "order:onOrdersChanged";
48
49
  function isBaseSalesManualProductDiscountProduct(product) {
49
50
  var _a, _b;
50
51
  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");
@@ -82,6 +83,18 @@ function getBaseSalesUniqueArrayMetadataKey(key) {
82
83
  return "unique_payment_number";
83
84
  return null;
84
85
  }
86
+ function isSameBaseSalesOrderRecord(left, right) {
87
+ if (!left || !right || typeof left !== "object" || typeof right !== "object")
88
+ return false;
89
+ const leftIdentities = new Set(
90
+ [left.order_id, left.id, left.external_sale_number, left.order_number].filter((value) => value !== void 0 && value !== null && value !== "").map(String)
91
+ );
92
+ if (leftIdentities.size === 0)
93
+ return false;
94
+ return [right.order_id, right.id, right.external_sale_number, right.order_number].some(
95
+ (value) => value !== void 0 && value !== null && value !== "" && leftIdentities.has(String(value))
96
+ );
97
+ }
85
98
  function getBaseSalesMetadataUid(item, metadataKey) {
86
99
  var _a;
87
100
  const uid = ((_a = item == null ? void 0 : item.metadata) == null ? void 0 : _a[metadataKey]) ?? (item == null ? void 0 : item[metadataKey]);
@@ -159,6 +172,9 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
159
172
  this.queuedAutoPaymentSync = false;
160
173
  this.autoPaymentSyncFlushing = false;
161
174
  this.autoPaymentSyncTimer = null;
175
+ this.salesDetailLoadInFlight = false;
176
+ this.serverOrderChangeUnsubscribe = null;
177
+ this.serverOrderChangeHydrateInFlight = null;
162
178
  }
163
179
  /**
164
180
  * 子类可覆盖此方法以追加/收敛要注册的子模块。
@@ -223,6 +239,53 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
223
239
  });
224
240
  }
225
241
  }
242
+ isCurrentSalesOrderRecord(order) {
243
+ var _a, _b;
244
+ const currentTempOrder = (_b = (_a = this.store.order) == null ? void 0 : _a.getTempOrder) == null ? void 0 : _b.call(_a);
245
+ const currentRecords = [
246
+ currentTempOrder,
247
+ this.currentSalesDetail
248
+ ].filter(Boolean);
249
+ return currentRecords.some((record) => isSameBaseSalesOrderRecord(record, order));
250
+ }
251
+ async syncCurrentSalesDetailFromServerOrderChange(payload) {
252
+ const changedOrders = Array.isArray(payload) ? payload : Array.isArray(payload == null ? void 0 : payload.changedOrders) ? payload.changedOrders : (payload == null ? void 0 : payload.data) && typeof payload.data === "object" ? [payload.data] : [];
253
+ if (this.salesDetailLoadInFlight || this.serverOrderChangeHydrateInFlight)
254
+ return;
255
+ const changedOrder = changedOrders.find(
256
+ (order) => this.isCurrentSalesOrderRecord(order)
257
+ );
258
+ if (!changedOrder)
259
+ return;
260
+ if (!this.store.order)
261
+ return;
262
+ this.serverOrderChangeHydrateInFlight = (async () => {
263
+ const sales = await this.store.order.hydrateTempOrderFromRecord(changedOrder, {
264
+ recalcOnHydrate: false
265
+ });
266
+ this.currentSalesDetail = sales;
267
+ await this.core.effects.emit(`${this.name}:onSalesOrderLoaded`, { sales });
268
+ })();
269
+ try {
270
+ await this.serverOrderChangeHydrateInFlight;
271
+ } finally {
272
+ this.serverOrderChangeHydrateInFlight = null;
273
+ }
274
+ }
275
+ registerServerOrderChangeSync() {
276
+ var _a, _b;
277
+ (_a = this.serverOrderChangeUnsubscribe) == null ? void 0 : _a.call(this);
278
+ const effects = (_b = this.core) == null ? void 0 : _b.effects;
279
+ if (!effects || typeof effects.on !== "function")
280
+ return;
281
+ this.serverOrderChangeUnsubscribe = effects.on(SERVER_ORDER_CHANGED_EVENT, (payload) => {
282
+ void this.syncCurrentSalesDetailFromServerOrderChange(payload).catch((error) => {
283
+ this.logError("sync sales detail from server order change failed", {
284
+ error: error instanceof Error ? error.message : String(error)
285
+ });
286
+ });
287
+ });
288
+ }
226
289
  hydrateOrderPaymentNames(payments) {
227
290
  if (!payments.length)
228
291
  return [];
@@ -637,9 +700,13 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
637
700
  );
638
701
  }
639
702
  await this.getPaymentMethodsAsync();
703
+ this.registerServerOrderChangeSync();
640
704
  this.core.effects.emit(`${this.name}:onInited`, {});
641
705
  }
642
706
  async destroy() {
707
+ var _a;
708
+ (_a = this.serverOrderChangeUnsubscribe) == null ? void 0 : _a.call(this);
709
+ this.serverOrderChangeUnsubscribe = null;
643
710
  Object.keys(this.store).forEach((key) => {
644
711
  if (this.reusedSharedSubModuleNames.has(key))
645
712
  return;
@@ -666,30 +733,35 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
666
733
  async loadSalesDetail(orderIdOrParams) {
667
734
  if (!this.store.order)
668
735
  throw new Error("order 模块未初始化");
669
- const params = typeof orderIdOrParams === "object" ? orderIdOrParams : { orderId: orderIdOrParams };
670
- const externalSaleNumber = params.externalSaleNumber || params.external_sale_number;
671
- const preloadedSalesDetail = params.preloadedSalesDetail;
672
- const lookup = params.orderId ?? externalSaleNumber ?? params.orderNumber ?? (preloadedSalesDetail == null ? void 0 : preloadedSalesDetail.order_id) ?? (preloadedSalesDetail == null ? void 0 : preloadedSalesDetail.external_sale_number) ?? (preloadedSalesDetail == null ? void 0 : preloadedSalesDetail.order_number);
673
- if (!preloadedSalesDetail && (lookup === void 0 || lookup === null || lookup === "")) {
674
- throw new Error("加载销售详情需要 orderIdexternalSaleNumber orderNumber");
675
- }
676
- const loadedRecord = preloadedSalesDetail ?? await this.store.order.getSalesOrderByLookup({
677
- lookup,
678
- forceRemote: params.forceRemote
679
- });
680
- if (!preloadedSalesDetail && (!loadedRecord || loadedRecord.code !== 200)) {
681
- const message = loadedRecord && (loadedRecord.message || loadedRecord.msg) || `加载销售详情失败: ${lookup}`;
682
- throw new Error(message);
683
- }
684
- const remoteRecord = preloadedSalesDetail ?? loadedRecord.data;
685
- const currentTempOrder = params.merge ? this.store.order.getTempOrder() : null;
686
- const record = params.merge ? mergeSalesDetailRecordWithTempOrder(currentTempOrder, remoteRecord) : remoteRecord;
687
- const sales = await this.store.order.hydrateTempOrderFromRecord(record, {
688
- recalcOnHydrate: false
689
- });
690
- this.currentSalesDetail = sales;
691
- await this.core.effects.emit(`${this.name}:onSalesOrderLoaded`, { sales });
692
- return sales;
736
+ this.salesDetailLoadInFlight = true;
737
+ try {
738
+ const params = typeof orderIdOrParams === "object" ? orderIdOrParams : { orderId: orderIdOrParams };
739
+ const externalSaleNumber = params.externalSaleNumber || params.external_sale_number;
740
+ const preloadedSalesDetail = params.preloadedSalesDetail;
741
+ const lookup = params.orderId ?? externalSaleNumber ?? params.orderNumber ?? (preloadedSalesDetail == null ? void 0 : preloadedSalesDetail.order_id) ?? (preloadedSalesDetail == null ? void 0 : preloadedSalesDetail.external_sale_number) ?? (preloadedSalesDetail == null ? void 0 : preloadedSalesDetail.order_number);
742
+ if (!preloadedSalesDetail && (lookup === void 0 || lookup === null || lookup === "")) {
743
+ throw new Error("加载销售详情需要 orderId、externalSaleNumber orderNumber");
744
+ }
745
+ const loadedRecord = preloadedSalesDetail ?? await this.store.order.getSalesOrderByLookup({
746
+ lookup,
747
+ forceRemote: params.forceRemote
748
+ });
749
+ if (!preloadedSalesDetail && (!loadedRecord || loadedRecord.code !== 200)) {
750
+ const message = loadedRecord && (loadedRecord.message || loadedRecord.msg) || `加载销售详情失败: ${lookup}`;
751
+ throw new Error(message);
752
+ }
753
+ const remoteRecord = preloadedSalesDetail ?? loadedRecord.data;
754
+ const currentTempOrder = params.merge ? this.store.order.getTempOrder() : null;
755
+ const record = params.merge ? mergeSalesDetailRecordWithTempOrder(currentTempOrder, remoteRecord) : remoteRecord;
756
+ const sales = await this.store.order.hydrateTempOrderFromRecord(record, {
757
+ recalcOnHydrate: false
758
+ });
759
+ this.currentSalesDetail = sales;
760
+ await this.core.effects.emit(`${this.name}:onSalesOrderLoaded`, { sales });
761
+ return sales;
762
+ } finally {
763
+ this.salesDetailLoadInFlight = false;
764
+ }
693
765
  }
694
766
  /** 获取当前已加载的销售详情(只读快照)。未加载过则返回 null。 */
695
767
  getSalesOrder() {
@@ -441,7 +441,19 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
441
441
  * 加车两阶段主决策(规格弹窗 / 资源编辑 / 直接加车)。
442
442
  * 与 ticketBooking `handleSelectProduct` + `handleBooking4Service` 等价。
443
443
  */
444
- decideAddProduct(item: any, options?: Partial<AddProductDecideContext>): import("./utils/addProductDecision").AddProductDecision;
444
+ decideAddProduct(item: any, options?: Partial<AddProductDecideContext>): {
445
+ action: "reloadCatalog";
446
+ } | {
447
+ action: "add";
448
+ cacheItem: any;
449
+ } | {
450
+ action: "requiresDetail";
451
+ payload: AddProductRequiresDetailPayload;
452
+ } | {
453
+ action: "requiresBookingEdit";
454
+ cacheItem: any;
455
+ payload: import("./utils/addProductDecision").AddProductRequiresBookingEditPayload;
456
+ };
445
457
  /** 规格弹窗 callback 后的第二段决策。 */
446
458
  decideAfterDetail(cacheItem: any, options?: Partial<AddProductDecideContext>): import("./utils/addProductDecision").AddProductDecision;
447
459
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "2.3.18",
4
+ "version": "2.3.19",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",