@pisell/pisellos 0.10.42 → 0.10.44

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 (101) hide show
  1. package/dist/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
  2. package/dist/model/strategy/adapter/itemRule/adapter.js +135 -35
  3. package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
  4. package/dist/model/strategy/adapter/itemRule/evaluator.js +25 -1
  5. package/dist/model/strategy/adapter/itemRule/type.d.ts +44 -0
  6. package/dist/model/strategy/adapter/itemRule/type.js +19 -1
  7. package/dist/model/strategy/adapter/promotion/index.js +0 -9
  8. package/dist/modules/Order/index.d.ts +40 -8
  9. package/dist/modules/Order/index.js +1438 -878
  10. package/dist/modules/Order/salesNotes.d.ts +31 -0
  11. package/dist/modules/Order/salesNotes.js +492 -0
  12. package/dist/modules/Order/types.d.ts +105 -8
  13. package/dist/modules/Order/types.js +6 -1
  14. package/dist/modules/Order/utils.d.ts +3 -1
  15. package/dist/modules/Order/utils.js +191 -71
  16. package/dist/modules/Payment/cashRecommendationAlgorithm.d.ts +4 -5
  17. package/dist/modules/Payment/cashRecommendationAlgorithm.js +17 -367
  18. package/dist/modules/ProductList/index.d.ts +2 -1
  19. package/dist/modules/ProductList/index.js +100 -20
  20. package/dist/modules/ProductList/types.d.ts +10 -0
  21. package/dist/modules/Rules/index.js +2 -1
  22. package/dist/server/index.d.ts +7 -0
  23. package/dist/server/index.js +45 -3
  24. package/dist/server/modules/order/index.js +6 -0
  25. package/dist/server/modules/order/types.d.ts +9 -0
  26. package/dist/server/utils/small-ticket.d.ts +1 -0
  27. package/dist/server/utils/small-ticket.js +142 -14
  28. package/dist/solution/BaseSales/index.d.ts +15 -1
  29. package/dist/solution/BaseSales/index.js +1240 -877
  30. package/dist/solution/BookingByStep/index.d.ts +1 -1
  31. package/dist/solution/BookingTicket/index.d.ts +1 -0
  32. package/dist/solution/BookingTicket/index.js +37 -16
  33. package/dist/solution/BookingTicket/types.d.ts +5 -1
  34. package/dist/solution/BookingTicket/utils/orderCustomer.js +3 -2
  35. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +171 -96
  36. package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +1 -1
  37. package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +2 -0
  38. package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.js +12 -3
  39. package/dist/solution/RegisterAndLogin/config.d.ts +9 -3
  40. package/dist/solution/RegisterAndLogin/config.js +95 -40
  41. package/dist/solution/RegisterAndLogin/index.js +4 -1
  42. package/dist/solution/ScanOrder/index.d.ts +1 -0
  43. package/dist/solution/ScanOrder/index.js +31 -27
  44. package/dist/solution/ScanOrder/utils.d.ts +1 -0
  45. package/dist/solution/ScanOrder/utils.js +2 -0
  46. package/dist/solution/UnifiedBookingSales/index.d.ts +15 -2
  47. package/dist/solution/UnifiedBookingSales/index.js +777 -510
  48. package/dist/solution/UnifiedBookingSales/types.d.ts +14 -1
  49. package/dist/solution/VenueBooking/index.d.ts +1 -0
  50. package/dist/solution/VenueBooking/index.js +8 -4
  51. package/lib/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
  52. package/lib/model/strategy/adapter/itemRule/adapter.js +73 -4
  53. package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
  54. package/lib/model/strategy/adapter/itemRule/evaluator.js +23 -1
  55. package/lib/model/strategy/adapter/itemRule/type.d.ts +44 -0
  56. package/lib/model/strategy/adapter/itemRule/type.js +19 -1
  57. package/lib/model/strategy/adapter/promotion/index.js +1 -46
  58. package/lib/modules/Order/index.d.ts +40 -8
  59. package/lib/modules/Order/index.js +434 -61
  60. package/lib/modules/Order/salesNotes.d.ts +31 -0
  61. package/lib/modules/Order/salesNotes.js +382 -0
  62. package/lib/modules/Order/types.d.ts +105 -8
  63. package/lib/modules/Order/types.js +5 -1
  64. package/lib/modules/Order/utils.d.ts +3 -1
  65. package/lib/modules/Order/utils.js +114 -1
  66. package/lib/modules/Payment/cashRecommendationAlgorithm.d.ts +4 -5
  67. package/lib/modules/Payment/cashRecommendationAlgorithm.js +9 -354
  68. package/lib/modules/ProductList/index.d.ts +2 -1
  69. package/lib/modules/ProductList/index.js +47 -2
  70. package/lib/modules/ProductList/types.d.ts +10 -0
  71. package/lib/modules/Rules/index.js +2 -1
  72. package/lib/server/index.d.ts +7 -0
  73. package/lib/server/index.js +39 -3
  74. package/lib/server/modules/order/index.js +6 -0
  75. package/lib/server/modules/order/types.d.ts +9 -0
  76. package/lib/server/utils/small-ticket.d.ts +1 -0
  77. package/lib/server/utils/small-ticket.js +136 -12
  78. package/lib/solution/BaseSales/index.d.ts +15 -1
  79. package/lib/solution/BaseSales/index.js +192 -22
  80. package/lib/solution/BookingByStep/index.d.ts +1 -1
  81. package/lib/solution/BookingTicket/index.d.ts +1 -0
  82. package/lib/solution/BookingTicket/index.js +23 -5
  83. package/lib/solution/BookingTicket/types.d.ts +5 -1
  84. package/lib/solution/BookingTicket/utils/orderCustomer.js +2 -1
  85. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +65 -18
  86. package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +1 -1
  87. package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +2 -0
  88. package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +5 -1
  89. package/lib/solution/RegisterAndLogin/config.d.ts +9 -3
  90. package/lib/solution/RegisterAndLogin/config.js +49 -8
  91. package/lib/solution/RegisterAndLogin/index.js +4 -1
  92. package/lib/solution/ScanOrder/index.d.ts +1 -0
  93. package/lib/solution/ScanOrder/index.js +5 -1
  94. package/lib/solution/ScanOrder/utils.d.ts +1 -0
  95. package/lib/solution/ScanOrder/utils.js +1 -0
  96. package/lib/solution/UnifiedBookingSales/index.d.ts +15 -2
  97. package/lib/solution/UnifiedBookingSales/index.js +125 -1
  98. package/lib/solution/UnifiedBookingSales/types.d.ts +14 -1
  99. package/lib/solution/VenueBooking/index.d.ts +1 -0
  100. package/lib/solution/VenueBooking/index.js +5 -1
  101. package/package.json +1 -1
