using CMSMicroservice.Application.Common.Exceptions; using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Domain.Common; 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.CreateManualPayment; public class CreateManualPaymentCommandHandler : IRequestHandler { private readonly IApplicationDbContext _context; private readonly ICurrentUserService _currentUser; private readonly ILogger _logger; public CreateManualPaymentCommandHandler( IApplicationDbContext context, ICurrentUserService currentUser, ILogger logger) { _context = context; _currentUser = currentUser; _logger = logger; } public async Task Handle( CreateManualPaymentCommand request, CancellationToken cancellationToken) { try { _logger.LogInformation( "Creating manual membership payment for UserId: {UserId}, Type: {Type}", request.UserId, request.Type ); // 1. بررسی Admin فعلی var currentUserId = _currentUser.UserId; if (string.IsNullOrEmpty(currentUserId)) { throw new UnauthorizedAccessException("کاربر احراز هویت نشده است"); } if (!long.TryParse(currentUserId, out var adminUserId)) { throw new UnauthorizedAccessException("شناسه کاربر نامعتبر است"); } // 2. بررسی وجود کاربر var user = await _context.Users .FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken); if (user == null) { _logger.LogWarning("User not found: {UserId}", request.UserId); throw new NotFoundException(nameof(User), request.UserId); } // 3. پیدا کردن کیف پول var wallet = await _context.UserWallets .FirstOrDefaultAsync(w => w.UserId == request.UserId, cancellationToken); if (wallet == null) { _logger.LogError("Wallet not found for UserId: {UserId}", request.UserId); throw new NotFoundException($"کیف پول کاربر {request.UserId} یافت نشد"); } // 4. محاسبه مبالغ var balanceAmount = SystemConstants.BasePackageAmount; // 56M var discountBalanceAmount = SystemConstants.BasePackageAmount * 2; // 112M var totalAmount = balanceAmount + discountBalanceAmount; // 168M // 5. ثبت تراکنش var transaction = new Transaction { Amount = totalAmount, Description = $"عضویت دستی باشگاه مشتریان - {request.Description} - مرجع: {request.ReferenceNumber}", PaymentStatus = PaymentStatus.Success, PaymentDate = DateTime.Now, RefId = request.ReferenceNumber, Type = TransactionType.DepositExternal1 }; _context.Transactions.Add(transaction); await _context.SaveChangesAsync(cancellationToken); // 6. ایجاد ManualPayment با وضعیت Approved (بدون نیاز به تایید دو مرحله‌ای) var manualPayment = new ManualPayment { UserId = request.UserId, Amount = totalAmount, Type = request.Type, Description = request.Description, ReferenceNumber = request.ReferenceNumber, ImagePath = request.ImagePath, ImageDocumentId = request.ImageDocumentId, Status = ManualPaymentStatus.Approved, RequestedBy = adminUserId, ApprovedBy = adminUserId, ApprovedAt = DateTime.Now, TransactionId = transaction.Id }; _context.ManualPayments.Add(manualPayment); // 7. اعمال تغییرات بر کیف پول var oldBalance = wallet.Balance; var oldDiscountBalance = wallet.DiscountBalance; wallet.Balance += balanceAmount; // +56M wallet.DiscountBalance += discountBalanceAmount; // +112M // 8. ثبت لاگ کیف پول var walletLog = new UserWalletChangeLog { WalletId = wallet.Id, CurrentBalance = wallet.Balance, ChangeValue = balanceAmount, CurrentNetworkBalance = wallet.NetworkBalance, ChangeNerworkValue = 0, CurrentDiscountBalance = wallet.DiscountBalance, ChangeDiscountValue = discountBalanceAmount, IsIncrease = true, RefrenceId = transaction.Id }; await _context.UserWalletChangeLogs.AddAsync(walletLog, cancellationToken); // 9. تنظیم روش خرید پکیج user.PackagePurchaseMethod = PackagePurchaseMethod.DirectPurchase; // 10. ذخیره همه تغییرات await _context.SaveChangesAsync(cancellationToken); _logger.LogInformation( "Manual membership payment created successfully. " + "ManualPaymentId: {Id}, UserId: {UserId}, TransactionId: {TransactionId}, " + "Balance: {OldBalance} -> {NewBalance}, DiscountBalance: {OldDiscount} -> {NewDiscount}", manualPayment.Id, request.UserId, transaction.Id, oldBalance, wallet.Balance, oldDiscountBalance, wallet.DiscountBalance ); return manualPayment.Id; } catch (Exception ex) when (ex is not NotFoundException && ex is not UnauthorizedAccessException) { _logger.LogError( ex, "Error creating manual membership payment for UserId: {UserId}", request.UserId ); throw; } } }