@pisell/pisellos
Version:
一个可扩展的前端模块化SDK框架,支持插件系统
1,055 lines (1,054 loc) • 94.2 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/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