/** * 转让钱包内部 API(纯新增) * 供 transfer-service Saga 编排器通过 HTTP 调用 * * 路由前缀:/api/v1/internal/wallet/* * 与 InternalWalletController(/api/v1/wallets/*) 分开,避免路由冲突 * * 回滚方式:删除此文件并从 api.module.ts 中移除引用 */ import { Controller, Post, Get, Body, Param, Logger } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { WalletApplicationService } from '@/application/services'; import { FreezeForTransferCommand, UnfreezeForTransferCommand, SettleTransferPaymentCommand, } from '@/application/commands'; import { Public } from '@/shared/decorators'; import { FreezeForTransferDto, UnfreezeForTransferDto, SettleTransferDto, } from '../dto/request/transfer-wallet.dto'; @ApiTags('Internal Transfer Wallet API') @Controller('internal/wallet') export class InternalTransferWalletController { private readonly logger = new Logger(InternalTransferWalletController.name); constructor( private readonly walletService: WalletApplicationService, ) {} /** * 冻结买方资金 * POST /api/v1/internal/wallet/freeze */ @Post('freeze') @Public() async freezeForTransfer(@Body() dto: FreezeForTransferDto): Promise<{ freezeId: string }> { this.logger.log(`[freeze] Request: accountSequence=${dto.accountSequence}, amount=${dto.amount}, transferOrderNo=${dto.transferOrderNo}`); const command = new FreezeForTransferCommand( dto.accountSequence, dto.amount, dto.transferOrderNo, dto.reason, ); const result = await this.walletService.freezeForTransfer(command); this.logger.log(`[freeze] Success: freezeId=${result.freezeId}`); return result; } /** * 解冻买方资金(补偿/回滚) * POST /api/v1/internal/wallet/unfreeze */ @Post('unfreeze') @Public() async unfreezeForTransfer(@Body() dto: UnfreezeForTransferDto): Promise<{ success: boolean }> { this.logger.log(`[unfreeze] Request: accountSequence=${dto.accountSequence}, freezeId=${dto.freezeId}, transferOrderNo=${dto.transferOrderNo}`); const command = new UnfreezeForTransferCommand( dto.accountSequence, dto.freezeId, dto.transferOrderNo, dto.reason, ); await this.walletService.unfreezeForTransfer(command); this.logger.log(`[unfreeze] Success: transferOrderNo=${dto.transferOrderNo}`); return { success: true }; } /** * 结算转让资金:买方冻结扣减 → 卖方入账 → 手续费归集 * POST /api/v1/internal/wallet/settle-transfer */ @Post('settle-transfer') @Public() async settleTransfer(@Body() dto: SettleTransferDto): Promise<{ success: boolean }> { this.logger.log(`[settle-transfer] Request: buyer=${dto.buyerAccountSequence}, seller=${dto.sellerAccountSequence}, transferOrderNo=${dto.transferOrderNo}`); const command = new SettleTransferPaymentCommand( dto.buyerAccountSequence, dto.sellerAccountSequence, dto.freezeId, dto.sellerReceiveAmount, dto.platformFeeAmount, dto.transferOrderNo, ); await this.walletService.settleTransferPayment(command); this.logger.log(`[settle-transfer] Success: transferOrderNo=${dto.transferOrderNo}`); return { success: true }; } /** * 查询钱包余额 * GET /api/v1/internal/wallet/balance/:accountSequence */ @Get('balance/:accountSequence') @Public() async getBalance(@Param('accountSequence') accountSequence: string): Promise<{ available: string; frozen: string; }> { const query = { userId: accountSequence } as any; const wallet = await this.walletService.getMyWallet(query); return { available: wallet.balances.usdt.available.toString(), frozen: wallet.balances.usdt.frozen.toString(), }; } }