444 lines
12 KiB
JavaScript
444 lines
12 KiB
JavaScript
import {
|
||
BigNumber
|
||
} from "bignumber.js";
|
||
import _ from "lodash";
|
||
|
||
|
||
|
||
/**
|
||
* 返回商品单价
|
||
* @param goods 商品
|
||
* @param user 用户信息
|
||
* @param {Object} shopInfo
|
||
*/
|
||
export function returnGoodsPrice(goods, user, shopInfo) {
|
||
if (goods.discount_sale_amount * 1 > 0) {
|
||
return goods.discount_sale_amount;
|
||
}
|
||
if(shopInfo&&!shopInfo.isMemberPrice){
|
||
return goods.salePrice;
|
||
}
|
||
if (user.isVip && goods.memberPrice * 1 <= goods.salePrice * 1 && goods.memberPrice * 1 > 0) {
|
||
return goods.memberPrice;
|
||
}
|
||
return goods.salePrice;
|
||
}
|
||
|
||
/**
|
||
* 返回商品分组
|
||
* @param arr 商品列表
|
||
*/
|
||
export function returnGoodsGroupMap(arr) {
|
||
let map = {};
|
||
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) {
|
||
const couponTypes = {
|
||
1: "满减券",
|
||
2: "商品券",
|
||
3: "折扣券",
|
||
4: "第二件半价券",
|
||
5: "消费送券",
|
||
6: "买一送一券",
|
||
7: "固定价格券",
|
||
8: "免配送费券",
|
||
};
|
||
return couponTypes[coupon.type] || "未知类型";
|
||
}
|
||
|
||
/**
|
||
* 返回商品券抵扣后的商品列表
|
||
* @param canDikouGoodsArr 可抵扣商品列表
|
||
* @param selCoupon 已选择的优惠券列表
|
||
* @param user 用户信息
|
||
*/
|
||
export function returnCanDikouGoodsArr(canDikouGoodsArr, selCoupon, user) {
|
||
const goodsCouponGoods = selCoupon
|
||
.filter((v) => v.type == 2)
|
||
.reduce((prve, cur) => {
|
||
prve.push(...cur.discount.hasDiscountGoodsArr);
|
||
return prve;
|
||
}, []);
|
||
const arr = _.cloneDeep(canDikouGoodsArr)
|
||
.map((v) => {
|
||
const findCart = goodsCouponGoods.find((carts) => carts.id == v.id);
|
||
if (findCart) {
|
||
v.num -= findCart.num;
|
||
}
|
||
return v;
|
||
})
|
||
.filter((v) => v.num > 0);
|
||
return arr;
|
||
}
|
||
|
||
/**
|
||
* 判断优惠券是否可使用,并返回不可用原因
|
||
*
|
||
* @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
|
||
* @returns {Object} - { canUse: boolean, reason: string } 可用状态及不可用原因
|
||
*/
|
||
export function returnCouponCanUse(args) {
|
||
let {
|
||
canDikouGoodsArr,
|
||
coupon,
|
||
goodsOrderPrice,
|
||
user,
|
||
selCoupon,
|
||
shopInfo
|
||
} = args;
|
||
|
||
// 优惠券未启用
|
||
if (!coupon.use) {
|
||
return {
|
||
canUse: false,
|
||
reason: "优惠券未启用"
|
||
};
|
||
}
|
||
|
||
canDikouGoodsArr = returnCanDikouGoodsArr(canDikouGoodsArr, selCoupon, user,shopInfo);
|
||
// 计算门槛金额
|
||
let fullAmount = goodsOrderPrice;
|
||
// 是否抵扣全部商品
|
||
const isDikouAll = coupon.useFoods.length === 0;
|
||
let canCalcGoodsArr = [];
|
||
// 订单里参与门槛计算的商品
|
||
if (!isDikouAll) {
|
||
canCalcGoodsArr = canDikouGoodsArr.filter((v) => {
|
||
return coupon.useFoods.find((food) => food.id == v.productId);
|
||
});
|
||
fullAmount = canCalcGoodsArr.reduce((pre, cur) => {
|
||
return pre + returnGoodsPrice(cur, user,shopInfo) * cur.num;
|
||
}, 0);
|
||
}
|
||
|
||
// 没有符合条件的商品
|
||
if (!isDikouAll && canCalcGoodsArr.length === 0) {
|
||
return {
|
||
canUse: false,
|
||
reason: "没有符合条件的商品"
|
||
};
|
||
}
|
||
|
||
// 不满足门槛金额
|
||
if (fullAmount < coupon.fullAmount) {
|
||
return {
|
||
canUse: false,
|
||
reason: `满${coupon.fullAmount}元可用,当前可参与金额${fullAmount}元`
|
||
};
|
||
}
|
||
|
||
// 商品券特殊验证
|
||
if (coupon.type === 2) {
|
||
if (!(isDikouAll || canCalcGoodsArr.length > 0)) {
|
||
return {
|
||
canUse: false,
|
||
reason: "没有符合条件的商品可抵扣"
|
||
};
|
||
}
|
||
}
|
||
|
||
// 买一送一券特殊验证
|
||
if (coupon.type === 6) {
|
||
let canUse = false;
|
||
if (isDikouAll) {
|
||
canUse = canDikouGoodsArr.some((v) => v.num >= 2);
|
||
} else if (canCalcGoodsArr.length > 0) {
|
||
canUse = canCalcGoodsArr.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 (canCalcGoodsArr.length > 0) {
|
||
canUse = canCalcGoodsArr.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, discountNum, user,shopInfo) {
|
||
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);
|
||
discountPrice += returnGoodsPrice(goods, user,shopInfo) * num;
|
||
hasCountNum += num;
|
||
hasDiscountGoodsArr.push({
|
||
...goods,
|
||
num
|
||
});
|
||
}
|
||
return {
|
||
discountPrice,
|
||
hasDiscountGoodsArr
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 计算优惠券抵扣金额
|
||
* @param arr 可抵扣商品列表
|
||
* @param coupon 优惠券
|
||
* @param user 用户信息
|
||
* @param goodsOrderPrice 商品订单金额
|
||
* @param selCoupon 已选择的优惠券列表
|
||
*/
|
||
export function returnCouponDiscount(arr, coupon, user, goodsOrderPrice, selCoupon) {
|
||
console.log('arr', arr);
|
||
const canDikouGoodsArr = returnCanDikouGoodsArr(arr, selCoupon, user);
|
||
console.log('canDikouGoodsArr', canDikouGoodsArr);
|
||
if (coupon.type == 2) {
|
||
return returnCouponProductDiscount(canDikouGoodsArr, coupon, user, goodsOrderPrice);
|
||
}
|
||
if (coupon.type == 6) {
|
||
return returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user, goodsOrderPrice);
|
||
}
|
||
if (coupon.type == 4) {
|
||
return returnSecoendDiscount(canDikouGoodsArr, coupon, user, goodsOrderPrice);
|
||
}
|
||
if (coupon.type == 3) {
|
||
return returnCouponZhekouDiscount(canDikouGoodsArr, coupon, user, goodsOrderPrice, selCoupon);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 折扣券抵扣金额
|
||
* @param canDikouGoodsArr 可抵扣商品列表
|
||
* @param coupon 优惠券
|
||
* @param user 用户信息
|
||
* @param goodsOrderPrice 商品订单金额
|
||
* @param selCoupon 已选择的优惠券列表
|
||
*
|
||
*/
|
||
export function returnCouponZhekouDiscount(
|
||
canDikouGoodsArr,
|
||
coupon,
|
||
user,
|
||
goodsOrderPrice,
|
||
selCoupon
|
||
) {
|
||
const {
|
||
discountRate,
|
||
maxDiscountAmount
|
||
} = coupon;
|
||
|
||
const goodsCouponDiscount = selCoupon
|
||
.filter((v) => v.type == 2)
|
||
.reduce((prve, cur) => {
|
||
return prve + cur.discount.discountPrice;
|
||
}, 0);
|
||
goodsOrderPrice -= goodsCouponDiscount;
|
||
// 使用bignumber处理高精度计算
|
||
// 1. 计算折扣率(百分比转小数):discountRate / 100
|
||
const discountRatio = new BigNumber(discountRate).dividedBy(100);
|
||
// 2. 计算优惠比例:1 - 折扣率(例如:8折的优惠比例是 1 - 0.8 = 0.2)
|
||
const discountAmountRatio = new BigNumber(1).minus(discountRatio);
|
||
// 3. 计算折扣金额:商品订单金额 × 优惠比例
|
||
let discountPrice = new BigNumber(goodsOrderPrice).times(discountAmountRatio).toNumber();
|
||
if (maxDiscountAmount != 0) {
|
||
discountPrice = discountPrice >= maxDiscountAmount ? maxDiscountAmount : discountPrice;
|
||
}
|
||
|
||
return {
|
||
discountPrice, // 折扣抵扣金额(即优惠的金额)
|
||
hasDiscountGoodsArr: [],
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 商品券抵扣金额
|
||
* @param canDikouGoodsArr 可抵扣商品列表
|
||
* @param coupon 优惠券
|
||
* @param user 用户信息
|
||
*/
|
||
export function returnCouponProductDiscount(canDikouGoodsArr, coupon, user) {
|
||
const {
|
||
useFoods,
|
||
discountNum,
|
||
useRule
|
||
} = coupon;
|
||
//抵扣商品数组
|
||
let discountGoodsArr = [];
|
||
//抵扣全部商品
|
||
if (useFoods.length === 0) {
|
||
if (useRule == "price_asc") {
|
||
discountGoodsArr = canDikouGoodsArr
|
||
.slice(canDikouGoodsArr.length - discountNum, canDikouGoodsArr.length)
|
||
.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(discountSelGoodsArr.length - discountNum, discountSelGoodsArr.length)
|
||
.reverse();
|
||
} else {
|
||
discountGoodsArr = discountSelGoodsArr.slice(0, discountNum);
|
||
}
|
||
}
|
||
const result = calcDiscountGoodsArrPrice(discountGoodsArr, discountNum, user);
|
||
return result;
|
||
}
|
||
|
||
// 返回买一送一券抵扣详情
|
||
/**
|
||
* @param canDikouGoodsArr 可抵扣商品列表
|
||
* @param coupon 优惠券
|
||
* @param user 用户信息
|
||
* @param shopInfo 店铺信息
|
||
*/
|
||
function returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user,shopInfo) {
|
||
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.slice(0, 1);
|
||
}
|
||
} 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.slice(0, 1);
|
||
}
|
||
}
|
||
const discountPrice = returnGoodsPrice(discountGoods, user,shopInfo);
|
||
const hasDiscountGoodsArr = [discountGoods];
|
||
return {
|
||
discountPrice,
|
||
hasDiscountGoodsArr
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 返回第二件半价券抵扣详情
|
||
* @param canDikouGoodsArr 可抵扣商品列表
|
||
* @param coupon 优惠券
|
||
* @param user 用户信息
|
||
* @param shopInfo 店铺信息
|
||
*/
|
||
function returnSecoendDiscount(canDikouGoodsArr, coupon, user,shopInfo) {
|
||
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.slice(0, 1);
|
||
}
|
||
} 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.slice(0, 1);
|
||
}
|
||
}
|
||
const discountPrice = returnGoodsPrice(discountGoods, user,shopInfo);
|
||
const hasDiscountGoodsArr = [discountGoods];
|
||
//返回半价价格
|
||
return {
|
||
discountPrice: new BigNumber(discountPrice).dividedBy(2).toNumber(),
|
||
hasDiscountGoodsArr,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 返回可以抵扣优惠券的商品列表,过滤掉赠品、临时商品,价格从高到低排序
|
||
* @param arr 商品列表
|
||
* @param user 用户信息
|
||
* @param shopInfo 店铺信息
|
||
*/
|
||
export function returnCanDikouGoods(arr, user, shopInfo) {
|
||
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, use, shopInfo) - returnGoodsPrice(a, user, shopInfo);
|
||
});
|
||
return result;
|
||
} |