@@ -1,8 +1,12 @@
1
1
  import type { InvoiceLayoutConfig, InvoiceTemplateSettings, OpenDataConfig } from '../../modules/OpenData';
2
- import type { ProductListLoadProductsParams } from '../../modules/ProductList';
2
+ import type { ProductListLoadProductsParams, ProductListStoreQueryParams } from '../../modules/ProductList';
3
+ import type { ProductData } from '../../modules/Product/types';
3
4
  import type { LoadScheduleAvailableDateParams } from '../../modules/Schedule/types';
4
5
  import type { AvailabilityDateRange, AvailabilityErrorCode, AvailabilityId, AvailabilityOccupancy, AvailabilityProduct, AvailabilityProjection, AvailabilityQuery, AvailabilityRequirementSelection, AvailabilityResource, AvailabilitySelectionValidationResult, DateAvailabilityQueryResult, GetProductTimeRangesRequest, ProductAvailabilityQueryResult, ProductTimeRange, ProductTimeRangeGroup, ResourceAvailabilityGroup, ResourceAvailabilityRangeGroup, TimeAvailabilityGroup, TimeAvailabilityItem } from '../../modules/ResourcePlanner';
5
6
  import type { BookingTicketState } from '../BookingTicket/types';
7
+ import type { AllergyRequirement } from '../../model/strategy/adapter/itemRule';
8
+ import type { SalesNoteDraftInput } from '../../modules/Order/types';
9
+ export type { ProductListStoreQueryParams } from '../../modules/ProductList';
6
10
  export type { AvailabilityAbsoluteRange, AvailabilityAssignment, AvailabilityCell, AvailabilityDateRange, AvailabilityDisplayRange, AvailabilityErrorCode, AvailabilityId, AvailabilityMode, AvailabilityOccupancy, AvailabilityProduct, AvailabilityProductKind, AvailabilityProjection, AvailabilityProjectionInput, AvailabilityProjectionMeta, AvailabilityQuery, AvailabilityQueryResult, AvailabilityRequirementGroup, AvailabilityRequirementGroupResult, AvailabilityRequirementSelection, AvailabilityResource, AvailabilityResourceOption, AvailabilityResourceType, AvailabilityResourceWindow, AvailabilityScheduleMode, AvailabilityScheduleRef, AvailabilityScheduleRule, AvailabilitySelectionValidationParams, AvailabilitySelectionValidationResult, AvailabilitySessionRange, AvailabilityStatus, DateAvailabilityGroup, DateAvailabilityItem, DateAvailabilityQuery, DateAvailabilityQueryResult, GetProductTimeRangesRequest, ProductAvailabilityGroup, ProductAvailabilityItem, ProductAvailabilityQuery, ProductAvailabilityQueryResult, ProductTimeRange, ProductTimeRangeGroup, QueryAvailabilityBaseRequest, ResourceAvailabilityGroup, ResourceAvailabilityQuery, ResourceAvailabilityQueryResult, ResourceAvailabilityRangeGroup, TimeAvailabilityGroup, TimeAvailabilityItem, TimeAvailabilityQuery, TimeAvailabilityQueryResult, } from '../../modules/ResourcePlanner';
7
11
  export interface UnifiedBookingSalesState extends BookingTicketState {
8
12
  }
