@pisell/pisellos 2.3.150 → 2.3.151

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 (43) hide show
  1. package/dist/model/strategy/adapter/itemRule/adapter.d.ts +3 -1
  2. package/dist/model/strategy/adapter/itemRule/adapter.js +74 -7
  3. package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +3 -1
  4. package/dist/model/strategy/adapter/itemRule/evaluator.js +13 -0
  5. package/dist/model/strategy/adapter/itemRule/type.d.ts +40 -1
  6. package/dist/model/strategy/adapter/itemRule/type.js +10 -0
  7. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  8. package/dist/modules/OpenData/types.d.ts +2 -0
  9. package/dist/modules/Order/index.d.ts +4 -2
  10. package/dist/modules/Order/index.js +115 -67
  11. package/dist/modules/Order/types.d.ts +7 -1
  12. package/dist/modules/Product/index.d.ts +1 -1
  13. package/dist/solution/BaseSales/fulfillmentItemRules.d.ts +27 -0
  14. package/dist/solution/BaseSales/fulfillmentItemRules.js +750 -0
  15. package/dist/solution/BaseSales/index.d.ts +5 -1
  16. package/dist/solution/BaseSales/index.js +1116 -1021
  17. package/dist/solution/BaseSales/pickupTiming.d.ts +2 -0
  18. package/dist/solution/BaseSales/pickupTiming.js +16 -5
  19. package/dist/solution/BookingByStep/index.d.ts +2 -2
  20. package/dist/solution/BookingTicket/index.d.ts +1 -0
  21. package/dist/solution/BookingTicket/index.js +444 -425
  22. package/lib/model/strategy/adapter/itemRule/adapter.d.ts +3 -1
  23. package/lib/model/strategy/adapter/itemRule/adapter.js +54 -4
  24. package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +3 -1
  25. package/lib/model/strategy/adapter/itemRule/evaluator.js +9 -0
  26. package/lib/model/strategy/adapter/itemRule/type.d.ts +40 -1
  27. package/lib/model/strategy/adapter/itemRule/type.js +10 -0
  28. package/lib/model/strategy/adapter/promotion/index.js +46 -1
  29. package/lib/modules/OpenData/types.d.ts +2 -0
  30. package/lib/modules/Order/index.d.ts +4 -2
  31. package/lib/modules/Order/index.js +33 -14
  32. package/lib/modules/Order/types.d.ts +7 -1
  33. package/lib/modules/Product/index.d.ts +1 -1
  34. package/lib/solution/BaseSales/fulfillmentItemRules.d.ts +27 -0
  35. package/lib/solution/BaseSales/fulfillmentItemRules.js +259 -0
  36. package/lib/solution/BaseSales/index.d.ts +5 -1
  37. package/lib/solution/BaseSales/index.js +38 -2
  38. package/lib/solution/BaseSales/pickupTiming.d.ts +2 -0
  39. package/lib/solution/BaseSales/pickupTiming.js +5 -1
  40. package/lib/solution/BookingByStep/index.d.ts +2 -2
  41. package/lib/solution/BookingTicket/index.d.ts +1 -0
  42. package/lib/solution/BookingTicket/index.js +3 -0
  43. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import type { EvaluationResult, RuntimeContext, ActionEffect } from '../../type';
2
2
  import type { BusinessAdapter } from '../type';
3
- import { type ItemRuleBusinessData, type QuantityCheckResult, type PrefillItemResult, type QuantityLimitResult, type AllergyRequirement } from './type';
3
+ import { type ItemRuleBusinessData, type ItemRuleCartAction, type QuantityCheckResult, type PrefillItemResult, type QuantityLimitResult, type AllergyRequirement } from './type';
4
4
  /**
5
5
  * ItemRule 适配器
6
6
  *
@@ -14,6 +14,7 @@ export declare class ItemRuleAdapter implements BusinessAdapter {
14
14
  transformResult(result: EvaluationResult, businessData?: ItemRuleBusinessData): {
15
15
  quantityChecks: QuantityCheckResult[];
16
16
  prefillItems: PrefillItemResult[];
17
+ cartActions: ItemRuleCartAction[];
17
18
  allergyRequirements: AllergyRequirement[];
18
19
  };
19
20
  private processAllergyCheck;
@@ -66,5 +67,6 @@ export declare class ItemRuleAdapter implements BusinessAdapter {
66
67
  * 根据 quantityFrom 计算预填数量
67
68
  */
