/** * Application Use Case: ProcessWalletTransactionUseCase * * Processes a wallet transaction (deposit or withdrawal). */ import type { IWalletRepository, ITransactionRepository } from '../../domain/repositories/IWalletRepository'; import type { Wallet, Transaction, TransactionType, ReferenceType } from '../../domain/entities/Wallet'; import type { IProcessWalletTransactionPresenter, ProcessWalletTransactionResultDTO, ProcessWalletTransactionViewModel, } from '../presenters/IProcessWalletTransactionPresenter'; import type { UseCase } from '@core/shared/application/UseCase'; export interface ProcessWalletTransactionInput { leagueId: string; type: TransactionType; amount: number; description: string; referenceId?: string; referenceType?: ReferenceType; } export class ProcessWalletTransactionUseCase implements UseCase { constructor( private readonly walletRepository: IWalletRepository, private readonly transactionRepository: ITransactionRepository, ) {} async execute( input: ProcessWalletTransactionInput, presenter: IProcessWalletTransactionPresenter, ): Promise { presenter.reset(); const { leagueId, type, amount, description, referenceId, referenceType } = input; if (!leagueId || !type || amount === undefined || !description) { throw new Error('Missing required fields: leagueId, type, amount, description'); } if (type !== ('deposit' as TransactionType) && type !== ('withdrawal' as TransactionType)) { throw new Error('Type must be "deposit" or "withdrawal"'); } let wallet = await this.walletRepository.findByLeagueId(leagueId); if (!wallet) { const id = `wallet-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; const newWallet: Wallet = { id, leagueId, balance: 0, totalRevenue: 0, totalPlatformFees: 0, totalWithdrawn: 0, currency: 'USD', createdAt: new Date(), }; wallet = await this.walletRepository.create(newWallet); } if (type === ('withdrawal' as TransactionType)) { if (amount > wallet.balance) { throw new Error('Insufficient balance'); } } const transactionId = `txn-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; const transaction: Transaction = { id: transactionId, walletId: wallet.id, type, amount, description, referenceId, referenceType, createdAt: new Date(), }; const createdTransaction = await this.transactionRepository.create(transaction); if (type === ('deposit' as TransactionType)) { wallet.balance += amount; wallet.totalRevenue += amount; } else { wallet.balance -= amount; wallet.totalWithdrawn += amount; } const updatedWallet = await this.walletRepository.update(wallet); const dto: ProcessWalletTransactionResultDTO = { wallet: { id: updatedWallet.id, leagueId: updatedWallet.leagueId, balance: updatedWallet.balance, totalRevenue: updatedWallet.totalRevenue, totalPlatformFees: updatedWallet.totalPlatformFees, totalWithdrawn: updatedWallet.totalWithdrawn, currency: updatedWallet.currency, createdAt: updatedWallet.createdAt, }, transaction: { id: createdTransaction.id, walletId: createdTransaction.walletId, type: createdTransaction.type, amount: createdTransaction.amount, description: createdTransaction.description, referenceId: createdTransaction.referenceId, referenceType: createdTransaction.referenceType, createdAt: createdTransaction.createdAt, }, }; presenter.present(dto); } }