@pisell/pisellos 2.2.71 → 2.2.73
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.
- package/dist/model/strategy/adapter/index.d.ts +2 -0
- package/dist/model/strategy/adapter/index.js +2 -1
- package/dist/model/strategy/adapter/promotion/adapter.d.ts +66 -0
- package/dist/model/strategy/adapter/promotion/adapter.js +271 -0
- package/dist/model/strategy/adapter/promotion/evaluator.d.ts +213 -0
- package/dist/model/strategy/adapter/promotion/evaluator.js +1210 -0
- package/dist/model/strategy/adapter/promotion/examples.d.ts +138 -0
- package/dist/model/strategy/adapter/promotion/examples.js +166 -0
- package/dist/model/strategy/adapter/promotion/index.d.ts +4 -0
- package/dist/model/strategy/adapter/promotion/index.js +0 -0
- package/dist/model/strategy/adapter/promotion/type.d.ts +447 -0
- package/dist/model/strategy/adapter/promotion/type.js +209 -0
- package/dist/model/strategy/adapter/walletPass/evaluator.js +4 -1
- package/dist/model/strategy/engine.d.ts +106 -0
- package/dist/model/strategy/engine.js +611 -0
- package/dist/model/strategy/index.d.ts +2 -93
- package/dist/model/strategy/index.js +6 -549
- package/dist/modules/BaseModule.d.ts +4 -0
- package/dist/modules/BaseModule.js +5 -0
- package/dist/modules/Product/index.d.ts +1 -1
- package/dist/modules/Rules/index.d.ts +1 -0
- package/dist/modules/Rules/index.js +52 -23
- package/dist/solution/BookingTicket/index.d.ts +1 -1
- package/lib/model/strategy/adapter/index.d.ts +2 -0
- package/lib/model/strategy/adapter/index.js +6 -0
- package/lib/model/strategy/adapter/promotion/adapter.d.ts +66 -0
- package/lib/model/strategy/adapter/promotion/adapter.js +217 -0
- package/lib/model/strategy/adapter/promotion/evaluator.d.ts +213 -0
- package/lib/model/strategy/adapter/promotion/evaluator.js +846 -0
- package/lib/model/strategy/adapter/promotion/examples.d.ts +138 -0
- package/lib/model/strategy/adapter/promotion/examples.js +192 -0
- package/lib/model/strategy/adapter/promotion/index.d.ts +4 -0
- package/lib/model/strategy/adapter/promotion/index.js +0 -0
- package/lib/model/strategy/adapter/promotion/type.d.ts +447 -0
- package/lib/model/strategy/adapter/promotion/type.js +51 -0
- package/lib/model/strategy/adapter/walletPass/evaluator.js +2 -1
- package/lib/model/strategy/engine.d.ts +106 -0
- package/lib/model/strategy/engine.js +450 -0
- package/lib/model/strategy/index.d.ts +2 -93
- package/lib/model/strategy/index.js +6 -381
- package/lib/modules/BaseModule.d.ts +4 -0
- package/lib/modules/BaseModule.js +3 -0
- package/lib/modules/Product/index.d.ts +1 -1
- package/lib/modules/Rules/index.d.ts +1 -0
- package/lib/modules/Rules/index.js +35 -19
- package/lib/solution/BookingTicket/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -201,6 +201,13 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
201
201
|
productList: hasApplicableDiscount ? result.productList : productList
|
|
202
202
|
};
|
|
203
203
|
}
|
|
204
|
+
}, {
|
|
205
|
+
key: "filterDiscountListByType",
|
|
206
|
+
value: function filterDiscountListByType(discountList, type) {
|
|
207
|
+
return (discountList || []).filter(function (item) {
|
|
208
|
+
return item.type === type || item.tag === type;
|
|
209
|
+
});
|
|
210
|
+
}
|
|
204
211
|
}, {
|
|
205
212
|
key: "calcDiscount",
|
|
206
213
|
value: function calcDiscount(_ref2, options) {
|
|
@@ -953,6 +960,9 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
953
960
|
}) && (!((_product$discount_lis5 = product.discount_list) !== null && _product$discount_lis5 !== void 0 && _product$discount_lis5.length) || ((_product11 = product) === null || _product11 === void 0 || (_product11 = _product11.discount_list) === null || _product11 === void 0 || (_product11$every = _product11.every) === null || _product11$every === void 0 ? void 0 : _product11$every.call(_product11, function (item) {
|
|
954
961
|
return item.type === 'product';
|
|
955
962
|
})));
|
|
963
|
+
if (product.inPromotion) {
|
|
964
|
+
isManualDiscount = false;
|
|
965
|
+
}
|
|
956
966
|
} else {
|
|
957
967
|
// bundle子商品:判断父主商品是否手动折扣
|
|
958
968
|
var parentProduct = flatItem.parentProduct;
|
|
@@ -1048,25 +1058,36 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
1048
1058
|
}),
|
|
1049
1059
|
price: product.price
|
|
1050
1060
|
}), {}, {
|
|
1051
|
-
discount_list:
|
|
1061
|
+
discount_list: _this3.filterDiscountListByType(product.discount_list, 'promotion')
|
|
1052
1062
|
}))]);
|
|
1053
1063
|
} else {
|
|
1064
|
+
var _ref7, _product$_promotion$f, _product12, _product$origin_total;
|
|
1065
|
+
var total = product.inPromotion ? (_ref7 = (_product$_promotion$f = (_product12 = product) === null || _product12 === void 0 || (_product12 = _product12._promotion) === null || _product12 === void 0 ? void 0 : _product12.finalPrice) !== null && _product$_promotion$f !== void 0 ? _product$_promotion$f : product.origin_total) !== null && _ref7 !== void 0 ? _ref7 : product.total : (_product$origin_total = product.origin_total) !== null && _product$origin_total !== void 0 ? _product$origin_total : product.total;
|
|
1066
|
+
var main_product_selling_price = product.price;
|
|
1067
|
+
if ((product.discount_list || []).some(function (item) {
|
|
1068
|
+
return item.type === 'promotion';
|
|
1069
|
+
})) {
|
|
1070
|
+
var _product$total, _product$main_product;
|
|
1071
|
+
total = (_product$total = product.total) !== null && _product$total !== void 0 ? _product$total : product.origin_total;
|
|
1072
|
+
main_product_selling_price = (_product$main_product = product.main_product_selling_price) !== null && _product$main_product !== void 0 ? _product$main_product : main_product_selling_price;
|
|
1073
|
+
}
|
|
1054
1074
|
processedProductsMap.set(product._id, [_this3.hooks.setProduct(originProduct, _objectSpread(_objectSpread({}, isManualDiscount ? {
|
|
1055
1075
|
price: product.price,
|
|
1056
1076
|
main_product_selling_price: product.price
|
|
1057
1077
|
} : {
|
|
1058
1078
|
_id: product._id.split('___')[0] + '___' + index,
|
|
1059
|
-
total:
|
|
1079
|
+
total: total,
|
|
1060
1080
|
price: product.price,
|
|
1061
|
-
main_product_selling_price:
|
|
1081
|
+
main_product_selling_price: main_product_selling_price
|
|
1062
1082
|
}), {}, {
|
|
1063
|
-
discount_list:
|
|
1083
|
+
discount_list: _this3.filterDiscountListByType(product.discount_list, 'promotion')
|
|
1064
1084
|
}))]);
|
|
1065
1085
|
}
|
|
1066
1086
|
} else {
|
|
1087
|
+
var _flatItem$bundleItem8;
|
|
1067
1088
|
// bundle子商品:保存到扁平化Map
|
|
1068
1089
|
processedFlatItemsMap.set(flatItem._id, [_objectSpread(_objectSpread({}, flatItem), {}, {
|
|
1069
|
-
discount_list: [],
|
|
1090
|
+
discount_list: _this3.filterDiscountListByType(((_flatItem$bundleItem8 = flatItem.bundleItem) === null || _flatItem$bundleItem8 === void 0 ? void 0 : _flatItem$bundleItem8.discount_list) || [], 'promotion'),
|
|
1070
1091
|
price: isManualDiscount ? flatItem.bundleItem.price : flatItem.bundleItem.original_price,
|
|
1071
1092
|
processed: true
|
|
1072
1093
|
})]);
|
|
@@ -1098,15 +1119,23 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
1098
1119
|
if (flatItem.type === 'main') {
|
|
1099
1120
|
// 主商品:保持原有逻辑
|
|
1100
1121
|
if (splitCount < totalQuantity && isNeedSplit) {
|
|
1122
|
+
var _product$origin_total2;
|
|
1123
|
+
var _total = (_product$origin_total2 = product.origin_total) !== null && _product$origin_total2 !== void 0 ? _product$origin_total2 : product.total;
|
|
1124
|
+
if ((product.discount_list || []).some(function (item) {
|
|
1125
|
+
return item.type === 'promotion';
|
|
1126
|
+
})) {
|
|
1127
|
+
var _product$total2;
|
|
1128
|
+
_total = (_product$total2 = product.total) !== null && _product$total2 !== void 0 ? _product$total2 : product.origin_total;
|
|
1129
|
+
}
|
|
1101
1130
|
arr.push(_this3.hooks.setProduct(originProduct, {
|
|
1102
|
-
discount_list:
|
|
1131
|
+
discount_list: _this3.filterDiscountListByType(product.discount_list, 'promotion'),
|
|
1103
1132
|
quantity: totalQuantity - splitCount,
|
|
1104
1133
|
_id: product._id.split('___')[0],
|
|
1105
|
-
total:
|
|
1134
|
+
total: _total
|
|
1106
1135
|
}));
|
|
1107
1136
|
}
|
|
1108
1137
|
for (var i = 0; i < splitCount; i++) {
|
|
1109
|
-
var
|
|
1138
|
+
var _originProduct, _selectedDiscount$met, _selectedDiscount$met2;
|
|
1110
1139
|
// 如果用过折扣卡,也就不存在拆分的情况了,这里直接使用上面计算出来的折扣卡
|
|
1111
1140
|
var _selectedDiscount = selectedDiscountCard || applicableDiscounts[i];
|
|
1112
1141
|
// 标记优惠券为已使用
|
|
@@ -1123,7 +1152,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
1123
1152
|
// 优先从 origin_total拿,可能会拿不到(比如用户端预约在没有配置 original_price 的情况下)
|
|
1124
1153
|
var productOriginTotal = product.origin_total || product.total || 0;
|
|
1125
1154
|
// 如果当前 product 有 discount_list,则先从 origin_total 拿
|
|
1126
|
-
if ((
|
|
1155
|
+
if (_this3.filterDiscountListByType(product.discount_list, 'promotion').length && product.origin_total) {
|
|
1127
1156
|
productOriginTotal = product.origin_total;
|
|
1128
1157
|
}
|
|
1129
1158
|
// 如果originProduct?._productInit?.original_price为 0,product.origin_total可能为空,此时取 product.total
|
|
@@ -1176,13 +1205,13 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
1176
1205
|
};
|
|
1177
1206
|
appliedProducts.push(discountDetail);
|
|
1178
1207
|
appliedDiscountProducts.set(_selectedDiscount.id, appliedProducts);
|
|
1179
|
-
var
|
|
1208
|
+
var _total2 = targetProductTotal;
|
|
1180
1209
|
if (product.options) {
|
|
1181
|
-
|
|
1210
|
+
_total2 = product.options.reduce(function (accumulator, currentValue) {
|
|
1182
1211
|
var currentPrice = new Decimal(currentValue.price || 0);
|
|
1183
1212
|
var currentNum = new Decimal(currentValue.num || 0);
|
|
1184
1213
|
return accumulator.add(currentPrice.mul(currentNum));
|
|
1185
|
-
}, new Decimal(
|
|
1214
|
+
}, new Decimal(_total2)).toNumber();
|
|
1186
1215
|
}
|
|
1187
1216
|
|
|
1188
1217
|
// 记录应用了优惠券的商品
|
|
@@ -1201,15 +1230,15 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
1201
1230
|
}),
|
|
1202
1231
|
variant: originProduct._productInit.variant,
|
|
1203
1232
|
original_price: new Decimal(product.price || 0).toNumber(),
|
|
1204
|
-
total:
|
|
1233
|
+
total: _total2
|
|
1205
1234
|
}));
|
|
1206
1235
|
} else {
|
|
1207
1236
|
arr.push(_this3.hooks.setProduct(originProduct, {
|
|
1208
|
-
discount_list: [discountDetail],
|
|
1237
|
+
discount_list: _this3.filterDiscountListByType(product.discount_list, 'promotion').concat([discountDetail]),
|
|
1209
1238
|
_id: product._id.split('___')[0] + '___' + _selectedDiscount.id + index,
|
|
1210
1239
|
price: _selectedDiscount.tag === 'good_pass' ? 0 : product.price,
|
|
1211
1240
|
quantity: isNeedSplit ? 1 : product.quantity,
|
|
1212
|
-
total:
|
|
1241
|
+
total: _total2,
|
|
1213
1242
|
origin_total: productOriginTotal,
|
|
1214
1243
|
main_product_selling_price: targetProductTotal
|
|
1215
1244
|
}));
|
|
@@ -1376,7 +1405,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
1376
1405
|
var getDefaultProduct = function getDefaultProduct() {
|
|
1377
1406
|
if (product.isClient) {
|
|
1378
1407
|
return _this3.hooks.setProduct(originProduct, {
|
|
1379
|
-
discount_list:
|
|
1408
|
+
discount_list: _this3.filterDiscountListByType(product.discount_list, 'promotion'),
|
|
1380
1409
|
price: product.price,
|
|
1381
1410
|
origin_total: getProductOriginTotalPrice({
|
|
1382
1411
|
product: {
|
|
@@ -1397,7 +1426,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
1397
1426
|
});
|
|
1398
1427
|
} else {
|
|
1399
1428
|
return _this3.hooks.setProduct(originProduct, {
|
|
1400
|
-
discount_list:
|
|
1429
|
+
discount_list: _this3.filterDiscountListByType(product.discount_list, 'promotion'),
|
|
1401
1430
|
total: product.total,
|
|
1402
1431
|
origin_total: product.origin_total,
|
|
1403
1432
|
price: product.price
|
|
@@ -1858,10 +1887,10 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
1858
1887
|
return true; // 单独购买时可用
|
|
1859
1888
|
}
|
|
1860
1889
|
if (isBundleItem) {
|
|
1861
|
-
var _flatItem$
|
|
1890
|
+
var _flatItem$bundleItem9, _flatItem$bundleItem10;
|
|
1862
1891
|
// 套餐中购买时,判断是否为原价
|
|
1863
|
-
var priceType = (_flatItem$
|
|
1864
|
-
var priceTypeExt = (_flatItem$
|
|
1892
|
+
var priceType = (_flatItem$bundleItem9 = flatItem.bundleItem) === null || _flatItem$bundleItem9 === void 0 ? void 0 : _flatItem$bundleItem9.price_type;
|
|
1893
|
+
var priceTypeExt = (_flatItem$bundleItem10 = flatItem.bundleItem) === null || _flatItem$bundleItem10 === void 0 ? void 0 : _flatItem$bundleItem10.price_type_ext;
|
|
1865
1894
|
// original_price 对应:
|
|
1866
1895
|
// 1. price_type: "markup" && price_type_ext: "product_price"
|
|
1867
1896
|
// markup_price 对应:
|
|
@@ -1899,10 +1928,10 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
1899
1928
|
return false; // 单独购买时不可用
|
|
1900
1929
|
}
|
|
1901
1930
|
if (isBundleItem) {
|
|
1902
|
-
var _flatItem$
|
|
1931
|
+
var _flatItem$bundleItem11, _flatItem$bundleItem12;
|
|
1903
1932
|
// 套餐中购买时,判断是否为原价
|
|
1904
|
-
var _priceType = (_flatItem$
|
|
1905
|
-
var _priceTypeExt = (_flatItem$
|
|
1933
|
+
var _priceType = (_flatItem$bundleItem11 = flatItem.bundleItem) === null || _flatItem$bundleItem11 === void 0 ? void 0 : _flatItem$bundleItem11.price_type;
|
|
1934
|
+
var _priceTypeExt = (_flatItem$bundleItem12 = flatItem.bundleItem) === null || _flatItem$bundleItem12 === void 0 ? void 0 : _flatItem$bundleItem12.price_type_ext;
|
|
1906
1935
|
|
|
1907
1936
|
// original_price 对应:
|
|
1908
1937
|
// 1. price_type: "markup" && price_type_ext: "product_price"
|
|
@@ -123,7 +123,7 @@ export declare class BookingTicketImpl extends BaseModule implements Module {
|
|
|
123
123
|
* 获取当前的客户搜索条件
|
|
124
124
|
* @returns 当前搜索条件
|
|
125
125
|
*/
|
|
126
|
-
getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "
|
|
126
|
+
getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "skip" | "num">;
|
|
127
127
|
/**
|
|
128
128
|
* 获取客户列表状态(包含滚动加载相关状态)
|
|
129
129
|
* @returns 客户状态
|
|
@@ -30,6 +30,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/model/strategy/adapter/index.ts
|
|
31
31
|
var adapter_exports = {};
|
|
32
32
|
__export(adapter_exports, {
|
|
33
|
+
PromotionAdapter: () => import_adapter.PromotionAdapter,
|
|
34
|
+
PromotionEvaluator: () => import_evaluator2.PromotionEvaluator,
|
|
33
35
|
WalletPassAdapter: () => import_walletPass.default,
|
|
34
36
|
WalletPassEvaluator: () => import_evaluator.WalletPassEvaluator
|
|
35
37
|
});
|
|
@@ -37,8 +39,12 @@ module.exports = __toCommonJS(adapter_exports);
|
|
|
37
39
|
__reExport(adapter_exports, require("./type"), module.exports);
|
|
38
40
|
var import_walletPass = __toESM(require("./walletPass"));
|
|
39
41
|
var import_evaluator = require("./walletPass/evaluator");
|
|
42
|
+
var import_evaluator2 = require("./promotion/evaluator");
|
|
43
|
+
var import_adapter = require("./promotion/adapter");
|
|
40
44
|
// Annotate the CommonJS export names for ESM import in node:
|
|
41
45
|
0 && (module.exports = {
|
|
46
|
+
PromotionAdapter,
|
|
47
|
+
PromotionEvaluator,
|
|
42
48
|
WalletPassAdapter,
|
|
43
49
|
WalletPassEvaluator,
|
|
44
50
|
...require("./type")
|
|
@@ -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,217 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/model/strategy/adapter/promotion/adapter.ts
|
|
20
|
+
var adapter_exports = {};
|
|
21
|
+
__export(adapter_exports, {
|
|
22
|
+
PromotionAdapter: () => PromotionAdapter,
|
|
23
|
+
default: () => adapter_default
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(adapter_exports);
|
|
26
|
+
var import_type = require("./type");
|
|
27
|
+
var PromotionAdapter = class {
|
|
28
|
+
constructor() {
|
|
29
|
+
this.name = "PromotionAdapter";
|
|
30
|
+
this.version = "1.0.0";
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 准备运行时上下文
|
|
34
|
+
*
|
|
35
|
+
* 将业务数据转换为策略引擎可识别的 RuntimeContext
|
|
36
|
+
*/
|
|
37
|
+
prepareContext(businessData) {
|
|
38
|
+
const { products, currentProduct, channel, custom } = businessData;
|
|
39
|
+
const now = /* @__PURE__ */ new Date();
|
|
40
|
+
const currentDateTime = this.formatDateTime(now);
|
|
41
|
+
const evaluatingProduct = currentProduct || (products.length > 0 ? products[0] : null);
|
|
42
|
+
return {
|
|
43
|
+
entities: {
|
|
44
|
+
products,
|
|
45
|
+
currentProduct: evaluatingProduct
|
|
46
|
+
},
|
|
47
|
+
attributes: {
|
|
48
|
+
// 当前时间(格式化字符串,用于时间条件判断)
|
|
49
|
+
currentDateTime,
|
|
50
|
+
// 当前评估的商品信息(用于 product_match 运算符)
|
|
51
|
+
productIdAndVariantId: evaluatingProduct ? {
|
|
52
|
+
product_id: evaluatingProduct.product_id,
|
|
53
|
+
product_variant_id: evaluatingProduct.product_variant_id
|
|
54
|
+
} : null,
|
|
55
|
+
// 渠道
|
|
56
|
+
channel: channel || "",
|
|
57
|
+
// 商品总数量
|
|
58
|
+
totalQuantity: products.reduce((sum, p) => sum + p.quantity, 0),
|
|
59
|
+
// 商品总金额
|
|
60
|
+
totalAmount: products.reduce((sum, p) => sum + p.price * p.quantity, 0),
|
|
61
|
+
// 自定义属性
|
|
62
|
+
...custom
|
|
63
|
+
},
|
|
64
|
+
metadata: {
|
|
65
|
+
timestamp: Date.now()
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 转换执行结果
|
|
71
|
+
*
|
|
72
|
+
* 将策略引擎的通用结果转换为业务层需要的格式
|
|
73
|
+
* 主要是整理 matchedActions,让业务层更容易使用
|
|
74
|
+
*/
|
|
75
|
+
transformResult(result, businessData) {
|
|
76
|
+
const applicableProducts = businessData ? this.getApplicableProducts(result, businessData) : [];
|
|
77
|
+
if (!result.applicable) {
|
|
78
|
+
return {
|
|
79
|
+
isApplicable: false,
|
|
80
|
+
applicableProducts: [],
|
|
81
|
+
reason: result.message,
|
|
82
|
+
reasonCode: result.code,
|
|
83
|
+
strategyResult: result
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const matchedAction = result.matchedActions[0];
|
|
87
|
+
if (!matchedAction) {
|
|
88
|
+
return {
|
|
89
|
+
isApplicable: false,
|
|
90
|
+
applicableProducts: [],
|
|
91
|
+
reason: "No matched action",
|
|
92
|
+
reasonCode: "NO_ACTION",
|
|
93
|
+
strategyResult: result
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const actionDetail = this.parseActionDetail(matchedAction);
|
|
97
|
+
return {
|
|
98
|
+
isApplicable: true,
|
|
99
|
+
actionType: matchedAction.type,
|
|
100
|
+
actionDetail,
|
|
101
|
+
applicableProducts,
|
|
102
|
+
strategyResult: result
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 格式化配置
|
|
107
|
+
*/
|
|
108
|
+
formatConfig(result, businessData) {
|
|
109
|
+
return { result, businessData };
|
|
110
|
+
}
|
|
111
|
+
// ============================================
|
|
112
|
+
// 私有辅助方法
|
|
113
|
+
// ============================================
|
|
114
|
+
/**
|
|
115
|
+
* 格式化日期时间
|
|
116
|
+
*/
|
|
117
|
+
formatDateTime(date) {
|
|
118
|
+
const year = date.getFullYear();
|
|
119
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
120
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
121
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
122
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
123
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
124
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* 解析 Action 详情
|
|
128
|
+
*
|
|
129
|
+
* 将 matchedAction 转换为更易用的结构
|
|
130
|
+
*/
|
|
131
|
+
parseActionDetail(action) {
|
|
132
|
+
switch (action.type) {
|
|
133
|
+
case import_type.PROMOTION_ACTION_TYPES.X_ITEMS_FOR_Y_PRICE:
|
|
134
|
+
return this.parseXItemsForYPriceAction(action);
|
|
135
|
+
case import_type.PROMOTION_ACTION_TYPES.BUY_X_GET_Y_FREE:
|
|
136
|
+
return this.parseBuyXGetYFreeAction(action);
|
|
137
|
+
default:
|
|
138
|
+
return void 0;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* 解析 X件Y元 Action
|
|
143
|
+
*/
|
|
144
|
+
parseXItemsForYPriceAction(action) {
|
|
145
|
+
const value = action.value || {};
|
|
146
|
+
const config = action.config || {};
|
|
147
|
+
return {
|
|
148
|
+
type: import_type.PROMOTION_ACTION_TYPES.X_ITEMS_FOR_Y_PRICE,
|
|
149
|
+
x: value.x || 2,
|
|
150
|
+
price: value.price || 0,
|
|
151
|
+
allowCrossProduct: config.allowCrossProduct ?? true,
|
|
152
|
+
cumulative: config.cumulative ?? true
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* 解析 买X送Y Action
|
|
157
|
+
*/
|
|
158
|
+
parseBuyXGetYFreeAction(action) {
|
|
159
|
+
const value = action.value || {};
|
|
160
|
+
const config = action.config || {};
|
|
161
|
+
return {
|
|
162
|
+
type: import_type.PROMOTION_ACTION_TYPES.BUY_X_GET_Y_FREE,
|
|
163
|
+
buyQuantity: value.buyQuantity || 1,
|
|
164
|
+
freeQuantity: value.freeQuantity || 1,
|
|
165
|
+
giftSelectionMode: config.giftSelectionMode || "user_select",
|
|
166
|
+
cumulative: config.cumulative ?? true,
|
|
167
|
+
giftProducts: config.giftProducts || []
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* 获取适用的商品列表
|
|
172
|
+
*
|
|
173
|
+
* 从购物车商品中筛选出符合策略条件的商品
|
|
174
|
+
*/
|
|
175
|
+
getApplicableProducts(result, businessData) {
|
|
176
|
+
const { products } = businessData;
|
|
177
|
+
const productMatchRule = this.findProductMatchRule(result.config);
|
|
178
|
+
if (!productMatchRule) {
|
|
179
|
+
return products;
|
|
180
|
+
}
|
|
181
|
+
const configProducts = productMatchRule.value;
|
|
182
|
+
return products.filter(
|
|
183
|
+
(product) => this.isProductMatch(product, configProducts)
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* 查找商品匹配规则
|
|
188
|
+
*/
|
|
189
|
+
findProductMatchRule(config) {
|
|
190
|
+
var _a;
|
|
191
|
+
if (!((_a = config == null ? void 0 : config.conditions) == null ? void 0 : _a.rules)) {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
return config.conditions.rules.find(
|
|
195
|
+
(rule) => rule.field === "productIdAndVariantId" && (rule.operator === "product_match" || rule.operator === "object_in")
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* 检查商品是否匹配
|
|
200
|
+
*/
|
|
201
|
+
isProductMatch(product, configProducts) {
|
|
202
|
+
return configProducts.some((config) => {
|
|
203
|
+
if (config.product_id !== product.product_id) {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
if (config.product_variant_id === 0) {
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
return config.product_variant_id === product.product_variant_id;
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
var adapter_default = PromotionAdapter;
|
|
214
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
215
|
+
0 && (module.exports = {
|
|
216
|
+
PromotionAdapter
|
|
217
|
+
});
|