@pisell/pisellos
Version:
一个可扩展的前端模块化SDK框架,支持插件系统
424 lines (422 loc) • 14.6 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/model/strategy/adapter/walletPass/evaluator.ts
var evaluator_exports = {};
__export(evaluator_exports, {
WalletPassEvaluator: () => WalletPassEvaluator
});
module.exports = __toCommonJS(evaluator_exports);
var import__ = require("../../index");
var import_utils = require("./utils");
var import_locales = require("./locales");
var import_decimal = __toESM(require("decimal.js"));
var defaultStrategyMetadataCustom = {
maxDeductionAmount: 99999,
maxUsagePerOrder: 0,
allowCrossProduct: true,
applicableProductLimit: 0,
deductTaxAndFee: true,
maxPassesPerItem: 0
};
var WalletPassEvaluator = class {
constructor() {
this.strategyConfigs = [];
this.locale = "en";
this.engine = new import__.StrategyEngine({
debug: false,
enableTrace: false
});
}
setStrategyConfigs(strategyConfigs) {
const newStrategyConfigs = strategyConfigs.filter((item) => item.metadata.type === "wallet_pass");
this.strategyConfigs = newStrategyConfigs;
}
getStrategyConfigs() {
return this.strategyConfigs;
}
setLocale(locale) {
this.locale = locale;
}
getText(key) {
var _a, _b;
return (_b = (_a = import_locales.locales) == null ? void 0 : _a[this.locale]) == null ? void 0 : _b[key];
}
/**
* 搜索券的格式
* @param input 输入
* @returns 返回搜索券的格式
*/
searchVoucherFormat(input) {
const results = this.evaluate(input);
return results.map((item) => {
var _a, _b;
if (item.isApplicable) {
return {
...item.voucher,
config: {
...(_a = item == null ? void 0 : item.strategyResult) == null ? void 0 : _a.config.metadata.custom
}
};
} else {
return {
...item.voucher,
config: {
...(_b = item == null ? void 0 : item.strategyResult) == null ? void 0 : _b.config.metadata.custom
},
_unified_available_status: 0,
reason: item.reason,
reasonCode: item.reasonCode
};
}
});
}
/**
* 评估可用的 vouchers
*/
evaluate(input) {
var _a, _b;
const { orderTotalAmount, products, vouchers, strategyConfigs } = input;
const productIds = products.map((p) => p.product_id);
const results = [];
for (const voucher of vouchers) {
const applicableStrategies = this.findApplicableStrategies(
voucher,
strategyConfigs || this.strategyConfigs
);
if (applicableStrategies.length === 0) {
results.push({
voucher,
isApplicable: true,
canUseCount: 0,
maxDeduction: 0,
deductTaxAndFee: true,
applicableProductIds: [],
reason: "",
reasonCode: "",
strategyResult: {
config: {
metadata: {
custom: {
...defaultStrategyMetadataCustom
}
}
}
}
});
continue;
}
const strategy = applicableStrategies[0];
const applicableProductIds = (0, import_utils.getApplicableProductIds)(voucher);
const { applicableTotal, applicableCount } = this.calculateApplicableProducts(
products,
applicableProductIds,
((_b = (_a = strategy == null ? void 0 : strategy.metadata) == null ? void 0 : _a.custom) == null ? void 0 : _b.deductTaxAndFee) ?? true
);
const context = {
entities: {
voucher,
products,
order: {
orderTotalAmount,
products
}
},
attributes: {
orderTotalAmount,
applicableProductTotalAmount: applicableTotal,
applicableProductCount: applicableCount,
voucherProductId: voucher.product_id,
productIds
},
metadata: {
timestamp: Date.now()
}
};
const evaluationResult = this.engine.evaluate(strategy, context);
const businessConfig = strategy.metadata.custom || {};
const maxDeduction = businessConfig.maxDeductionAmount || 0;
const canUseCount = businessConfig.maxUsagePerOrder || 0;
const deductTaxAndFee = businessConfig.deductTaxAndFee ?? true;
if (evaluationResult.applicable) {
results.push({
voucher,
isApplicable: true,
canUseCount,
maxDeduction,
deductTaxAndFee,
applicableProductIds: applicableProductIds || [],
strategyResult: evaluationResult
});
} else {
let reasonCode = "not_meet_the_required_conditions";
if (evaluationResult.code) {
const codeMapping = {
INSUFFICIENT_AMOUNT: "not_meet_the_required_conditions",
USAGE_LIMIT_EXCEEDED: "usage_limit_reached",
CHANNEL_NOT_ALLOWED: "not_available_for_this_channel",
ORDER_TYPE_NOT_ALLOWED: "not_valid_for_this_order_type",
DEDUCTION_LIMIT_EXCEEDED: "exceeds_the_maximum_deduction_limit"
};
reasonCode = codeMapping[evaluationResult.code] || "not_meet_the_required_conditions";
}
results.push({
voucher,
isApplicable: false,
canUseCount: 0,
maxDeduction: 0,
deductTaxAndFee: false,
applicableProductIds: [],
reason: this.getText(reasonCode),
reasonCode,
strategyResult: evaluationResult
});
}
}
return results;
}
/** 检查代金券/折扣卡是否可用 并返回config */
checkVoucherAvailability(input) {
var _a, _b, _c, _d, _e;
const { orderTotalAmount, products, vouchers } = input;
const results = this.evaluate(input);
const isAvailable = ((_a = results[0]) == null ? void 0 : _a.isApplicable) || false;
return {
isAvailable,
config: {
...(_e = (_d = (_c = (_b = results[0]) == null ? void 0 : _b.strategyResult) == null ? void 0 : _c.config) == null ? void 0 : _d.metadata) == null ? void 0 : _e.custom
}
};
}
/**
* 获取推荐券
* @param input 输入
* @returns 返回推荐券列表
*/
getRecommendedVouchers(input) {
const { orderTotalAmount, products, vouchers } = input;
const noApplicableVoucher = [];
const applicableVoucher = [];
vouchers.forEach((voucher) => {
if (voucher.unified_available_status === 1) {
applicableVoucher.push(voucher);
} else {
noApplicableVoucher.push(voucher);
}
});
const results = this.evaluate({
...input,
vouchers: applicableVoucher
});
const newVouchers = [];
results.forEach((item) => {
var _a, _b, _c;
if (item.isApplicable) {
newVouchers.push({
...item.voucher,
config: {
...defaultStrategyMetadataCustom,
...((_c = (_b = (_a = item == null ? void 0 : item.strategyResult) == null ? void 0 : _a.config) == null ? void 0 : _b.metadata) == null ? void 0 : _c.custom) || {}
}
});
} else {
noApplicableVoucher.push({
...item.voucher,
_unified_available_status: 0,
reason: item.reason,
reasonCode: item.reasonCode
});
}
});
const { recommended, transformList } = this.processVouchers(
newVouchers,
orderTotalAmount,
products
);
const recommendedAmount = recommended.reduce((sum, item) => {
return new import_decimal.default(sum).add(item._available_max_amount || 0).toNumber();
}, 0);
return {
// 推荐券总金额
recommendedAmount,
// 推荐券列表
recommended,
// 格式化后的可用券列表
transformList,
// 后端不可用券列表 和前端基于策略返回的 不可用列表 合并
noApplicableVoucher
};
}
enhanceWithReason(voucher) {
if (voucher._unified_available_status === 0 && voucher.reasonCode) {
return {
...voucher,
reason: this.getText(voucher.reasonCode)
};
}
return voucher;
}
/**
* 优惠券处理函数
* @param applicableVouchers 可用的券列表
* @param orderTotalAmount 订单总金额
* @param products 订单商品列表
* @returns 返回推荐券列表和全部列表,每个券包含 _available_max_amount 和 _unified_available_status
*/
processVouchers(vouchers, orderTotalAmount, products) {
const result = (0, import_utils.processVouchers)(vouchers, orderTotalAmount, products);
return {
recommended: result.recommended.map(
(item) => this.enhanceWithReason(item)
),
transformList: result.transformList.map(
(item) => this.enhanceWithReason(item)
)
};
}
/**
* 重新计算优惠券状态(基于已选券的增量计算)
* @param allVouchers 所有原始券列表
* @param selectedVouchers 已选中的券列表(按选中顺序)
* @param orderTotalAmount 订单总金额
* @param products 订单商品列表
* @returns 返回更新后的所有券列表和已选券的详细抵扣信息
*/
recalculateVouchers(allVouchers, selectedVouchers, orderTotalAmount, products) {
const result = (0, import_utils.recalculateVouchers)(
allVouchers,
selectedVouchers,
orderTotalAmount,
products
);
return {
allWithUpdatedStatus: result.allWithUpdatedStatus.map(
(item) => this.enhanceWithReason(item)
),
selectedWithDetails: result.selectedWithDetails.map(
(item) => this.enhanceWithReason(item)
)
};
}
/**
* 查找适用于指定 voucher 的策略配置
*/
findApplicableStrategies(voucher, strategyConfigs) {
return strategyConfigs.filter((config) => {
return this.checkVoucherInStrategy(voucher.product_id, config);
});
}
/**
* 检查策略中是否包含指定的 voucher ID
*/
checkVoucherInStrategy(voucherProductId, config) {
const rules = config.conditions.rules;
for (const rule of rules) {
if ("operator" in rule && "rules" in rule) {
if (this.checkVoucherInConditionGroup(voucherProductId, rule)) {
return true;
}
} else {
const conditionRule = rule;
if (conditionRule.field === "voucherProductId" && conditionRule.operator === "in" && Array.isArray(conditionRule.value)) {
if (conditionRule.value.includes(voucherProductId)) {
return true;
}
}
if (conditionRule.field === "voucherProductId" && (conditionRule.operator === "=" || conditionRule.operator === "==")) {
if (conditionRule.value === voucherProductId) {
return true;
}
}
}
}
return false;
}
/**
* 递归检查条件组中是否包含 voucher ID
*/
checkVoucherInConditionGroup(voucherProductId, group) {
for (const rule of group.rules) {
if ("operator" in rule && "rules" in rule) {
if (this.checkVoucherInConditionGroup(voucherProductId, rule)) {
return true;
}
} else {
if (rule.field === "voucherProductId" && rule.operator === "in" && Array.isArray(rule.value)) {
if (rule.value.includes(voucherProductId)) {
return true;
}
}
if (rule.field === "voucherProductId" && (rule.operator === "=" || rule.operator === "==")) {
if (rule.value === voucherProductId) {
return true;
}
}
}
}
return false;
}
/**
* 计算适用商品的总金额和数量
*/
calculateApplicableProducts(products, applicableProductIds, deductTaxAndFee) {
let total = 0;
let count = 0;
if (applicableProductIds !== null && applicableProductIds.length === 0) {
return { applicableTotal: 0, applicableCount: 0 };
}
products.forEach((product) => {
const productQuantity = (0, import_utils.getProductQuantity)(product);
const isMainProductApplicable = applicableProductIds === null || applicableProductIds.includes(product.product_id);
if (isMainProductApplicable) {
total += (0, import_utils.getMainProductPrice)(product, deductTaxAndFee) * productQuantity;
count += productQuantity;
}
if (product.product_bundle && product.product_bundle.length > 0) {
product.product_bundle.forEach((bundleItem) => {
if ((0, import_utils.getBundleItemIsOriginalPrice)(bundleItem)) {
const isBundleItemApplicable = applicableProductIds === null || applicableProductIds.includes(bundleItem.bundle_product_id);
if (isBundleItemApplicable) {
const bundleItemQuantity = bundleItem.num * productQuantity;
total += (0, import_utils.getBundleItemPrice)(
bundleItem,
productQuantity,
deductTaxAndFee
);
count += bundleItemQuantity;
}
}
});
}
});
return { applicableTotal: total, applicableCount: count };
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
WalletPassEvaluator
});