fix: 优惠券方法更新
This commit is contained in:
parent
cd351be6d0
commit
93e290fbaf
|
|
@ -181,7 +181,6 @@ export function returnCouponCanUse(args) {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 商品兑换券,第二件半价和买一送一判断是否有可用商品
|
||||
if ([2, 4, 5].includes(coupon.type)) {
|
||||
if (coupon.type == 2 && fullAmount < coupon.fullAmount) {
|
||||
|
|
@ -190,6 +189,7 @@ export function returnCouponCanUse(args) {
|
|||
reason: `满${coupon.fullAmount}元可用,当前可参与金额${fullAmount}元`,
|
||||
};
|
||||
}
|
||||
|
||||
// 没有符合条件的商品
|
||||
if (isDikouAll && canDikouGoodsArr.length === 0) {
|
||||
return {
|
||||
|
|
@ -217,8 +217,8 @@ export function returnCouponCanUse(args) {
|
|||
let canUse = false;
|
||||
if (isDikouAll) {
|
||||
canUse = canDikouGoodsArr.some((v) => v.num >= 2);
|
||||
} else if (canCalcGoodsArr.length > 0) {
|
||||
canUse = canCalcGoodsArr.some((v) => v.num >= 2);
|
||||
} else if (canUseGoodsArr.length > 0) {
|
||||
canUse = canUseGoodsArr.some((v) => v.num >= 2);
|
||||
}
|
||||
|
||||
if (!canUse) {
|
||||
|
|
@ -234,10 +234,9 @@ export function returnCouponCanUse(args) {
|
|||
let canUse = false;
|
||||
if (isDikouAll) {
|
||||
canUse = canDikouGoodsArr.some((v) => v.num >= 2);
|
||||
} else if (canCalcGoodsArr.length > 0) {
|
||||
canUse = canCalcGoodsArr.some((v) => v.num >= 2);
|
||||
} else if (canUseGoodsArr.length > 0) {
|
||||
canUse = canUseGoodsArr.some((v) => v.num >= 2);
|
||||
}
|
||||
|
||||
if (!canUse) {
|
||||
return {
|
||||
canUse: false,
|
||||
|
|
@ -296,6 +295,7 @@ export function calcDiscountGoodsArrPrice(discountGoodsArr, discountNum, user, s
|
|||
* @param shopInfo 店铺信息
|
||||
*/
|
||||
export function returnCouponDiscount(arr, coupon, user, goodsOrderPrice, selCoupon, shopInfo) {
|
||||
arr = returnCanDikouGoods(arr, user, shopInfo);
|
||||
const canDikouGoodsArr = returnCanDikouGoodsArr(arr, selCoupon, user);
|
||||
if (coupon.type == 2) {
|
||||
return returnCouponProductDiscount(canDikouGoodsArr, coupon, user, shopInfo);
|
||||
|
|
|
|||
|
|
@ -242,6 +242,7 @@ export interface OrderExtraConfig {
|
|||
export interface OrderCostSummary {
|
||||
// 商品总件数
|
||||
goodsTotal: number;
|
||||
totalDiscountAmount: number,
|
||||
goodsRealAmount: number; // 商品真实原价总和
|
||||
goodsOriginalAmount: number; // 商品原价总和
|
||||
goodsDiscountAmount: number; // 商品折扣金额
|
||||
|
|
@ -263,333 +264,10 @@ export interface OrderCostSummary {
|
|||
pointUsed: number; // 实际使用的积分
|
||||
newUserDiscount: number; // 新用户减免金额(元,默认0)
|
||||
dinnerType?: "dine-in" | "take-out"; // 就餐类型(堂食/自取/配送/快递)
|
||||
config: OrderExtraConfig; // 订单额外费用配置
|
||||
}
|
||||
|
||||
// ============================ 2. 基础工具函数(核心修正:所有商品ID匹配用product_id) ============================
|
||||
/**
|
||||
* 后端优惠券转工具库Coupon的转换函数
|
||||
* @param backendCoupon 后端返回的优惠券
|
||||
* @param currentStoreId 当前门店ID(用于验证门店适用性)
|
||||
* @param dinnerType 就餐类型(用于验证使用场景)
|
||||
* @param currentTime 当前时间(默认取当前时间,用于有效期判断)
|
||||
* @returns 工具库 Coupon | null(不支持的券类型/无效券返回null)
|
||||
*/
|
||||
export function convertBackendCouponToToolCoupon(
|
||||
backendCoupon: BackendCoupon,
|
||||
currentStoreId: string,
|
||||
dinnerType: "dine-in" | "take-out",
|
||||
currentTime: Date = new Date()
|
||||
): Coupon | null {
|
||||
// 1. 基础校验:必选字段缺失直接返回null
|
||||
if (!backendCoupon.id || backendCoupon.type === undefined) {
|
||||
console.warn("优惠券必选字段缺失", backendCoupon);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 2. 转换券类型:后端数字枚举 → 工具库字符串枚举
|
||||
const couponType = mapBackendCouponTypeToTool(backendCoupon.type);
|
||||
if (!couponType) {
|
||||
console.warn(
|
||||
`不支持的优惠券类型:${backendCoupon.type}(券ID:${backendCoupon.id})`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 3. 统一处理所有券类型的applicableProductIds(映射后端foods,此处为商品ID列表)
|
||||
const applicableProductIds =
|
||||
backendCoupon.foods === "" || !backendCoupon.foods
|
||||
? [] // 空字符串/undefined → 全部商品(按商品ID匹配)
|
||||
: backendCoupon.foods.split(",").map((id) => id.trim()); // 逗号分隔 → 指定商品ID数组
|
||||
|
||||
const useType =
|
||||
backendCoupon?.useType?.split(",")?.map((v) =>
|
||||
v
|
||||
.replace(/[\[\]]/g, "")
|
||||
.replace(/""/g, '"')
|
||||
.replace(/["']/g, "")
|
||||
) || [];
|
||||
// 4. 计算基础公共字段(含多维度可用性校验)
|
||||
const baseCoupon: BaseCoupon = {
|
||||
id: backendCoupon.id,
|
||||
type: couponType,
|
||||
name: backendCoupon.name || "",
|
||||
available: isCouponAvailable(
|
||||
backendCoupon,
|
||||
currentStoreId,
|
||||
dinnerType,
|
||||
currentTime
|
||||
),
|
||||
useShops: getApplicableStoreIds(backendCoupon, currentStoreId),
|
||||
discountShare: backendCoupon.discountShare === 1,
|
||||
vipPriceShare: backendCoupon.vipPriceShare === 1,
|
||||
useType: useType,
|
||||
isValid: isCouponInValidPeriod(backendCoupon, currentTime),
|
||||
applicableProductIds: applicableProductIds,
|
||||
};
|
||||
// 5. 按券类型补充专属字段
|
||||
switch (couponType) {
|
||||
case CouponType.FULL_REDUCTION:
|
||||
return {
|
||||
...baseCoupon,
|
||||
fullAmount: backendCoupon.fullAmount || 0,
|
||||
discountAmount: backendCoupon.discountAmount || 0,
|
||||
maxDiscountAmount: backendCoupon.maxDiscountAmount ?? Infinity,
|
||||
} as FullReductionCoupon;
|
||||
|
||||
case CouponType.DISCOUNT:
|
||||
return {
|
||||
...baseCoupon,
|
||||
discountRate: formatDiscountRate(backendCoupon.discountRate),
|
||||
maxDiscountAmount: backendCoupon.maxDiscountAmount ?? Infinity,
|
||||
} as DiscountCoupon;
|
||||
|
||||
case CouponType.SECOND_HALF:
|
||||
return {
|
||||
...baseCoupon,
|
||||
maxUseCountPerOrder:
|
||||
backendCoupon.useLimit === -10086
|
||||
? Infinity
|
||||
: backendCoupon.useLimit || 1,
|
||||
} as SecondHalfPriceCoupon;
|
||||
|
||||
case CouponType.BUY_ONE_GET_ONE:
|
||||
return {
|
||||
...baseCoupon,
|
||||
maxUseCountPerOrder:
|
||||
backendCoupon.useLimit === -10086
|
||||
? Infinity
|
||||
: backendCoupon.useLimit || 1,
|
||||
} as BuyOneGetOneCoupon;
|
||||
|
||||
case CouponType.EXCHANGE:
|
||||
return {
|
||||
...baseCoupon,
|
||||
deductCount: backendCoupon.discountNum || 1,
|
||||
sortRule:
|
||||
backendCoupon.useRule === "price_asc"
|
||||
? "low_price_first"
|
||||
: "high_price_first",
|
||||
} as ExchangeCoupon;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------ 转换辅助函数 ------------------------------
|
||||
/**
|
||||
* 后端优惠券类型(数字)→ 工具库优惠券类型(字符串枚举)
|
||||
*/
|
||||
function mapBackendCouponTypeToTool(
|
||||
backendType: number
|
||||
): CouponType | undefined {
|
||||
const typeMap: Record<number, CouponType> = {
|
||||
1: CouponType.FULL_REDUCTION, // 1-满减券
|
||||
2: CouponType.EXCHANGE, // 2-商品兑换券
|
||||
3: CouponType.DISCOUNT, // 3-折扣券
|
||||
4: CouponType.SECOND_HALF, // 4-第二件半价券
|
||||
6: CouponType.BUY_ONE_GET_ONE, // 6-买一送一券
|
||||
};
|
||||
return typeMap[backendType];
|
||||
}
|
||||
|
||||
/**
|
||||
* 多维度判断优惠券是否可用:状态+库存+有效期+隔天生效+每日时段+每周周期+门店+就餐类型
|
||||
*/
|
||||
function isCouponAvailable(
|
||||
backendCoupon: BackendCoupon,
|
||||
currentStoreId: string,
|
||||
dinnerType: "dine-in" | "take-out",
|
||||
currentTime: Date = new Date()
|
||||
): boolean {
|
||||
// 1. 状态校验:必须启用(status=1)
|
||||
if (backendCoupon.status === 0) return false;
|
||||
|
||||
// 3. 有效期校验:必须在有效期内
|
||||
if (!isCouponInValidPeriod(backendCoupon, currentTime)) return false;
|
||||
|
||||
// 4. 隔天生效校验:若设置了隔天生效,需超过生效时间
|
||||
if (!isCouponEffectiveAfterDays(backendCoupon, currentTime)) return false;
|
||||
|
||||
// 5. 每日时段校验:当前时间需在每日可用时段内(useTimeType=custom时生效)
|
||||
if (!isCouponInDailyTimeRange(backendCoupon, currentTime)) return false;
|
||||
|
||||
// 6. 每周周期校验:当前星期几需在可用周期内(useDays非空时生效)
|
||||
// if (!isCouponInWeekDays(backendCoupon, currentTime)) return false;
|
||||
|
||||
// 7. 门店匹配校验:当前门店需在适用门店范围内
|
||||
// if (!isStoreMatch(backendCoupon, currentStoreId)) return false;
|
||||
|
||||
// 8. 就餐类型校验:当前就餐类型需在可用类型范围内
|
||||
// if (!isDinnerTypeMatch(backendCoupon, dinnerType)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断优惠券是否在有效期内(处理后端validType逻辑)
|
||||
*/
|
||||
function isCouponInValidPeriod(
|
||||
backendCoupon: BackendCoupon,
|
||||
currentTime: Date
|
||||
): boolean {
|
||||
const { validType, validStartTime, validEndTime, validDays, createTime } =
|
||||
backendCoupon;
|
||||
|
||||
// 固定时间有效期(validType=fixed):直接对比validStartTime和validEndTime
|
||||
if (validType === "fixed" && validStartTime && validEndTime) {
|
||||
const start = new Date(validStartTime);
|
||||
const end = new Date(validEndTime);
|
||||
return currentTime >= start && currentTime <= end;
|
||||
}
|
||||
|
||||
// 自定义天数有效期(validType=custom):创建时间+validDays天
|
||||
if (validType === "custom" && createTime && validDays) {
|
||||
const create = new Date(createTime);
|
||||
const end = new Date(create.getTime() + validDays * 24 * 60 * 60 * 1000); // 加N天
|
||||
|
||||
return currentTime <= end;
|
||||
}
|
||||
|
||||
// 无有效期配置:默认视为无效
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 隔天生效校验:若设置了daysToTakeEffect,需超过生效时间(创建时间+N天的0点)
|
||||
*/
|
||||
function isCouponEffectiveAfterDays(
|
||||
backendCoupon: BackendCoupon,
|
||||
currentTime: Date
|
||||
): boolean {
|
||||
if (!backendCoupon.daysToTakeEffect || backendCoupon.daysToTakeEffect <= 0)
|
||||
return true;
|
||||
if (!backendCoupon.createTime) return false;
|
||||
|
||||
const create = new Date(backendCoupon.createTime);
|
||||
const effectiveTime = new Date(create);
|
||||
effectiveTime.setDate(create.getDate() + backendCoupon.daysToTakeEffect);
|
||||
effectiveTime.setHours(0, 0, 0, 0); // 隔天0点生效
|
||||
|
||||
return currentTime >= effectiveTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 每日时段校验:当前时间需在useStartTime和useEndTime之间(仅比较时分秒,支持跨天)
|
||||
*/
|
||||
function isCouponInDailyTimeRange(
|
||||
backendCoupon: BackendCoupon,
|
||||
currentTime: Date
|
||||
): boolean {
|
||||
// 全时段可用或未配置时段类型 → 直接通过
|
||||
if (backendCoupon.useTimeType === "all" || !backendCoupon.useTimeType)
|
||||
return true;
|
||||
// 非自定义时段 → 默认可用(兼容未配置场景)
|
||||
if (backendCoupon.useTimeType !== "custom") return true;
|
||||
// 缺少时段配置 → 无效
|
||||
if (!backendCoupon.useStartTime || !backendCoupon.useEndTime) return false;
|
||||
|
||||
// 解析时分(如"10:30" → [10, 30])
|
||||
const [startHours, startMinutes] = backendCoupon.useStartTime
|
||||
.split(":")
|
||||
.map(Number);
|
||||
const [endHours, endMinutes] = backendCoupon.useEndTime
|
||||
.split(":")
|
||||
.map(Number);
|
||||
|
||||
// 转换为当天分钟数(便于比较)
|
||||
const currentMinutes = currentTime.getHours() * 60 + currentTime.getMinutes();
|
||||
const startTotalMinutes = startHours * 60 + startMinutes;
|
||||
const endTotalMinutes = endHours * 60 + endMinutes;
|
||||
|
||||
// 处理跨天场景(如22:00-02:00)
|
||||
if (startTotalMinutes <= endTotalMinutes) {
|
||||
return (
|
||||
currentMinutes >= startTotalMinutes && currentMinutes <= endTotalMinutes
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
currentMinutes >= startTotalMinutes || currentMinutes <= endTotalMinutes
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 每周周期校验:当前星期几需在useDays范围内(如"周一,周二")
|
||||
*/
|
||||
function isCouponInWeekDays(
|
||||
backendCoupon: BackendCoupon,
|
||||
currentTime: Date
|
||||
): boolean {
|
||||
if (!backendCoupon.useDays) return true; // 未配置周期 → 默认可用
|
||||
|
||||
// 星期映射:getDay()返回0=周日,1=周一...6=周六
|
||||
const weekDayMap = {
|
||||
0: "周七",
|
||||
1: "周一",
|
||||
2: "周二",
|
||||
3: "周三",
|
||||
4: "周四",
|
||||
5: "周五",
|
||||
6: "周六",
|
||||
};
|
||||
const currentWeekDay =
|
||||
weekDayMap[currentTime.getDay() as keyof typeof weekDayMap];
|
||||
return backendCoupon.useDays.split(",").includes(currentWeekDay);
|
||||
}
|
||||
|
||||
/**
|
||||
* 门店匹配校验:根据useShopType判断当前门店是否适用
|
||||
*/
|
||||
function isStoreMatch(
|
||||
backendCoupon: BackendCoupon,
|
||||
currentStoreId: string
|
||||
): boolean {
|
||||
const { useShopType, useShops, shopId } = backendCoupon;
|
||||
|
||||
switch (useShopType) {
|
||||
case "all": // 所有门店适用
|
||||
return true;
|
||||
case "custom": // 指定门店适用(useShops逗号分割,门店ID)
|
||||
return useShops ? useShops.split(",").includes(currentStoreId) : false;
|
||||
case "only": // 仅本店适用(shopId为门店ID)
|
||||
return shopId ? String(shopId) === currentStoreId : false;
|
||||
default: // 未配置 → 默认为仅本店
|
||||
return shopId ? String(shopId) === currentStoreId : false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 就餐类型匹配校验:当前就餐类型需在useType范围内(如"dine,pickup")
|
||||
*/
|
||||
function isDinnerTypeMatch(
|
||||
backendCoupon: BackendCoupon,
|
||||
dinnerType: string
|
||||
): boolean {
|
||||
if (!backendCoupon.useType) return true; // 未配置 → 默认可用
|
||||
return backendCoupon.useType.split(",").includes(dinnerType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理适用门店ID:根据useShopType返回对应数组(供BaseCoupon使用)
|
||||
*/
|
||||
function getApplicableStoreIds(
|
||||
backendCoupon: BackendCoupon,
|
||||
currentStoreId: string
|
||||
): string[] {
|
||||
const { useShopType, useShops, shopId } = backendCoupon;
|
||||
|
||||
switch (useShopType) {
|
||||
case "all": // 所有门店适用:返回空数组(工具库空数组表示无限制)
|
||||
return [];
|
||||
case "custom": // 指定门店适用:useShops逗号分割转数组(门店ID)
|
||||
return useShops ? useShops.split(",").map((id) => id.trim()) : [];
|
||||
case "only": // 仅当前店铺适用:返回shopId(转字符串,门店ID)
|
||||
return shopId ? [shopId.toString()] : [];
|
||||
default: // 未配置:默认仅当前门店适用
|
||||
return [currentStoreId];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 折扣率格式化:后端discountRate(%)→ 工具库小数(如90→0.9)
|
||||
|
|
@ -1406,25 +1084,7 @@ function isStoreMatchByList(
|
|||
return useShops.includes(currentStoreId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 优惠券计算策略工厂(根据优惠券类型获取对应策略,易扩展)
|
||||
*/
|
||||
function getCouponStrategy(couponType: CouponType): CouponCalculationStrategy {
|
||||
switch (couponType) {
|
||||
case CouponType.FULL_REDUCTION:
|
||||
return new FullReductionStrategy();
|
||||
case CouponType.DISCOUNT:
|
||||
return new DiscountStrategy();
|
||||
case CouponType.SECOND_HALF:
|
||||
return new SecondHalfPriceStrategy();
|
||||
case CouponType.BUY_ONE_GET_ONE:
|
||||
return new BuyOneGetOneStrategy();
|
||||
case CouponType.EXCHANGE:
|
||||
return new ExchangeCouponStrategy();
|
||||
default:
|
||||
throw new Error(`不支持的优惠券类型:${couponType}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 计算优惠券抵扣金额(处理互斥逻辑,选择最优优惠券,按商品ID排除,新增细分统计)
|
||||
|
|
@ -1502,15 +1162,18 @@ export function calcTotalPackFee(
|
|||
goodsList: BaseCartItem[],
|
||||
dinnerType: "dine-in" | "take-out"
|
||||
): number {
|
||||
if (dinnerType !== "take-out") return 0;
|
||||
// if (dinnerType !== "take-out") return 0;
|
||||
let total = new BigNumber(0);
|
||||
|
||||
for (const goods of goodsList) {
|
||||
const availableNum = Math.max(0, goods.number - (goods.returnNum || 0));
|
||||
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 = dinnerType === "take-out" ? availableNum : 0;
|
||||
let packNum = availableNum;
|
||||
if (goods.product_type === GoodsType.WEIGHT) {
|
||||
packNum = Math.min(packNum, 1);
|
||||
}
|
||||
|
|
@ -1661,8 +1324,8 @@ export function calculateOrderCostSummary(
|
|||
const merchantReductionConfig = config.merchantReduction;
|
||||
let merchantReductionActualAmount = 0;
|
||||
|
||||
// 计算商家减免的可抵扣上限:商品实际金额 - 优惠券 - 积分(避免减免后为负)
|
||||
const maxMerchantReductionLimit = new BigNumber(goodsRealAmount)
|
||||
// 计算商家减免的可抵扣上限:商品实际金额 - 优惠券 - 积分(避免减免后为负) 再加上餐位费和打包费
|
||||
let maxMerchantReductionLimit = new BigNumber(goodsRealAmount)
|
||||
.minus(couponDeductionAmount)
|
||||
.minus(pointDeductionAmount)
|
||||
.isGreaterThan(0)
|
||||
|
|
@ -1671,6 +1334,9 @@ export function calculateOrderCostSummary(
|
|||
.minus(pointDeductionAmount)
|
||||
: new BigNumber(0);
|
||||
|
||||
maxMerchantReductionLimit = maxMerchantReductionLimit.plus(seatFee).plus(packFee)
|
||||
|
||||
|
||||
switch (merchantReductionConfig.type) {
|
||||
case MerchantReductionType.FIXED_AMOUNT:
|
||||
// 固定金额减免:取配置金额与上限的最小值,且不小于0
|
||||
|
|
@ -1713,17 +1379,36 @@ export function calculateOrderCostSummary(
|
|||
.minus(couponDeductionAmount) // 减去优惠券抵扣
|
||||
.minus(newUserDiscount) // 新客立减
|
||||
.minus(pointDeductionAmount) // 减去积分抵扣
|
||||
.minus(merchantReductionActualAmount); // 减去商家实际减免金额
|
||||
// .minus(merchantReductionActualAmount); // 减去商家实际减免金额
|
||||
|
||||
// 确保折扣后金额不小于0,再加上后续费用
|
||||
const nonNegativeAmount = discountedAmount.gt(0) ? discountedAmount : new BigNumber(0);
|
||||
const finalPayAmount = nonNegativeAmount
|
||||
.plus(seatFee) // 加上餐位费(不参与减免)
|
||||
.plus(packFee) // 加上打包费(不参与减免)
|
||||
.plus(additionalFee); // 加上附加费
|
||||
.plus(additionalFee) // 加上附加费
|
||||
.minus(merchantReductionActualAmount); // 减去商家实际减免金额
|
||||
|
||||
|
||||
const finalPayAmountNonNegative = Math.max(0, finalPayAmount.toNumber());
|
||||
|
||||
//计算全部的优惠金额
|
||||
const totalDiscountAmount = new BigNumber(goodsDiscountAmount) // 商品折扣
|
||||
.plus(couponDeductionAmount) // 减去优惠券抵扣
|
||||
.plus(newUserDiscount) // 新客立减
|
||||
.plus(pointDeductionAmount) // 减去积分抵扣
|
||||
.plus(merchantReductionActualAmount).toNumber(); // 减去商家实际减免金额
|
||||
|
||||
//最原始价格
|
||||
const originalAmount = new BigNumber(goodsRealAmount) // 商品真实原价总和
|
||||
.minus(goodsDiscountAmount) // 减去商品折扣
|
||||
.minus(couponDeductionAmount) // 减去优惠券抵扣
|
||||
.minus(newUserDiscount) // 新客立减
|
||||
.minus(pointDeductionAmount) // 减去积分抵扣
|
||||
.minus(merchantReductionActualAmount).toNumber(); // 减去商家实际减免金额
|
||||
|
||||
|
||||
|
||||
// 6. 返回完整费用汇总(包含商家减免明细)
|
||||
return {
|
||||
// 商品总件数
|
||||
|
|
@ -1737,7 +1422,8 @@ export function calculateOrderCostSummary(
|
|||
pointDeductionAmount,
|
||||
seatFee,
|
||||
packFee,
|
||||
|
||||
// 全部优惠金额
|
||||
totalDiscountAmount,
|
||||
// 商家减免明细(含类型、原始配置、实际金额)
|
||||
merchantReduction: {
|
||||
type: merchantReductionConfig.type,
|
||||
|
|
@ -1750,6 +1436,7 @@ export function calculateOrderCostSummary(
|
|||
pointUsed: usedPoints,
|
||||
newUserDiscount,
|
||||
dinnerType,
|
||||
config
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -1766,9 +1453,6 @@ export const OrderPriceCalculator = {
|
|||
formatDiscountRate,
|
||||
filterThresholdGoods,
|
||||
isWeightGoods,
|
||||
// 优惠券转换
|
||||
convertBackendCouponToToolCoupon,
|
||||
mapBackendCouponTypeToTool,
|
||||
// 商品价格计算
|
||||
calcSingleGoodsRealPrice,
|
||||
calcGoodsOriginalAmount,
|
||||
|
|
|
|||
|
|
@ -31,10 +31,14 @@
|
|||
<!-- 打包费 -->
|
||||
<template v-if="carts.packNum > 0">
|
||||
<div class="cart-title"><span>打包费</span></div>
|
||||
<extra-fee name="打包费" :number="carts.packNum" :price="carts.packFee"></extra-fee>
|
||||
<extra-fee
|
||||
name="打包费"
|
||||
:number="carts.packNum"
|
||||
:price="carts.orderCostSummary.packFee"
|
||||
></extra-fee>
|
||||
</template>
|
||||
<!-- 餐位费 -->
|
||||
<template v-if="perpole >= 1">
|
||||
<template v-if="perpole >= 1 && carts.dinnerType == 'dine-in'">
|
||||
<div class="cart-title"><span>餐位费</span></div>
|
||||
<extra-fee name="餐位费" :number="perpole" :price="canWeiFee"></extra-fee>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -253,11 +253,7 @@ function refGuaZhangConfirm(guazhangRen) {
|
|||
function refGuaZhangShow() {
|
||||
refGuaZhang.value.open();
|
||||
}
|
||||
//商品列表
|
||||
let goodsArr = [];
|
||||
|
||||
//优惠券
|
||||
let $goodsPayPriceMap = {};
|
||||
const refCoupon = ref();
|
||||
let quansSelArr = ref([]);
|
||||
function openCoupon() {
|
||||
|
|
@ -276,7 +272,6 @@ function refCouponConfirm(e, goodsList) {
|
|||
title: v.name,
|
||||
};
|
||||
});
|
||||
goodsArr = goodsList;
|
||||
console.log("refCouponConfirm", e);
|
||||
carts.setCoupons(e);
|
||||
|
||||
|
|
@ -291,7 +286,6 @@ function delQuan(row) {
|
|||
}
|
||||
carts.setCoupons(quansSelArr.value);
|
||||
}
|
||||
function couponChange(data) {}
|
||||
|
||||
//打折
|
||||
const refDiscount = ref();
|
||||
|
|
@ -313,25 +307,40 @@ function discountConfirm(e) {
|
|||
usePointsNumber.value = 0;
|
||||
}
|
||||
|
||||
//计算商家减免前金额
|
||||
// 计算商家减免前金额(使用bignumber.js确保精度)
|
||||
function returnMerchantReductionDiscount() {
|
||||
const {
|
||||
goodsOriginalAmount, // 商品原价总和
|
||||
goodsDiscountAmount, // 减去商品折扣
|
||||
couponDeductionAmount, // 减去优惠券抵扣
|
||||
pointDeductionAmount, // 减去积分抵扣
|
||||
merchantReductionActualAmount, // 减去商家实际减免金额
|
||||
seatFee, // 加上餐位费(不参与减免)
|
||||
packFee, // 加上打包费(不参与减免)
|
||||
goodsDiscountAmount, // 商品折扣
|
||||
couponDeductionAmount, // 优惠券抵扣
|
||||
pointDeductionAmount, // 积分抵扣
|
||||
seatFee, // 餐位费(不参与减免)
|
||||
packFee, // 打包费(不参与减免)
|
||||
additionalFee,
|
||||
} = carts.orderCostSummary;
|
||||
const total =
|
||||
goodsOriginalAmount - // 商品原价总和
|
||||
goodsDiscountAmount - // 减去商品折扣
|
||||
couponDeductionAmount; // 减去优惠券抵扣
|
||||
|
||||
return total <= 0 ? 0 : total;
|
||||
// 将所有金额转换为BigNumber实例
|
||||
const originalAmount = new BigNumber(goodsOriginalAmount);
|
||||
const discountAmount = new BigNumber(goodsDiscountAmount);
|
||||
const couponAmount = new BigNumber(couponDeductionAmount);
|
||||
const pointAmount = new BigNumber(pointDeductionAmount);
|
||||
const seat = new BigNumber(seatFee);
|
||||
const pack = new BigNumber(packFee);
|
||||
const additional = new BigNumber(additionalFee);
|
||||
|
||||
// 按照原逻辑进行精确计算
|
||||
const total = originalAmount
|
||||
.minus(discountAmount) // 减去商品折扣
|
||||
.minus(couponAmount) // 减去优惠券抵扣
|
||||
.minus(pointAmount) // 减去积分抵扣
|
||||
.plus(seat) // 加上餐位费
|
||||
.plus(pack) // 加上打包费
|
||||
.plus(additional); // 加上附加费
|
||||
|
||||
// 确保结果不小于0,返回数字类型
|
||||
return total.lte(0) ? 0 : total.toNumber();
|
||||
}
|
||||
|
||||
function discountShow(e) {
|
||||
refDiscount.value.open({
|
||||
// amount: carts.goodsTotal - productCouponDiscountAmount.value,
|
||||
|
|
@ -396,7 +405,11 @@ const pointsRes = ref({ usable: true, maxUsablePoints: 0, minDeductionPoints: 0
|
|||
const usePointsNumber = ref(0);
|
||||
//积分可抵扣最大金额
|
||||
const scoreMaxMoney = computed(() => {
|
||||
return carts.orderCostSummary.finalPayAmount + carts.orderCostSummary.pointDeductionAmount;
|
||||
return (
|
||||
carts.orderCostSummary.finalPayAmount +
|
||||
carts.orderCostSummary.pointDeductionAmount -
|
||||
carts.orderCostSummary.merchantReduction.actualAmount
|
||||
);
|
||||
});
|
||||
watch(
|
||||
() => scoreMaxMoney.value,
|
||||
|
|
@ -433,14 +446,7 @@ const emits = defineEmits(["chooseUser", "paysuccess"]);
|
|||
function chooseUser() {
|
||||
emits("chooseUser");
|
||||
}
|
||||
const coupDiscount = computed(() => {
|
||||
const total =
|
||||
props.orderInfo.fullCouponDiscountAmount * 1 + props.orderInfo.productCouponDiscountAmount * 1;
|
||||
if (total <= 0) {
|
||||
return 0;
|
||||
}
|
||||
return total.toFixed(2);
|
||||
});
|
||||
|
||||
const score = reactive({
|
||||
list: [],
|
||||
sel: -1,
|
||||
|
|
@ -495,7 +501,7 @@ function returnPayParams() {
|
|||
orderId: props.orderInfo.id,
|
||||
// discountRatio: (checkOrderPay.discount / 100).toFixed(2),
|
||||
discountRatio: 0,
|
||||
seatNum: props.perpole * 1,
|
||||
seatNum: carts.dinnerType == "dine-in" ? props.perpole * 1 : 0,
|
||||
originAmount: carts.orderCostSummary.goodsRealAmount,
|
||||
discountAmount: discountAmount.value,
|
||||
productCouponDiscountAmount: carts.orderCostSummary.productCouponDeduction,
|
||||
|
|
|
|||
Loading…
Reference in New Issue