@pisell/pisellos 2.2.183 → 2.2.184

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.
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
311
311
  date: string;
312
312
  status: string;
313
313
  week: string;
314
- weekNum: 0 | 1 | 2 | 6 | 3 | 5 | 4;
314
+ weekNum: 0 | 5 | 1 | 4 | 2 | 3 | 6;
315
315
  }[]>;
316
316
  submitTimeSlot(timeSlots: TimeSliceItem): void;
317
317
  private getScheduleDataByIds;
@@ -929,6 +929,7 @@ export var BookingTicketImpl = /*#__PURE__*/function (_BaseSalesImpl) {
929
929
  return;
930
930
  }
931
931
  var previousCustomerId = (_this$store$order$get3 = this.store.order.getOrderCustomer()) === null || _this$store$order$get3 === void 0 ? void 0 : _this$store$order$get3.customer_id;
932
+ var snapshotBeforeSet = this.store.order.getOrderCustomerSnapshot();
932
933
  var patch = formatOrderCustomerPatch(customer);
933
934
  var customerUnchanged = Number(previousCustomerId || 0) === Number(patch.customer_id || 0);
934
935
  if (!customerUnchanged) {
@@ -936,7 +937,15 @@ export var BookingTicketImpl = /*#__PURE__*/function (_BaseSalesImpl) {
936
937
  this.hasManualDiscountSelection = false;
937
938
  }
938
939
  this.store.order.setOrderCustomer(patch, customer);
940
+ var snapshotAfterOrderSet = this.store.order.getOrderCustomerSnapshot();
939
941
  if (customerUnchanged) {
942
+ // hydrate 后 customer_id 已存在但 _extend.customerSnapshot 仍为空时,
943
+ // 须通知 SalesSdk 刷新 selected(否则会一直停在 onSalesOrderLoaded 时的 null)。
944
+ var snapshotReplenished = !snapshotBeforeSet && Boolean(snapshotAfterOrderSet);
945
+ if (snapshotReplenished) {
946
+ var _next2 = this.buildOrderCustomerPayload();
947
+ this.core.effects.emit("".concat(this.name, ":onOrderCustomerChange"), _next2);
948
+ }
940
949
  return;
941
950
  }
942
951
  var next = this.buildOrderCustomerPayload();
@@ -528,7 +528,8 @@ var PromotionEvaluator = class {
528
528
  return b.price - a.price;
529
529
  });
530
530
  const totalUnits = unitProducts.length;
531
- const groupCount = cumulative ? Math.floor(totalUnits / x) : totalUnits >= x ? 1 : 0;
531
+ const isCumulative = cumulative !== false;
532
+ const groupCount = isCumulative ? Math.floor(totalUnits / x) : totalUnits >= x ? 1 : 0;
532
533
  const promotionUnits = groupCount * x;
533
534
  const inPromotionUnits = unitProducts.slice(0, promotionUnits);
534
535
  const notInPromotionUnits = unitProducts.slice(promotionUnits);
@@ -0,0 +1,49 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // src/model/strategy/adapter/promotion/index.ts
30
+ var promotion_exports = {};
31
+ __export(promotion_exports, {
32
+ BUY_X_GET_Y_FREE_STRATEGY: () => import_examples.BUY_X_GET_Y_FREE_STRATEGY,
33
+ PromotionAdapter: () => import_adapter.PromotionAdapter,
34
+ PromotionEvaluator: () => import_evaluator.PromotionEvaluator,
35
+ X_ITEMS_FOR_Y_PRICE_STRATEGY: () => import_examples.X_ITEMS_FOR_Y_PRICE_STRATEGY,
36
+ default: () => import_adapter2.default
37
+ });
38
+ module.exports = __toCommonJS(promotion_exports);
39
+ var import_evaluator = require("./evaluator");
40
+ var import_adapter = require("./adapter");
41
+ var import_adapter2 = __toESM(require("./adapter"));
42
+ var import_examples = require("./examples");
43
+ // Annotate the CommonJS export names for ESM import in node:
44
+ 0 && (module.exports = {
45
+ BUY_X_GET_Y_FREE_STRATEGY,
46
+ PromotionAdapter,
47
+ PromotionEvaluator,
48
+ X_ITEMS_FOR_Y_PRICE_STRATEGY
49
+ });
@@ -312,6 +312,8 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
312
312
  recalcOnHydrate?: boolean;
