更新计算方法,添加新图标

This commit is contained in:
YeMingfei666 2025-10-20 17:19:36 +08:00
parent dc0cd2076c
commit a2e1300626
3 changed files with 235 additions and 118 deletions

View File

@ -0,0 +1,10 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.9166 11.6667H2.08331V17.5H17.9166V11.6667Z" fill="#999999" stroke="#999999" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M17.9166 2.5H2.08331V8.33333H17.9166V2.5Z" fill="#999999" stroke="#999999" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.24998 5.41665C6.24998 4.95641 5.87688 4.58331 5.41665 4.58331C4.95641 4.58331 4.58331 4.95641 4.58331 5.41665C4.58331 5.87688 4.95641 6.24998 5.41665 6.24998C5.87688 6.24998 6.24998 5.87688 6.24998 5.41665Z" fill="white"/>
<path d="M6.24998 14.5833C6.24998 14.1231 5.87688 13.75 5.41665 13.75C4.95641 13.75 4.58331 14.1231 4.58331 14.5833C4.58331 15.0436 4.95641 15.4167 5.41665 15.4167C5.87688 15.4167 6.24998 15.0436 6.24998 14.5833Z" fill="white"/>
<path d="M9.58335 5.41665C9.58335 4.95641 9.21026 4.58331 8.75002 4.58331C8.28978 4.58331 7.91669 4.95641 7.91669 5.41665C7.91669 5.87688 8.28978 6.24998 8.75002 6.24998C9.21026 6.24998 9.58335 5.87688 9.58335 5.41665Z" fill="white"/>
<path d="M9.58335 14.5833C9.58335 14.1231 9.21026 13.75 8.75002 13.75C8.28978 13.75 7.91669 14.1231 7.91669 14.5833C7.91669 15.0436 8.28978 15.4167 8.75002 15.4167C9.21026 15.4167 9.58335 15.0436 9.58335 14.5833Z" fill="white"/>
<path d="M12.9167 5.41669H14.5834" stroke="white" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.9167 14.5833H14.5834" stroke="white" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.667 4.583V3.328C1.667 2.871 2.047 2.5 2.493 2.5H17.507C17.963 2.5 18.333 2.87 18.333 3.328V16.672C18.333 17.129 17.953 17.5 17.507 17.5H2.493C2.3844 17.4999 2.27688 17.4783 2.1766 17.4367C2.07631 17.395 1.98522 17.334 1.90852 17.2571C1.83181 17.1802 1.77101 17.0889 1.72957 16.9886C1.68813 16.8882 1.66687 16.7806 1.667 16.672V15.833H16.667V6.083L10 12.083L1.667 4.583ZM0 8.333H4.167V10H0V8.333ZM0 12.5H6.667V14.167H0V12.5Z" fill="#999999"/>
</svg>

After

Width:  |  Height:  |  Size: 557 B

View File

