发布商品,商品图片使用oss服务器地址
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import type { Prisma } from '@prisma/client';
|
||||
import { calcBenefitAmount, calcBenefitSummary, generateCouponNo } from '@dukang/domain';
|
||||
import { PrismaService } from '../../common/prisma/prisma.module';
|
||||
import { serializeBigInt } from '../../common/decorators/current-user.decorator';
|
||||
import { buildBenefitLedgerEvent, benefitLedgerWhere } from '../../common/event/event.helpers';
|
||||
|
||||
export type CouponAllocation = { couponId: string; amount: number };
|
||||
|
||||
@Injectable()
|
||||
export class BenefitService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
@@ -85,4 +88,73 @@ export class BenefitService {
|
||||
});
|
||||
return serializeBigInt({ coupon, ledgers });
|
||||
}
|
||||
|
||||
/** 核销扣减券余额(乐观锁),由 redeem 模块调用 */
|
||||
async deductCoupons(
|
||||
tx: Prisma.TransactionClient,
|
||||
allocations: CouponAllocation[],
|
||||
refType: 'STORE',
|
||||
refId: bigint,
|
||||
) {
|
||||
for (const alloc of allocations) {
|
||||
const coupon = await tx.benefitCoupon.findUniqueOrThrow({
|
||||
where: { id: BigInt(alloc.couponId) },
|
||||
});
|
||||
const allocAmount = alloc.amount;
|
||||
const updated = await tx.benefitCoupon.updateMany({
|
||||
where: { id: coupon.id, version: coupon.version, balance: { gte: allocAmount } },
|
||||
data: {
|
||||
usedAmount: { increment: allocAmount },
|
||||
balance: { decrement: allocAmount },
|
||||
version: { increment: 1 },
|
||||
status: Number(coupon.balance) - allocAmount <= 0 ? 'USED_UP' : 'ACTIVE',
|
||||
},
|
||||
});
|
||||
if (updated.count === 0) throw new Error('BENEFIT_DEDUCT_CONFLICT');
|
||||
|
||||
const newBalance = Number(coupon.balance) - allocAmount;
|
||||
await tx.commonEvent.create({
|
||||
data: buildBenefitLedgerEvent({
|
||||
userId: coupon.userId,
|
||||
couponId: coupon.id,
|
||||
type: 'REDEEM',
|
||||
amount: -allocAmount,
|
||||
balanceAfter: newBalance,
|
||||
refType,
|
||||
refId,
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** 退款作废权益 */
|
||||
async voidCouponsOnRefund(orderId: bigint) {
|
||||
const coupons = await this.prisma.benefitCoupon.findMany({
|
||||
where: { orderId, status: { in: ['ACTIVE', 'USED_UP'] } },
|
||||
});
|
||||
for (const coupon of coupons) {
|
||||
const balance = Number(coupon.balance);
|
||||
if (balance <= 0 && coupon.status === 'USED_UP') continue;
|
||||
await this.prisma.$transaction(async (tx) => {
|
||||
await tx.benefitCoupon.update({
|
||||
where: { id: coupon.id },
|
||||
data: { status: 'VOID', balance: 0 },
|
||||
});
|
||||
if (balance > 0) {
|
||||
await tx.commonEvent.create({
|
||||
data: buildBenefitLedgerEvent({
|
||||
userId: coupon.userId,
|
||||
couponId: coupon.id,
|
||||
type: 'REFUND_VOID',
|
||||
amount: -balance,
|
||||
balanceAfter: 0,
|
||||
refType: 'ORDER',
|
||||
refId: orderId,
|
||||
remark: '退款作废权益',
|
||||
}),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user