发布商品,商品图片使用oss服务器地址

This commit is contained in:
2026-07-06 08:53:03 +08:00
parent a0466f023e
commit 5ba69eb935
60 changed files with 2776 additions and 157 deletions
@@ -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: '退款作废权益',
}),
});
}
});
}
}
}