核销代码

This commit is contained in:
2026-07-06 22:10:45 +08:00
parent 047cf879f8
commit 386ee9e754
6 changed files with 191 additions and 16 deletions
@@ -150,23 +150,38 @@ export class RedeemService {
throw new BadRequestException('核销码数据异常');
}
const allocSum = allocations.reduce((sum, item) => sum + item.amount, 0);
if (Math.abs(allocSum - cached.amount) > 0.001) {
const normalizedAllocations = allocations.map((item) => ({
couponId: String(item.couponId),
amount: Number(item.amount),
}));
const tokenAmount = Number(cached.amount);
if (!Number.isFinite(tokenAmount) || tokenAmount <= 0) {
throw new BadRequestException('核销码数据异常');
}
for (const alloc of allocations) {
const allocSum = normalizedAllocations.reduce((sum, item) => sum + item.amount, 0);
if (Math.abs(allocSum - tokenAmount) > 0.001) {
throw new BadRequestException('核销码数据异常');
}
for (const alloc of normalizedAllocations) {
let couponId: bigint;
try {
couponId = BigInt(alloc.couponId);
} catch {
throw new BadRequestException('核销码数据异常');
}
const coupon = await this.prisma.benefitCoupon.findUnique({
where: { id: BigInt(alloc.couponId) },
where: { id: couponId },
});
if (!coupon) throw new BadRequestException('券不存在');
const check = validateRedeemAmount(Number(coupon.balance), alloc.amount, Number(coupon.balance));
if (!check.ok) throw new BadRequestException(check.message);
}
const amount = Number(cached.amount);
const cityRule = await this.prisma.commonCityCommissionRule.findFirst({
where: { city: { stores: { some: { id: account.storeId } } } },
const amount = tokenAmount;
const cityRule = await this.prisma.commonCityCommissionRule.findUnique({
where: { cityId: account.store.cityId },
});
const settlementRate = cityRule ? Number(cityRule.storeSettlementRate) : 0.6;
const settleAmount = calcRedeemSettleAmount(amount, settlementRate);
@@ -174,29 +189,40 @@ export class RedeemService {
let record;
try {
record = await this.prisma.$transaction(async (tx) => {
await this.benefitService.deductCoupons(tx, allocations, 'STORE', account.storeId);
await this.benefitService.deductCoupons(tx, normalizedAllocations, 'STORE', account.storeId);
const redeemRecord = await tx.redeemRecord.create({
data: {
redeemNo: generateRedeemNo(),
userId: BigInt(cached.userId),
couponId: BigInt(allocations[0].couponId),
couponId: BigInt(normalizedAllocations[0].couponId),
storeId: account.storeId,
amount,
settleAmount,
},
});
await this.settlementService.createStorePayout(
redeemRecord.id,
account.storeId,
amount,
settleAmount,
settlementRate,
tx,
);
return redeemRecord;
});
} catch (e) {
if (e instanceof Error && e.message === 'BENEFIT_DEDUCT_CONFLICT') {
throw new BadRequestException('核销失败,请重试');
}
if (e instanceof Error && e.message === 'BENEFIT_ALLOC_INVALID') {
throw new BadRequestException('核销码数据异常');
}
throw e;
}
await this.settlementService.createStorePayout(record.id, account.storeId, amount, settleAmount, settlementRate);
await this.redis.del(`redeem:token:${body.token}`);
this.analyticsService.trackOneSafe(BigInt(cached.userId), 'SHOP_H5', {