import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common'; import { PrismaService } from '../../common/prisma/prisma.module'; import { RedeemService } from '../redeem/redeem.service'; import type { AdminRedeemDebugCreateTokenDto, AdminRedeemDebugPhoneBalanceDto, AdminRedeemDebugPhoneConfirmDto, AdminRedeemDebugPhonePrepareDto, AdminRedeemDebugPhoneStoreDto, AdminRedeemDebugStoreTokenDto, } from './dto/admin-mutate.dto'; @Injectable() export class AdminRedeemDebugService { constructor( private readonly prisma: PrismaService, private readonly redeemService: RedeemService, ) {} private parseStoreId(value: string): bigint { const normalized = String(value ?? '').trim(); if (!normalized || !/^\d+$/.test(normalized)) { throw new BadRequestException('门店 ID 格式无效'); } return BigInt(normalized); } private async resolveUserId(identifier: string): Promise { const normalized = String(identifier ?? '').trim(); if (!normalized) { throw new BadRequestException('请填写用户 ID、用户编号或手机号'); } if (/^\d+$/.test(normalized)) { const byId = await this.prisma.user.findUnique({ where: { id: BigInt(normalized) }, select: { id: true }, }); if (byId) return byId.id; const byPhone = await this.prisma.user.findFirst({ where: { phone: normalized }, select: { id: true }, }); if (byPhone) return byPhone.id; } else { const byNo = await this.prisma.user.findFirst({ where: { userNo: normalized }, select: { id: true }, }); if (byNo) return byNo.id; } throw new NotFoundException('用户不存在,请检查 ID、用户编号或手机号'); } private async resolveStoreAccountId(storeId: string): Promise { const account = await this.prisma.storeAccount.findFirst({ where: { storeId: this.parseStoreId(storeId), status: 'ACTIVE' }, orderBy: { id: 'asc' }, select: { id: true, store: { select: { name: true } } }, }); if (!account) { throw new NotFoundException('该门店无可用账户,请先创建门店账户'); } return account.id; } async createToken(dto: AdminRedeemDebugCreateTokenDto) { const userId = await this.resolveUserId(dto.userId); return this.redeemService.createToken(userId, { amount: dto.amount, couponId: dto.couponId?.trim() || undefined, storeId: dto.storeId?.trim() || undefined, }); } async preview(dto: AdminRedeemDebugStoreTokenDto) { const storeAccountId = await this.resolveStoreAccountId(dto.storeId); return this.redeemService.previewRedeem(storeAccountId, dto.token); } async confirm(dto: AdminRedeemDebugStoreTokenDto) { const storeAccountId = await this.resolveStoreAccountId(dto.storeId); return this.redeemService.confirmRedeem(storeAccountId, { token: dto.token }); } async sendPhoneLookupSms(dto: AdminRedeemDebugPhoneStoreDto) { const storeAccountId = await this.resolveStoreAccountId(dto.storeId); return this.redeemService.sendPhoneLookupSms(storeAccountId, dto.phone); } async phoneBalance(dto: AdminRedeemDebugPhoneBalanceDto) { const storeAccountId = await this.resolveStoreAccountId(dto.storeId); return this.redeemService.verifyPhoneAndGetBalance(storeAccountId, dto.phone, dto.code); } async phonePrepare(dto: AdminRedeemDebugPhonePrepareDto) { const storeAccountId = await this.resolveStoreAccountId(dto.storeId); return this.redeemService.preparePhoneRedeem(storeAccountId, dto.sessionId, dto.amount); } async phoneConfirm(dto: AdminRedeemDebugPhoneConfirmDto) { const storeAccountId = await this.resolveStoreAccountId(dto.storeId); return this.redeemService.confirmPhoneRedeem(storeAccountId, dto.sessionId, dto.code); } }