using CMSMicroservice.Application.ClubMembershipCQ.Commands.ActivateClubMembership; 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 ISender _sender; private readonly ILogger _logger; public CreateManualPaymentCommandHandler( IApplicationDbContext context, ICurrentUserService currentUser, ISender sender, ILogger logger) { _context = context; _currentUser = currentUser; _sender = sender; _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. بارگذاری پکیج انتخاب‌شده (یا پکیج پایه اگر PackageId=0) Domain.Entities.Package package; if (request.PackageId > 0) { package = await _context.Packages .FirstOrDefaultAsync(p => p.Id == request.PackageId && !p.IsDeleted, cancellationToken) ?? throw new NotFoundException($"پکیج با شناسه {request.PackageId} یافت نشد"); } else { package = await _context.Packages .FirstOrDefaultAsync(p => p.IsBasePackage && !p.IsDeleted, cancellationToken) ?? throw new NotFoundException("پکیج پایه یافت نشد"); } var balanceAmount = package.Price; var discountBalanceAmount = (long)(package.Price * package.DiscountMultiplier); // 5. ثبت تراکنش var transaction = new Transaction { Amount = balanceAmount, 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 = balanceAmount, 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; wallet.DiscountBalance += discountBalanceAmount; // 8. ثبت لاگ کیف پول var walletLog = new UserWalletHistory { WalletId = wallet.Id, CurrentBalance = 0, ChangeValue = balanceAmount, CurrentNetworkBalance = wallet.NetworkBalance, ChangeNerworkValue = 0, CurrentDiscountBalance =0, ChangeDiscountValue = discountBalanceAmount, IsIncrease = true, RefrenceId = transaction.Id, PackageId = package.Id }; await _context.UserWalletHistories.AddAsync(walletLog, cancellationToken); // 9. تنظیم روش خرید پکیج user.PackagePurchaseMethod = PackagePurchaseMethod.DirectPurchase; // 10. ذخیره همه تغییرات await _context.SaveChangesAsync(cancellationToken); // 11. فعال‌سازی باشگاه مشتریان — ساخت Cycle و آماده‌سازی برای AcceptContract // این مرحله تضمین می‌کند که: // الف) ClubMembershipCycle ساخته شود تا والدین امتیاز «عضو جدید» بگیرند // ب) Pool توسط AcceptContract (که کاربر در FO امضا می‌کند) شارژ شود try { await _sender.Send(new ActivateClubMembershipCommand { UserId = request.UserId, ForceActivation = true, PackageId = package.Id }, cancellationToken); } catch (Exception activateEx) { // عضویت باشگاه اختیاری است — خطا نباید پرداخت دستی را برگرداند _logger.LogWarning( activateEx, "Club membership activation failed after manual payment for UserId {UserId} — payment recorded successfully", request.UserId ); } _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; } } }