313
313
  }): Promise<OrderTempOrder>;
314
314
  private normalizeTempOrderForRuntime;
315
+ private normalizeHydratedProductOptionItem;
316
+ private resolveHydratedProductOptions;
315
317
  private normalizeHydratedOrderProduct;
316
318
  getLastOrderInfo(): Record<string, any> | undefined;
317
319
  getOrderInfo(order_id: number): Promise<any>;
@@ -1443,7 +1443,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1443
1443
  productToAdd.product_option_item,
1444
1444
  productToAdd.product_bundle
1445
1445
  );
1446
- const normalizedIncoming = (0, import_utils3.normalizeOrderProduct)(productToAdd);
1446
+ const normalizedIncoming = (0, import_utils.mergeOrderProductDisplayFields)(
1447
+ productToAdd,
1448
+ (0, import_utils3.normalizeOrderProduct)(productToAdd)
1449
+ );
1447
1450
  normalizedIncoming.discount_list = (0, import_utils.normalizeOrderProductDiscountList)(
1448
1451
  normalizedIncoming.discount_list
1449
1452
  );
@@ -1496,13 +1499,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1496
1499
  } else {
1497
1500
  const targetProduct = matchedProduct;
1498
1501
  const targetUid = (_a = targetProduct.metadata) == null ? void 0 : _a.unique_identification_number;
1499
- const normalizedProduct = (0, import_utils3.normalizeOrderProduct)({
1500
- ...productToAdd,
1501
- metadata: {
1502
- ...productToAdd.metadata || {},
1503
- unique_identification_number: targetUid
1504
- }
1505
- });
1502
+ const normalizedProduct = (0, import_utils.mergeOrderProductDisplayFields)(
1503
+ targetProduct,
1504
+ (0, import_utils3.normalizeOrderProduct)({
1505
+ ...productToAdd,
1506
+ metadata: {
1507
+ ...productToAdd.metadata || {},
1508
+ unique_identification_number: targetUid
1509
+ }
1510
+ })
1511
+ );
1506
1512
  normalizedProduct.discount_list = (0, import_utils.normalizeOrderProductDiscountList)(
1507
1513
  normalizedProduct.discount_list
1508
1514
  );
@@ -1621,7 +1627,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1621
1627
  delete nextProduct.metadata.main_product_original_price;
1622
1628
  delete nextProduct.metadata.price_schema_version;
1623
1629
  }
1624
- let normalizedProduct = (0, import_utils3.normalizeOrderProduct)(nextProduct);
1630
+ let normalizedProduct = (0, import_utils.mergeOrderProductDisplayFields)(
1631
+ nextProduct,
1632
+ (0, import_utils3.normalizeOrderProduct)(nextProduct)
1633
+ );
1625
1634
  normalizedProduct.discount_list = (0, import_utils.normalizeOrderProductDiscountList)(
1626
1635
  normalizedProduct.discount_list
1627
1636
  );
@@ -2240,7 +2249,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2240
2249
  async getOrderInfoByRemote(order_id) {
2241
2250
  const res = await this.request.get(`/order/sales/${order_id}`, {
2242
2251
  with: ["products", "bookings", "payments", "customer", "summary", "contacts_info"]
2243
- });
2252
+ }, { osServer: true });
2244
2253
  if (res.code === 200) {
2245
2254
  this.store.lastOrderInfo = res.data;
2246
2255
  }
@@ -2265,6 +2274,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2265
2274
  return nextTempOrder;
