UNPKG

@pisell/pisellos

Version:

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

1,055 lines (1,054 loc) 94.2 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/modules/Rules/index.ts var Rules_exports = {}; __export(Rules_exports, { RulesModule: () => RulesModule }); module.exports = __toCommonJS(Rules_exports); var import_BaseModule = require("../BaseModule"); var import_types = require("./types"); var import_utils = require("../../solution/ShopDiscount/utils"); var import_utils2 = require("../Cart/utils"); var import_decimal = __toESM(require("decimal.js")); var import_lodash_es = require("lodash-es"); var import_dayjs = __toESM(require("dayjs")); var import_utils3 = require("../../solution/ShopDiscount/utils"); var import_utils4 = require("../../solution/ShopDiscount/utils"); var RulesModule = class extends import_BaseModule.BaseModule { constructor(name, version) { super(name, version); this.defaultName = "rules"; this.defaultVersion = "1.0.0"; this.hooks = {}; } async initialize(core, options) { this.core = core; this.hooks = options == null ? void 0 : options.hooks; this.store = options == null ? void 0 : options.store; this.window = core.getPlugin("window"); } async setRulesList(rulesList) { this.store.rulesList = rulesList; await this.core.effects.emit(`${this.name}:onRulesListChange`, rulesList); } getRulesList() { return this.store.rulesList; } getWalletPassEvaluator() { var _a, _b; return (_b = (_a = this.window).getWalletPassEvaluator) == null ? void 0 : _b.call(_a); } // 商品不需要holder,则不需要判断,直接返回true,商品需要holder但是还没填写,那么暂时不使用带有holder的券,直到填写才去匹配 checkHolderMatch(discount, product, holders) { var _a; if (((_a = discount.holder) == null ? void 0 : _a.holder_type) !== "form") return true; const orderHolderId = Array.isArray(holders) && holders.length > 0 ? holders[0].form_record_id : void 0; const productHolderId = Array.isArray(product.holder_id) ? product.holder_id[0] : product.holder_id; if (!product.isNeedHolder) return true; if (!orderHolderId && !productHolderId) return false; return (productHolderId || orderHolderId) === discount.holder.holder_id; } // 判断discountList 是否可以对当前productList生效 isDiscountListAvailable({ oldDiscountList, newDiscountList, productList, orderTotalAmount, holders, isFormSubject }) { if (!newDiscountList || newDiscountList.length === 0) { return { isAvailable: false, discountList: oldDiscountList, productList }; } if (productList.every((item) => { var _a; const product = this.hooks.getProduct(item); return product.booking_id && (((_a = product.discount_list) == null ? void 0 : _a.length) || (newDiscountList[0].tag === "good_pass" ? product.price == 0 : product.total == 0)); })) { return { isAvailable: false, discountList: oldDiscountList, productList, unavailableReason: import_types.UnavailableReason.AlreadyUsed }; } const filteredOldDiscountList = oldDiscountList.filter( (discount) => !discount.isEditMode && (discount.tag !== "good_pass" || discount.isScan) ); const mergedDiscountList = (0, import_utils.uniqueById)([ ...filteredOldDiscountList, ...newDiscountList ]); const result = this.calcDiscount({ discountList: mergedDiscountList, productList: [...productList], holders, orderTotalAmount, isFormSubject }, { scan: true }); let hasApplicableDiscount = false; const newDiscountIds = newDiscountList.map((discount) => discount.id); result.productList.forEach((product) => { const { discount_list, bundle } = this.hooks.getProduct(product); const allDiscountList = [...discount_list || []]; (bundle || []).forEach((item) => { allDiscountList.push(...(item == null ? void 0 : item.discount_list) || []); }); if (allDiscountList && allDiscountList.length > 0) { const usedNewDiscount = allDiscountList.some( (discount) => { var _a; return newDiscountIds.includes((_a = discount == null ? void 0 : discount.discount) == null ? void 0 : _a.resource_id); } ); if (usedNewDiscount) { hasApplicableDiscount = true; } } }); let unavailableReason; if (!hasApplicableDiscount) { unavailableReason = this.getUnavailableReason(newDiscountList, productList); } return { isAvailable: hasApplicableDiscount, discountList: hasApplicableDiscount ? result.discountList : oldDiscountList, productList: hasApplicableDiscount ? result.productList : productList, unavailableReason }; } filterDiscountListByType(discountList, type) { return (discountList || []).filter((item) => item.type === type || item.tag === type); } // 获取券不可用的原因 getUnavailableReason(discountList, productList) { var _a; for (const discount of discountList) { for (const item of productList) { const product = this.hooks.getProduct(item); const bookingTime = ((product == null ? void 0 : product.startDate) || (0, import_dayjs.default)()).format("YYYY-MM-DD HH:mm:ss"); const filteredList = (0, import_utils.filterDiscountListByBookingTime)([discount], bookingTime); if (filteredList.length === 0) { return import_types.UnavailableReason.TimeLimit; } } } for (const discount of discountList) { const limitedData = discount.limited_relation_product_data; let hasApplicableProduct = false; for (const item of productList) { const product = this.hooks.getProduct(item); if (limitedData.type === "product_all") { hasApplicableProduct = true; break; } else if ((_a = limitedData.product_ids) == null ? void 0 : _a.includes(product.id)) { hasApplicableProduct = true; break; } } if (!hasApplicableProduct) { return import_types.UnavailableReason.ProductNotApplicable; } } return import_types.UnavailableReason.Unknown; } calcDiscount({ discountList, productList, holders, isFormSubject, orderTotalAmount }, options) { const editModeDiscount = []; const addModeDiscount = []; discountList.forEach((discount) => { if (discount.isEditMode) { editModeDiscount.push(discount); } else { addModeDiscount.push(discount); } }); const editModeOrderLevelProductIds = /* @__PURE__ */ new Set(); editModeDiscount.forEach((discount) => { var _a, _b; if (((_a = discount.discount) == null ? void 0 : _a.discount_calculation_mode) === "order_level") { editModeOrderLevelProductIds.add((_b = discount == null ? void 0 : discount.discount) == null ? void 0 : _b.discount_product_id); } }); if (editModeOrderLevelProductIds.size > 0) { addModeDiscount.forEach((discount) => { if (editModeOrderLevelProductIds.has(discount.product_id)) { discount.isDisabled = true; } }); } const filteredDiscountList = addModeDiscount.filter((discount) => { return !discount.isManualSelect; }); const flattenProductsWithBundle = (productList2) => { const flattened = []; productList2.forEach((originProduct) => { const product = this.hooks.getProduct(originProduct); flattened.push({ type: "main", originProduct, product, price: Number(product.price || 0), id: product.id, _id: product._id, parentId: product._id, quantity: product.quantity, num: product.num, booking_id: product.booking_id }); if (product.bundle && Array.isArray(product.bundle) && product.bundle.length > 0) { product.bundle.forEach((bundleItem, bundleIndex) => { flattened.push({ type: "bundle", originProduct, parentProduct: product, bundleItem, bundleIndex, // 虚拟商品属性 price: Number(bundleItem.price || 0), id: bundleItem._bundle_product_id, // 🔥 使用 _bundle_product_id _id: `${product._id}_bundle_${bundleIndex}`, parentId: product._id, num: bundleItem.num || 1, quantity: bundleItem.num || 1, total: new import_decimal.default(bundleItem.price || 0).mul(bundleItem.num || 1).toNumber(), origin_total: new import_decimal.default(bundleItem.price || 0).mul(bundleItem.num || 1).toNumber(), original_price: bundleItem.original_price, // 继承主商品属性 booking_id: bundleItem.booking_id, discount_list: bundleItem.discount_list || [] }); }); } }); return flattened; }; const sortedDiscountList = [...filteredDiscountList].sort((a, b) => { const isHolderDiscount = (discount) => { var _a, _b; return ((_b = (_a = discount.metadata) == null ? void 0 : _a.holder) == null ? void 0 : _b.type) === "custom"; }; const isGoodPass = (discount) => discount.tag === "good_pass"; const isOrderLevelDiscount = (discount) => { var _a; return discount.tag === "product_discount_card" && ((_a = discount.metadata) == null ? void 0 : _a.discount_calculation_mode) === "order_level"; }; const isItemLevelDiscount = (discount) => { var _a; return discount.tag === "product_discount_card" && ((_a = discount.metadata) == null ? void 0 : _a.discount_calculation_mode) !== "order_level"; }; const getPriority = (discount) => { const isHolder = isHolderDiscount(discount); if (isHolder) { if (isGoodPass(discount)) return 1; if (isItemLevelDiscount(discount)) return 2; if (isOrderLevelDiscount(discount)) return 3; } else { if (isGoodPass(discount)) return 4; if (isItemLevelDiscount(discount)) return 5; if (isOrderLevelDiscount(discount)) return 6; } return 7; }; function compareByExpireTime(itemA, itemB) { if (itemA.expire_time && itemB.expire_time) { const timeA = new Date(itemA.expire_time).getTime(); const timeB = new Date(itemB.expire_time).getTime(); return timeA - timeB; } return itemA.expire_time ? -1 : itemB.expire_time ? 1 : 0; } function compareDiscountCardValue(itemA, itemB) { var _a, _b; const typeA = ((_a = itemA.metadata) == null ? void 0 : _a.discount_card_type) || "percent"; const typeB = ((_b = itemB.metadata) == null ? void 0 : _b.discount_card_type) || "percent"; if (typeA === "fixed_amount" && typeB === "percent") return -1; if (typeA === "percent" && typeB === "fixed_amount") return 1; if (typeA === "fixed_amount" && typeB === "fixed_amount") { if (itemA.par_value !== itemB.par_value) { const valueA = new import_decimal.default(itemA.par_value || 0); const valueB = new import_decimal.default(itemB.par_value || 0); return valueB.minus(valueA).toNumber(); } } if (typeA === "percent" && typeB === "percent") { if (itemA.par_value !== itemB.par_value) { const valueA = new import_decimal.default(100).minus(itemA.par_value || 0); const valueB = new import_decimal.default(100).minus(itemB.par_value || 0); return valueA.minus(valueB).toNumber(); } } return 0; } const priorityA = getPriority(a); const priorityB = getPriority(b); if (priorityA !== priorityB) { return priorityA - priorityB; } if (isGoodPass(a) && isGoodPass(b)) { return compareByExpireTime(a, b); } if (a.tag === "product_discount_card" && b.tag === "product_discount_card") { const valueCompare = compareDiscountCardValue(a, b); if (valueCompare !== 0) return valueCompare; return compareByExpireTime(a, b); } return compareByExpireTime(a, b); }); const flattenedList = flattenProductsWithBundle(productList); const isEditModeAddNewProduct = flattenedList.find((n) => n.booking_id) && flattenedList.find((n) => !n.booking_id); const sortedFlattenedList = flattenedList.sort((a, b) => { var _a, _b; const priceA = new import_decimal.default( a.type === "bundle" ? a.original_price ?? a.price ?? "0" : a.price || "0" ); const priceB = new import_decimal.default( b.type === "bundle" ? b.original_price ?? b.price ?? "0" : b.price || "0" ); if (priceA.equals(priceB)) { if (a.type !== b.type) { return a.type === "main" ? -1 : 1; } if (a.type === "main" && b.type === "main") { if (a.product.quantity === b.product.quantity) { return (((_a = b.product.discount_list) == null ? void 0 : _a.length) || 0) - (((_b = a.product.discount_list) == null ? void 0 : _b.length) || 0); } return a.product.quantity - b.product.quantity; } if (a.type === "bundle" && b.type === "bundle") { return (a.num || 1) - (b.num || 1); } } return priceB.minus(priceA).toNumber(); }); const evaluator = this.getWalletPassEvaluator(); if (evaluator) { addModeDiscount.forEach((discount) => { var _a, _b; const discountType = discount.tag || discount.type; if (["good_pass", "discount_card", "product_discount_card"].includes( discountType )) { const voucher = { id: discount.id, amount: Number(discount.par_value || 0), balance: Number(discount.balance || 0), type: discountType, product_id: discount.product_id, unified_available_status: 1, available_product_type: (_a = discount.limited_relation_product_data) == null ? void 0 : _a.type, available_product_ids: (_b = discount.limited_relation_product_data) == null ? void 0 : _b.product_ids }; const productsForEvaluate = sortedFlattenedList.map((item) => ({ product_id: item.id, price: item.price || 0, quantity: item.quantity || item.num || 1, selling_price: item.price || 0 })); const result = evaluator.checkVoucherAvailability({ orderTotalAmount, products: productsForEvaluate, vouchers: [voucher] }); if (result.isAvailable) { discount.config = { ...result.config, isAvailable: true }; } else { discount.config = { isAvailable: false }; } } }); } const usedDiscounts = /* @__PURE__ */ new Map(); const usedProductIdCounts = /* @__PURE__ */ new Map(); const usedDiscountCardLimitCounts = /* @__PURE__ */ new Map(); editModeDiscount.forEach((discount) => { var _a; const discountType = discount.tag || discount.type; if (["discount_card", "product_discount_card"].includes(discountType)) { const currentCount = usedDiscountCardLimitCounts.get(discount.id) || 0; usedDiscountCardLimitCounts.set(discount.id, currentCount + (((_a = discount.metadata) == null ? void 0 : _a.num) || 1)); } }); const discountApplicability = /* @__PURE__ */ new Map(); const discountApplicableProducts = /* @__PURE__ */ new Map(); addModeDiscount.forEach((discount) => { discountApplicability.set(discount.id, []); discountApplicableProducts.set(discount.id, []); }); const orderLevelDiscountAllocations = /* @__PURE__ */ new Map(); const orderLevelDiscountApplicableItems = /* @__PURE__ */ new Map(); const itemApplicableDiscounts = /* @__PURE__ */ new Map(); const checkItemApplicableForDiscount = (flatItem, discount) => { var _a, _b, _c, _d, _e, _f, _g, _h; let product; if (flatItem.type === "main") { product = flatItem.product; } else { product = { _id: flatItem._id, id: flatItem.id, price: flatItem.price, quantity: flatItem.quantity, num: flatItem.num, booking_id: flatItem.booking_id, discount_list: flatItem.discount_list || [], startDate: (_a = flatItem.parentProduct) == null ? void 0 : _a.startDate }; } const isAvailableProduct = flatItem.type === "main" ? !((product == null ? void 0 : product.booking_id) && ((_b = product == null ? void 0 : product.discount_list) == null ? void 0 : _b.length) && ((_c = product == null ? void 0 : product.discount_list) == null ? void 0 : _c.every((d) => d.id && ["good_pass", "discount_card", "product_discount_card"].includes(d.tag || d.type)))) : !((flatItem == null ? void 0 : flatItem.booking_id) && !!((_e = (_d = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _d.discount_list) == null ? void 0 : _e.length) && ((_g = (_f = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _f.discount_list) == null ? void 0 : _g.every((d) => d.id))); if (!isAvailableProduct) { return false; } if ((0, import_lodash_es.isBoolean)(product.vouchersApplicable) && !product.vouchersApplicable) { return false; } if (Number(product.price) <= 0 || !product.price) { return false; } const limitedData = discount.limited_relation_product_data; const timeLimit = !!(0, import_utils.filterDiscountListByBookingTime)([discount], ((product == null ? void 0 : product.startDate) || (0, import_dayjs.default)()).format("YYYY-MM-DD HH:mm:ss")).length; if (!timeLimit) { return false; } let isLimitedProduct = false; if (limitedData.type === "product_all") { if (limitedData.filter === 1 && ((_h = limitedData.exclude_product_ids) == null ? void 0 : _h.includes(product.id))) { isLimitedProduct = false; } else { isLimitedProduct = true; } } else if (limitedData.product_ids && limitedData.product_ids.includes(product.id)) { isLimitedProduct = true; } const isBundleAvailable = this.checkPackageSubItemUsageRules(discount, flatItem); return isLimitedProduct && isBundleAvailable; }; const selectedOrderLevelDiscounts = sortedDiscountList.filter((discount) => { return (0, import_utils3.isOrderLevelFixedAmountDiscount)(discount) && discount.isSelected !== false; }); selectedOrderLevelDiscounts.forEach((discount) => { const applicableItemIds = /* @__PURE__ */ new Set(); sortedFlattenedList.forEach((flatItem) => { if (checkItemApplicableForDiscount(flatItem, discount)) { applicableItemIds.add(flatItem._id); if (!itemApplicableDiscounts.has(flatItem._id)) { itemApplicableDiscounts.set(flatItem._id, /* @__PURE__ */ new Set()); } itemApplicableDiscounts.get(flatItem._id).add(discount.id); } }); orderLevelDiscountApplicableItems.set(discount.id, applicableItemIds); }); const occupiedItems = /* @__PURE__ */ new Map(); selectedOrderLevelDiscounts.forEach((discount) => { const limitedData = discount.limited_relation_product_data; const isExclusiveDiscount = limitedData.type !== "product_all"; if (isExclusiveDiscount) { const applicableItems = orderLevelDiscountApplicableItems.get(discount.id); if (applicableItems) { applicableItems.forEach((itemId) => { if (!occupiedItems.has(itemId)) { occupiedItems.set(itemId, discount.id); } }); } } }); console.log("occupiedItems", occupiedItems, "orderLevelDiscountApplicableItems", orderLevelDiscountApplicableItems); sortedDiscountList.forEach((discount) => { if (!(0, import_utils3.isOrderLevelFixedAmountDiscount)(discount)) { return; } const applicableProducts = []; sortedFlattenedList.forEach((flatItem) => { var _a, _b, _c; const occupyingDiscountId = occupiedItems.get(flatItem._id); if (occupyingDiscountId !== void 0 && occupyingDiscountId !== discount.id) { return; } if (!checkItemApplicableForDiscount(flatItem, discount)) { return; } let product; if (flatItem.type === "main") { product = flatItem.product; } else { product = { _id: flatItem._id, id: flatItem.id, price: flatItem.price, quantity: flatItem.quantity, num: flatItem.num }; } const quantity = flatItem.type === "main" ? product.num || product.quantity || 1 : (product.num || product.quantity || 1) * (((_a = flatItem.parentProduct) == null ? void 0 : _a.num) || ((_b = flatItem.parentProduct) == null ? void 0 : _b.quantity) || 1); const originalAmount = flatItem.type === "main" ? Number(product.price ?? 0) : Number(flatItem.original_price ?? flatItem.price ?? 0); const productData = { productId: flatItem._id, amount: originalAmount, quantity }; if (flatItem.type === "bundle") { productData.parentQuantity = ((_c = flatItem.parentProduct) == null ? void 0 : _c.quantity) || 1; } applicableProducts.push(productData); }); if (applicableProducts.length > 0) { const allocation = (0, import_utils4.calculateOrderLevelDiscountAllocation)(discount, applicableProducts); orderLevelDiscountAllocations.set(discount.id, allocation); } }); const processedProductsMap = /* @__PURE__ */ new Map(); const appliedDiscountProducts = /* @__PURE__ */ new Map(); sortedFlattenedList.forEach((flatItem) => { var _a; let product, originProduct; if (flatItem.type === "main") { product = flatItem.product; originProduct = flatItem.originProduct; } else { product = { startDate: (_a = flatItem == null ? void 0 : flatItem.parentProduct) == null ? void 0 : _a.startDate, _id: flatItem._id, id: flatItem.id, price: flatItem.price, quantity: flatItem.quantity, num: flatItem.num, total: flatItem.total, origin_total: flatItem.origin_total, booking_id: flatItem.booking_id, discount_list: flatItem.discount_list || [] }; originProduct = flatItem.originProduct; } addModeDiscount.forEach((discount) => { var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j; const limitedData = discount == null ? void 0 : discount.limited_relation_product_data; const _tempVar = (flatItem == null ? void 0 : flatItem.type) === "bundle" ? flatItem == null ? void 0 : flatItem.parentProduct : flatItem == null ? void 0 : flatItem.product; const isHolderMatch = this.checkHolderMatch( discount, { isNeedHolder: isFormSubject && !(_tempVar == null ? void 0 : _tempVar.isNormalProduct), holder_id: (_tempVar == null ? void 0 : _tempVar.holder_id) || product.holder_id }, holders ); let timeLimit = true; timeLimit = !!(0, import_utils.filterDiscountListByBookingTime)([discount], ((product == null ? void 0 : product.startDate) || (0, import_dayjs.default)()).format("YYYY-MM-DD HH:mm:ss")).length; const isLimitedProduct = (limitedData.type === "product_all" && limitedData.filter !== 1 || limitedData.type === "product_all" && limitedData.filter === 1 && !limitedData.exclude_product_ids.includes(product.id) || limitedData.product_ids && limitedData.product_ids.includes(product.id)) && isHolderMatch; const isAvailableProduct = flatItem.type === "main" ? !((product == null ? void 0 : product.booking_id) && ((_a2 = product == null ? void 0 : product.discount_list) == null ? void 0 : _a2.length) && ((_b = product == null ? void 0 : product.discount_list) == null ? void 0 : _b.every( (discount2) => discount2.id && [ "good_pass", "discount_card", "product_discount_card" ].includes(discount2.tag || discount2.type) ))) : !((flatItem == null ? void 0 : flatItem.booking_id) && !!((_d = (_c = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _c.discount_list) == null ? void 0 : _d.length) && ((_f = (_e = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _e.discount_list) == null ? void 0 : _f.every((discount2) => discount2.id))); const isBundleAvailable = this.checkPackageSubItemUsageRules(discount, flatItem); if (isAvailableProduct && isLimitedProduct && timeLimit && isBundleAvailable && ((_g = discount.config) == null ? void 0 : _g.isAvailable)) { (_h = discountApplicability.get(discount.id)) == null ? void 0 : _h.push(product.id); const applicableProducts = discountApplicableProducts.get(discount.id) || []; const discountType = discount.tag || discount.type; const isGoodPass = discountType === "good_pass"; const num = isGoodPass || (flatItem == null ? void 0 : flatItem.type) === "main" ? 1 : product.num; const productData = { amount: product.price * num, type: discountType, tag: discountType, discount: { discount_card_type: (_i = discount == null ? void 0 : discount.metadata) == null ? void 0 : _i.discount_card_type, fixed_amount: product.price, discount_calculation_mode: (_j = discount == null ? void 0 : discount.metadata) == null ? void 0 : _j.discount_calculation_mode, resource_id: discount.id, title: discount.format_title, original_amount: product.price || product.origin_total, pre_value: discount.par_value, product_id: originProduct.id, discount_product_id: discount.product_id }, metadata: { num, discount_rule_uncheck_flag: discount == null ? void 0 : discount.discount_rule_uncheck_flag } }; applicableProducts.push(productData); discountApplicableProducts.set(discount.id, applicableProducts); } }); }); const processedFlatItemsMap = /* @__PURE__ */ new Map(); sortedFlattenedList.forEach((flatItem, index) => { var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J; let product, originProduct; if (flatItem.type === "main") { product = flatItem.product; originProduct = flatItem.originProduct; } else { product = { startDate: (_a = flatItem == null ? void 0 : flatItem.parentProduct) == null ? void 0 : _a.startDate, _id: flatItem._id, id: flatItem.id, price: flatItem.price, quantity: flatItem.quantity, num: flatItem.num, total: flatItem.total, original_price: (_b = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _b.original_price, origin_total: (_c = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _c.original_price, booking_id: flatItem.booking_id, discount_list: ((_d = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _d.discount_list) || [] }; originProduct = flatItem.originProduct; } if ((product == null ? void 0 : product.booking_id) && ((_e = product.discount_list) == null ? void 0 : _e.length) && ((_f = product == null ? void 0 : product.discount_list) == null ? void 0 : _f.every( (discount) => discount.id && ["good_pass", "discount_card", "product_discount_card"].includes( discount.tag || discount.type ) ))) { if (flatItem.type === "main") { processedProductsMap.set(product._id, [originProduct]); } else { processedFlatItemsMap.set(flatItem._id, [ { ...flatItem, processed: true } ]); } return; } const applicableDiscounts = sortedDiscountList.filter((discount) => { var _a2, _b2, _c2, _d2, _e2; const discountType2 = discount.tag || discount.type; if (["good_pass", "discount_card", "product_discount_card"].includes( discountType2 )) { if (discount.config === void 0 || !((_a2 = discount == null ? void 0 : discount.config) == null ? void 0 : _a2.isAvailable)) { return false; } } if ((Number(product.price) <= 0 || !product.price) && !((_b2 = product.discount_list) == null ? void 0 : _b2.length) && (discount.tag || discount.type) === "good_pass") return false; if ((Number(product.price) <= 0 || !product.price) && !((_c2 = product.discount_list) == null ? void 0 : _c2.find((n) => { var _a3; return ((_a3 = n.discount) == null ? void 0 : _a3.resource_id) === discount.id; })) && (discount.tag || discount.type) !== "good_pass") return false; const targetUsedDiscounts = usedDiscounts.get(discount.id); if (targetUsedDiscounts && (discount.tag || discount.type) === "good_pass") return false; if ((discount.tag || discount.type) === "good_pass") { const maxUsagePerOrder = (_d2 = discount.config) == null ? void 0 : _d2.maxUsagePerOrder; if (maxUsagePerOrder && maxUsagePerOrder > 0) { const currentUsedCount = usedProductIdCounts.get(discount.product_id) || 0; if (currentUsedCount >= maxUsagePerOrder) { return false; } } } const discountTypeForLimit = discount.tag || discount.type; if (["discount_card", "product_discount_card"].includes(discountTypeForLimit)) { const applicableProductLimitConfig = ((_e2 = discount.config) == null ? void 0 : _e2.applicableProductLimit) || 0; if (applicableProductLimitConfig > 0) { const currentUsedLimitCount = usedDiscountCardLimitCounts.get(discount.id) || 0; if (currentUsedLimitCount >= applicableProductLimitConfig) { return false; } } } const limitedData = discount.limited_relation_product_data; const _tempVar = (flatItem == null ? void 0 : flatItem.type) === "bundle" ? flatItem == null ? void 0 : flatItem.parentProduct : flatItem == null ? void 0 : flatItem.product; const isHolderMatch = this.checkHolderMatch( discount, { isNeedHolder: isFormSubject && !(_tempVar == null ? void 0 : _tempVar.isNormalProduct), holder_id: (_tempVar == null ? void 0 : _tempVar.holder_id) || product.holder_id }, holders ); if (!isHolderMatch) return false; let timeLimit = true; timeLimit = !!(0, import_utils.filterDiscountListByBookingTime)([discount], (product.startDate || (0, import_dayjs.default)()).format("YYYY-MM-DD HH:mm:ss")).length; if (!timeLimit) { return false; } if (limitedData.type === "product_all") { if (limitedData.filter === 1 && limitedData.exclude_product_ids.includes(product.id)) { return false; } if (!this.checkPackageSubItemUsageRules(discount, flatItem)) { return false; } return true; } else if (limitedData.product_ids && limitedData.product_ids.includes(product.id)) { if (!this.checkPackageSubItemUsageRules(discount, flatItem)) { return false; } return true; } return false; }); const selectedDiscountCard = applicableDiscounts.find( (n) => n.isScan && n.isSelected && (n.tag || n.type) !== "good_pass" ); const selectedDiscount = selectedDiscountCard || applicableDiscounts[0]; let isManualDiscount = false; if (flatItem.type === "main") { isManualDiscount = typeof product.isManualDiscount === "boolean" ? product.isManualDiscount : product.total != product.origin_total && (product.bundle || []).every( (item) => { var _a2; return !((_a2 = item.discount_list || []) == null ? void 0 : _a2.length); } ) && (!((_g = product.discount_list) == null ? void 0 : _g.length) || ((_i = (_h = product == null ? void 0 : product.discount_list) == null ? void 0 : _h.every) == null ? void 0 : _i.call( _h, (item) => item.type === "product" ))); if (product.inPromotion) { isManualDiscount = false; } } else { const parentProduct = flatItem.parentProduct; if (parentProduct) { isManualDiscount = typeof parentProduct.isManualDiscount === "boolean" ? parentProduct.isManualDiscount : parentProduct.total != parentProduct.origin_total && (parentProduct.bundle || []).every( (item) => { var _a2; return !((_a2 = item.discount_list || []) == null ? void 0 : _a2.length); } ) && (!((_j = parentProduct.discount_list) == null ? void 0 : _j.length) || ((_l = (_k = parentProduct == null ? void 0 : parentProduct.discount_list) == null ? void 0 : _k.every) == null ? void 0 : _l.call( _k, (item) => item.type === "product" ))); } } if (options == null ? void 0 : options.discountId) { if (flatItem.type === "main" && ((_m = product.discount_list) == null ? void 0 : _m.some( (item) => { var _a2; return ((_a2 = item.discount) == null ? void 0 : _a2.resource_id) === options.discountId; } ))) { isManualDiscount = false; } if (flatItem.type === "bundle") { if (((_n = product.discount_list) == null ? void 0 : _n.some( (item) => { var _a2; return ((_a2 = item.discount) == null ? void 0 : _a2.resource_id) === options.discountId; } )) || ((_p = (_o = flatItem.parentProduct) == null ? void 0 : _o.discount_list) == null ? void 0 : _p.some( (item) => { var _a2; return ((_a2 = item.discount) == null ? void 0 : _a2.resource_id) === options.discountId; } ))) { isManualDiscount = false; } } } if (options == null ? void 0 : options.selectedList) { if (flatItem.type === "main" && ((_q = product.discount_list) == null ? void 0 : _q.some( (item) => { var _a2; return (_a2 = options == null ? void 0 : options.selectedList) == null ? void 0 : _a2.some( (n) => { var _a3; return n.discountId === ((_a3 = item.discount) == null ? void 0 : _a3.resource_id); } ); } ))) { isManualDiscount = false; } if (flatItem.type === "bundle") { if (((_r = product.discount_list) == null ? void 0 : _r.some( (item) => { var _a2; return (_a2 = options == null ? void 0 : options.selectedList) == null ? void 0 : _a2.some( (n) => { var _a3; return n.discountId === ((_a3 = item.discount) == null ? void 0 : _a3.resource_id); } ); } )) || ((_t = (_s = flatItem.parentProduct) == null ? void 0 : _s.discount_list) == null ? void 0 : _t.some( (item) => { var _a2; return (_a2 = options == null ? void 0 : options.selectedList) == null ? void 0 : _a2.some( (n) => { var _a3; return n.discountId === ((_a3 = item.discount) == null ? void 0 : _a3.resource_id); } ); } ))) { isManualDiscount = false; } } } if (applicableDiscounts.length === 0 || isManualDiscount || (0, import_lodash_es.isBoolean)(product.vouchersApplicable) && !product.vouchersApplicable) { if (flatItem.type === "main") { if (product.isClient) { processedProductsMap.set(product._id, [ this.hooks.setProduct(originProduct, { ...isManualDiscount ? {} : { origin_total: (0, import_utils2.getProductOriginTotalPrice)({ product: { original_price: product.original_price }, bundle: product.bundle, options: product.options }), variant: originProduct._productInit.variant, original_price: originProduct._productInit.original_price, total: (0, import_utils2.getProductTotalPrice)({ product: { price: product.price }, bundle: product.bundle, options: product.options }), price: product.price }, discount_list: this.filterDiscountListByType(product.discount_list, "promotion") }) ]); } else { let total = product.inPromotion ? ((_u = product == null ? void 0 : product._promotion) == null ? void 0 : _u.finalPrice) ?? product.origin_total ?? product.total : product.origin_total ?? product.total; let main_product_selling_price = product.price ?? product.main_product_selling_price; if ((product.discount_list || []).some((item) => item.type === "promotion") || (0, import_lodash_es.isBoolean)(product.vouchersApplicable) && !product.vouchersApplicable) { total = product.total ?? product.origin_total; main_product_selling_price = product.main_product_selling_price ?? main_product_selling_price; } processedProductsMap.set(product._id, [ this.hooks.setProduct(originProduct, { ...isManualDiscount ? { price: product.price } : { _id: product._id.split("___")[0] + "___" + index, total, price: product.price, main_product_selling_price }, discount_list: this.filterDiscountListByType(product.discount_list, "promotion") }) ]); } } else { processedFlatItemsMap.set(flatItem._id, [{ ...flatItem, discount_list: this.filterDiscountListByType(((_v = flatItem.bundleItem) == null ? void 0 : _v.discount_list) || [], "promotion"), price: isManualDiscount ? flatItem.bundleItem.price : flatItem.bundleItem.original_price, processed: true }]); } return; } if (applicableDiscounts.length && product.booking_id && typeof selectedDiscount.isManualSelect === "undefined" && !(options == null ? void 0 : options.scan) && !isEditModeAddNewProduct) { return; } const discountType = selectedDiscount.tag || selectedDiscount.type; const isGoodPass = discountType === "good_pass"; const isDiscountCard = ["discount_card", "product_discount_card"].includes(discountType); const applicableProductLimit = ((_w = selectedDiscount.config) == null ? void 0 : _w.applicableProductLimit) || 0; const isNeedSplit = isGoodPass || isDiscountCard && applicableProductLimit > 0; const totalQuantity = product.quantity || product.num || 1; const availableGoodPassCount = applicableDiscounts.filter( (item) => (item.tag || item.type) === "good_pass" ).length; let maxUsageLimit; if (isGoodPass) { maxUsageLimit = availableGoodPassCount; if (selectedDiscount.config && selectedDiscount.config.maxUsagePerOrder) { maxUsageLimit = Math.min( availableGoodPassCount, selectedDiscount.config.maxUsagePerOrder ); } } else if (isDiscountCard && applicableProductLimit > 0) { const usedLimitCount = usedDiscountCardLimitCounts.get(selectedDiscount.id) || 0; maxUsageLimit = Math.max(0, applicableProductLimit - usedLimitCount); } else { maxUsageLimit = 1; } const splitCount = isNeedSplit ? Math.min(product.quantity || product.num || 1, maxUsageLimit) : 1; const arr = []; if (flatItem.type === "main") { if (splitCount < totalQuantity && isNeedSplit) { let total = product.origin_total ?? product.total; if ((product.discount_list || []).some((item) => item.type === "promotion")) { total = product.total ?? product.origin_total; } arr.push( this.hooks.setProduct(originProduct, { discount_list: this.filterDiscountListByType(product.discount_list, "promotion"), quantity: totalQuantity - splitCount, _id: product._id.split("___")[0], total }) ); } for (let i = 0; i < splitCount; i++) { const currentSelectedDiscount = isGoodPass ? selectedDiscountCard || applicableDiscounts[i] : selectedDiscountCard || applicableDiscounts[0]; usedDiscounts.set(currentSelectedDiscount.id, true); if ((currentSelectedDiscount.tag || currentSelectedDiscount.type) === "good_pass") { const currentCount = usedProductIdCounts.get(currentSelectedDiscount.product_id) || 0; usedProductIdCounts.set(currentSelectedDiscount.product_id, currentCount + 1); } const currentDiscountTypeForCount = currentSelectedDiscount.tag || currentSelectedDiscount.type; if (["discount_card", "product_discount_card"].includes(currentDiscountTypeForCount)) { const currentLimitCount = usedDiscountCardLimitCounts.get(currentSelectedDiscount.id) || 0; usedDiscountCardLimitCounts.set(currentSelectedDiscount.id, currentLimitCount + 1); } const appliedProducts = appliedDiscountProducts.get(currentSelectedDiscount.id) || []; let productOriginTotal = product.origin_total || product.total || 0; if (this.filterDiscountListByType(product.discount_list, "promotion").length && product.origin_total) { productOriginTotal = product.origin_total; } if (Number(((_x = originProduct == null ? void 0 : originProduct._productInit) == null ? void 0 : _x.original_price) || 0) > 0 && product.origin_total && product.total && product.origin_total !== product.total) { productOriginTotal = product.total; } const isOrderLevel = (0, import_utils3.isOrderLevelFixedAmountDiscount)(selectedDiscount); const orderLevelAllocation = isOrderLevel ? orderLevelDiscountAllocations.get(selectedDiscount.id) : null; const productAllocation = orderLevelAllocation == null ? void 0 : orderLevelAllocation.get(flatItem._id); let targetProductTotal; let amount; let productDiscountDifference; if (isOrderLevel && productAllocation) { amount = productAllocation.discountAmount; productDiscountDifference = productAllocation.difference; targetProductTotal = Math.max(new import_decimal.default(product.price).minus(amount).toNumber(), 0); } else { targetProductTotal = (0, import_utils.getDiscountAmount)(currentSelectedDiscount, product.price, product.price); amount = new import_decimal.default(product.price).minus(new import_decimal.default(targetProductTotal)).toNumber(); } const currentDiscountType = currentSelectedDiscount.tag === "product_discount_card" ? "discount_card" : currentSelectedDiscount.tag; const discountType2 = selectedDiscount.tag || selectedDiscount.type; const currentIsGoodPass = currentDiscountType === "good_pass"; const discountDetail = { amount, type: selectedDiscount.tag === "product_discount_card" ? "discount_card" : discountType2, discount: { discount_card_type: (_y = selectedDiscount == null ? void 0 : selectedDiscount.metadata) == null ? void 0 : _y.discount_card_type, fixed_amount: amount, discount_calculation_mode: (_z = selectedDiscount == null ? void 0 : selectedDiscount.metadata) == null ? void 0 : _z.discount_calculation_mode, resource_id: selectedDiscount.id, title: selectedDiscount.format_title, original_amount: product.price, product_id: originProduct.id, percent: currentSelectedDiscount.par_value, discount_product_id: currentSelectedDiscount.product_id }, // 前端使用的num数量,为了计算优惠金额(拆分时为1) _num: isNeedSplit ? 1 : product.num, config: currentSelectedDiscount == null ? void 0 : currentSelectedDiscount.config, metadata: { num: 1, discount_rule_uncheck_flag: selectedDiscount == null ? void 0 : selectedDiscount.discount_rule_uncheck_flag, // 🔥 order_level 分摊差值 ...productDiscountDifference !== void 0 && { product_discount_difference: productDiscountDifference } } }; appliedProducts.push(discountDetail); appliedDiscountProducts.set(currentSelectedDiscount.id, appliedProducts); let total = targetProductTotal; if (product.options) { total = product.options.reduce((accumulator, currentValue) => { const currentPrice = new import_decimal.default(currentValue.price || 0); const currentNum = new import_decimal.default(currentValue.num || 0); return accumulator.add(currentPrice.mul(currentNum)); }, new import_decimal.default(total)).toNumber(); } if (product.isClient) { arr.push( this.hooks.setProduct(originProduct, { discount_list: [discountDetail], price: currentIsGoodPass ? product.price - discountDetail.amount : product.price, quantity: isNeedSplit ? 1 : product.quantity, origin_total: (0, import_utils2.getProductOriginTotalPrice)({ product: { original_price: product.original_price }, bundle: product.bundle, options: product.options }), variant: originProduct._productInit.variant, original_price: new import_decimal.default(product.price || 0).toNumber(), total }) ); } else { arr.push( this.hooks.setProduct(originProduct, { discount_list: this.filterDiscountListByType(product.discount_list, "promotion").concat([discountDetail]), _id: product._id.split("___")[0] + "___" + currentSelectedDiscount.id + "_" + i + "_" + index, price: currentIsGoodPass ? 0 : product.price, quantity: isNeedSplit ? 1 : product.quantity, total, origin_total: productOriginTotal, main_product_selling_price: targetProductTotal }) ); } } processedProductsMap.set(product._id, arr); } else { const processedItems = []; if (isNeedSplit) { const discountNum = splitCount; const normalNum = totalQuantity - discountNum; for (let i = 0; i < discountNum; i++) { const currentBundleDiscount = isGoodPass ? selecte