using CMSMicroservice.Application.Common.Exceptions; using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Domain.Entities; using CMSMicroservice.Domain.Entities.Payment; using CMSMicroservice.Domain.Enums; using MediatR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; namespace CMSMicroservice.Application.ManualPaymentCQ.Commands.ApproveManualPayment; public class ApproveManualPaymentCommandHandler : IRequestHandler { private readonly IApplicationDbContext _context; private readonly ICurrentUserService _currentUser; private readonly ILogger _logger; public ApproveManualPaymentCommandHandler( IApplicationDbContext context, ICurrentUserService currentUser, ILogger logger) { _context = context; _currentUser = currentUser; _logger = logger; } public async Task Handle( ApproveManualPaymentCommand request, CancellationToken cancellationToken) { try { _logger.LogInformation( "Approving manual payment: {ManualPaymentId}", request.ManualPaymentId ); // 1. پیدا کردن ManualPayment var manualPayment = await _context.ManualPayments .Include(m => m.User) .FirstOrDefaultAsync(m => m.Id == request.ManualPaymentId, cancellationToken); if (manualPayment == null) { _logger.LogWarning("ManualPayment not found: {Id}", request.ManualPaymentId); throw new NotFoundException(nameof(ManualPayment), request.ManualPaymentId); } // 2. بررسی وضعیت if (manualPayment.Status != ManualPaymentStatus.Pending) { _logger.LogWarning( "ManualPayment {Id} is not in Pending status: {Status}", request.ManualPaymentId, manualPayment.Status ); throw new BadRequestException($"فقط درخواست‌های در وضعیت Pending قابل تایید هستند. وضعیت فعلی: {manualPayment.Status}"); } // 3. بررسی SuperAdmin var currentUserId = _currentUser.UserId; if (string.IsNullOrEmpty(currentUserId)) { throw new UnauthorizedAccessException("کاربر احراز هویت نشده است"); } if (!long.TryParse(currentUserId, out var approvedById)) { throw new UnauthorizedAccessException("شناسه کاربر نامعتبر است"); } // 4. پیدا کردن Wallet کاربر var wallet = await _context.UserWallets .FirstOrDefaultAsync(w => w.UserId == manualPayment.UserId, cancellationToken); if (wallet == null) { _logger.LogError("Wallet not found for UserId: {UserId}", manualPayment.UserId); throw new NotFoundException($"کیف پول کاربر {manualPayment.UserId} یافت نشد"); } // 5. ایجاد Transaction var transaction = new Transaction { Amount = manualPayment.Amount, Description = $"پرداخت دستی - {manualPayment.Type} - {manualPayment.Description}", PaymentStatus = PaymentStatus.Success, PaymentDate = DateTime.Now, RefId = manualPayment.ReferenceNumber, Type = MapToTransactionType(manualPayment.Type) }; _context.Transactions.Add(transaction); await _context.SaveChangesAsync(cancellationToken); // 6. اعمال تغییرات بر کیف پول var oldBalance = wallet.Balance; var oldDiscountBalance = wallet.DiscountBalance; var oldNetworkBalance = wallet.NetworkBalance; switch (manualPayment.Type) { case ManualPaymentType.CashDeposit: case ManualPaymentType.Settlement: case ManualPaymentType.ErrorCorrection: wallet.Balance += manualPayment.Amount; wallet.DiscountBalance += manualPayment.Amount; // لاگ Balance await _context.UserWalletHistories.AddAsync(new UserWalletHistory { WalletId = wallet.Id, CurrentBalance = wallet.Balance, ChangeValue = manualPayment.Amount, CurrentNetworkBalance = wallet.NetworkBalance, ChangeNerworkValue = 0, CurrentDiscountBalance = oldDiscountBalance, ChangeDiscountValue = 0, IsIncrease = true, RefrenceId = transaction.Id }, cancellationToken); // لاگ DiscountBalance await _context.UserWalletHistories.AddAsync(new UserWalletHistory { WalletId = wallet.Id, CurrentBalance = wallet.Balance, ChangeValue = 0, CurrentNetworkBalance = wallet.NetworkBalance, ChangeNerworkValue = 0, CurrentDiscountBalance = wallet.DiscountBalance, ChangeDiscountValue = manualPayment.Amount, IsIncrease = true, RefrenceId = transaction.Id }, cancellationToken); break; case ManualPaymentType.DiscountWalletCharge: wallet.DiscountBalance += manualPayment.Amount; await _context.UserWalletHistories.AddAsync(new UserWalletHistory { WalletId = wallet.Id, CurrentBalance = wallet.Balance, ChangeValue = 0, CurrentNetworkBalance = wallet.NetworkBalance, ChangeNerworkValue = 0, CurrentDiscountBalance = wallet.DiscountBalance, ChangeDiscountValue = manualPayment.Amount, IsIncrease = true, RefrenceId = transaction.Id }, cancellationToken); break; case ManualPaymentType.NetworkWalletCharge: wallet.NetworkBalance += manualPayment.Amount; await _context.UserWalletHistories.AddAsync(new UserWalletHistory { WalletId = wallet.Id, CurrentBalance = wallet.Balance, ChangeValue = 0, CurrentNetworkBalance = wallet.NetworkBalance, ChangeNerworkValue = manualPayment.Amount, CurrentDiscountBalance = wallet.DiscountBalance, ChangeDiscountValue = 0, IsIncrease = true, RefrenceId = transaction.Id }, cancellationToken); break; case ManualPaymentType.Refund: // بازگشت وجه - کم کردن از Balance و DiscountBalance if (wallet.Balance < manualPayment.Amount) { throw new BadRequestException("موجودی کیف پول برای بازگشت وجه کافی نیست"); } wallet.Balance -= manualPayment.Amount; if (wallet.DiscountBalance >= manualPayment.Amount) { wallet.DiscountBalance -= manualPayment.Amount; } await _context.UserWalletHistories.AddAsync(new UserWalletHistory { WalletId = wallet.Id, CurrentBalance = wallet.Balance, ChangeValue = manualPayment.Amount, CurrentNetworkBalance = wallet.NetworkBalance, ChangeNerworkValue = 0, CurrentDiscountBalance = wallet.DiscountBalance, ChangeDiscountValue = wallet.DiscountBalance < oldDiscountBalance ? manualPayment.Amount : 0, IsIncrease = false, RefrenceId = transaction.Id }, cancellationToken); break; default: // Other یا سایر موارد - فقط Balance wallet.Balance += manualPayment.Amount; await _context.UserWalletHistories.AddAsync(new UserWalletHistory { WalletId = wallet.Id, CurrentBalance = wallet.Balance, ChangeValue = manualPayment.Amount, CurrentNetworkBalance = wallet.NetworkBalance, ChangeNerworkValue = 0, CurrentDiscountBalance = wallet.DiscountBalance, ChangeDiscountValue = 0, IsIncrease = true, RefrenceId = transaction.Id }, cancellationToken); break; } // 7. به‌روزرسانی ManualPayment manualPayment.Status = ManualPaymentStatus.Approved; manualPayment.ApprovedBy = approvedById; manualPayment.ApprovedAt = DateTime.Now; manualPayment.TransactionId = transaction.Id; await _context.SaveChangesAsync(cancellationToken); _logger.LogInformation( "Manual payment approved successfully. Id: {Id}, UserId: {UserId}, Amount: {Amount}, ApprovedBy: {ApprovedBy}", manualPayment.Id, manualPayment.UserId, manualPayment.Amount, approvedById ); return true; } catch (Exception ex) { _logger.LogError( ex, "Error approving manual payment: {ManualPaymentId}", request.ManualPaymentId ); throw; } } private TransactionType MapToTransactionType(ManualPaymentType type) { return type switch { ManualPaymentType.CashDeposit => TransactionType.DepositExternal1, ManualPaymentType.DiscountWalletCharge => TransactionType.DiscountWalletCharge, ManualPaymentType.NetworkWalletCharge => TransactionType.NetworkCommission, ManualPaymentType.Settlement => TransactionType.DepositExternal1, ManualPaymentType.ErrorCorrection => TransactionType.DepositExternal1, ManualPaymentType.Refund => TransactionType.Withdraw, _ => TransactionType.DepositExternal1 }; } }