68
69
  private resolvePrefillQuantity;
70
+ private processDeleteProduct;
69
71
  }
70
72
  export default ItemRuleAdapter;
@@ -50,11 +50,13 @@ class ItemRuleAdapter {
50
50
  transformResult(result, businessData) {
51
51
  const quantityChecks = [];
52
52
  const prefillItems = [];
53
+ const cartActions = [];
53
54
  const allergyRequirements = [];
54
55
  if (!result.applicable || !businessData) {
55
56
  return {
56
57
  quantityChecks,
57
58
  prefillItems,
59
+ cartActions,
58
60
  allergyRequirements
59
61
  };
60
62
  }
@@ -66,7 +68,27 @@ class ItemRuleAdapter {
66
68
  }
67
69
  } else if (action.type === _type.ITEM_RULE_ACTION_TYPES.PREFILL_CART) {
68
70
  const items = this.processPrefillCart(action, businessData);
69
- prefillItems.push(...items);
71
+ prefillItems.push(...items.filter(item => item.quantity > 0));
72
+ if (items.length) {
73
+ cartActions.push({
74
+ type: _type.ITEM_RULE_ACTION_TYPES.PREFILL_CART,
75
+ strategyId: result.config.metadata.id,
76
+ ruleId: action.id,
77
+ priority: action.priority ?? 0,
78
+ products: items
79
+ });
80
+ }
81
+ } else if (action.type === _type.ITEM_RULE_ACTION_TYPES.DELETE_PRODUCT) {
82
+ const products = this.processDeleteProduct(action, businessData);
83
+ if (products.length) {
84
+ cartActions.push({
85
+ type: _type.ITEM_RULE_ACTION_TYPES.DELETE_PRODUCT,
86
+ strategyId: result.config.metadata.id,
87
+ ruleId: action.id,
88
+ priority: action.priority ?? 0,
89
+ products
90
+ });
91
+ }
70
92
  } else if (action.type === _type.ITEM_RULE_ACTION_TYPES.ALLERGY_CHECK) {
71
93
  const requirement = this.processAllergyCheck(action, result, businessData);
72
94
  if (requirement) allergyRequirements.push(requirement);
@@ -75,6 +97,7 @@ class ItemRuleAdapter {
75
97
  return {
76
98
  quantityChecks,
77
99
  prefillItems,
100
+ cartActions,
78
101
  allergyRequirements
79
102
  };
80
103
  }
@@ -423,16 +446,24 @@ class ItemRuleAdapter {
423
446
 
424
447
  processPrefillCart(action, businessData) {
425
448
  const config = action.config;
426
- if (!config?.products) return [];
449
+ if (!Array.isArray(config?.products)) return [];
450
+ if (config.scope !== businessData.executionScope) return [];
451
+ if (config.scope === 'set_handover' && action.target !== 'cart') return [];
427
452
  const results = [];
428
453
  for (const prefillProduct of config.products) {
429
454
  const quantity = this.resolvePrefillQuantity(prefillProduct.quantityFrom, prefillProduct.quantity, businessData);
430
- if (quantity <= 0) continue;
455
+ const shouldSyncZero = config.scope === 'set_handover' && prefillProduct.repeat_skip === true;
456
+ if (!Number.isFinite(quantity) || quantity < 0 || quantity === 0 && !shouldSyncZero) {
457
+ continue;
458
+ }
431
459
  results.push({
432
460
  ruleId: action.id,
433
461
  product_id: prefillProduct.product_id,
434
462
  product_variant_id: prefillProduct.product_variant_id,
435
- quantity
463
+ quantity,
464
+ ...(prefillProduct.repeat_skip !== undefined ? {
465
+ repeat_skip: prefillProduct.repeat_skip === true
466
+ } : {})
436
467
  });
437
468
  }
438
469
  return results;
@@ -449,10 +480,29 @@ class ItemRuleAdapter {
449
480
  return businessData.pax.adult;
450
481
  case 'fixed':
451
482
  return fixedValue ?? 0;
483
+ case 'main_product_number':
484
+ {
485
+ const mainProductNumber = businessData.mainProductNumber ?? 0;
486
+ return Number.isFinite(mainProductNumber) ? Math.max(0, mainProductNumber) : 0;
487
+ }
452
488
  default:
453
489
  return fixedValue ?? 0;
454
490
  }
455
491
  }
492
+ processDeleteProduct(action, businessData) {
493
+ const config = action.config;
494
+ if (action.target !== 'cart' || config?.scope !== 'set_handover' || config.scope !== businessData.executionScope || !Array.isArray(config.products)) {
495
+ return [];
496
+ }
497
+ const productIds = new Set();
498
+ for (const product of config.products) {
499
+ const productId = Number(product?.product_id);
500
+ if (Number.isInteger(productId) && productId > 0) productIds.add(productId);
501
+ }
502
+ return Array.from(productIds, product_id => ({
503
+ product_id
504
+ }));
505
+ }
456
506
  }
457
507
  exports.ItemRuleAdapter = ItemRuleAdapter;
458
508
  var _default = exports.default = ItemRuleAdapter;
@@ -1,5 +1,5 @@
1
1
  import type { StrategyConfig } from '../../type';
2
- import { type ItemRuleBusinessData, type ItemRuleEvaluationResult, type QuantityCheckResult, type QuantityLimitResult, type PrefillItemResult, type AllergyRequirement } from './type';
2
+ import { type ItemRuleBusinessData, type ItemRuleEvaluationResult, type QuantityCheckResult, type QuantityLimitResult, type PrefillItemResult, type ItemRuleCartAction, type AllergyRequirement } from './type';
3
3
  /**
4
4
  * ItemRule 评估器
5
5
  *
@@ -47,4 +47,6 @@ export declare class ItemRuleEvaluator {
47
47
  * 便捷方法:仅获取需要预填到购物车的商品
48
48
  */
49
49
  getPrefillItems(businessData: ItemRuleBusinessData): PrefillItemResult[];
50
+ /** 获取按优先级排序的购物车动作,交由销售业务层执行。 */
51
+ getCartActions(businessData: ItemRuleBusinessData): ItemRuleCartAction[];
50
52
  }
@@ -43,6 +43,7 @@ class ItemRuleEvaluator {
43
43
  const configs = businessData.strategyConfigs ? businessData.strategyConfigs.filter(c => c.metadata.type === 'item_rule') : this.strategyConfigs;
44
44
  const allQuantityChecks = [];
45
45
  const allPrefillItems = [];
46
+ const allCartActions = [];
46
47
  const allAllergyRequirements = [];
47
48
  const rawResults = [];
48
49
  const context = this.adapter.prepareContext(businessData);
@@ -52,16 +53,19 @@ class ItemRuleEvaluator {
52
53
  const {
53
54
  quantityChecks,
54
55
  prefillItems,
56
+ cartActions,
55
57
  allergyRequirements
56
58
  } = this.adapter.transformResult(evalResult, businessData);
57
59
  allQuantityChecks.push(...quantityChecks);
58
60
  allPrefillItems.push(...prefillItems);
61
+ allCartActions.push(...cartActions);
59
62
  allAllergyRequirements.push(...allergyRequirements);
60
63
  }
61
64
  const failedChecks = allQuantityChecks.filter(c => !c.passed);
62
65
  return {
63
66
  quantityChecks: allQuantityChecks,
64
67
  prefillItems: allPrefillItems,
68
+ cartActions: allCartActions.sort((left, right) => right.priority - left.priority),
65
69
  allergyRequirements: allAllergyRequirements,
66
70
  allPassed: failedChecks.length === 0,
67
71
  failedChecks,
@@ -130,5 +134,10 @@ class ItemRuleEvaluator {
130
134
  const result = this.evaluate(businessData);
131
135
  return result.prefillItems;
132
136
  }
137
+
138
+ /** 获取按优先级排序的购物车动作,交由销售业务层执行。 */
139
+ getCartActions(businessData) {
140
+ return this.evaluate(businessData).cartActions;
141
+ }
133
142
  }
134
143
  exports.ItemRuleEvaluator = ItemRuleEvaluator;
@@ -4,6 +4,8 @@ export declare const ITEM_RULE_ACTION_TYPES: {
4
4
  readonly QUANTITY_CHECK: "QUANTITY_CHECK";
5
5
  /** 预填购物车 */
6
6
  readonly PREFILL_CART: "PREFILL_CART";
7
+ /** 按商品 ID 删除购物车商品 */
8
+ readonly DELETE_PRODUCT: "DELETE_PRODUCT";
7
9
  /** 加购前过敏信息确认 */
8
10
  readonly ALLERGY_CHECK: "ALLERGY_CHECK";
9
11
  };
@@ -101,6 +103,10 @@ export interface AllergyRequirement {
101
103
  promptScope: AllergyPromptScope;
102
104
  allowNote: boolean;
103
105
  }
106
+ /** 购物车动作触发时机,与数量校验的提交范围相互独立。 */
107
+ export type ItemRuleExecutionScope = 'set_handover';
108
+ /** 预填数量来源;主商品数量不扩展到 QUANTITY_CHECK。 */
109
+ export type PrefillQuantitySource = QuantitySource | 'main_product_number';
104
110
  /**
105
111
  * 预填商品项
106
112
  */
@@ -110,9 +116,11 @@ export interface PrefillProduct {
110
116
  /** 变体 ID(可选,0 或不填表示无变体/默认) */
111
117
  product_variant_id?: number;
112
118
  /** 数量来源 */
113
- quantityFrom: QuantitySource;
119
+ quantityFrom: PrefillQuantitySource;
114
120
  /** 固定数量(当 quantityFrom 为 'fixed' 时使用) */
115
121
  quantity?: number;
122
+ /** 设置取餐方式时同步自动附加行的数量,重复执行不累加。 */
123
+ repeat_skip?: boolean;
116
124
  }
117
125
  /**
118
126
  * Prefill Cart Action 的详细配置
@@ -120,9 +128,18 @@ export interface PrefillProduct {
120
128
  * 存储在 ActionEffect.config 中
121
129
  */
122
130
  export interface PrefillCartConfig {
131
+ /** 不填时保持原有预填时机;set_handover 仅在设置取餐方式时执行。 */
132
+ scope?: ItemRuleExecutionScope;
123
133
  /** 要预填的商品列表 */
124
134
  products: PrefillProduct[];
125
135
  }
136
+ /** 删除指定商品的全部购物车行,不区分变体或是否为自动添加。 */
137
+ export interface DeleteProductConfig {
138
+ scope: ItemRuleExecutionScope;
139
+ products: Array<{
140
+ product_id: number;
141
+ }>;
142
+ }
126
143
  /**
127
144
  * 购物车商品摘要
128
145
  */
@@ -157,6 +174,10 @@ export interface ItemRuleBusinessData {
157
174
  historicalItems?: CartItemSummary[];
158
175
  /** 服务类型(如 'dine-in', 'takeaway') */
159
176
  serviceType?: string;
177
+ /** 当前购物车动作触发时机;未填时不评估 set_handover 动作。 */
178
+ executionScope?: ItemRuleExecutionScope;
179
+ /** 由销售业务层提供的主商品总数量,不包含附加费用商品。 */
180
+ mainProductNumber?: number;
160
181
  /** 当前业务渠道(如 'kiosk', 'pos', 'online_store') */
161
182
  channel?: string;
162
183
  /** 当前正在加入购物车的商品;ALLERGY_CHECK 只读取该商品的 Target。 */
@@ -209,7 +230,23 @@ export interface PrefillItemResult {
209
230
  product_variant_id?: number;
210
231
  /** 应添加的数量 */
211
232
  quantity: number;
233
+ /** true 时执行器同步自动附加行数量;quantity=0 表示移除该自动行。 */
234
+ repeat_skip?: boolean;
212
235
  }
236
+ /** 保留不同购物车动作之间的优先级与执行顺序。 */
237
+ export type ItemRuleCartAction = {
238
+ strategyId: string;
239
+ ruleId: string;
240
+ priority: number;
241
+ } & ({
242
+ type: 'PREFILL_CART';
243
+ products: PrefillItemResult[];
244
+ } | {
245
+ type: 'DELETE_PRODUCT';
246
+ products: Array<{
247
+ product_id: number;
248
+ }>;
249
+ });
213
250
  /**
214
251
  * 单条规则的数量限制(不含校验结果,仅描述配置中的约束)
215
252
  */
@@ -258,6 +295,8 @@ export interface ItemRuleEvaluationResult {
258
295
  quantityChecks: QuantityCheckResult[];
259
296
  /** 需要预填的商品列表 */
260
297
  prefillItems: PrefillItemResult[];
298
+ /** 按 priority 降序排列的购物车动作;同优先级保持策略与动作顺序。 */
299
+ cartActions: ItemRuleCartAction[];
261
300
  /** 当前商品命中的过敏门禁要求;不同 Action/商品不会合并。 */
262
301
  allergyRequirements: AllergyRequirement[];
263
302
  /** 所有校验是否全部通过 */
@@ -13,6 +13,8 @@ const ITEM_RULE_ACTION_TYPES = exports.ITEM_RULE_ACTION_TYPES = {
13
13
  QUANTITY_CHECK: 'QUANTITY_CHECK',
14
14
  /** 预填购物车 */
15
15
  PREFILL_CART: 'PREFILL_CART',
16
+ /** 按商品 ID 删除购物车商品 */
17
+ DELETE_PRODUCT: 'DELETE_PRODUCT',
16
18
  /** 加购前过敏信息确认 */
17
19
  ALLERGY_CHECK: 'ALLERGY_CHECK'
18
20
  };
@@ -78,6 +80,10 @@ const ITEM_RULE_TEMPLATES = exports.ITEM_RULE_TEMPLATES = {
78
80
  // Prefill Cart 相关类型
79
81
  // ============================================
80
82
 
83
+ /** 购物车动作触发时机,与数量校验的提交范围相互独立。 */
84
+
85
+ /** 预填数量来源;主商品数量不扩展到 QUANTITY_CHECK。 */
86
+
81
87
  /**
82
88
  * 预填商品项
83
89
  */
@@ -88,6 +94,8 @@ const ITEM_RULE_TEMPLATES = exports.ITEM_RULE_TEMPLATES = {
88
94
  * 存储在 ActionEffect.config 中
89
95
  */
90
96
 
97
+ /** 删除指定商品的全部购物车行,不区分变体或是否为自动添加。 */
98
+
91
99
  // ============================================
92
100
  // 业务数据类型(Evaluator 输入)
93
101
  // ============================================
@@ -116,6 +124,8 @@ const ITEM_RULE_TEMPLATES = exports.ITEM_RULE_TEMPLATES = {
116
124
  * 单个 Prefill Cart 的预填结果
117
125
  */
118
126
 
127
+ /** 保留不同购物车动作之间的优先级与执行顺序。 */
128
+
119
129
  /**
120
130
  * 单条规则的数量限制(不含校验结果,仅描述配置中的约束)
121
131
  */
@@ -1 +1,46 @@
1
- "use strict";
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "BUY_X_GET_Y_FREE_STRATEGY", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _examples.BUY_X_GET_Y_FREE_STRATEGY;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "ITEM_REWARD_STRATEGY", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _examples.ITEM_REWARD_STRATEGY;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "PromotionAdapter", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _adapter.PromotionAdapter;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "PromotionEvaluator", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _evaluator.PromotionEvaluator;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "X_ITEMS_FOR_Y_PRICE_STRATEGY", {
31
+ enumerable: true,
32
+ get: function () {
33
+ return _examples.X_ITEMS_FOR_Y_PRICE_STRATEGY;
34
+ }
35
+ });
36
+ Object.defineProperty(exports, "default", {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _adapter.default;
40
+ }
41
+ });
42
+ var _evaluator = require("./evaluator");
43
+ var _adapter = _interopRequireWildcard(require("./adapter"));
44
+ var _examples = require("./examples");
45
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
46
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
@@ -82,6 +82,8 @@ export interface OpenDataConfig {
82
82
  'sale.enabled_item_rules'?: number[];
83
83
  'fulfillment.enable_pickup'?: boolean;
84
84
  'fulfillment.handover_mode'?: string[];
85
+ 'fulfillment.takeaway_fees_rules'?: number[];
86
+ 'fulfillment.dine_in_fees_rules'?: number[];
85
87
  'fulfillment.pickup.timing_mode'?: 'asap_only' | 'scheduled_only' | 'asap_and_scheduled';
86
88
  'fulfillment.pickup.schedule'?: number[];
87
89
  'fulfillment.pickup.advance_days'?: number;
@@ -509,7 +509,9 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
509
509
  private applyOrderProductUpdateToTempOrder;
510
510
  updateOrderProduct(params: UpdateOrderProductParams): Promise<OrderProduct[]>;
511
511
  updateOrderProducts(paramsList: UpdateOrderProductParams[]): Promise<OrderProduct[]>;
512
- updateOrderProductQuantity(params: UpdateOrderProductQuantityParams): Promise<OrderProduct[]>;
512
+ updateOrderProductQuantity(params: UpdateOrderProductQuantityParams, options?: {
513
+ isCurrentOrder?: () => boolean;
514
+ }): Promise<OrderProduct[]>;
513
515
  updateOrderBooking(params: UpdateOrderBookingParams): any[];
514
516
  /**
515
517
  * 商品行写路径收尾:促销 → 折扣 → 清洗 → summary → 持久化。
@@ -593,7 +595,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
593
595
  generateIdempotencyToken(): string;
594
596
  syncPaymentsToOrder<T = any>(params: SyncPaymentsToOrderParams): Promise<SyncPaymentsToOrderResult<T>>;
595
597
  createOrder(params: CommitOrderParams['query']): {
596
- type: "appointment_booking" | "virtual";
598
+ type: "virtual" | "appointment_booking";
597
599
  platform: string;
598
600
  sales_channel: string;
599
601
  order_sales_channel: string;
@@ -3792,7 +3792,7 @@ class OrderModule extends _BaseModule.BaseModule {
3792
3792
  const uid = line.metadata?.unique_identification_number || line.unique_identification_number;
3793
3793
  return uid !== undefined && uid !== null && String(uid) === String(insertAfterProductUid);
3794
3794
  }) : -1;
3795
- let insertAtIndex = anchorIndex >= 0 ? anchorIndex + 1 : undefined;
3795
+ let insertAtIndex = options?.insertAtStart ? 0 : anchorIndex >= 0 ? anchorIndex + 1 : undefined;
3796
3796
  try {
3797
3797
  if (booking) {
3798
3798
  const productRecord = product;
@@ -4320,7 +4320,9 @@ class OrderModule extends _BaseModule.BaseModule {
4320
4320
  });
4321
4321
  return tempOrder.products;
4322
4322
  }
4323
- async updateOrderProductQuantity(params) {
4323
+ async updateOrderProductQuantity(params, options) {
4324
+ const isCurrentOrder = options?.isCurrentOrder;
4325
+ if (isCurrentOrder && !isCurrentOrder()) return this.store.tempOrder?.products || [];
4324
4326
  const {
4325
4327
  product_id,
4326
4328
  product_variant_id,
@@ -4389,19 +4391,27 @@ class OrderModule extends _BaseModule.BaseModule {
4389
4391
  if (normalizedProduct.num > targetProduct.num) {
4390
4392
  this.createCartIntentCommitGuard('increase_quantity', tempOrder)();
4391
4393
  }
4394
+ if (isCurrentOrder && !isCurrentOrder()) return tempOrder.products;
4392
4395
  tempOrder.products[productIndex] = normalizedProduct;
4393
- this.prepareVirtualSettlementTempOrder(tempOrder);
4394
- const isVirtualSettlement = this.isActiveVirtualSettlementOrder(tempOrder);
4395
- const promotionPayload = !isVirtualSettlement ? await this.evaluatePromotion() : null;
4396
- if (!isVirtualSettlement) {
4397
- this.applyDiscount();
4396
+ if (isCurrentOrder) {
4397
+ await this.finalizeProductOrderMutation(tempOrder, {
4398
+ skipEditDiscountConfigRefresh: true,
4399
+ isCurrentOrder
4400
+ });
4401
+ } else {
4402
+ this.prepareVirtualSettlementTempOrder(tempOrder);
4403
+ const isVirtualSettlement = this.isActiveVirtualSettlementOrder(tempOrder);
4404
+ const promotionPayload = !isVirtualSettlement ? await this.evaluatePromotion() : null;
4405
+ if (!isVirtualSettlement) {
4406
+ this.applyDiscount();
4407
+ }
4408
+ this.sanitizeTempOrderProducts(tempOrder);
4409
+ await this.recalculateSummary({
4410
+ createIfMissing: true
4411
+ });
4412
+ this.persistTempOrder();
4413
+ this.emitPromotionApplied(promotionPayload);
4398
4414
  }
4399
- this.sanitizeTempOrderProducts(tempOrder);
4400
- await this.recalculateSummary({
4401
- createIfMissing: true
4402
- });
4403
- this.persistTempOrder();
4404
- this.emitPromotionApplied(promotionPayload);
4405
4415
  this.logInfo('updateOrderProductQuantity success', {
4406
4416
  params
4407
4417
  });
@@ -4466,6 +4476,8 @@ class OrderModule extends _BaseModule.BaseModule {
4466
4476
  * await order.removeProductsFromOrder([identityA, identityB]);
4467
4477
  */
4468
4478
  async removeProductsFromOrder(identities, options) {
4479
+ const isCurrentOrder = options?.isCurrentOrder;
4480
+ if (isCurrentOrder && !isCurrentOrder()) return this.store.tempOrder?.products || [];
4469
4481
  const tempOrder = this.ensureTempOrder();
4470
4482
  if (!identities.length) {
4471
4483
  return tempOrder.products;
@@ -4533,7 +4545,14 @@ class OrderModule extends _BaseModule.BaseModule {
4533
4545
  }
4534
4546
  }
4535
4547
  this.removeSalesNotesForMissingProductLines(tempOrder);
4536
- await this.finalizeAfterProductsMutation(tempOrder);
4548
+ if (isCurrentOrder) {
4549
+ await this.finalizeProductOrderMutation(tempOrder, {
4550
+ skipEditDiscountConfigRefresh: true,
4551
+ isCurrentOrder
4552
+ });
4553
+ } else {
4554
+ await this.finalizeAfterProductsMutation(tempOrder);
4555
+ }
4537
4556
  this.logInfo('removeProductsFromOrder success', {
4538
4557
  identities
4539
4558
  });
@@ -441,6 +441,8 @@ export type AddProductBookingInput = Record<string, any>;
441
441
  */
442
442
  export interface AddProductToOrderOptions {
443
443
  insertAfterProductUid?: string;
444
+ /** 新增商品行插入 products 首位,优先于 insertAfterProductUid。 */
445
+ insertAtStart?: boolean;
444
446
  /** 跳过同商品/规格匹配,始终新增购物车行。 */
445
447
  disableMerge?: boolean;
446
448
  /** 商品行 UID 落定后,由 OrderModule 原子绑定到该行的 Sales Notes 草稿。 */
@@ -460,6 +462,8 @@ export interface AddProductToOrderOptions {
460
462
  * 预约合并行减量时仍删除最新真实行,再把剩余代表行移动到被删除代表行原位置。
461
463
  */
462
464
  export interface RemoveProductsFromOrderOptions {
465
+ /** 自动购物车写入的订单归属检查;失效时不再变更或发布异步收尾结果。 */
466
+ isCurrentOrder?: () => boolean;
463
467
  preserveDisplayPosition?: {
464
468
  remainingProductUid: string;
465
469
  anchorProductUid: string;
@@ -897,7 +901,9 @@ export interface OrderModuleAPI {
897
901
  updateOrderProduct: (params: UpdateOrderProductParams) => Promise<OrderProduct[]>;
898
902
  /** 批量更新购物车行,末尾仅触发一次促销重算与 summary 刷新 */
899
903
  updateOrderProducts: (paramsList: UpdateOrderProductParams[]) => Promise<OrderProduct[]>;
900
- updateOrderProductQuantity: (params: UpdateOrderProductQuantityParams) => Promise<OrderProduct[]>;
904
+ updateOrderProductQuantity: (params: UpdateOrderProductQuantityParams, options?: {
905
+ isCurrentOrder?: () => boolean;
906
+ }) => Promise<OrderProduct[]>;
901
907
  updateOrderBooking: (params: UpdateOrderBookingParams) => any[];
902
908
  removeProductFromOrder: (identity: OrderProductIdentity, options?: RemoveProductsFromOrderOptions) => Promise<OrderProduct[]>;
903
909
  /** 批量删除购物车行,末尾仅触发一次促销重算与 summary 刷新 */
@@ -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" | "normal" | "session";
52
+ getProductType(): "normal" | "duration" | "session";
53
53
  }
@@ -0,0 +1,27 @@
1
+ import type { OrderModule } from '../../modules/Order';
2
+ import type { ShopServiceType } from '../../modules/Order/types';
3
+ import type { ProductList } from '../../modules/ProductList';
4
+ import type { OpenDataConfig } from '../../modules/OpenData/types';
5
+ interface FulfillmentItemRulesHost {
6
+ getOrder: () => OrderModule;
7
+ getProducts: () => ProductList | undefined;
8
+ loadOpenData: () => Promise<OpenDataConfig | null>;
9
+ getScope: () => string;
10
+ getOtherParams: () => Record<string, any>;
11
+ fetchStrategyModels: (ids: number[]) => Promise<any>;
12
+ reportError: (error: unknown) => void;
13
+ }
14
+ /** Executes item rules at the sales boundary, independent of the calling template. */
15
+ export declare class FulfillmentItemRulesController {
16
+ private readonly host;
17
+ private sequence;
18
+ private pending;
19
+ private evaluator;
20
+ constructor(host: FulfillmentItemRulesHost);
21
+ invalidate(): void;
22
+ apply(serviceType: ShopServiceType): Promise<void>;
23
+ private loadProducts;
24
+ private getMainProductNumber;
25
+ private loadPrefillSources;
26
+ }
27
+ export {};