2266
2275
  }
2267
2276
  normalizeTempOrderForRuntime(raw, options) {
2277
+ var _a, _b;
2268
2278
  const nextTempOrder = {
2269
2279
  ...this.createDefaultTempOrderInstance(),
2270
2280
  ...raw || {}
@@ -2284,7 +2294,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2284
2294
  delete nextTempOrder.holder_id;
2285
2295
  nextTempOrder.metadata = raw.metadata && typeof raw.metadata === "object" ? { ...raw.metadata } : {};
2286
2296
  nextTempOrder.holder = raw.holder && typeof raw.holder === "object" ? { ...raw.holder } : null;
2287
- nextTempOrder.products = Array.isArray(raw.products) ? raw.products.map((p) => this.normalizeHydratedOrderProduct(p)) : [];
2297
+ const rawProducts = Array.isArray(raw.products) ? raw.products : [];
2298
+ nextTempOrder.products = rawProducts.length > 0 ? rawProducts.map((p) => this.normalizeHydratedOrderProduct(p)) : [];
2288
2299
  nextTempOrder.bookings = Array.isArray(raw.bookings) ? raw.bookings.map((b) => ({
2289
2300
  ...b || {},
2290
2301
  is_all: (0, import_utils.normalizeBookingIsAll)(b || {}),
@@ -2299,19 +2310,57 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2299
2310
  ...raw._extend,
2300
2311
  productsByUid: raw._extend.productsByUid || {}
2301
2312
  } : { productsByUid: {} };
2313
+ const tempOrderExtend = nextTempOrder._extend;
2314
+ const productsByUid = tempOrderExtend.productsByUid || {};
2315
+ for (const [index, product] of nextTempOrder.products.entries()) {
2316
+ const uid = (_a = product.metadata) == null ? void 0 : _a.unique_identification_number;
2317
+ if (!uid)
2318
+ continue;
2319
+ const existed = productsByUid[uid] && typeof productsByUid[uid] === "object" ? productsByUid[uid] : {};
2320
+ const rawProduct = rawProducts[index] && typeof rawProducts[index] === "object" ? rawProducts[index] : product;
2321
+ const origin = existed.origin ?? rawProduct._origin ?? ((_b = rawProduct.metadata) == null ? void 0 : _b.origin) ?? rawProduct;
2322
+ productsByUid[uid] = {
2323
+ ...existed,
2324
+ origin: (0, import_lodash_es.cloneDeep)(origin)
2325
+ };
2326
+ }
2327
+ tempOrderExtend.productsByUid = productsByUid;
2302
2328
  if ((options == null ? void 0 : options.ensureIdentity) !== false) {
2303
2329
  this.ensureExternalSaleNumber(nextTempOrder);
2304
2330
  }
2305
2331
  nextTempOrder.vouchers = raw.vouchers || [];
2306
2332
  return nextTempOrder;
2307
2333
  }
2334
+ normalizeHydratedProductOptionItem(optionItem) {
2335
+ const rawNum = (optionItem == null ? void 0 : optionItem.num) ?? (optionItem == null ? void 0 : optionItem.quantity) ?? 1;
2336
+ const parsedNum = Number(rawNum);
2337
+ const rawPrice = (optionItem == null ? void 0 : optionItem.price) ?? (optionItem == null ? void 0 : optionItem.add_price) ?? 0;
2338
+ const parsedPrice = Number(rawPrice);
2339
+ return {
2340
+ option_group_item_id: optionItem == null ? void 0 : optionItem.option_group_item_id,
2341
+ option_group_id: optionItem == null ? void 0 : optionItem.option_group_id,
2342
+ num: Number.isFinite(parsedNum) && parsedNum > 0 ? parsedNum : 1,
2343
+ price: Number.isFinite(parsedPrice) ? parsedPrice : 0
2344
+ };
2345
+ }
2346
+ resolveHydratedProductOptions(row) {
2347
+ var _a;
2348
+ if (Array.isArray(row.product_option_item) && row.product_option_item.length > 0) {
2349
+ return row.product_option_item;
2350
+ }
2351
+ const skuOptions = (_a = row.product_sku) == null ? void 0 : _a.option;
2352
+ if (!Array.isArray(skuOptions))
2353
+ return [];
2354
+ return skuOptions.map(
2355
+ (optionItem) => this.normalizeHydratedProductOptionItem(optionItem || {})
2356
+ );
2357
+ }
2308
2358
  normalizeHydratedOrderProduct(product) {
2309
2359
  const row = { ...product || {} };
2310
2360
  if (row.num === void 0 && row.product_quantity !== void 0) {
2311
2361
  row.num = row.product_quantity;
2312
2362
  }
2313
- if (!Array.isArray(row.product_option_item))
2314
- row.product_option_item = [];
2363
+ row.product_option_item = this.resolveHydratedProductOptions(row);
2315
2364
  if (!Array.isArray(row.product_bundle))
2316
2365
  row.product_bundle = [];
2317
2366
  if (!row.metadata || typeof row.metadata !== "object")
@@ -2327,6 +2376,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2327
2376
  const result = {
2328
2377
  ...row,
2329
2378
  ...normalized,
2379
+ product_sku: row.product_sku,
2330
2380
  metadata: {
2331
2381
  ...row.metadata,
2332
2382
  ...normalized.metadata
@@ -397,6 +397,7 @@ export interface SubmitSalesOrderParams {
397
397
  products: OrderSubmitProduct[];
398
398
  bookings: OrderSubmitBooking[];
399
399
  payments: any[];
400
+ vouchers: any[];
400
401
  surcharges?: any[];
401
402
  relation_forms: any[];
402
403
  form_record_ids?: OrderSubmitFormRecord[];
@@ -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
  }
@@ -430,7 +430,6 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
430
430
  throw new Error("order 模块未初始化");
431
431
  const params = typeof orderIdOrParams === "object" ? orderIdOrParams : { orderId: orderIdOrParams };
432
432
  const externalSaleNumber = params.externalSaleNumber || params.external_sale_number;
433
- debugger;
434
433
  if (!params.forceRemote) {
435
434
  const localRecord = params.orderId !== void 0 ? await this.store.order.getLocalOrderByOrderId(params.orderId) : externalSaleNumber ? await this.store.order.getLocalOrderByExternalSaleNumber(externalSaleNumber) : params.orderNumber ? await this.store.order.getLocalOrderByOrderNumber(params.orderNumber) : null;
436
435
  if (localRecord) {
@@ -176,6 +176,18 @@ export declare function getOrderProductOriginalPriceForPromotion(product: any):
176
176
  export declare function mergeIdenticalPromotionCartLines(products: any[]): any[];
177
177
  /** 获取行 uid(统一以 `metadata.unique_identification_number` 为唯一键) */
178
178
  export declare function getOrderProductUid(product: any): string;
179
+ /**
180
+ * 促销评估前合并同 SKU 拆分行(含促销/原价行),避免加购后仅前 2 件享受优惠。
181
+ * 带 `booking_uid` 的预约行不参与合并(每次加车独立 booking + 商品行)。
182
+ *
183
+ * @example
184
+ * consolidateMainProductsForPromotion([
185
+ * { item: promoLineNum2, originalListIndex: 0 },
186
+ * { item: regularLineNum2, originalListIndex: 1 },
187
+ * ]);
188
+ * // => 单行 num=4,清除 _promotion 后重新评估
189
+ */
190
+ export declare function buildConsolidateKeyForPromotion(item: any): string;
179
191
  /**
180
192
  * 从策略配置的 product_match 规则提取可参与商品列表。
181
193
  *
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  var cartPromotion_exports = {};
31
31
  __export(cartPromotion_exports, {
32
32
  appendPromotionTags: () => appendPromotionTags,
33
+ buildConsolidateKeyForPromotion: () => buildConsolidateKeyForPromotion,
33
34
  calculateUnfulfilledPromotions: () => calculateUnfulfilledPromotions,
34
35
  extractProductMatchIdentifiersFromStrategyConfig: () => extractProductMatchIdentifiersFromStrategyConfig,
35
36
  getOrderProductBasePrice: () => getOrderProductBasePrice,
@@ -151,7 +152,7 @@ function resolveXItemsExpectedUnitPrice(promotion, sourceCartNum) {
151
152
  return Number(new import_decimal.default(y).div(x).toDecimalPlaces(2).toFixed(2));
152
153
  }
153
154
  function mergeIdenticalPromotionCartLines(products) {
154
- var _a, _b, _c;
155
+ var _a, _b, _c, _d;
155
156
  if (!Array.isArray(products) || products.length <= 1) {
156
157
  return [...products || []];
157
158
  }
@@ -177,10 +178,12 @@ function mergeIdenticalPromotionCartLines(products) {
177
178
  const promoUnitPrice = String(
178
179
  promotion.finalPrice ?? ((_c = line.metadata) == null ? void 0 : _c.main_product_selling_price) ?? ""
179
180
  );
181
+ const bookingUid = (line == null ? void 0 : line.booking_uid) ?? ((_d = line == null ? void 0 : line.metadata) == null ? void 0 : _d.booking_uid);
180
182
  const mergeKey = [
181
183
  line.product_id,
182
184
  line.product_variant_id ?? 0,
183
185
  fingerprint,
186
+ bookingUid ? String(bookingUid) : "",
184
187
  promotion.strategyId,
185
188
  unitPrice,
186
189
  promoUnitPrice
@@ -197,7 +200,7 @@ function mergeIdenticalPromotionCartLines(products) {
197
200
  return merged;
198
201
  }
199
202
  function dedupePromotionProcessedLines(lines) {
200
- var _a, _b, _c, _d, _e, _f, _g;
203
+ var _a, _b, _c, _d, _e, _f, _g, _h;
201
204
  if (!Array.isArray(lines) || lines.length <= 1)
202
205
  return [...lines || []];
203
206
  const passthrough = [];
@@ -263,9 +266,24 @@ function dedupePromotionProcessedLines(lines) {
263
266
  return promotionDelta(line) > promotionDelta(best) ? line : best;
264
267
  }, pool[0]);
265
268
  }
266
- winner.num = (0, import_utils2.getSafeProductNum)(sourceCartNum || winner.num || 1);
269
+ const winnerIsXItems = getPromotionActionType((_c = winner.metadata) == null ? void 0 : _c._promotion) === X_ITEMS_FOR_Y_PRICE;
270
+ if (winnerIsXItems) {
271
+ const xItemsGroupLines = group.filter(
272
+ (line) => {
273
+ var _a2;
274
+ return getPromotionActionType((_a2 = line.metadata) == null ? void 0 : _a2._promotion) === X_ITEMS_FOR_Y_PRICE;
275
+ }
276
+ );
277
+ const evaluatedPromoQty = xItemsGroupLines.reduce(
278
+ (sum, line) => sum + Number(line.num || 0),
279
+ 0
280
+ );
281
+ winner.num = (0, import_utils2.getSafeProductNum)(evaluatedPromoQty || winner.num || 1);
282
+ } else {
283
+ winner.num = (0, import_utils2.getSafeProductNum)(sourceCartNum || winner.num || 1);
284
+ }
267
285
  const recomputeUnit = resolveXItemsExpectedUnitPrice(
268
- (_c = winner.metadata) == null ? void 0 : _c._promotion,
286
+ (_d = winner.metadata) == null ? void 0 : _d._promotion,
269
287
  sourceCartNum
270
288
  );
271
289
  if (recomputeUnit != null) {
@@ -273,13 +291,13 @@ function dedupePromotionProcessedLines(lines) {
273
291
  applyPromoUnitPriceToLine(winner, {
274
292
  promoUnitPrice: recomputeUnit,
275
293
  originalBasePrice: Number(promo.originalPrice),
276
- strategyTitle: (_d = promo.strategyMetadata) == null ? void 0 : _d.name
294
+ strategyTitle: (_e = promo.strategyMetadata) == null ? void 0 : _e.name
277
295
  });
278
296
  promo.finalPrice = recomputeUnit;
279
297
  }
280
298
  for (const line of group) {
281
- const giftInfo = (_f = (_e = line.metadata) == null ? void 0 : _e._promotion) == null ? void 0 : _f.giftInfo;
282
- if (giftInfo && ((_g = winner.metadata) == null ? void 0 : _g._promotion) && !winner.metadata._promotion.giftInfo) {
299
+ const giftInfo = (_g = (_f = line.metadata) == null ? void 0 : _f._promotion) == null ? void 0 : _g.giftInfo;
300
+ if (giftInfo && ((_h = winner.metadata) == null ? void 0 : _h._promotion) && !winner.metadata._promotion.giftInfo) {
283
301
  winner.metadata._promotion.giftInfo = giftInfo;
284
302
  }
285
303
  }
@@ -309,12 +327,93 @@ function getProductBundleForEvaluator(product) {
309
327
  _bundle_product_id: (b == null ? void 0 : b._bundle_product_id) ?? (b == null ? void 0 : b.bundle_product_id) ?? (b == null ? void 0 : b.product_id)
310
328
  }));
311
329
  }
330
+ function buildConsolidateKeyForPromotion(item) {
331
+ var _a;
332
+ const fingerprint = (0, import_utils2.buildProductLineFingerprint)(
333
+ item.product_option_item,
334
+ item.product_bundle
335
+ );
336
+ const bookingUid = (item == null ? void 0 : item.booking_uid) ?? ((_a = item == null ? void 0 : item.metadata) == null ? void 0 : _a.booking_uid);
337
+ if (bookingUid !== void 0 && bookingUid !== null && String(bookingUid) !== "") {
338
+ return [
339
+ item.product_id,
340
+ item.product_variant_id ?? 0,
341
+ fingerprint,
342
+ String(bookingUid)
343
+ ].join("#");
344
+ }
345
+ return [item.product_id, item.product_variant_id ?? 0, fingerprint].join("#");
346
+ }
347
+ function consolidateMainProductsForPromotion(entries) {
348
+ if (!Array.isArray(entries) || entries.length <= 1) {
349
+ return [...entries || []];
350
+ }
351
+ const groups = /* @__PURE__ */ new Map();
352
+ for (const { item, originalListIndex } of entries) {
353
+ const key = buildConsolidateKeyForPromotion(item);
354
+ const existing = groups.get(key);
355
+ if (!existing) {
356
+ const mergedItem = (0, import_lodash_es.cloneDeep)(item);
357
+ const metadata = mergedItem.metadata || {};
358
+ delete metadata._promotion;
359
+ mergedItem.metadata = metadata;
360
+ if (Array.isArray(mergedItem.product_bundle)) {
361
+ for (const bundle of mergedItem.product_bundle) {
362
+ if (bundle && typeof bundle === "object")
363
+ delete bundle._promotion;
364
+ }
365
+ }
366
+ groups.set(key, { item: mergedItem, originalListIndex });
367
+ continue;
368
+ }
369
+ existing.item.num = (0, import_utils2.getSafeProductNum)(
370
+ Number(existing.item.num || 0) + Number(item.num || 0)
371
+ );
372
+ }
373
+ return Array.from(groups.values());
374
+ }
375
+ function splitXItemsPromoLinesByGroup(lines, strategyActionMap) {
376
+ var _a;
377
+ const result = [];
378
+ for (const line of lines) {
379
+ const promo = (_a = line == null ? void 0 : line.metadata) == null ? void 0 : _a._promotion;
380
+ if (!(promo == null ? void 0 : promo.inPromotion) || !promo.strategyId) {
381
+ result.push(line);
382
+ continue;
383
+ }
384
+ if (getPromotionActionType(promo) !== X_ITEMS_FOR_Y_PRICE) {
385
+ result.push(line);
386
+ continue;
387
+ }
388
+ const actionMeta = strategyActionMap.get(promo.strategyId);
389
+ const detail = (actionMeta == null ? void 0 : actionMeta.actionDetail) ?? promo.actionDetail;
390
+ const x = Number(detail == null ? void 0 : detail.x);
391
+ const num = Number(line.num || 0);
392
+ const isCumulative = (detail == null ? void 0 : detail.cumulative) !== false;
393
+ if (!isCumulative || !Number.isFinite(x) || x <= 0 || num <= x || num % x !== 0) {
394
+ result.push(line);
395
+ continue;
396
+ }
397
+ const groupCount = num / x;
398
+ for (let i = 0; i < groupCount; i++) {
399
+ const splitLine = (0, import_lodash_es.cloneDeep)(line);
400
+ splitLine.num = (0, import_utils2.getSafeProductNum)(x);
401
+ splitLine.metadata = {
402
+ ...splitLine.metadata || {},
403
+ unique_identification_number: (0, import_utils.createUuidV4)()
404
+ };
405
+ result.push(splitLine);
406
+ }
407
+ }
408
+ return result;
409
+ }
312
410
  function generateNumericId() {
313
411
  return Math.floor(Math.random() * 1e9) + Date.now();
314
412
  }
315
413
  function convertToPromotionProduct(product, index) {
316
414
  const metadata = (product == null ? void 0 : product.metadata) || {};
317
415
  const numericId = generateNumericId();
416
+ const originalItem = product;
318
417
  return {
319
418
  id: numericId,
320
419
  product_id: Number((product == null ? void 0 : product.product_id) ?? 0) || 0,
@@ -323,7 +422,7 @@ function convertToPromotionProduct(product, index) {
323
422
  price: getOrderProductOriginalPriceForPromotion(product),
324
423
  quantity: Number((product == null ? void 0 : product.num) ?? 1) || 1,
325
424
  bundle: getProductBundleForEvaluator(product),
326
- _originalItem: product,
425
+ _originalItem: originalItem,
327
426
  _originalId: getOrderProductUid(product),
328
427
  _originalIndex: index
329
428
  };
@@ -548,7 +647,10 @@ function processCartPromotion(list, evaluator, options) {
548
647
  mainProductsWithIndex.push({ item, originalListIndex: i });
549
648
  }
550
649
  }
551
- const mainProducts = mainProductsWithIndex.map((x) => x.item);
650
+ const consolidatedMainProductsWithIndex = consolidateMainProductsForPromotion(
651
+ mainProductsWithIndex
652
+ );
653
+ const mainProducts = consolidatedMainProductsWithIndex.map((x) => x.item);
552
654
  const existingGifts = existingGiftsWithIndex.map((x) => x.item);
553
655
  if (mainProducts.length === 0) {
554
656
  const editProducts = editProductsWithIndex.map((x) => x.item);
@@ -574,7 +676,7 @@ function processCartPromotion(list, evaluator, options) {
574
676
  }
575
677
  const promotionProducts = [];
576
678
  const originalItemMap = /* @__PURE__ */ new Map();
577
- const productsForStrategies = mainProductsWithIndex.map(({ item }, i) => {
679
+ const productsForStrategies = consolidatedMainProductsWithIndex.map(({ item }, i) => {
578
680
  var _a2;
579
681
  return {
580
682
  id: i,
@@ -586,8 +688,8 @@ function processCartPromotion(list, evaluator, options) {
586
688
  bundle: getProductBundleForEvaluator(item)
587
689
  };
588
690
  });
589
- for (let i = 0; i < mainProductsWithIndex.length; i++) {
590
- const { item, originalListIndex } = mainProductsWithIndex[i];
691
+ for (let i = 0; i < consolidatedMainProductsWithIndex.length; i++) {
692
+ const { item, originalListIndex } = consolidatedMainProductsWithIndex[i];
591
693
  const promotionProduct = convertToPromotionProduct(item, originalListIndex);
592
694
  promotionProducts.push(promotionProduct);
593
695
  originalItemMap.set(promotionProduct.id, { item, index: originalListIndex });
@@ -765,6 +867,8 @@ function processCartPromotion(list, evaluator, options) {
765
867
  processedProducts.splice(0, processedProducts.length, ...dedupedPromotionLines);
766
868
  const mergedPromotionLines = mergeIdenticalPromotionCartLines(processedProducts);
767
869
  processedProducts.splice(0, processedProducts.length, ...mergedPromotionLines);
870
+ const splitPromoLines = splitXItemsPromoLinesByGroup(processedProducts, strategyActionMap);
871
+ processedProducts.splice(0, processedProducts.length, ...splitPromoLines);
768
872
  for (const product of processedProducts) {
769
873
  const metadata = product.metadata || {};
770
874
  if (metadata._promotion)
@@ -812,6 +916,7 @@ function processCartPromotion(list, evaluator, options) {
812
916
  delete product._sortIndex;
813
917
  delete product._sortSubIndex;
814
918
  delete product._originalProductUid;
919
+ delete product._sourceCartNum;
815
920
  }
816
921
  return {
817
922
  products: processedProducts,
@@ -824,6 +929,7 @@ function processCartPromotion(list, evaluator, options) {
824
929
  // Annotate the CommonJS export names for ESM import in node:
825
930
  0 && (module.exports = {
826
931
  appendPromotionTags,
932
+ buildConsolidateKeyForPromotion,
827
933
  calculateUnfulfilledPromotions,
828
934
  extractProductMatchIdentifiersFromStrategyConfig,
829
935
  getOrderProductBasePrice,
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
311
311
  date: string;
312
312
  status: string;
313
313
  week: string;
314
- weekNum: 0 | 1 | 2 | 6 | 3 | 5 | 4;
314
+ weekNum: 0 | 5 | 1 | 4 | 2 | 3 | 6;
315
315
  }[]>;
316
316
  submitTimeSlot(timeSlots: TimeSliceItem): void;
317
317
  private getScheduleDataByIds;
@@ -520,6 +520,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
520
520
  return;
521
521
  }
522
522
  const previousCustomerId = (_a = this.store.order.getOrderCustomer()) == null ? void 0 : _a.customer_id;
523
+ const snapshotBeforeSet = this.store.order.getOrderCustomerSnapshot();
523
524
  const patch = (0, import_orderCustomer.formatOrderCustomerPatch)(customer);
524
525
  const customerUnchanged = Number(previousCustomerId || 0) === Number(patch.customer_id || 0);
525
526
  if (!customerUnchanged) {
@@ -527,7 +528,13 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
527
528
  this.hasManualDiscountSelection = false;
528
529
  }
529
530
  this.store.order.setOrderCustomer(patch, customer);
531
+ const snapshotAfterOrderSet = this.store.order.getOrderCustomerSnapshot();
530
532
  if (customerUnchanged) {
533
+ const snapshotReplenished = !snapshotBeforeSet && Boolean(snapshotAfterOrderSet);
534
+ if (snapshotReplenished) {
535
+ const next2 = this.buildOrderCustomerPayload();
536
+ this.core.effects.emit(`${this.name}:onOrderCustomerChange`, next2);
537
+ }
531
538
  return;
532
539
  }
533
540
  const next = this.buildOrderCustomerPayload();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "2.2.183",
4
+ "version": "2.2.184",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",