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