feat(ops): show redeem records on benefit coupon detail
CI / verify (pull_request) Has been cancelled

Reuse the same coupon redeem trace as order detail (primary/secondary, allocations).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-22 23:52:48 +08:00
parent aeb72154a7
commit cd206d6baa
4 changed files with 482 additions and 220 deletions
@@ -5,6 +5,7 @@ import { serializeBigInt } from '../../common/decorators/current-user.decorator'
import { buildBenefitLedgerEvent, benefitLedgerWhere } from '../../common/event/event.helpers';
import { mapBenefitLedgerCompat } from '../../common/compat/v31-compat';
import { BenefitService } from '../benefit/benefit.service';
import { AdminRedeemService } from './admin-redeem.service';
import type { AdminBenefitCouponsQueryDto, AdminBenefitLedgersQueryDto } from './dto/admin-query.dto';
import type { AdminBenefitGrantDto } from './dto/admin-mutate.dto';
@@ -13,6 +14,7 @@ export class AdminBenefitService {
constructor(
private readonly prisma: PrismaService,
private readonly benefitService: BenefitService,
private readonly adminRedeemService: AdminRedeemService,
) {}
async listCoupons(query: AdminBenefitCouponsQueryDto) {
@@ -45,16 +47,23 @@ export class AdminBenefitService {
include: {
user: { select: { id: true, userNo: true, phone: true, nickname: true } },
order: { select: { id: true, orderNo: true, status: true, payAmount: true } },
redeemRecords: { orderBy: { createdAt: 'desc' }, take: 10, include: { store: { select: { id: true, name: true } } } },
},
});
if (!coupon) throw new NotFoundException('权益券不存在');
const ledgers = await this.prisma.commonEvent.findMany({
where: benefitLedgerWhere(undefined, id),
orderBy: { createdAt: 'desc' },
take: 20,
const [ledgers, redeemTrace] = await Promise.all([
this.prisma.commonEvent.findMany({
where: benefitLedgerWhere(undefined, id),
orderBy: { createdAt: 'desc' },
take: 20,
}),
this.adminRedeemService.buildCouponRedeemTrace(coupon),
]);
return serializeBigInt({
...coupon,
ledgers,
redeemSummary: redeemTrace.redeemSummary,
redeemRecords: redeemTrace.redeemRecords,
});
return serializeBigInt({ ...coupon, ledgers });
}
async voidCoupon(id: bigint) {