@pisell/pisellos 0.0.461 → 0.0.463

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.
@@ -1,5 +1,5 @@
1
1
  export * from './type';
2
2
  export { default as WalletPassAdapter } from './walletPass';
3
3
  export { WalletPassEvaluator } from './walletPass/evaluator';
4
- import { PromotionEvaluator, PromotionAdapter } from './promotion';
5
- export { PromotionEvaluator, PromotionAdapter };
4
+ export { PromotionEvaluator } from './promotion/evaluator';
5
+ export { PromotionAdapter } from './promotion/adapter';
@@ -1,5 +1,5 @@
1
1
  export * from "./type";
2
2
  export { default as WalletPassAdapter } from "./walletPass";
3
3
  export { WalletPassEvaluator } from "./walletPass/evaluator";
4
- import { PromotionEvaluator, PromotionAdapter } from "./promotion";
5
- export { PromotionEvaluator, PromotionAdapter };
4
+ export { PromotionEvaluator } from "./promotion/evaluator";
5
+ export { PromotionAdapter } from "./promotion/adapter";
@@ -0,0 +1,66 @@
1
+ import type { EvaluationResult, RuntimeContext } from '../../type';
2
+ import type { BusinessAdapter } from '../type';
3
+ import type { PromotionBusinessData, PromotionTransformResult } from './type';
4
+ /**
5
+ * Promotion 适配器
6
+ *
7
+ * 用于将促销活动业务数据转换为策略引擎可识别的格式
8
+ * 策略引擎只负责匹配,具体的优惠计算由业务层完成
9
+ */
10
+ export declare class PromotionAdapter implements BusinessAdapter {
11
+ name: string;
12
+ version: string;
13
+ /**
14
+ * 准备运行时上下文
15
+ *
16
+ * 将业务数据转换为策略引擎可识别的 RuntimeContext
17
+ */
18
+ prepareContext(businessData: PromotionBusinessData): RuntimeContext;
19
+ /**
20
+ * 转换执行结果
21
+ *
22
+ * 将策略引擎的通用结果转换为业务层需要的格式
23
+ * 主要是整理 matchedActions,让业务层更容易使用
24
+ */
25
+ transformResult(result: EvaluationResult, businessData?: PromotionBusinessData): PromotionTransformResult;
26
+ /**
27
+ * 格式化配置
28
+ */
29
+ formatConfig(result: EvaluationResult, businessData?: PromotionBusinessData): {
30
+ result: EvaluationResult;
31
+ businessData?: PromotionBusinessData;
32
+ };
33
+ /**
34
+ * 格式化日期时间
35
+ */
36
+ private formatDateTime;
37
+ /**
38
+ * 解析 Action 详情
39
+ *
40
+ * 将 matchedAction 转换为更易用的结构
41
+ */
42
+ private parseActionDetail;
43
+ /**
44
+ * 解析 X件Y元 Action
45
+ */
46
+ private parseXItemsForYPriceAction;
47
+ /**
48
+ * 解析 买X送Y Action
49
+ */
50
+ private parseBuyXGetYFreeAction;
51
+ /**
52
+ * 获取适用的商品列表
53
+ *
54
+ * 从购物车商品中筛选出符合策略条件的商品
55
+ */
56
+ private getApplicableProducts;
57
+ /**
58
+ * 查找商品匹配规则
59
+ */
60
+ private findProductMatchRule;
61
+ /**
62
+ * 检查商品是否匹配
63
+ */
64
+ private isProductMatch;
65
+ }
66
+ export default PromotionAdapter;
@@ -0,0 +1,271 @@
1
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
5
+ function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
6
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
7
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
8
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
9
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
10
+ import { PROMOTION_ACTION_TYPES } from "./type";
11
+ // ============================================
12
+ // Promotion 适配器实现
13
+ // ============================================
14
+
15
+ /**
16
+ * Promotion 适配器
17
+ *
18
+ * 用于将促销活动业务数据转换为策略引擎可识别的格式
19
+ * 策略引擎只负责匹配,具体的优惠计算由业务层完成
20
+ */
21
+ export var PromotionAdapter = /*#__PURE__*/function () {
22
+ function PromotionAdapter() {
23
+ _classCallCheck(this, PromotionAdapter);
24
+ _defineProperty(this, "name", 'PromotionAdapter');
25
+ _defineProperty(this, "version", '1.0.0');
26
+ }
27
+ _createClass(PromotionAdapter, [{
28
+ key: "prepareContext",
29
+ value:
30
+ /**
31
+ * 准备运行时上下文
32
+ *
33
+ * 将业务数据转换为策略引擎可识别的 RuntimeContext
34
+ */
35
+ function prepareContext(businessData) {
36
+ var products = businessData.products,
37
+ currentProduct = businessData.currentProduct,
38
+ channel = businessData.channel,
39
+ custom = businessData.custom;
40
+
41
+ // 当前时间(用于时间条件判断)
42
+ var now = new Date();
43
+ var currentDateTime = this.formatDateTime(now);
44
+
45
+ // 如果有 currentProduct,用于单商品场景(商品卡片展示)
46
+ var evaluatingProduct = currentProduct || (products.length > 0 ? products[0] : null);
47
+ return {
48
+ entities: {
49
+ products: products,
50
+ currentProduct: evaluatingProduct
51
+ },
52
+ attributes: _objectSpread({
53
+ // 当前时间(格式化字符串,用于时间条件判断)
54
+ currentDateTime: currentDateTime,
55
+ // 当前评估的商品信息(用于 product_match 运算符)
56
+ productIdAndVariantId: evaluatingProduct ? {
57
+ product_id: evaluatingProduct.product_id,
58
+ product_variant_id: evaluatingProduct.product_variant_id
59
+ } : null,
60
+ // 渠道
61
+ channel: channel || '',
62
+ // 商品总数量
63
+ totalQuantity: products.reduce(function (sum, p) {
64
+ return sum + p.quantity;
65
+ }, 0),
66
+ // 商品总金额
67
+ totalAmount: products.reduce(function (sum, p) {
68
+ return sum + p.price * p.quantity;
69
+ }, 0)
70
+ }, custom),
71
+ metadata: {
72
+ timestamp: Date.now()
73
+ }
74
+ };
75
+ }
76
+
77
+ /**
78
+ * 转换执行结果
79
+ *
80
+ * 将策略引擎的通用结果转换为业务层需要的格式
81
+ * 主要是整理 matchedActions,让业务层更容易使用
82
+ */
83
+ }, {
84
+ key: "transformResult",
85
+ value: function transformResult(result, businessData) {
86
+ // 获取适用的商品列表
87
+ var applicableProducts = businessData ? this.getApplicableProducts(result, businessData) : [];
88
+ if (!result.applicable) {
89
+ return {
90
+ isApplicable: false,
91
+ applicableProducts: [],
92
+ reason: result.message,
93
+ reasonCode: result.code,
94
+ strategyResult: result
95
+ };
96
+ }
97
+
98
+ // 获取第一个匹配的 action(按 priority 排序后的)
99
+ var matchedAction = result.matchedActions[0];
100
+ if (!matchedAction) {
101
+ return {
102
+ isApplicable: false,
103
+ applicableProducts: [],
104
+ reason: 'No matched action',
105
+ reasonCode: 'NO_ACTION',
106
+ strategyResult: result
107
+ };
108
+ }
109
+
110
+ // 解析 action 详情
111
+ var actionDetail = this.parseActionDetail(matchedAction);
112
+ return {
113
+ isApplicable: true,
114
+ actionType: matchedAction.type,
115
+ actionDetail: actionDetail,
116
+ applicableProducts: applicableProducts,
117
+ strategyResult: result
118
+ };
119
+ }
120
+
121
+ /**
122
+ * 格式化配置
123
+ */
124
+ }, {
125
+ key: "formatConfig",
126
+ value: function formatConfig(result, businessData) {
127
+ return {
128
+ result: result,
129
+ businessData: businessData
130
+ };
131
+ }
132
+
133
+ // ============================================
134
+ // 私有辅助方法
135
+ // ============================================
136
+
137
+ /**
138
+ * 格式化日期时间
139
+ */
140
+ }, {
141
+ key: "formatDateTime",
142
+ value: function formatDateTime(date) {
143
+ var year = date.getFullYear();
144
+ var month = String(date.getMonth() + 1).padStart(2, '0');
145
+ var day = String(date.getDate()).padStart(2, '0');
146
+ var hours = String(date.getHours()).padStart(2, '0');
147
+ var minutes = String(date.getMinutes()).padStart(2, '0');
148
+ var seconds = String(date.getSeconds()).padStart(2, '0');
149
+ return "".concat(year, "-").concat(month, "-").concat(day, " ").concat(hours, ":").concat(minutes, ":").concat(seconds);
150
+ }
151
+
152
+ /**
153
+ * 解析 Action 详情
154
+ *
155
+ * 将 matchedAction 转换为更易用的结构
156
+ */
157
+ }, {
158
+ key: "parseActionDetail",
159
+ value: function parseActionDetail(action) {
160
+ switch (action.type) {
161
+ case PROMOTION_ACTION_TYPES.X_ITEMS_FOR_Y_PRICE:
162
+ return this.parseXItemsForYPriceAction(action);
163
+ case PROMOTION_ACTION_TYPES.BUY_X_GET_Y_FREE:
164
+ return this.parseBuyXGetYFreeAction(action);
165
+ default:
166
+ return undefined;
167
+ }
168
+ }
169
+
170
+ /**
171
+ * 解析 X件Y元 Action
172
+ */
173
+ }, {
174
+ key: "parseXItemsForYPriceAction",
175
+ value: function parseXItemsForYPriceAction(action) {
176
+ var _config$allowCrossPro, _config$cumulative;
177
+ var value = action.value || {};
178
+ var config = action.config || {};
179
+ return {
180
+ type: PROMOTION_ACTION_TYPES.X_ITEMS_FOR_Y_PRICE,
181
+ x: value.x || 2,
182
+ price: value.price || 0,
183
+ allowCrossProduct: (_config$allowCrossPro = config.allowCrossProduct) !== null && _config$allowCrossPro !== void 0 ? _config$allowCrossPro : true,
184
+ cumulative: (_config$cumulative = config.cumulative) !== null && _config$cumulative !== void 0 ? _config$cumulative : true
185
+ };
186
+ }
187
+
188
+ /**
189
+ * 解析 买X送Y Action
190
+ */
191
+ }, {
192
+ key: "parseBuyXGetYFreeAction",
193
+ value: function parseBuyXGetYFreeAction(action) {
194
+ var _config$cumulative2;
195
+ var value = action.value || {};
196
+ var config = action.config || {};
197
+ return {
198
+ type: PROMOTION_ACTION_TYPES.BUY_X_GET_Y_FREE,
199
+ buyQuantity: value.buyQuantity || 1,
200
+ freeQuantity: value.freeQuantity || 1,
201
+ giftSelectionMode: config.giftSelectionMode || 'user_select',
202
+ cumulative: (_config$cumulative2 = config.cumulative) !== null && _config$cumulative2 !== void 0 ? _config$cumulative2 : true,
203
+ giftProducts: config.giftProducts || []
204
+ };
205
+ }
206
+
207
+ /**
208
+ * 获取适用的商品列表
209
+ *
210
+ * 从购物车商品中筛选出符合策略条件的商品
211
+ */
212
+ }, {
213
+ key: "getApplicableProducts",
214
+ value: function getApplicableProducts(result, businessData) {
215
+ var _this = this;
216
+ var products = businessData.products;
217
+
218
+ // 从策略配置中获取商品范围条件
219
+ var productMatchRule = this.findProductMatchRule(result.config);
220
+ if (!productMatchRule) {
221
+ // 如果没有商品范围条件,所有商品都适用
222
+ return products;
223
+ }
224
+ var configProducts = productMatchRule.value;
225
+
226
+ // 筛选适用的商品
227
+ return products.filter(function (product) {
228
+ return _this.isProductMatch(product, configProducts);
229
+ });
230
+ }
231
+
232
+ /**
233
+ * 查找商品匹配规则
234
+ */
235
+ }, {
236
+ key: "findProductMatchRule",
237
+ value: function findProductMatchRule(config) {
238
+ var _config$conditions;
239
+ if (!(config !== null && config !== void 0 && (_config$conditions = config.conditions) !== null && _config$conditions !== void 0 && _config$conditions.rules)) {
240
+ return null;
241
+ }
242
+ return config.conditions.rules.find(function (rule) {
243
+ return rule.field === 'productIdAndVariantId' && (rule.operator === 'product_match' || rule.operator === 'object_in');
244
+ });
245
+ }
246
+
247
+ /**
248
+ * 检查商品是否匹配
249
+ */
250
+ }, {
251
+ key: "isProductMatch",
252
+ value: function isProductMatch(product, configProducts) {
253
+ return configProducts.some(function (config) {
254
+ // 首先检查 product_id
255
+ if (config.product_id !== product.product_id) {
256
+ return false;
257
+ }
258
+
259
+ // 如果配置的 product_variant_id = 0,只需要 product_id 匹配
260
+ if (config.product_variant_id === 0) {
261
+ return true;
262
+ }
263
+
264
+ // 否则需要 product_variant_id 精确匹配
265
+ return config.product_variant_id === product.product_variant_id;
266
+ });
267
+ }
268
+ }]);
269
+ return PromotionAdapter;
270
+ }();
271
+ export default PromotionAdapter;
@@ -111,9 +111,10 @@ export declare class PromotionEvaluator {
111
111
  * 只检查商品 ID 匹配和策略时间范围
112
112
  *
113
113
  * @param input 评估输入(商品列表)
114
+ * @param matchVariant 是否需要匹配 product_variant_id,默认 true(严格匹配),false 时只匹配 product_id
114
115
  * @returns 每个商品的适用策略完整数据
115
116
  */
116
- getProductsApplicableStrategies(input: PromotionEvaluatorInput): Array<{
117
+ getProductsApplicableStrategies(input: PromotionEvaluatorInput, matchVariant?: boolean): Array<{
117
118
  product: PromotionProduct;
118
119
  applicableStrategies: Array<{
119
120
  strategyId: string;
@@ -16,7 +16,7 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
16
16
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
17
17
  import Decimal from 'decimal.js';
18
18
  import { StrategyEngine } from "../../engine";
19
- import { PromotionAdapter } from "./index";
19
+ import { PromotionAdapter } from "./adapter";
20
20
  import { PROMOTION_ACTION_TYPES } from "./type";
21
21
 
22
22
  // ============================================
@@ -504,11 +504,14 @@ export var PromotionEvaluator = /*#__PURE__*/function () {
504
504
  * 只检查商品 ID 匹配和策略时间范围
505
505
  *
506
506
  * @param input 评估输入(商品列表)
507
+ * @param matchVariant 是否需要匹配 product_variant_id,默认 true(严格匹配),false 时只匹配 product_id
507
508
  * @returns 每个商品的适用策略完整数据
508
509
  */
509
510
  }, {
510
511
  key: "getProductsApplicableStrategies",
511
512
  value: function getProductsApplicableStrategies(input) {
513
+ var _this3 = this;
514
+ var matchVariant = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
512
515
  var products = input.products,
513
516
  strategyConfigs = input.strategyConfigs,
514
517
  channel = input.channel;
@@ -517,7 +520,7 @@ export var PromotionEvaluator = /*#__PURE__*/function () {
517
520
  var _iterator7 = _createForOfIteratorHelper(products),
518
521
  _step7;
519
522
  try {
520
- for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
523
+ var _loop = function _loop() {
521
524
  var product = _step7.value;
522
525
  var applicableStrategies = [];
523
526
 
@@ -527,34 +530,54 @@ export var PromotionEvaluator = /*#__PURE__*/function () {
527
530
  try {
528
531
  for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
529
532
  var config = _step8.value;
530
- // 准备单商品上下文
531
- var context = this.adapter.prepareContext({
532
- products: [product],
533
- currentProduct: product,
533
+ var contextProduct = product;
534
+ if (!matchVariant) {
535
+ // 只匹配 product_id,忽略 product_variant_id
536
+ var productMatchRule = _this3.findProductMatchRule(config);
537
+ if (productMatchRule) {
538
+ var configProducts = productMatchRule.value;
539
+ var matchedConfig = configProducts.find(function (item) {
540
+ return item.product_id === product.product_id;
541
+ });
542
+ if (!matchedConfig) {
543
+ // product_id 不在策略适用范围内,跳过
544
+ continue;
545
+ }
546
+ // 用配置中的 variant_id 构造上下文,确保引擎 product_match 通过
547
+ if (matchedConfig.product_variant_id !== 0 && matchedConfig.product_variant_id !== product.product_variant_id) {
548
+ contextProduct = _objectSpread(_objectSpread({}, product), {}, {
549
+ product_variant_id: matchedConfig.product_variant_id
550
+ });
551
+ }
552
+ }
553
+ }
554
+ var context = _this3.adapter.prepareContext({
555
+ products: [contextProduct],
556
+ currentProduct: contextProduct,
534
557
  channel: channel
535
558
  });
536
559
 
537
560
  // 评估策略
538
- var result = this.engine.evaluate(config, context);
561
+ var result = _this3.engine.evaluate(config, context);
539
562
  if (result.applicable && result.matchedActions.length > 0) {
540
563
  var action = result.matchedActions[0];
541
- var transformedResult = this.adapter.transformResult(result, {
564
+ var transformedResult = _this3.adapter.transformResult(result, {
542
565
  products: [product],
543
566
  currentProduct: product,
544
567
  channel: channel
545
568
  });
546
569
  if (transformedResult.actionDetail) {
547
570
  // 计算所需数量和可参与商品列表
548
- var _this$getPromotionReq = this.getPromotionRequirements(action.type, transformedResult.actionDetail, config),
549
- requiredQuantity = _this$getPromotionReq.requiredQuantity,
550
- eligibleProducts = _this$getPromotionReq.eligibleProducts;
571
+ var _this3$getPromotionRe = _this3.getPromotionRequirements(action.type, transformedResult.actionDetail, config),
572
+ requiredQuantity = _this3$getPromotionRe.requiredQuantity,
573
+ eligibleProducts = _this3$getPromotionRe.eligibleProducts;
551
574
  applicableStrategies.push({
552
575
  strategyId: config.metadata.id,
553
576
  strategyName: config.metadata.name,
554
577
  strategyMetadata: config.metadata,
555
578
  actionType: action.type,
556
579
  actionDetail: transformedResult.actionDetail,
557
- display: this.getDisplayConfig(config),
580
+ display: _this3.getDisplayConfig(config),
558
581
  strategyConfig: config,
559
582
  requiredQuantity: requiredQuantity,
560
583
  eligibleProducts: eligibleProducts
@@ -572,6 +595,9 @@ export var PromotionEvaluator = /*#__PURE__*/function () {
572
595
  applicableStrategies: applicableStrategies,
573
596
  hasApplicableStrategy: applicableStrategies.length > 0
574
597
  });
598
+ };
599
+ for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
600
+ _loop();
575
601
  }
576
602
  } catch (err) {
577
603
  _iterator7.e(err);
@@ -0,0 +1,138 @@
1
+ /**
2
+ * X件Y元策略配置示例
3
+ *
4
+ * 业务规则:
5
+ * - 每X件商品固定价格Y元(可累计)
6
+ * - 支持跨商品组合(A+B可以凑成一组)
7
+ * - 买5件 = 2组优惠 + 1件原价
8
+ *
9
+ * 商品匹配规则:
10
+ * - product_variant_id = 0 表示匹配任意变体
11
+ * - product_variant_id != 0 表示精确匹配该变体
12
+ */
13
+ export declare const X_ITEMS_FOR_Y_PRICE_STRATEGY: {
14
+ metadata: {
15
+ id: string;
16
+ name: {
17
+ en: string;
18
+ 'zh-CN': string;
19
+ 'zh-HK': string;
20
+ };
21
+ type: string;
22
+ custom: {
23
+ display: {
24
+ product_card: {
25
+ text: {
26
+ en: string;
27
+ 'zh-CN': string;
28
+ 'zh-HK': string;
29
+ };
30
+ type: string;
31
+ };
32
+ };
33
+ };
34
+ };
35
+ conditions: {
36
+ operator: string;
37
+ rules: ({
38
+ type: string;
39
+ field: string;
40
+ value: string;
41
+ operator: string;
42
+ } | {
43
+ type: string;
44
+ field: string;
45
+ value: {
46
+ product_id: number;
47
+ product_variant_id: number;
48
+ }[];
49
+ operator: string;
50
+ })[];
51
+ actionIds: string[];
52
+ };
53
+ actions: {
54
+ id: string;
55
+ type: string;
56
+ value: {
57
+ x: number;
58
+ price: number;
59
+ };
60
+ valueType: string;
61
+ target: string;
62
+ priority: number;
63
+ config: {
64
+ allowCrossProduct: boolean;
65
+ cumulative: boolean;
66
+ };
67
+ }[];
68
+ };
69
+ /**
70
+ * 买X送Y策略配置示例
71
+ *
72
+ * 业务规则:
73
+ * - 买X件送Y件(可累计:买2送2、买3送3...)
74
+ * - 赠品由用户从列表中选择
75
+ *
76
+ * 商品匹配规则:
77
+ * - product_variant_id = 0 表示匹配任意变体
78
+ * - product_variant_id != 0 表示精确匹配该变体
79
+ */
80
+ export declare const BUY_X_GET_Y_FREE_STRATEGY: {
81
+ metadata: {
82
+ id: string;
83
+ name: {
84
+ en: string;
85
+ 'zh-CN': string;
86
+ 'zh-HK': string;
87
+ };
88
+ type: string;
89
+ custom: {
90
+ display: {
91
+ product_card: {
92
+ text: {
93
+ en: string;
94
+ 'zh-CN': string;
95
+ 'zh-HK': string;
96
+ };
97
+ type: string;
98
+ };
99
+ };
100
+ };
101
+ };
102
+ conditions: {
103
+ operator: string;
104
+ rules: ({
105
+ type: string;
106
+ field: string;
107
+ value: string;
108
+ operator: string;
109
+ } | {
110
+ type: string;
111
+ field: string;
112
+ value: {
113
+ product_id: number;
114
+ product_variant_id: number;
115
+ }[];
116
+ operator: string;
117
+ })[];
118
+ actionIds: string[];
119
+ };
120
+ actions: {
121
+ id: string;
122
+ type: string;
123
+ value: {
124
+ buyQuantity: number;
125
+ freeQuantity: number;
126
+ };
127
+ valueType: string;
128
+ target: string;
129
+ priority: number;
130
+ config: {
131
+ cumulative: boolean;
132
+ giftProducts: {
133
+ product_id: number;
134
+ product_variant_id: number;
135
+ }[];
136
+ };
137
+ }[];
138
+ };