@@ -24,6 +28,12 @@ export declare enum UnifiedBookingSalesHooks {
24
28
  export interface UnifiedBookingSalesOtherParams extends Record<string, any> {
25
29
  enableSessionStoragePersist?: boolean;
26
30
  }
31
+ export type UnifiedBookingSalesAllergyRequirement = AllergyRequirement;
32
+ export interface UnifiedBookingSalesResolveProductAllergyRequirementParams {
33
+ productId: number | string;
34
+ productVariantId?: number | string;
35
+ channel?: string;
36
+ }
27
37
  export interface UnifiedBookingSalesLoadOpenDataParams {
28
38
  businessCode: string;
29
39
  channel: string;
@@ -151,6 +161,8 @@ export interface ContextualCommitAvailabilitySelectionParams {
151
161
  requirementSelections: AvailabilityRequirementSelection[];
152
162
  partySize: number;
153
163
  bookingCount?: number;
164
+ /** 新增商品行时与商品、预约在同一次 Order mutation 内写入的 Sales Notes。 */
165
+ salesNotes?: SalesNoteDraftInput[];
154
166
  /** 编辑预约时,允许本次显式报价覆盖已落库订单行的历史价格。 */
155
167
  allowBookingReprice?: boolean;
156
168
  /** 编辑预约重报价后,允许订单模块重新应用已选编辑态折扣。 */
@@ -214,6 +226,7 @@ export interface UnifiedBookingSalesApi {
214
226
  /** Date-first calendar availability backed by ScheduleModule. */
215
227
  loadScheduleAvailableDate: (params: LoadScheduleAvailableDateParams) => Promise<unknown>;
216
228
  loadProductsByScheduleDate: (params: UnifiedBookingSalesLoadProductsByScheduleDateParams) => Promise<unknown[]>;
229
+ queryProducts: (params?: ProductListStoreQueryParams) => Promise<ProductData[]>;
217
230
  stageRetailProducts: (params: UnifiedBookingSalesStageRetailProductsParams) => Promise<Record<string, any> | null>;
218
231
  addRetailProduct: (params: UnifiedBookingSalesAddRetailProductParams) => Promise<Record<string, any>[]>;
219
232
  prepareAvailabilityProjection: (params: UnifiedBookingSalesPrepareAvailabilityProjectionParams) => Promise<AvailabilityContextRef>;
@@ -15,6 +15,7 @@ interface VenueBookingItemRuleRuntimeConfig {
15
15
  pax?: Partial<PaxInfo>;
16
16
  historicalItems?: CartItemSummary[];
17
17
  serviceType?: string;
18
+ channel?: string;
18
19
  submissionIndex?: number;
19
20
  custom?: Record<string, any>;
20
21
  }
@@ -3140,7 +3140,11 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseSalesImpl) {
3140
3140
  }, {
3141
3141
  key: "getItemRuleRuntimeConfig",
3142
3142
  value: function getItemRuleRuntimeConfig() {
3143
- return this.itemRuleRuntimeConfig || {};
3143
+ var _ref6, _runtimeConfig$channe, _runtimeConfig$custom, _this$otherParams21;
3144
+ var runtimeConfig = this.itemRuleRuntimeConfig || {};
3145
+ return _objectSpread(_objectSpread({}, runtimeConfig), {}, {
3146
+ channel: (_ref6 = (_runtimeConfig$channe = runtimeConfig.channel) !== null && _runtimeConfig$channe !== void 0 ? _runtimeConfig$channe : (_runtimeConfig$custom = runtimeConfig.custom) === null || _runtimeConfig$custom === void 0 ? void 0 : _runtimeConfig$custom.channel) !== null && _ref6 !== void 0 ? _ref6 : (_this$otherParams21 = this.otherParams) === null || _this$otherParams21 === void 0 ? void 0 : _this$otherParams21.channel
3147
+ });
3144
3148
  }
3145
3149
  }, {
3146
3150
  key: "ensureItemRuleConfigsLoaded",
@@ -3806,14 +3810,14 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseSalesImpl) {
3806
3810
  key: "setOtherParams",
3807
3811
  value: function () {
3808
3812
  var _setOtherParams = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee46(params) {
3809
- var _ref7,
3810
- _ref7$cover,
3813
+ var _ref8,
3814
+ _ref8$cover,
3811
3815
  cover,
3812
3816
  _args46 = arguments;
3813
3817
  return _regeneratorRuntime().wrap(function _callee46$(_context46) {
3814
3818
  while (1) switch (_context46.prev = _context46.next) {
3815
3819
  case 0:
3816
- _ref7 = _args46.length > 1 && _args46[1] !== undefined ? _args46[1] : {}, _ref7$cover = _ref7.cover, cover = _ref7$cover === void 0 ? false : _ref7$cover;
3820
+ _ref8 = _args46.length > 1 && _args46[1] !== undefined ? _args46[1] : {}, _ref8$cover = _ref8.cover, cover = _ref8$cover === void 0 ? false : _ref8$cover;
3817
3821
  if (cover) {
3818
3822
  this.otherParams = params;
3819
3823
  } else {
@@ -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 } from './type';
3
+ import { type ItemRuleBusinessData, type QuantityCheckResult, type PrefillItemResult, type QuantityLimitResult, type AllergyRequirement } from './type';
4
4
  /**
5
5
  * ItemRule 适配器
6
6
  *
@@ -14,7 +14,10 @@ export declare class ItemRuleAdapter implements BusinessAdapter {
14
14
  transformResult(result: EvaluationResult, businessData?: ItemRuleBusinessData): {
15
15
  quantityChecks: QuantityCheckResult[];
16
16
  prefillItems: PrefillItemResult[];
17
+ allergyRequirements: AllergyRequirement[];
17
18
  };
19
+ private processAllergyCheck;
20
+ private normalizeAllergyDataSourceItems;
18
21
  formatConfig(result: EvaluationResult, businessData?: ItemRuleBusinessData): {
19
22
  result: EvaluationResult;
20
23
  businessData?: ItemRuleBusinessData;
@@ -19,14 +19,17 @@ class ItemRuleAdapter {
19
19
  pax,
20
20
  cartItems,
21
21
  serviceType,
22
+ channel,
22
23
  submissionIndex,
23
24
  custom
24
25
  } = businessData;
26
+ const resolvedChannel = String(channel ?? custom?.channel ?? '').trim();
25
27
  return {
26
28
  entities: {
27
29
  cartItems,
28
30
  historicalItems: businessData.historicalItems || [],
29
- pax
31
+ pax,
32
+ currentProduct: businessData.currentProduct
30
33
  },
31
34
  attributes: {
32
35
  serviceType: serviceType || '',
@@ -36,7 +39,8 @@ class ItemRuleAdapter {
36
39
  submissionIndex: submissionIndex ?? 0,
37
40
  cartItemCount: cartItems.length,
38
41
  cartTotalQuantity: cartItems.reduce((sum, item) => sum + item.quantity, 0),
39
- ...custom
42
+ ...custom,
43
+ channel: resolvedChannel
40
44
  },
41
45
  metadata: {
42
46
  timestamp: Date.now()
@@ -46,10 +50,12 @@ class ItemRuleAdapter {
46
50
  transformResult(result, businessData) {
47
51
  const quantityChecks = [];
48
52
  const prefillItems = [];
53
+ const allergyRequirements = [];
49
54
  if (!result.applicable || !businessData) {
50
55
  return {
51
56
  quantityChecks,
52
- prefillItems
57
+ prefillItems,
58
+ allergyRequirements
53
59
  };
54
60
  }
55
61
  for (const action of result.matchedActions) {
@@ -61,13 +67,76 @@ class ItemRuleAdapter {
61
67
  } else if (action.type === _type.ITEM_RULE_ACTION_TYPES.PREFILL_CART) {
62
68
  const items = this.processPrefillCart(action, businessData);
63
69
  prefillItems.push(...items);
70
+ } else if (action.type === _type.ITEM_RULE_ACTION_TYPES.ALLERGY_CHECK) {
71
+ const requirement = this.processAllergyCheck(action, result, businessData);
72
+ if (requirement) allergyRequirements.push(requirement);
64
73
  }
65
74
  }
66
75
  return {
67
76
  quantityChecks,
68
- prefillItems
77
+ prefillItems,
78
+ allergyRequirements
69
79
  };
70
80
  }
81
+
82
+ // ============================================
83
+ // Allergy Check 处理
84
+ // ============================================
85
+
86
+ processAllergyCheck(action, result, businessData) {
87
+ const config = action.config;
88
+ const currentProduct = businessData.currentProduct;
89
+ if (!config || config.targetType !== 'product' || config.promptScope !== 'once_per_order_product' || !Array.isArray(config.targets) || !currentProduct) {
90
+ return null;
91
+ }
92
+ const currentProductId = Number(currentProduct.product_id);
93
+ const currentVariantId = Number(currentProduct.product_variant_id ?? 0);
94
+ if (!Number.isFinite(currentProductId) || currentProductId <= 0) return null;
95
+ const productTargets = config.targets.filter(item => Number(item.product_id) === currentProductId);
96
+ const target = productTargets.find(item => currentVariantId > 0 && Number(item.product_variant_id ?? 0) === currentVariantId) ?? productTargets.find(item => Number(item.product_variant_id ?? 0) <= 0);
97
+ if (!target || target.dataSource?.type !== 'inline') return null;
98
+ const items = this.normalizeAllergyDataSourceItems(target.dataSource.items);
99
+ if (!items.length) return null;
100
+ return {
101
+ strategyId: result.config.metadata.id,
102
+ ruleId: action.id,
103
+ priority: action.priority ?? 0,
104
+ targetType: 'product',
105
+ product_id: currentProductId,
106
+ ...(Number(target.product_variant_id ?? 0) > 0 ? {
107
+ product_variant_id: Number(target.product_variant_id)
108
+ } : {}),
109
+ dataSource: {
110
+ type: 'inline',
111
+ items
112
+ },
113
+ promptScope: config.promptScope,
114
+ allowNote: config.allowNote === true
115
+ };
116
+ }
117
+ normalizeAllergyDataSourceItems(items) {
118
+ if (!Array.isArray(items)) return [];
119
+ const uniqueIds = new Set();
120
+ const normalized = [];
121
+ for (const item of items) {
122
+ const id = String(item?.id ?? '').trim();
123
+ const rawLabel = item?.label;
124
+ const label = typeof rawLabel === 'string' ? rawLabel.trim() : Object.entries(rawLabel || {}).reduce((labels, [locale, value]) => {
125
+ if (typeof value === 'string' && value.trim().length > 0) {
126
+ labels[locale] = value.trim();
127
+ }
128
+ return labels;
129
+ }, {});
130
+ const hasLabel = typeof label === 'string' ? label.length > 0 : Object.keys(label).length > 0;
131
+ if (!id || !hasLabel || uniqueIds.has(id)) continue;
132
+ uniqueIds.add(id);
133
+ normalized.push({
134
+ id,
135
+ label
136
+ });
137
+ }
138
+ return normalized;
139
+ }
71
140
  formatConfig(result, businessData) {
72
141
  return {
73
142
  result,
@@ -1,5 +1,5 @@
1
1
  import type { StrategyConfig } from '../../type';
2
- import { type ItemRuleBusinessData, type ItemRuleEvaluationResult, type QuantityCheckResult, type QuantityLimitResult, type PrefillItemResult } from './type';
2
+ import { type ItemRuleBusinessData, type ItemRuleEvaluationResult, type QuantityCheckResult, type QuantityLimitResult, type PrefillItemResult, type AllergyRequirement } from './type';
3
3
  /**
4
4
  * ItemRule 评估器
5
5
  *
@@ -21,6 +21,13 @@ export declare class ItemRuleEvaluator {
21
21
  * 完整评估:数量校验 + 预填购物车
22
22
  */
23
23
  evaluate(businessData: ItemRuleBusinessData): ItemRuleEvaluationResult;
24
+ /**
25
+ * 获取当前商品优先级最高的过敏门禁要求。
26
+ *
27
+ * 不同商品或不同 Action 的数据源不会合并;相同优先级按
28
+ * strategyId + ruleId 稳定排序,保证多次评估结果一致。
29
+ */
30
+ getAllergyRequirement(businessData: ItemRuleBusinessData): AllergyRequirement | null;
24
31
  /**
25
32
  * 获取当前配置中各商品的数量限制
26
33
  *
@@ -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 allAllergyRequirements = [];
46
47
  const rawResults = [];
47
48
  const context = this.adapter.prepareContext(businessData);
48
49
  for (const config of configs) {
@@ -50,21 +51,42 @@ class ItemRuleEvaluator {
50
51
  rawResults.push(evalResult);
51
52
  const {
52
53
  quantityChecks,
53
- prefillItems
54
+ prefillItems,
55
+ allergyRequirements
54
56
  } = this.adapter.transformResult(evalResult, businessData);
55
57
  allQuantityChecks.push(...quantityChecks);
56
58
  allPrefillItems.push(...prefillItems);
59
+ allAllergyRequirements.push(...allergyRequirements);
57
60
  }
58
61
  const failedChecks = allQuantityChecks.filter(c => !c.passed);
59
62
  return {
60
63
  quantityChecks: allQuantityChecks,
61
64
  prefillItems: allPrefillItems,
65
+ allergyRequirements: allAllergyRequirements,
62
66
  allPassed: failedChecks.length === 0,
63
67
  failedChecks,
64
68
  rawResults
65
69
  };
66
70
  }
67
71
 
72
+ /**
73
+ * 获取当前商品优先级最高的过敏门禁要求。
74
+ *
75
+ * 不同商品或不同 Action 的数据源不会合并;相同优先级按
76
+ * strategyId + ruleId 稳定排序,保证多次评估结果一致。
77
+ */
78
+ getAllergyRequirement(businessData) {
79
+ const requirements = this.evaluate(businessData).allergyRequirements;
80
+ if (!requirements.length) return null;
81
+ return [...requirements].sort((left, right) => {
82
+ const priorityDiff = right.priority - left.priority;
83
+ if (priorityDiff !== 0) return priorityDiff;
84
+ const strategyDiff = left.strategyId.localeCompare(right.strategyId);
85
+ if (strategyDiff !== 0) return strategyDiff;
86
+ return left.ruleId.localeCompare(right.ruleId);
87
+ })[0];
88
+ }
89
+
68
90
  /**
69
91
  * 获取当前配置中各商品的数量限制
70
92
  *
@@ -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
+ /** 加购前过敏信息确认 */
8
+ readonly ALLERGY_CHECK: "ALLERGY_CHECK";
7
9
  };
8
10
  export type ItemRuleActionType = (typeof ITEM_RULE_ACTION_TYPES)[keyof typeof ITEM_RULE_ACTION_TYPES];
9
11
  export declare const ITEM_RULE_TEMPLATES: {
@@ -63,6 +65,42 @@ export interface TargetItem {
63
65
  /** 变体 ID */
64
66
  product_variant_id?: number;
65
67
  }
68
+ /** 策略展示文案,可由调用方按当前 locale 解析。 */
69
+ export type ItemRuleLocalizedText = string | Record<string, string>;
70
+ /** 内联过敏源选项。稳定 id 用于保存选择,label 只负责展示。 */
71
+ export interface AllergyDataSourceItem {
72
+ id: string;
73
+ label: ItemRuleLocalizedText;
74
+ }
75
+ /** 当前仅支持随策略下发的内联过敏源。 */
76
+ export interface AllergyDataSource {
77
+ type: 'inline';
78
+ items: AllergyDataSourceItem[];
79
+ }
80
+ /** 每个目标商品独立持有自己的过敏源,禁止跨商品合并。 */
81
+ export interface AllergyTargetItem extends TargetItem {
82
+ dataSource: AllergyDataSource;
83
+ }
84
+ export type AllergyPromptScope = 'once_per_order_product';
85
+ /** ALLERGY_CHECK Action 的商品级配置。 */
86
+ export interface AllergyCheckConfig {
87
+ targetType: 'product';
88
+ targets: AllergyTargetItem[];
89
+ promptScope: AllergyPromptScope;
90
+ allowNote?: boolean;
91
+ }
92
+ /** 当前商品命中的单条过敏门禁要求。 */
93
+ export interface AllergyRequirement {
94
+ strategyId: string;
95
+ ruleId: string;
96
+ priority: number;
97
+ targetType: 'product';
98
+ product_id: number;
99
+ product_variant_id?: number;
100
+ dataSource: AllergyDataSource;
101
+ promptScope: AllergyPromptScope;
102
+ allowNote: boolean;
103
+ }
66
104
  /**
67
105
  * 预填商品项
68
106
  */
@@ -119,6 +157,10 @@ export interface ItemRuleBusinessData {
119
157
  historicalItems?: CartItemSummary[];
120
158
  /** 服务类型(如 'dine-in', 'takeaway') */
121
159
  serviceType?: string;
160
+ /** 当前业务渠道(如 'kiosk', 'pos', 'online_store') */
161
+ channel?: string;
162
+ /** 当前正在加入购物车的商品;ALLERGY_CHECK 只读取该商品的 Target。 */
163
+ currentProduct?: Pick<TargetItem, 'product_id' | 'product_variant_id'>;
122
164
  /** 当前提交次数(0=首次提交, >0=追加提交) */
123
165
  submissionIndex?: number;
124
166
  /** 策略配置列表(可选,如果不传则使用 setStrategyConfigs 设置的) */
@@ -216,6 +258,8 @@ export interface ItemRuleEvaluationResult {
216
258
  quantityChecks: QuantityCheckResult[];
217
259
  /** 需要预填的商品列表 */
218
260
  prefillItems: PrefillItemResult[];
261
+ /** 当前商品命中的过敏门禁要求;不同 Action/商品不会合并。 */
262
+ allergyRequirements: AllergyRequirement[];
219
263
  /** 所有校验是否全部通过 */
220
264
  allPassed: boolean;
221
265
  /** 未通过的校验列表 */
@@ -12,7 +12,9 @@ const ITEM_RULE_ACTION_TYPES = exports.ITEM_RULE_ACTION_TYPES = {
12
12
  /** 数量校验 */
13
13
  QUANTITY_CHECK: 'QUANTITY_CHECK',
14
14
  /** 预填购物车 */
15
- PREFILL_CART: 'PREFILL_CART'
15
+ PREFILL_CART: 'PREFILL_CART',
16
+ /** 加购前过敏信息确认 */
17
+ ALLERGY_CHECK: 'ALLERGY_CHECK'
16
18
  };
17
19
  // ============================================
18
20
  // Rule Template 类型(创建规则时的起始模板)
@@ -56,6 +58,22 @@ const ITEM_RULE_TEMPLATES = exports.ITEM_RULE_TEMPLATES = {
56
58
 
57
59
  /** 目标项 */
58
60
 
61
+ // ============================================
62
+ // Allergy Check 相关类型
63
+ // ============================================
64
+
65
+ /** 策略展示文案,可由调用方按当前 locale 解析。 */
66
+
67
+ /** 内联过敏源选项。稳定 id 用于保存选择,label 只负责展示。 */
68
+
69
+ /** 当前仅支持随策略下发的内联过敏源。 */
70
+
71
+ /** 每个目标商品独立持有自己的过敏源,禁止跨商品合并。 */
72
+
73
+ /** ALLERGY_CHECK Action 的商品级配置。 */
74
+
75
+ /** 当前商品命中的单条过敏门禁要求。 */
76
+
59
77
  // ============================================
60
78
  // Prefill Cart 相关类型
61
79
  // ============================================
@@ -1,46 +1 @@
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; }
1
+ "use strict";
@@ -3,7 +3,7 @@ import { BaseModule } from '../BaseModule';
3
3
  import { OrderModuleAPI, CommitOrderParams, UpdateOrderBookingParams, UpdateOrderProductParams, UpdateOrderProductQuantityParams, CancelOrderParams, ChangeBookingStatusParams, CheckoutOrderParams } from './types';
4
4
  import { CartItem } from '../Cart/types';
5
5
  import { type SubmitPayloadEnhancer } from './utils';
6
- import type { OrderAmountSnapshot, AddProductBookingInput, AddProductToOrderOptions, OrderIdentitySnapshot, OrderPaymentSource, OrderSnapshot, OrderSyncState, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, SubmitSalesOrderParams, OrderProduct, OrderProductIdentity, OrderSummary, OrderTempOrder, OrderPaymentData, OrderPaymentUpdateOptions, OrderPaymentUpdateResult, SendCustomerPayLinkParams, UpdateTempOrderCustomerInput, OrderCustomerPatch, OrderCustomerView, ReplaceTempOrderOptions, OrderPromotionEvaluator, OrderGiftSelectResolver, OrderUnfulfilledPromotion, OrderLastGiftActions, RemoveProductsFromOrderOptions } from './types';
6
+ import type { OrderAmountSnapshot, AddProductBookingInput, AddProductToOrderOptions, OrderIdentitySnapshot, OrderPaymentSource, OrderSnapshot, OrderSyncState, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, SubmitSalesOrderParams, OrderProduct, OrderProductIdentity, OrderSummary, OrderTempOrder, OrderPaymentData, OrderPaymentUpdateOptions, OrderPaymentUpdateResult, SendCustomerPayLinkParams, UpdateTempOrderCustomerInput, OrderCustomerPatch, OrderCustomerView, ReplaceTempOrderOptions, OrderPromotionEvaluator, OrderGiftSelectResolver, OrderUnfulfilledPromotion, OrderLastGiftActions, RemoveProductsFromOrderOptions, SalesNote, SalesNotesMutationSnapshot, SetSalesNoteInput, PickupReferenceMode, ShopServiceData, ShopServiceType } from './types';
7
7
  import type { ICustomer } from '../AccountList/types';
8
8
  import type { Discount } from '../Discount/types';
9
9
  import { UnavailableReason } from '../Rules/types';
@@ -20,6 +20,8 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
20
20
  private openCache;
21
21
  private sessionStoragePersistEnabled;
22
22
  private sessionStorageRestoreRecord;
23
+ /** 只允许当前订单最新的 prepare/config 请求回写客户资产态。 */
24
+ private customerWalletPrepareConfigEpoch;
23
25
  private salesSummaryModuleName;
24
26
  private rulesHooksOverride?;
25
27
  private moduleHooksOverride?;
@@ -29,8 +31,10 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
29
31
  private promotionEvaluator;
30
32
  /** 赠品选择 resolver;由 SDK host bridge 注入 */
31
33
  private giftSelectResolver;
32
- /** applyPromotion 递归保护 flag(写路径同步调 applyPromotion,禁止重入) */
34
+ /** 促销评估递归保护 flag(写路径同步评估促销,禁止重入) */
33
35
  private isApplyingPromotion;
36
+ /** 保持旧事件语义:同步事件监听器内触发的订单写入不得递归评估促销。 */
37
+ private isEmittingPromotionApplied;
34
38
  /** 商品曾应用过客户券卡,客户变更剥离后需强制跑一次 calcDiscount 复位价格 */
35
39
  private hasActiveCustomerBoundDiscount;
36
40
  /** 最近一次 applyPromotion 的未满足促销提示 */
@@ -76,6 +80,11 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
76
80
  private logError;
77
81
  private registerDiscountModules;
78
82
  private createDefaultRulesHooks;
83
+ /**
84
+ * Stable across notifyTempOrderChanged's immutable copy, but changes when a
85
+ * different local/server order becomes current.
86
+ */
87
+ private getDiscountConfigOrderIdentityKey;
79
88
  loadDiscountConfig(params: {
80
89
  customerId: number;
81
90
  action?: 'create' | 'edit';
@@ -85,6 +94,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
85
94
  getDiscountList(): Discount[];
86
95
  getAvailableWalletIds(): number[];
87
96
  getVirtualCurrencyList(): import("../Discount/types").VirtualCurrencyAsset[];
97
+ getCustomerWalletPrepareConfigEpoch(): number;
88
98
  private syncScannedDiscountsToOriginalDiscountList;
89
99
  private ensureEditDiscountConfigForProductChange;
90
100
  scanCode(code: string, customerId?: number): Promise<{
@@ -124,7 +134,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
124
134
  */
125
135
  appendPromotionTags<T extends Record<string, any>>(products: T[]): T[];
126
136
  /**
127
- * 应用购物车促销:计算 → 差异化赠品 → 写回 tempOrder.products → emit onPromotionApplied。
137
+ * 只执行购物车促销评估与赠品写回,不发布稳定态事件。
128
138
  *
129
139
  * 调用时机:写路径(add/update/remove/clear/setCustomer)末尾自动触发;外部一般无需手动调。
130
140
  *
@@ -132,8 +142,13 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
132
142
  * - 不调用任何公开 CRUD API(如 removeProductFromOrder),全部内部 mutate tempOrder.products,避免事件风暴;
133
143
  * - 用 `isApplyingPromotion` 防递归;
134
144
  * - 多选项赠品依赖 giftSelectResolver,未注入则跳过且 console.warn;
135
- * - 不主动调用 applyDiscount / recalculateSummary,调用方负责跟进。
145
+ * - 不主动调用 applyDiscount / recalculateSummary,调用方负责跟进;
146
+ * - 返回的 payload 只能在 applyDiscount(商品写路径还需 summary/persist)完成后发布。
136
147
  */
148
+ private evaluatePromotion;
149
+ /** 发布促销稳定态;products 必须读取折扣计算后的当前数组。 */
150
+ private emitPromotionApplied;
151
+ /** 公开入口:促销、折扣、summary 与持久化完成后发布稳定态事件。 */
137
152
  applyPromotion(): Promise<void>;
138
153
  /** 最近一次 applyPromotion 输出的未满足促销列表 */
139
154
  getUnfulfilledPromotions(): OrderUnfulfilledPromotion[];
@@ -169,8 +184,10 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
169
184
  consumeSessionStorageRestore(): Record<string, any> | null;
170
185
  notifyTempOrderChanged(): void;
171
186
  private createDefaultTempOrderInstance;
172
- private clearTempOrderPointCardSnapshot;
173
- private writePointCardSnapshotFromPrepareConfig;
187
+ private clearTempOrderCustomerWalletSnapshots;
188
+ private clearCustomerWalletState;
189
+ private clearCustomerWalletRuntimeState;
190
+ private writeCustomerWalletSnapshotsFromPrepareConfig;
174
191
  private createExternalSaleNumber;
175
192
  private ensureExternalSaleNumber;
176
193
  private ensureRequestUniqueIdempotencyToken;
@@ -306,9 +323,24 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
306
323
  updateTempOrderNote(note: string, sync: boolean): string | Promise<string>;
307
324
  syncTempOrderNoteToRemote(orderId: number | string, note: string): Promise<string>;
308
325
  getTempOrderNote(): string;
326
+ private ensureSalesNotesRuntimeState;
327
+ private ensureSalesNotesLoadedForMutation;
328
+ private normalizeSalesNoteUuid;
329
+ private getSalesNotePrimaryRelation;
330
+ private removeSalesNotesForMissingProductLines;
331
+ private setSalesNoteOnTempOrder;
332
+ getSalesNotes(): SalesNote[];
333
+ createSalesNotesMutationSnapshot(): SalesNotesMutationSnapshot;
334
+ restoreSalesNotesMutationSnapshot(snapshot: SalesNotesMutationSnapshot): void;
335
+ setSalesNote(input: SetSalesNoteInput): Promise<SalesNote>;
336
+ removeSalesNote(uuid: string): Promise<void>;
337
+ clearSalesNotes(): Promise<void>;
309
338
  updateTempOrderShopDiscount(amount: string | number): string;
310
339
  updateTempOrderDepositAmount(amount: string | number): OrderSummary;
311
340
  updateTempOrderBuzzer(buzzer: string): string;
341
+ private updateTempOrderShopServiceData;
342
+ updateTempOrderPickupReferenceMode(mode: PickupReferenceMode): ShopServiceData;
343
+ updateTempOrderServiceType(serviceType: ShopServiceType): ShopServiceData;
312
344
  updateTempOrderContactsInfo(contactsInfo: Record<string, any> | null): Record<string, any> | null;
313
345
  private buildTempOrderCustomer;
314
346
  private isCustomerBoundDiscount;
@@ -476,7 +508,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
476
508
  removeProductFromOrder(identity: OrderProductIdentity, options?: RemoveProductsFromOrderOptions): Promise<OrderProduct[]>;
477
509
  /**
478
510
  * 仅清空购物车行(products / bookings),不重置整单。
479
- * 用于「仅清空商品」;客户、备注、支付等协议字段保持不变。
511
+ * 普通整单 note 保持不变;以商品行为主体的 Sales Notes 同步删除。
480
512
  */
481
513
  clearOrderCartLines(): Promise<OrderTempOrder>;
482
514
  /**
@@ -618,4 +650,4 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
618
650
  getOrderInfo(order_id: number): Promise<any>;
619
651
  getVouchers(): any[];
620
652
  }
621
- export type { AddProductToOrderOptions, OrderMetaList, PointCardSnapshotItem, RemoveProductsFromOrderOptions, UpdateOrderBookingParams, UpdateOrderProductParams, UpdateOrderProductQuantityParams, } from './types';
653
+ export type { AddProductToOrderOptions, OrderMetaList, PointCardSnapshotItem, VirtualCurrencySnapshotItem, RemoveProductsFromOrderOptions, SalesNote, SalesNoteDraftInput, SalesNoteLocalizedSelection, SalesNoteLocalizedText, SalesNoteRelation, SalesNoteTextInput, SetSalesNoteInput, UpdateOrderBookingParams, UpdateOrderProductParams, UpdateOrderProductQuantityParams, } from './types';