@ -223,6 +223,17 @@ export interface MerchantReductionConfig {
fixedAmount?: number; // 固定减免金额(元,仅 FIXED_AMOUNT 生效≥0 fixedAmount?: number; // 固定减免金额(元,仅 FIXED_AMOUNT 生效≥0
discountRate?: number; // 折扣率(%,仅 DISCOUNT_RATE 生效0-100如 90 代表 9 折) discountRate?: number; // 折扣率(%,仅 DISCOUNT_RATE 生效0-100如 90 代表 9 折)
} }
/**商家霸王餐配置 */
export interface FreeDineConfig {
enable: boolean; //是否开启
rechargeThreshold: number; //订单满多少元可以使用
rechargeTimes: number; //充值多少倍免单
withCoupon: boolean; //与优惠券同享
withPoints: boolean; //与积分同享
useType?: string[]; //使用类型 dine-in店内 takeout 自取 post快递takeaway外卖
useShopType?: string; //all 全部 part部分
shopIdList?: number[]; //可用门店id
}
/** 订单额外费用配置 */ /** 订单额外费用配置 */
export interface OrderExtraConfig { export interface OrderExtraConfig {
// merchantReduction: number; // 商家减免金额默认0 // merchantReduction: number; // 商家减免金额默认0
@ -238,14 +249,15 @@ export interface OrderExtraConfig {
newUserDiscount?: number; // 新用户减免金额默认0 newUserDiscount?: number; // 新用户减免金额默认0
fullReductionActivities: FullReductionActivity[]; // 当前店铺的满减活动列表(后端返回结构) fullReductionActivities: FullReductionActivity[]; // 当前店铺的满减活动列表(后端返回结构)
currentDinnerType: "dine-in" | "take-out" | "take-away" | "post"; // 当前就餐类型匹配useType currentDinnerType: "dine-in" | "take-out" | "take-away" | "post"; // 当前就餐类型匹配useType
isFreeDine?: boolean; //是否霸王餐
freeDineConfig?: FreeDineConfig;
} }
/** 订单费用汇总(修改:补充商家减免类型和明细) */ /** 订单费用汇总(修改:补充商家减免类型和明细) */
export interface OrderCostSummary { export interface OrderCostSummary {
// 商品总件数 // 商品总件数
goodsTotal: number; goodsTotal: number;
totalDiscountAmount: number, totalDiscountAmount: number;
goodsRealAmount: number; // 商品真实原价总和 goodsRealAmount: number; // 商品真实原价总和
goodsOriginalAmount: number; // 商品原价总和 goodsOriginalAmount: number; // 商品原价总和
goodsDiscountAmount: number; // 商品折扣金额 goodsDiscountAmount: number; // 商品折扣金额
@ -275,9 +287,10 @@ export interface OrderCostSummary {
usedThreshold?: FullReductionThreshold; // 实际使用的满减阈值(多门槛中选最优) usedThreshold?: FullReductionThreshold; // 实际使用的满减阈值(多门槛中选最优)
actualAmount: number; // 满减实际减免金额(元) actualAmount: number; // 满减实际减免金额(元)
}; };
// 订单原支付金额
orderOriginFinalPayAmount: number; //订单原金额(包含打包费+餐位费)
} }
/** 满减活动阈值单条满减规则满X减Y- 对应 MkDiscountThresholdInsertGroupDefaultGroup */ /** 满减活动阈值单条满减规则满X减Y- 对应 MkDiscountThresholdInsertGroupDefaultGroup */
export interface FullReductionThreshold { export interface FullReductionThreshold {
activityId?: number; // 关联满减活动ID activityId?: number; // 关联满减活动ID
@ -308,25 +321,15 @@ export interface FullReductionActivity {
isDel?: boolean; // 是否删除0=否1=是后端字段isDel默认false isDel?: boolean; // 是否删除0=否1=是后端字段isDel默认false
} }
// ============================ 扩展:订单配置与费用汇总(加入后端满减类型) ============================
/** 扩展订单额外配置:使用后端满减活动类型 */
export interface OrderExtraConfig {
// ... 原有字段不变 ...
fullReductionActivities: FullReductionActivity[]; // 当前店铺的满减活动列表(后端返回结构)
currentDinnerType: "dine-in" | "take-out" | "take-away" | "post"; // 当前就餐类型匹配useType
}
// 辅助枚举星期映射用于useDays校验 // 辅助枚举星期映射用于useDays校验
const WEEKDAY_MAP = { const WEEKDAY_MAP = {
"周一": 1, 周一: 1,
"周二": 2, 周二: 2,
"周三": 3, 周三: 3,
"周四": 4, 周四: 4,
"周五": 5, 周五: 5,
"周六": 6, 周六: 6,
"周日": 0 // JS中getDay()返回0=周日 周日: 0, // JS中getDay()返回0=周日
}; };
/** /**
@ -335,7 +338,10 @@ const WEEKDAY_MAP = {
* @param currentTime * @param currentTime
* @returns * @returns
*/ */
function isInDailyTimeRange(activity: FullReductionActivity, currentTime: Date): boolean { function isInDailyTimeRange(
activity: FullReductionActivity,
currentTime: Date
): boolean {
// 全时段无需校验 // 全时段无需校验
if (activity.useTimeType === "all") return true; if (activity.useTimeType === "all") return true;
// 无时段配置则不通过 // 无时段配置则不通过
@ -365,11 +371,16 @@ function isInDailyTimeRange(activity: FullReductionActivity, currentTime: Date):
* @param currentTime * @param currentTime
* @returns * @returns
*/ */
function isInWeeklyCycle(activity: FullReductionActivity, currentTime: Date): boolean { function isInWeeklyCycle(
activity: FullReductionActivity,
currentTime: Date
): boolean {
// 无周期配置则不通过 // 无周期配置则不通过
if (!activity.useDays) return false; if (!activity.useDays) return false;
const currentWeekday = currentTime.getDay(); // 0=周日1=周一...6=周六 const currentWeekday = currentTime.getDay(); // 0=周日1=周一...6=周六
const allowedWeekdays = activity.useDays.split(",").map(day => WEEKDAY_MAP[day as keyof typeof WEEKDAY_MAP]); const allowedWeekdays = activity.useDays
.split(",")
.map((day) => WEEKDAY_MAP[day as keyof typeof WEEKDAY_MAP]);
return allowedWeekdays.includes(currentWeekday); return allowedWeekdays.includes(currentWeekday);
} }
@ -379,11 +390,14 @@ function isInWeeklyCycle(activity: FullReductionActivity, currentTime: Date): bo
* @param currentDinnerType * @param currentDinnerType
* @returns * @returns
*/ */
function isDinnerTypeMatch(activity: FullReductionActivity, currentDinnerType: string): boolean { function isDinnerTypeMatch(
activity: FullReductionActivity,
currentDinnerType: string
): boolean {
if (!activity.useType) return false; if (!activity.useType) return false;
const allowedTypes = activity.useType.split(","); const allowedTypes = activity.useType.split(",");
//满减活动的就餐类型和当前券类型字段值不一样暂时返回true //满减活动的就餐类型和当前券类型字段值不一样暂时返回true
return true return true;
} }
/** /**
* *
@ -400,22 +414,20 @@ export function filterOptimalFullReductionActivity(
currentTime: Date = new Date() currentTime: Date = new Date()
): FullReductionActivity | undefined { ): FullReductionActivity | undefined {
if (!activities || !activities.length) return undefined; if (!activities || !activities.length) return undefined;
console.log("原始满减活动列表:", activities);
// 第一步:基础筛选(未删除+当前店铺+活动进行中+就餐类型匹配) // 第一步:基础筛选(未删除+当前店铺+活动进行中+就餐类型匹配)
const baseEligible = activities.filter(activity => { const baseEligible = activities.filter((activity) => {
return ( return (
activity.isDel !== true && // 未删除 activity.isDel !== true && // 未删除
activity.shopId === currentShopId && // 当前店铺 // activity.shopId === currentShopId && // 当前店铺
activity.status === 2 && // 状态=2进行中 // activity.status === 2 && // 状态=2进行中
isDinnerTypeMatch(activity, currentDinnerType) && // 就餐类型匹配 isDinnerTypeMatch(activity, currentDinnerType) && // 就餐类型匹配
activity.thresholds?.length // 至少有一个满减阈值 activity.thresholds?.length // 至少有一个满减阈值
); );
}); });
if (!baseEligible.length) return undefined; if (!baseEligible.length) return undefined;
// 第二步:时间筛选(有效期内+周期内+时段内) // 第二步:时间筛选(有效期内+周期内+时段内)
const timeEligible = baseEligible.filter(activity => { const timeEligible = baseEligible.filter((activity) => {
// 1. 校验有效期validStartTime ~ validEndTime // 1. 校验有效期validStartTime ~ validEndTime
if (!activity.validStartTime || !activity.validEndTime) return false; if (!activity.validStartTime || !activity.validEndTime) return false;
const startDate = new Date(activity.validStartTime); const startDate = new Date(activity.validStartTime);
@ -485,6 +497,13 @@ export function isTemporaryGoods(goods: BaseCartItem): boolean {
export function isGiftGoods(goods: BaseCartItem): boolean { export function isGiftGoods(goods: BaseCartItem): boolean {
return !!goods.is_gift; return !!goods.is_gift;
} }
/**
*
*/
export function useTypeCanUse(useType: string[]) {
const arr = ["all", "dine-in", "take-out", "take-away", "post"];
return useType.some((item) => arr.includes(item));
}
/** /**
* SKU会员价 > > * SKU会员价 > >
@ -713,11 +732,8 @@ export function calcGoodsOriginalAmount(goodsList: BaseCartItem[]): number {
basePrice = new BigNumber(goods?.discountSaleAmount ?? 0); basePrice = new BigNumber(goods?.discountSaleAmount ?? 0);
} else if (goods.is_gift) { } else if (goods.is_gift) {
basePrice = new BigNumber(0); basePrice = new BigNumber(0);
} } else {
else { basePrice = new BigNumber(goods.skuData?.salePrice ?? goods.salePrice); // SKU原价优先
basePrice = new BigNumber(
goods.skuData?.salePrice ?? goods.salePrice
); // SKU原价优先
} }
total = total.plus(basePrice.multipliedBy(availableNum)); total = total.plus(basePrice.multipliedBy(availableNum));
@ -796,33 +812,47 @@ export function selectOptimalThreshold(
if (!thresholds.length) return undefined; if (!thresholds.length) return undefined;
// 第一步确定满减门槛基数根据discountShare规则 // 第一步确定满减门槛基数根据discountShare规则
const thresholdBase = discountShare === 1 const thresholdBase = baseAmount;
? new BigNumber(goodsRealAmount) // 与限时折扣同享→用折扣后金额
: new BigNumber(goodsOriginalAmount); // 不同享→用原价
// 第二步:筛选「满金额≤基数」且「减免金额>0」的有效阈值 // 第二步:筛选「满金额≤基数」且「减免金额>0」的有效阈值
const validThresholds = thresholds.filter(threshold => { const validThresholds = thresholds.filter((threshold) => {
const fullAmount = new BigNumber(threshold.fullAmount || 0); const fullAmount = new BigNumber(threshold.fullAmount || 0);
const discountAmount = new BigNumber(threshold.discountAmount || 0); const discountAmount = new BigNumber(threshold.discountAmount || 0);
return fullAmount.isLessThanOrEqualTo(thresholdBase) && discountAmount.isGreaterThan(0); return (
fullAmount.isLessThanOrEqualTo(thresholdBase) &&
discountAmount.isGreaterThan(0)
);
}); });
if (!validThresholds.length) return undefined; if (!validThresholds.length) return undefined;
// 第三步选择最优阈值优先级1.满金额最小 → 2.减免金额最大) // 第三步选择最优阈值优先级1.满金额最小 → 2.减免金额最大)
return validThresholds.sort((a, b) => { // const sortValidThresholds = validThresholds.sort((a, b) => {
const aFull = new BigNumber(a.fullAmount || 0); // const aFull = new BigNumber(a.fullAmount || 0);
const bFull = new BigNumber(b.fullAmount || 0); // const bFull = new BigNumber(b.fullAmount || 0);
const aDiscount = new BigNumber(a.discountAmount || 0); // const aDiscount = new BigNumber(a.discountAmount || 0);
const bDiscount = new BigNumber(b.discountAmount || 0); // const bDiscount = new BigNumber(b.discountAmount || 0);
// 先比满金额越小越优先满1减10 比 满100减20 更优) // // 先比满金额越小越优先满1减10 比 满100减20 更优)
if (!aFull.isEqualTo(bFull)) { // if (!aFull.isEqualTo(bFull)) {
return aFull.comparedTo(bFull) || 0; // Ensure a number is always returned // return aFull.comparedTo(bFull) || 0; // Ensure a number is always returned
} // }
// 再比减免金额:越大越优先 // // 再比减免金额:越大越优先
return bDiscount.comparedTo(aDiscount) || 0; // Ensure a number is always returned // return bDiscount.comparedTo(aDiscount) || 0; // Ensure a number is always returned
})[0]; // })
// 找到抵扣金额最大的门槛项
const maxDiscountThreshold = validThresholds.reduce(
(maxItem, currentItem) => {
// 处理空值默认抵扣金额为0
const maxDiscount = new BigNumber(maxItem?.discountAmount || 0);
const currentDiscount = new BigNumber(currentItem?.discountAmount || 0);
// 比较当前项和已存最大项的抵扣金额,保留更大的
return currentDiscount.gt(maxDiscount) ? currentItem : maxItem;
},
validThresholds[0] || null
); // 初始值为数组第一项若数组为空则返回null
console.log("maxDiscountThreshold", maxDiscountThreshold);
return maxDiscountThreshold;
} }
/** /**
@ -835,7 +865,7 @@ export function selectOptimalThreshold(
export function calcFullReductionAmount( export function calcFullReductionAmount(
baseAmount: number, baseAmount: number,
optimalActivity?: FullReductionActivity, optimalActivity?: FullReductionActivity,
optimalThreshold?: FullReductionThreshold, optimalThreshold?: FullReductionThreshold
): number { ): number {
if (!optimalActivity || !optimalThreshold) return 0; if (!optimalActivity || !optimalThreshold) return 0;
@ -854,7 +884,6 @@ export function calcFullReductionAmount(
return truncateToTwoDecimals(actualReduction.toNumber()); return truncateToTwoDecimals(actualReduction.toNumber());
} }
// ------------------------------ 策略辅助函数 ------------------------------ // ------------------------------ 策略辅助函数 ------------------------------
/** /**
* useShops列表判断门店是否匹配BaseCoupon的useShops字段 * useShops列表判断门店是否匹配BaseCoupon的useShops字段
@ -869,8 +898,6 @@ function isStoreMatchByList(
return useShops.includes(currentStoreId); return useShops.includes(currentStoreId);
} }
/** /**
* ID排除 * ID排除
* @param backendCoupons * @param backendCoupons
@ -953,12 +980,15 @@ export function calcTotalPackFee(
for (const goods of goodsList) { for (const goods of goodsList) {
const packNumber = goods.packNumber ? goods.packNumber * 1 : 0; const packNumber = goods.packNumber ? goods.packNumber * 1 : 0;
let availableNum = Math.max(0, goods.number - (goods.returnNum || 0)); let availableNum = Math.max(0, goods.number - (goods.returnNum || 0));
availableNum = Math.min(availableNum, packNumber);
if (availableNum === 0) continue; if (availableNum === 0) continue;
// 计算单个商品打包数量外卖全打包堂食按配置称重商品≤1 // 计算单个商品打包数量外卖全打包堂食按配置称重商品≤1
let packNum = availableNum; let packNum = Math.min(availableNum, packNumber);
if (dinnerType === "take-out") {
packNum = availableNum
}
if (goods.product_type === GoodsType.WEIGHT) { if (goods.product_type === GoodsType.WEIGHT) {
packNum = Math.min(packNum, 1); packNum = Math.min(packNum, 1);
} }
@ -997,6 +1027,7 @@ export function calcPointDeduction(
deductionAmount: number; deductionAmount: number;
usedPoints: number; usedPoints: number;
} { } {
console.log("calcPointDeduction", userPoints, rule, maxDeductionLimit);
if (rule.pointsPerYuan <= 0 || userPoints <= 0) { if (rule.pointsPerYuan <= 0 || userPoints <= 0) {
return { deductionAmount: 0, usedPoints: 0 }; return { deductionAmount: 0, usedPoints: 0 };
} }
@ -1047,14 +1078,24 @@ export function calculateOrderCostSummary(
cartOrder: Record<string, number> = {}, cartOrder: Record<string, number> = {},
currentTime: Date = new Date() currentTime: Date = new Date()
): OrderCostSummary { ): OrderCostSummary {
//是否使用霸王餐,霸王餐配置
const { isFreeDine, freeDineConfig } = config;
// ------------------------------ 1. 基础费用计算 ------------------------------ // ------------------------------ 1. 基础费用计算 ------------------------------
const goodsOriginalAmount = calcGoodsOriginalAmount(goodsList); // 商品原价总和 const goodsOriginalAmount = calcGoodsOriginalAmount(goodsList); // 商品原价总和
const goodsRealAmount = calcGoodsRealAmount( // 商品折扣后总和 const goodsRealAmount = calcGoodsRealAmount(
// 商品折扣后总和
goodsList, goodsList,
{ isMember: config.isMember, memberDiscountRate: config.memberDiscountRate }, {
isMember: config.isMember,
memberDiscountRate: config.memberDiscountRate,
},
activities activities
); );
const goodsDiscountAmount = calcGoodsDiscountAmount(goodsOriginalAmount, goodsRealAmount); // 商品折扣金额 const goodsDiscountAmount = calcGoodsDiscountAmount(
goodsOriginalAmount,
goodsRealAmount
); // 商品折扣金额
const newUserDiscount = config.newUserDiscount || 0; // 新客立减 const newUserDiscount = config.newUserDiscount || 0; // 新客立减
// ------------------------------ 2. 满减活动计算(核心步骤) ------------------------------ // ------------------------------ 2. 满减活动计算(核心步骤) ------------------------------
@ -1069,12 +1110,21 @@ export function calculateOrderCostSummary(
currentTime currentTime
); );
// 其他费用计算(原有逻辑不变) ------------------------------
const packFee = calcTotalPackFee(goodsList, dinnerType); // 打包费
let seatFee = calcSeatFee(config.seatFeeConfig); // 餐位费
seatFee = dinnerType === "dine-in" ? seatFee : 0; // 外卖不收餐位费
const additionalFee = Math.max(0, config.additionalFee); // 附加费
// 2.2 计算满减基数(先扣新客立减) // 2.2 计算满减基数(先扣新客立减)
const baseAfterNewUserDiscount = new BigNumber(goodsRealAmount) let baseAfterNewUserDiscount = new BigNumber(goodsRealAmount)
.minus(newUserDiscount) .minus(newUserDiscount)
.isGreaterThan(0) .plus(packFee)
? new BigNumber(goodsRealAmount).minus(newUserDiscount).toNumber() .plus(seatFee)
: 0; .plus(additionalFee)
.toNumber();
baseAfterNewUserDiscount =
baseAfterNewUserDiscount > 0 ? baseAfterNewUserDiscount : 0;
// 2.3 选择最优满减阈值(多门槛场景) // 2.3 选择最优满减阈值(多门槛场景)
if (usedFullReductionActivity) { if (usedFullReductionActivity) {
@ -1090,10 +1140,9 @@ export function calculateOrderCostSummary(
fullReductionAmount = calcFullReductionAmount( fullReductionAmount = calcFullReductionAmount(
baseAfterNewUserDiscount, baseAfterNewUserDiscount,
usedFullReductionActivity, usedFullReductionActivity,
usedFullReductionThreshold, usedFullReductionThreshold
); );
} }
// ------------------------------ 3. 优惠券抵扣(适配满减同享规则) ------------------------------ // ------------------------------ 3. 优惠券抵扣(适配满减同享规则) ------------------------------
let couponDeductionAmount = 0; let couponDeductionAmount = 0;
let productCouponDeduction = 0; let productCouponDeduction = 0;
@ -1101,57 +1150,85 @@ export function calculateOrderCostSummary(
let usedCoupon: Coupon | undefined; let usedCoupon: Coupon | undefined;
let excludedProductIds: string[] = []; let excludedProductIds: string[] = [];
const couponResult = calcCouponDeduction(
// 原有优惠券计算函数
backendCoupons,
goodsList,
{
currentStoreId: config.currentStoreId,
isMember: config.isMember,
memberDiscountRate: config.memberDiscountRate,
activities,
cartOrder,
dinnerType,
currentTime,
}
);
couponDeductionAmount = couponResult.deductionAmount;
productCouponDeduction = couponResult.productCouponDeduction;
fullCouponDeduction = couponResult.fullCouponDeduction;
usedCoupon = couponResult.usedCoupon;
excludedProductIds = couponResult.excludedProductIds;
// 若满减与优惠券同享couponShare=1才计算优惠券否则优惠券抵扣为0 // 若满减与优惠券同享couponShare=1才计算优惠券否则优惠券抵扣为0
if (usedFullReductionActivity?.couponShare === 1) { if (usedFullReductionActivity && !usedFullReductionActivity.couponShare) {
const couponResult = calcCouponDeduction( // 原有优惠券计算函数 couponDeductionAmount = 0;
backendCoupons, productCouponDeduction = 0;
goodsList, fullCouponDeduction = 0;
{ usedCoupon = undefined;
currentStoreId: config.currentStoreId, excludedProductIds = [];
isMember: config.isMember,
memberDiscountRate: config.memberDiscountRate,
activities,
cartOrder,
dinnerType,
currentTime
}
);
couponDeductionAmount = couponResult.deductionAmount;
productCouponDeduction = couponResult.productCouponDeduction;
fullCouponDeduction = couponResult.fullCouponDeduction;
usedCoupon = couponResult.usedCoupon;
excludedProductIds = couponResult.excludedProductIds;
} }
// ------------------------------ 4. 积分抵扣(适配满减同享规则) ------------------------------ // ------------------------------ 4. 积分抵扣(适配满减同享规则) ------------------------------
let pointDeductionAmount = 0; let pointDeductionAmount = 0;
let usedPoints = 0; let usedPoints = 0;
// 计算积分抵扣基数(商品折扣后 - 新客立减 - 满减 - 优惠券 // 计算积分抵扣基数(商品折扣后 - 新客立减 - 满减 - 优惠券 + 餐位费 + 打包费 + 附加费)
const maxPointDeductionLimit = new BigNumber(goodsRealAmount) let maxPointDeductionLimit = new BigNumber(goodsRealAmount)
.minus(newUserDiscount) .minus(newUserDiscount)
.minus(fullReductionAmount) .minus(fullReductionAmount)
.minus(couponDeductionAmount) .minus(couponDeductionAmount)
.isGreaterThan(0) .plus(seatFee)
? new BigNumber(goodsRealAmount).minus(newUserDiscount).minus(fullReductionAmount).minus(couponDeductionAmount).toNumber() .plus(packFee)
: 0; .plus(additionalFee)
.toNumber();
maxPointDeductionLimit =
maxPointDeductionLimit > 0 ? maxPointDeductionLimit : 0;
// 若满减与积分同享pointsShare=1才计算积分否则积分抵扣为0
if ((usedFullReductionActivity?.pointsShare === 1) && maxPointDeductionLimit > 0) { const pointResult = calcPointDeduction(
const pointResult = calcPointDeduction( config.userPoints,
config.userPoints, config.pointDeductionRule,
config.pointDeductionRule, maxPointDeductionLimit
maxPointDeductionLimit );
); console.log("积分抵扣结果:", pointResult);
pointDeductionAmount = pointResult.deductionAmount;
usedPoints = pointResult.usedPoints; pointDeductionAmount = pointResult.deductionAmount;
usedPoints = pointResult.usedPoints;
// 若满减与积分不同享pointsShare=1积分抵扣为0
if (usedFullReductionActivity && !usedFullReductionActivity.pointsShare) {
console.log("满减与积分不同享:积分抵扣为0");
pointDeductionAmount = 0;
usedPoints = 0;
} }
// ------------------------------ 5. 其他费用计算(原有逻辑不变) ------------------------------ //使用霸王餐
const packFee = calcTotalPackFee(goodsList, dinnerType); // 打包费 if (isFreeDine && freeDineConfig && freeDineConfig.enable) {
let seatFee = calcSeatFee(config.seatFeeConfig); // 餐位费 console.log("使用霸王餐");
seatFee = dinnerType === "dine-in" ? seatFee : 0; // 外卖不收餐位费 //不与优惠券同享
const additionalFee = Math.max(0, config.additionalFee); // 附加费 if (!freeDineConfig.withCoupon) {
couponDeductionAmount = 0;
productCouponDeduction = 0;
fullCouponDeduction = 0;
usedCoupon = undefined;
excludedProductIds = [];
}
//不与积分同享
if (!freeDineConfig.withPoints) {
pointDeductionAmount = 0;
usedPoints = 0;
}
}
// 商家减免计算(原有逻辑不变) // 商家减免计算(原有逻辑不变)
const merchantReductionConfig = config.merchantReduction; const merchantReductionConfig = config.merchantReduction;
@ -1164,7 +1241,14 @@ export function calculateOrderCostSummary(
.plus(seatFee) .plus(seatFee)
.plus(packFee) .plus(packFee)
.isGreaterThan(0) .isGreaterThan(0)
? new BigNumber(goodsRealAmount).minus(newUserDiscount).minus(fullReductionAmount).minus(couponDeductionAmount).minus(pointDeductionAmount).plus(seatFee).plus(packFee).toNumber() ? new BigNumber(goodsRealAmount)
.minus(newUserDiscount)
.minus(fullReductionAmount)
.minus(couponDeductionAmount)
.minus(pointDeductionAmount)
.plus(seatFee)
.plus(packFee)
.toNumber()
: 0; : 0;
switch (merchantReductionConfig.type) { switch (merchantReductionConfig.type) {
@ -1175,11 +1259,17 @@ export function calculateOrderCostSummary(
); );
break; break;
case MerchantReductionType.DISCOUNT_RATE: case MerchantReductionType.DISCOUNT_RATE:
const validRate = Math.max(0, Math.min(100, merchantReductionConfig.discountRate || 0)) / 100; const validRate =
merchantReductionActualAmount = maxMerchantReductionLimit * (1 - validRate); Math.max(0, Math.min(100, merchantReductionConfig.discountRate || 0)) /
100;
merchantReductionActualAmount =
maxMerchantReductionLimit * (1 - validRate);
break; break;
} }
merchantReductionActualAmount = Math.max(0, truncateToTwoDecimals(merchantReductionActualAmount)); merchantReductionActualAmount = Math.max(
0,
truncateToTwoDecimals(merchantReductionActualAmount)
);
// ------------------------------ 6. 最终实付金额计算 ------------------------------ // ------------------------------ 6. 最终实付金额计算 ------------------------------
const finalPayAmountBn = new BigNumber(goodsRealAmount) const finalPayAmountBn = new BigNumber(goodsRealAmount)
@ -1191,7 +1281,17 @@ export function calculateOrderCostSummary(
.plus(seatFee) .plus(seatFee)
.plus(packFee) .plus(packFee)
.plus(additionalFee); .plus(additionalFee);
const finalPayAmount = Math.max(0, truncateToTwoDecimals(finalPayAmountBn.toNumber())); let finalPayAmount = Math.max(
0,
truncateToTwoDecimals(finalPayAmountBn.toNumber())
);
// ------------------------------ 使用霸王餐计算 ------------------------------
let orderOriginFinalPayAmount = finalPayAmount;
if (isFreeDine && freeDineConfig && freeDineConfig.enable) {
finalPayAmount = BigNumber(finalPayAmount)
.times(freeDineConfig.rechargeTimes)
.toNumber();
}
// ------------------------------ 7. 总优惠金额计算 ------------------------------ // ------------------------------ 7. 总优惠金额计算 ------------------------------
const totalDiscountAmount = truncateToTwoDecimals( const totalDiscountAmount = truncateToTwoDecimals(
@ -1207,12 +1307,14 @@ export function calculateOrderCostSummary(
const scoreMaxMoney = new BigNumber(finalPayAmount) const scoreMaxMoney = new BigNumber(finalPayAmount)
.plus(pointDeductionAmount) .plus(pointDeductionAmount)
.minus(merchantReductionActualAmount) .minus(merchantReductionActualAmount)
.toNumber() .toNumber();
// ------------------------------ 8. 返回完整结果 ------------------------------ // ------------------------------ 8. 返回完整结果 ------------------------------
return { return {
goodsTotal: goodsList.reduce((sum, g) => sum + Math.max(0, g.number - (g.returnNum || 0)), 0), goodsTotal: goodsList.reduce(
(sum, g) => sum + Math.max(0, g.number - (g.returnNum || 0)),
0
),
goodsRealAmount, goodsRealAmount,
goodsOriginalAmount, goodsOriginalAmount,
goodsDiscountAmount, goodsDiscountAmount,
@ -1223,18 +1325,20 @@ export function calculateOrderCostSummary(
seatFee, seatFee,
packFee, packFee,
totalDiscountAmount, totalDiscountAmount,
//最终支付原金额
orderOriginFinalPayAmount,
//积分最大可抵扣金额 //积分最大可抵扣金额
scoreMaxMoney, scoreMaxMoney,
// 满减活动明细(后端字段) // 满减活动明细(后端字段)
fullReduction: { fullReduction: {
usedActivity: usedFullReductionActivity, usedActivity: usedFullReductionActivity,
usedThreshold: usedFullReductionThreshold, usedThreshold: usedFullReductionThreshold,
actualAmount: truncateToTwoDecimals(fullReductionAmount) actualAmount: truncateToTwoDecimals(fullReductionAmount),
}, },
merchantReduction: { merchantReduction: {
type: merchantReductionConfig.type, type: merchantReductionConfig.type,
originalConfig: merchantReductionConfig, originalConfig: merchantReductionConfig,
actualAmount: merchantReductionActualAmount actualAmount: merchantReductionActualAmount,
}, },
additionalFee, additionalFee,
finalPayAmount, finalPayAmount,
@ -1242,7 +1346,7 @@ export function calculateOrderCostSummary(
pointUsed: usedPoints, pointUsed: usedPoints,
newUserDiscount, newUserDiscount,
dinnerType, dinnerType,
config config,
}; };
} }