UNPKG

@pisell/pisellos

Version:

一个可扩展的前端模块化SDK框架,支持插件系统

424 lines (422 loc) 14.6 kB
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 });