889 lines
23 KiB
TypeScript
889 lines
23 KiB
TypeScript
import { BigNumber } from "bignumber.js";
|
||
import _ from "lodash";
|
||
|
||
export interface Goods {
|
||
productId: string | number; // 商品ID(唯一标识商品,用于优惠券/活动匹配,必选)
|
||
skuId: string | number; // 商品规格ID(唯一标识商品规格,如颜色/尺寸)
|
||
id: string | number; // 购物车ID(唯一标识购物车中的条目,如购物车项主键)
|
||
product_id: string | number; // 商品ID(唯一标识商品,用于优惠券/活动匹配,必选)
|
||
salePrice: number; // 商品原价(元)
|
||
number: number; // 商品数量
|
||
product_type: string; // 商品类型
|
||
is_temporary?: number; // 是否临时菜(默认false)
|
||
is_gift?: number; // 是否赠菜(默认false)
|
||
returnNum?: number; // 退货数量(历史订单用,默认0)
|
||
memberPrice: number; // 商品会员价(元,优先级:商品会员价 > 会员折扣)
|
||
discountSaleAmount?: number; // 商家改价后单价(元,优先级最高)
|
||
packFee?: number; // 单份打包费(元,默认0)
|
||
packNumber?: number; // 堂食打包数量(默认0)
|
||
skuData?: {
|
||
// SKU扩展数据(可选)
|
||
id: string | number; // SKU ID(唯一标识商品规格,如颜色/尺寸)
|
||
memberPrice?: number; // SKU会员价
|
||
salePrice?: number; // SKU原价
|
||
};
|
||
discount_sale_amount: number; // 商家改价后单价(元,优先级最高)
|
||
[property: string]: any;
|
||
}
|
||
|
||
export interface User {
|
||
isVip: number; // 是否会员 1是会员
|
||
[property: string]: any;
|
||
}
|
||
|
||
export interface ShopInfo {
|
||
isMemberPrice: number; // 是否开启会员价 1是开启
|
||
[property: string]: any;
|
||
}
|
||
|
||
export interface ThresholdFood {
|
||
id: string | number; // 商品ID
|
||
[property: string]: any;
|
||
}
|
||
export interface UseFood {
|
||
id: string | number;
|
||
[property: string]: any;
|
||
}
|
||
export interface Coupon {
|
||
id: string | number;
|
||
use: boolean;
|
||
type: number;
|
||
thresholdFoods: ThresholdFood[];
|
||
useFoods: UseFood[];
|
||
noUseRestrictions?: string;
|
||
discountShare: number; // 是否与折扣优惠同享 1是同享
|
||
vipPriceShare: number; // 是否与会员优惠同享 1是同享
|
||
otherCouponShare: number; // 是否与其他优惠券同享 1是同享
|
||
fullAmount: number; // 使用门槛金额
|
||
discountRate: number; // 折扣率(满减券:折扣金额/门槛金额,折扣券:折扣率)
|
||
maxDiscountAmount: number; // 最大折扣金额(满减券:折扣金额,折扣券:折扣金额)
|
||
discountNum: number; // 抵扣商品数量(商品券:抵扣商品数量,折扣券:0)
|
||
useRule: string; // 使用规则(price_asc:按商品单价升序,price_desc:按商品单价降序)
|
||
}
|
||
|
||
export interface couponDiscount {
|
||
discountPrice: number;
|
||
hasDiscountGoodsArr: Goods[];
|
||
}
|
||
export interface selCoupon extends Coupon {
|
||
discount?: couponDiscount;
|
||
}
|
||
|
||
export interface couponCalcParams {
|
||
canDikouGoodsArr: Goods[];
|
||
coupon: Coupon;
|
||
user: User;
|
||
shopInfo: ShopInfo;
|
||
selCoupon: selCoupon[];
|
||
goodsOrderPrice: number; //商品订单总价
|
||
isMemberPrice: number; // 是否开启会员价 1是开启
|
||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined;
|
||
}
|
||
|
||
//限时折扣配置
|
||
export interface TimeLimitDiscountConfig {
|
||
/**
|
||
* 折扣优先级 limit-time/vip-price
|
||
*/
|
||
discountPriority: string;
|
||
/**
|
||
* 折扣% 范围1-99
|
||
*/
|
||
discountRate: number;
|
||
/**
|
||
* 参与商品
|
||
*/
|
||
foods: string;
|
||
/**
|
||
* 参与商品 1全部 2部分
|
||
*/
|
||
foodType: number;
|
||
/**
|
||
* 自增主键
|
||
*/
|
||
id: number;
|
||
/**
|
||
* 店铺ID
|
||
*/
|
||
shopId: number;
|
||
/**
|
||
* 可使用类型:堂食 dine-in 外带 take-out 外卖 take-away 配送 post
|
||
*/
|
||
useType: string;
|
||
[property: string]: any;
|
||
}
|
||
|
||
export interface CanDikouGoodsArrArgs {
|
||
canDikouGoodsArr: Goods[];
|
||
selCoupon: selCoupon[];
|
||
user: User;
|
||
shopInfo: ShopInfo;
|
||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined;
|
||
}
|
||
|
||
/**
|
||
* 返回商品单价
|
||
* @param goods 商品
|
||
* @param user 用户信息
|
||
* @param {Object} shopInfo
|
||
*/
|
||
export function returnGoodsPrice(
|
||
goods: Goods,
|
||
user: User,
|
||
shopInfo: ShopInfo,
|
||
limitTimeDiscount: TimeLimitDiscountConfig | null | undefined
|
||
) {
|
||
if (!goods) {
|
||
return 0;
|
||
}
|
||
//是否可以使用会员价
|
||
const canUseVipPrice =
|
||
user &&
|
||
user.isVip &&
|
||
user.isMemberPrice &&
|
||
goods.memberPrice * 1 > 0 &&
|
||
shopInfo &&
|
||
shopInfo.isMemberPrice;
|
||
// 商家改价
|
||
if (goods.discount_sale_amount * 1 > 0) {
|
||
return goods.salePrice;
|
||
}
|
||
// 限时折扣
|
||
if (limitTimeDiscount && limitTimeDiscount.id) {
|
||
const canUseFoods = limitTimeDiscount.foods.split(",");
|
||
const canUseLimit =
|
||
limitTimeDiscount.foodType == 1 ||
|
||
canUseFoods.includes(`${goods.productId}`);
|
||
if (canUseLimit && limitTimeDiscount.discountPriority == "limit-time") {
|
||
return new BigNumber(goods.salePrice)
|
||
.times(limitTimeDiscount.discountRate / 100)
|
||
.decimalPlaces(2, BigNumber.ROUND_UP)
|
||
.toNumber();
|
||
}
|
||
|
||
if (canUseLimit && limitTimeDiscount.discountPriority == "vip-price") {
|
||
if (canUseVipPrice) {
|
||
return goods.memberPrice;
|
||
} else {
|
||
return new BigNumber(goods.salePrice)
|
||
.times(limitTimeDiscount.discountRate / 100)
|
||
.decimalPlaces(2, BigNumber.ROUND_UP)
|
||
.toNumber();
|
||
}
|
||
}
|
||
}
|
||
if (canUseVipPrice) {
|
||
return goods.memberPrice;
|
||
}
|
||
return goods.salePrice;
|
||
}
|
||
|
||
/**
|
||
* 返回商品分组
|
||
* @param arr 商品列表
|
||
*/
|
||
export function returnGoodsGroupMap(arr: Goods[]) {
|
||
let map: { [key: string]: Goods[] } = {};
|
||
arr.forEach((v) => {
|
||
const key = v.productId + "_" + v.skuId;
|
||
if (!map[key]) {
|
||
map[key] = [];
|
||
}
|
||
map[key].push(v);
|
||
});
|
||
return map;
|
||
}
|
||
|
||
/**
|
||
* 优惠券类型:1-满减券,2-商品兑换券,3-折扣券,4-第二件半价券,5-消费送券,6-买一送一券,7-固定价格券,8-免配送费券
|
||
* @param coupon
|
||
*/
|
||
export function returnCoupType(coupon: Coupon) {
|
||
const couponTypes = {
|
||
1: "满减券",
|
||
2: "商品券",
|
||
3: "折扣券",
|
||
4: "第二件半价券",
|
||
5: "消费送券",
|
||
6: "买一送一券",
|
||
7: "固定价格券",
|
||
8: "免配送费券",
|
||
};
|
||
return couponTypes[coupon.type as keyof typeof couponTypes] || "未知类型";
|
||
}
|
||
|
||
|
||
/**
|
||
* 返回商品券抵扣后的商品列表
|
||
* @param canDikouGoodsArr 可抵扣商品列表
|
||
* @param selCoupon 已选择的优惠券列表
|
||
* @param user 用户信息
|
||
*/
|
||
export function returnCanDikouGoodsArr(args: CanDikouGoodsArrArgs) {
|
||
const { canDikouGoodsArr, selCoupon, user, shopInfo, limitTimeDiscount } =
|
||
args;
|
||
const types = [2, 4, 6];
|
||
// 收集已抵扣商品并关联对应的优惠券类型
|
||
const goodsCouponGoods = selCoupon
|
||
.filter((v) => types.includes(v.type))
|
||
.reduce((prev: Goods[], cur) => {
|
||
// 给每个抵扣商品添加所属优惠券类型
|
||
if (cur && cur.discount) {
|
||
const goodsWithType = cur.discount.hasDiscountGoodsArr.map((goods) => ({
|
||
...goods,
|
||
couponType: cur.type, // 记录该商品是被哪种类型的优惠券抵扣的
|
||
}));
|
||
prev.push(...goodsWithType);
|
||
}
|
||
return prev;
|
||
}, []);
|
||
const arr = _.cloneDeep(canDikouGoodsArr)
|
||
.map((v) => {
|
||
const findCart = goodsCouponGoods.find((carts) => carts.id == v.id);
|
||
if (findCart) {
|
||
// 根据优惠券类型判断扣减数量
|
||
if ([4, 6].includes(findCart.couponType)) {
|
||
// 类型4(第二件半价)或6(买一送一),数量减2
|
||
v.num -= 2;
|
||
} else {
|
||
// 其他类型(如类型2商品券),按原逻辑扣减对应数量
|
||
v.num -= findCart.num;
|
||
}
|
||
}
|
||
return v;
|
||
})
|
||
.filter((v) => {
|
||
const canUseNum = v.num - (v.returnNum || 0);
|
||
if (canUseNum <= 0 || v.is_temporary == 1 || v.is_gift == 1) {
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}); // 过滤掉数量<=0的商品,赠菜,临时菜
|
||
|
||
return arr;
|
||
}
|
||
|
||
|
||
/**
|
||
* 返回商品是否享用了会员价/会员折扣
|
||
* @param {*} goods
|
||
*/
|
||
function returnGoodsIsUseVipPrice(shopInfo: ShopInfo, user: User, goods: Goods) {
|
||
if (goods.is_time_discount) {
|
||
return false;
|
||
}
|
||
if (shopInfo.isMemberPrice != 1 || user.isVip != 1) {
|
||
return false;
|
||
}
|
||
if (shopInfo.isMemberPrice == 1 && user.isVip == 1) {
|
||
console.log('goods', goods);
|
||
if (goods.memberPrice <= 0) {
|
||
return false;
|
||
}else{
|
||
return true;
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
/**
|
||
* 返回可以计算抵扣金额的商品列表
|
||
*/
|
||
function returnCanCalcGoodsList(canCalcGoodsArr: Goods[], coupon: Coupon, shopInfo: ShopInfo, user: User) {
|
||
return canCalcGoodsArr.filter((goods) => {
|
||
|
||
if (
|
||
!coupon.discountShare &&
|
||
(goods.is_time_discount || goods.isTimeDiscount)
|
||
) {
|
||
return false;
|
||
}
|
||
if (
|
||
!coupon.vipPriceShare &&
|
||
returnGoodsIsUseVipPrice(shopInfo, user, goods)
|
||
) {
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 判断优惠券是否可使用,并返回不可用原因
|
||
*
|
||
* @param {Object} args - 函数参数集合
|
||
* @param {Array} args.canDikouGoodsArr - 可参与抵扣的商品列表
|
||
* @param {Object} args.coupon - 优惠券信息对象
|
||
* @param {boolean} args.coupon.use - 优惠券是否启用
|
||
* @param {Array} args.coupon.useFoods - 优惠券适用的商品ID列表
|
||
* @param {number} args.coupon.fullAmount - 优惠券使用门槛金额
|
||
* @param {number} args.coupon.type - 优惠券类型
|
||
* @param {number} args.goodsOrderPrice - 订单中所有商品的总金额
|
||
* @param {Object} args.user - 用户信息对象
|
||
* @param {Object} args.selCoupon - 已经选择的优惠券信息对象
|
||
* @param {Object} args.shopInfo
|
||
* @param {boolean} args.limitTimeDiscount - 限时折扣
|
||
* @returns {Object} - { canUse: boolean, reason: string } 可用状态及不可用原因
|
||
*/
|
||
export function returnCouponCanUse(args: couponCalcParams) {
|
||
|
||
let {
|
||
canDikouGoodsArr,
|
||
coupon,
|
||
goodsOrderPrice,
|
||
user,
|
||
selCoupon,
|
||
shopInfo,
|
||
isMemberPrice,
|
||
limitTimeDiscount,
|
||
} = args;
|
||
// 优惠券未启用
|
||
if (!coupon.use) {
|
||
return {
|
||
canUse: false,
|
||
reason: coupon.noUseRestrictions || "不在可用时间段内",
|
||
};
|
||
}
|
||
if (
|
||
limitTimeDiscount &&
|
||
limitTimeDiscount.id &&
|
||
limitTimeDiscount.foodType == 1 &&
|
||
!coupon.discountShare
|
||
) {
|
||
return {
|
||
canUse: false,
|
||
reason: coupon.noUseRestrictions || "不可与限时折扣同享",
|
||
};
|
||
}
|
||
|
||
// 计算门槛金额
|
||
let fullAmount = goodsOrderPrice;
|
||
canDikouGoodsArr = returnCanDikouGoodsArr(args);
|
||
//优惠券指定门槛商品列表
|
||
let canCalcGoodsArr = [...canDikouGoodsArr];
|
||
//部分商品参与门槛计算
|
||
if (coupon.thresholdFoods.length) {
|
||
canCalcGoodsArr = canDikouGoodsArr.filter((v) => {
|
||
return coupon.thresholdFoods.find((food) => food.id == v.productId);
|
||
});
|
||
}
|
||
console.log("canCalcGoodsArr",canCalcGoodsArr);
|
||
|
||
canCalcGoodsArr = returnCanCalcGoodsList(
|
||
canCalcGoodsArr,
|
||
coupon,
|
||
shopInfo,
|
||
user
|
||
);
|
||
|
||
fullAmount = canCalcGoodsArr.reduce((pre, cur) => {
|
||
return (
|
||
pre + returnGoodsPrice(cur, user, shopInfo, limitTimeDiscount) * cur.num
|
||
);
|
||
}, 0);
|
||
|
||
// 是否全部商品可用
|
||
const isDikouAll = coupon.useFoods.length === 0;
|
||
// 订单可用商品列表
|
||
let canUseGoodsArr: Goods[] = [];
|
||
if (!isDikouAll) {
|
||
canUseGoodsArr = canDikouGoodsArr.filter((v) => {
|
||
return coupon.useFoods.find((food) => food.id == v.productId);
|
||
});
|
||
}
|
||
// if (user.isVip && !coupon.vipPriceShare) {
|
||
// return {
|
||
// canUse: false,
|
||
// reason: "非会员可用",
|
||
// };
|
||
// }
|
||
if (selCoupon.length > 0 && !selCoupon[0].otherCouponShare) {
|
||
return {
|
||
canUse: false,
|
||
reason: "当前选中的券不可与其他券同享",
|
||
};
|
||
}
|
||
if (selCoupon.length > 0 && !coupon.otherCouponShare) {
|
||
return {
|
||
canUse: false,
|
||
reason: "当前选中的券不可与其他券同享",
|
||
};
|
||
}
|
||
// 满减券和折扣券计算门槛金额是否满足
|
||
if ([1, 3].includes(coupon.type)) {
|
||
if (canCalcGoodsArr.length <= 0) {
|
||
return {
|
||
canUse: false,
|
||
reason: "没有可参与计算门槛的商品",
|
||
};
|
||
}
|
||
// 不满足门槛金额
|
||
if (fullAmount < coupon.fullAmount) {
|
||
return {
|
||
canUse: false,
|
||
reason: `满${coupon.fullAmount}元可用,当前可参与金额${fullAmount}元`,
|
||
};
|
||
}
|
||
}
|
||
// 商品兑换券,第二件半价和买一送一判断是否有可用商品
|
||
if ([2, 4, 5].includes(coupon.type)) {
|
||
if(coupon.type==2){
|
||
console.log("isDikouAll",isDikouAll);
|
||
console.log("canCalcGoodsArr",canCalcGoodsArr);
|
||
}
|
||
|
||
|
||
|
||
// 没有符合条件的商品
|
||
if (isDikouAll && canDikouGoodsArr.length === 0) {
|
||
return {
|
||
canUse: false,
|
||
reason: "没有符合条件的商品",
|
||
};
|
||
}
|
||
if (!isDikouAll && canUseGoodsArr.length === 0) {
|
||
return {
|
||
canUse: false,
|
||
reason: "没有符合条件的商品",
|
||
};
|
||
}
|
||
if (coupon.type == 2) {
|
||
if (canCalcGoodsArr.length <= 0) {
|
||
return {
|
||
canUse: false,
|
||
reason: "没有符合计算门槛条件的商品",
|
||
};
|
||
}
|
||
if (fullAmount < coupon.fullAmount) {
|
||
return {
|
||
canUse: false,
|
||
reason: `满${coupon.fullAmount}元可用,当前可参与金额${fullAmount}元`,
|
||
};
|
||
}
|
||
}
|
||
}
|
||
//商品兑换券是否达到门槛金额
|
||
if (coupon.type == 2 && goodsOrderPrice < coupon.fullAmount) {
|
||
return {
|
||
canUse: false,
|
||
reason: `满${coupon.fullAmount}元可用,当前可参与金额${fullAmount}元`,
|
||
};
|
||
}
|
||
|
||
// 买一送一券特殊验证
|
||
if (coupon.type === 6) {
|
||
let canUse = false;
|
||
if (isDikouAll) {
|
||
canUse = canDikouGoodsArr.some((v) => v.num >= 2);
|
||
} else if (canUseGoodsArr.length > 0) {
|
||
canUse = canUseGoodsArr.some((v) => v.num >= 2);
|
||
}
|
||
|
||
if (!canUse) {
|
||
return {
|
||
canUse: false,
|
||
reason: "需要购买至少2件相同的商品才能使用",
|
||
};
|
||
}
|
||
}
|
||
|
||
// 第二件半价券特殊验证
|
||
if (coupon.type === 4) {
|
||
let canUse = false;
|
||
if (isDikouAll) {
|
||
canUse = canDikouGoodsArr.some((v) => v.num >= 2);
|
||
} else if (canUseGoodsArr.length > 0) {
|
||
canUse = canUseGoodsArr.some((v) => v.num >= 2);
|
||
}
|
||
if (!canUse) {
|
||
return {
|
||
canUse: false,
|
||
reason: "需要购买至少2件相同的商品才能使用",
|
||
};
|
||
}
|
||
}
|
||
|
||
// 所有条件都满足
|
||
return {
|
||
canUse: true,
|
||
reason: "",
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 计算抵扣商品金额
|
||
* @param discountGoodsArr 可抵扣商品列表
|
||
* @param discountNum 抵扣数量
|
||
* @param user 用户信息
|
||
* @param {Object} shopInfo 店铺信息
|
||
*/
|
||
export function calcDiscountGoodsArrPrice(
|
||
discountGoodsArr: Goods[],
|
||
discountNum: number,
|
||
user: User,
|
||
shopInfo: ShopInfo,
|
||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
|
||
) {
|
||
let hasCountNum = 0;
|
||
let discountPrice = 0;
|
||
let hasDiscountGoodsArr = [];
|
||
|
||
for (let i = 0; i < discountGoodsArr.length; i++) {
|
||
if (hasCountNum >= discountNum) {
|
||
break;
|
||
}
|
||
const goods = discountGoodsArr[i];
|
||
const shengyuNum = discountNum - hasCountNum;
|
||
const num = Math.min(goods.num, shengyuNum);
|
||
const realPrice = returnGoodsPrice(
|
||
goods,
|
||
user,
|
||
shopInfo,
|
||
limitTimeDiscount
|
||
);
|
||
|
||
discountPrice += realPrice * num;
|
||
|
||
hasCountNum += num;
|
||
hasDiscountGoodsArr.push({
|
||
...goods,
|
||
num,
|
||
});
|
||
}
|
||
|
||
return {
|
||
discountPrice,
|
||
hasDiscountGoodsArr,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 计算优惠券抵扣金额
|
||
* @param arr 可抵扣商品列表
|
||
* @param coupon 优惠券
|
||
* @param user 用户信息
|
||
* @param goodsOrderPrice 商品订单金额
|
||
* @param selCoupon 已选择的优惠券列表
|
||
* @param shopInfo 店铺信息
|
||
* @param limitTimeDiscount 限时折扣
|
||
*/
|
||
export function returnCouponDiscount(
|
||
arr: Goods[],
|
||
coupon: Coupon,
|
||
user: User,
|
||
goodsOrderPrice: number,
|
||
selCoupon: selCoupon[],
|
||
shopInfo: ShopInfo,
|
||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
|
||
|
||
) {
|
||
arr = returnCanDikouGoods(arr, user, shopInfo,limitTimeDiscount);
|
||
const canDikouGoodsArr = returnCanDikouGoodsArr({
|
||
canDikouGoodsArr: arr,
|
||
selCoupon,
|
||
user,
|
||
shopInfo,
|
||
limitTimeDiscount,
|
||
});
|
||
if (coupon.type == 2) {
|
||
return returnCouponProductDiscount(
|
||
canDikouGoodsArr,
|
||
coupon,
|
||
user,
|
||
shopInfo,
|
||
limitTimeDiscount
|
||
);
|
||
}
|
||
if (coupon.type == 6) {
|
||
const result = returnCouponBuyOneGiveOneDiscount(
|
||
canDikouGoodsArr,
|
||
coupon,
|
||
user,
|
||
shopInfo,
|
||
limitTimeDiscount
|
||
);
|
||
return result;
|
||
}
|
||
if (coupon.type == 4) {
|
||
return returnSecoendDiscount(
|
||
canDikouGoodsArr,
|
||
coupon,
|
||
user,
|
||
shopInfo,
|
||
limitTimeDiscount
|
||
);
|
||
}
|
||
if (coupon.type == 3) {
|
||
return returnCouponZhekouDiscount(
|
||
canDikouGoodsArr,
|
||
coupon,
|
||
user,
|
||
goodsOrderPrice,
|
||
selCoupon,
|
||
limitTimeDiscount
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 折扣券抵扣金额
|
||
* @param canDikouGoodsArr 可抵扣商品列表
|
||
* @param coupon 优惠券
|
||
* @param user 用户信息
|
||
* @param goodsOrderPrice 商品订单金额
|
||
* @param selCoupon 已选择的优惠券列表
|
||
* @param limitTimeDiscount 限时折扣
|
||
*/
|
||
export function returnCouponZhekouDiscount(
|
||
canDikouGoodsArr: Goods[],
|
||
coupon: Coupon,
|
||
user: User,
|
||
goodsOrderPrice: number,
|
||
selCoupon: selCoupon[],
|
||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
|
||
) {
|
||
const { discountRate, maxDiscountAmount } = coupon;
|
||
|
||
// 计算商品优惠券折扣总和,使用BigNumber避免精度问题
|
||
const goodsCouponDiscount = selCoupon
|
||
.filter((v) => v.type == 2)
|
||
.reduce((prve, cur) => {
|
||
return new BigNumber(prve).plus(
|
||
new BigNumber(cur?.discount?.discountPrice || 0)
|
||
);
|
||
}, new BigNumber(0));
|
||
|
||
// 将商品订单价格转换为BigNumber并减去优惠券折扣
|
||
const adjustedGoodsOrderPrice = new BigNumber(goodsOrderPrice).minus(
|
||
goodsCouponDiscount
|
||
);
|
||
|
||
// 计算优惠比例:(100 - 折扣率) / 100
|
||
const discountAmountRatio = new BigNumber(100)
|
||
.minus(discountRate)
|
||
.dividedBy(100);
|
||
|
||
// 计算折扣金额:调整后的商品订单金额 × 优惠比例
|
||
let discountPrice = adjustedGoodsOrderPrice
|
||
.times(discountAmountRatio)
|
||
.decimalPlaces(2, BigNumber.ROUND_FLOOR)
|
||
.toNumber();
|
||
|
||
// 应用最大折扣金额限制
|
||
if (maxDiscountAmount !== 0) {
|
||
discountPrice =
|
||
discountPrice >= maxDiscountAmount ? maxDiscountAmount : discountPrice;
|
||
}
|
||
|
||
return {
|
||
discountPrice, // 折扣抵扣金额(即优惠的金额)
|
||
hasDiscountGoodsArr: [],
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 商品券抵扣金额
|
||
* @param canDikouGoodsArr 可抵扣商品列表
|
||
* @param coupon 优惠券
|
||
* @param user 用户信息
|
||
* @param shopInfo 店铺信息
|
||
*/
|
||
export function returnCouponProductDiscount(
|
||
canDikouGoodsArr: Goods[],
|
||
coupon: Coupon,
|
||
user: User,
|
||
shopInfo: ShopInfo,
|
||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
|
||
) {
|
||
const { useFoods, discountNum, useRule } = coupon;
|
||
|
||
//抵扣商品数组
|
||
let discountGoodsArr = [];
|
||
|
||
//抵扣全部商品
|
||
if (useFoods.length === 0) {
|
||
if (useRule == "price_asc") {
|
||
discountGoodsArr = canDikouGoodsArr.slice(discountNum * -1).reverse();
|
||
} else {
|
||
discountGoodsArr = canDikouGoodsArr.slice(0, discountNum);
|
||
}
|
||
} else {
|
||
//抵扣选中商品
|
||
const discountSelGoodsArr = canDikouGoodsArr.filter((v) =>
|
||
useFoods.find((food) => food.id == v.productId)
|
||
);
|
||
if (useRule == "price_asc") {
|
||
discountGoodsArr = discountSelGoodsArr.slice(discountNum * -1).reverse();
|
||
} else {
|
||
discountGoodsArr = discountSelGoodsArr.slice(0, discountNum);
|
||
}
|
||
}
|
||
|
||
|
||
const result = calcDiscountGoodsArrPrice(
|
||
discountGoodsArr,
|
||
discountNum,
|
||
user,
|
||
shopInfo,
|
||
limitTimeDiscount
|
||
);
|
||
return result;
|
||
}
|
||
|
||
// 返回买一送一券抵扣详情
|
||
/**
|
||
* @param canDikouGoodsArr 可抵扣商品列表
|
||
* @param coupon 优惠券
|
||
* @param user 用户信息
|
||
* @param shopInfo 店铺信息
|
||
*/
|
||
function returnCouponBuyOneGiveOneDiscount(
|
||
canDikouGoodsArr: Goods[],
|
||
coupon: Coupon,
|
||
user: User,
|
||
shopInfo: ShopInfo,
|
||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
|
||
) {
|
||
const { useFoods, useRule } = coupon;
|
||
//抵扣商品
|
||
let discountGoods = undefined;
|
||
//符合买一送一条件的商品
|
||
const canUseGoods = canDikouGoodsArr.filter((v) => v.num >= 2);
|
||
//抵扣全部商品
|
||
if (useFoods.length === 0) {
|
||
if (useRule == "price_asc") {
|
||
discountGoods = canUseGoods[canUseGoods.length - 1];
|
||
} else {
|
||
discountGoods = canUseGoods[0];
|
||
}
|
||
} else {
|
||
//符合抵扣条件的商品
|
||
const canUseGoods1 = canUseGoods.filter((v) =>
|
||
useFoods.find((food) => food.id == v.productId)
|
||
);
|
||
if (useRule == "price_asc") {
|
||
discountGoods = canUseGoods1[canUseGoods1.length - 1];
|
||
} else {
|
||
discountGoods = canUseGoods1[0];
|
||
}
|
||
}
|
||
let discountPrice = 0;
|
||
let hasDiscountGoodsArr: Goods[] = [];
|
||
if (discountGoods) {
|
||
discountPrice = returnGoodsPrice(
|
||
discountGoods,
|
||
user,
|
||
shopInfo,
|
||
limitTimeDiscount
|
||
);
|
||
hasDiscountGoodsArr = [discountGoods];
|
||
}
|
||
return {
|
||
discountPrice: discountPrice <= 0 ? 0 : discountPrice,
|
||
hasDiscountGoodsArr,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 返回第二件半价券抵扣详情
|
||
* @param canDikouGoodsArr 可抵扣商品列表
|
||
* @param coupon 优惠券
|
||
* @param user 用户信息
|
||
* @param shopInfo 店铺信息
|
||
*/
|
||
function returnSecoendDiscount(
|
||
canDikouGoodsArr: Goods[],
|
||
coupon: Coupon,
|
||
user: User,
|
||
shopInfo: ShopInfo,
|
||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
|
||
) {
|
||
const { useFoods, useRule } = coupon;
|
||
//抵扣商品
|
||
let discountGoods = undefined;
|
||
//符合条件的商品
|
||
const canUseGoods = canDikouGoodsArr.filter((v) => v.num >= 2);
|
||
//抵扣全部商品
|
||
if (useFoods.length === 0) {
|
||
if (useRule == "price_asc") {
|
||
discountGoods = canUseGoods[canUseGoods.length - 1];
|
||
} else {
|
||
discountGoods = canUseGoods[0];
|
||
}
|
||
} else {
|
||
//符合抵扣条件的商品
|
||
const canUseGoods1 = canUseGoods.filter((v) =>
|
||
useFoods.find((food) => food.id == v.productId)
|
||
);
|
||
if (useRule == "price_asc") {
|
||
discountGoods = canUseGoods1[canUseGoods1.length - 1];
|
||
} else {
|
||
discountGoods = canUseGoods1[0];
|
||
}
|
||
}
|
||
let discountPrice = 0;
|
||
let hasDiscountGoodsArr: Goods[] = [];
|
||
if (discountGoods) {
|
||
discountPrice = returnGoodsPrice(
|
||
discountGoods,
|
||
user,
|
||
shopInfo,
|
||
limitTimeDiscount
|
||
);
|
||
hasDiscountGoodsArr = [discountGoods];
|
||
}
|
||
//返回半价价格
|
||
return {
|
||
discountPrice:
|
||
discountPrice <= 0
|
||
? 0
|
||
: new BigNumber(discountPrice).dividedBy(2).toNumber(),
|
||
hasDiscountGoodsArr,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 返回可以抵扣优惠券的商品列表,过滤掉赠品、临时商品,价格从高到低排序
|
||
* @param arr 商品列表
|
||
* @param user 用户信息
|
||
* @param shopInfo 店铺信息
|
||
* @param limitTimeDiscount 限时折扣
|
||
*/
|
||
export function returnCanDikouGoods(
|
||
arr: Goods[],
|
||
user: User,
|
||
shopInfo: ShopInfo,
|
||
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
|
||
) {
|
||
const result = arr
|
||
.filter((v) => {
|
||
return v.is_temporary != 1 && v.is_gift != 1;
|
||
})
|
||
.filter((v) => {
|
||
return v.num > 0;
|
||
})
|
||
.sort((a, b) => {
|
||
return (
|
||
returnGoodsPrice(b, user, shopInfo, limitTimeDiscount) -
|
||
returnGoodsPrice(a, user, shopInfo, limitTimeDiscount)
|
||
);
|
||
});
|
||
return result;
|
||
}
|
||
export const utils = {
|
||
returnGoodsPrice,
|
||
returnGoodsGroupMap,
|
||
returnCoupType,
|
||
returnCanDikouGoods,
|
||
returnCanDikouGoodsArr,
|
||
returnCouponCanUse,
|
||
calcDiscountGoodsArrPrice,
|
||
returnCouponDiscount,
|
||
returnCouponProductDiscount,
|
||
returnCouponZhekouDiscount,
|
||
};
|
||
|
||
export default utils;
|