using CMSMicroservice.Application.Common.Exceptions; using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Application.Common.Models; using CMSMicroservice.Domain.Entities; using CMSMicroservice.Domain.Enums; using MediatR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using ValidationException = FluentValidation.ValidationException; namespace CMSMicroservice.Application.PackageCQ.Commands.VerifyPackagePurchase; public class VerifyPackagePurchaseCommandHandler : IRequestHandler { private readonly IApplicationDbContext _context; private readonly IPaymentGatewayService _paymentGateway; private readonly ILogger _logger; public VerifyPackagePurchaseCommandHandler( IApplicationDbContext context, IPaymentGatewayService paymentGateway, ILogger logger) { _context = context; _paymentGateway = paymentGateway; _logger = logger; } public async Task Handle( VerifyPackagePurchaseCommand request, CancellationToken cancellationToken) { try { _logger.LogInformation( "Verifying package purchase. OrderId: {OrderId}, Authority: {Authority}", request.OrderId, request.Authority ); // 1. پیدا کردن سفارش var order = await _context.UserOrders .Include(o => o.Package) .Include(o => o.User) .FirstOrDefaultAsync(o => o.Id == request.OrderId, cancellationToken); if (order == null) { _logger.LogWarning("Order not found: {OrderId}", request.OrderId); throw new NotFoundException(nameof(UserOrder), request.OrderId); } // 2. بررسی اینکه سفارش قبلاً پرداخت نشده باشد if (order.PaymentStatus == PaymentStatus.Success) { _logger.LogWarning("Order {OrderId} is already paid", request.OrderId); return true; } // 3. Verify با درگاه بانکی var verifyResult = await _paymentGateway.VerifyPaymentAsync( request.Authority, request.Authority // verificationToken - در بعضی درگاه‌ها همان Authority است ); if (!verifyResult.IsSuccess) { _logger.LogWarning( "Payment verification failed for OrderId {OrderId}: {Message}", request.OrderId, verifyResult.Message ); order.PaymentStatus = PaymentStatus.Reject; await _context.SaveChangesAsync(cancellationToken); throw new ValidationException($"تراکنش ناموفق: {verifyResult.Message}"); } // 4. شارژ کیف پول کاربر var wallet = await _context.UserWallets .FirstOrDefaultAsync(w => w.UserId == order.UserId, cancellationToken); if (wallet == null) { _logger.LogError("Wallet not found for UserId: {UserId}", order.UserId); throw new NotFoundException($"کیف پول کاربر با شناسه {order.UserId} یافت نشد"); } // شارژ Balance (موجودی عادی) var oldBalance = wallet.Balance; wallet.Balance += order.Amount; _logger.LogInformation( "Charging Balance for UserId {UserId}: {OldBalance} -> {NewBalance}", order.UserId, oldBalance, wallet.Balance ); // شارژ DiscountBalance (موجودی تخفیف) var oldDiscountBalance = wallet.DiscountBalance; wallet.DiscountBalance += order.Amount; _logger.LogInformation( "Charging DiscountBalance for UserId {UserId}: {OldBalance} -> {NewBalance}", order.UserId, oldDiscountBalance, wallet.DiscountBalance ); // 5. ثبت Transaction var transaction = new Transaction { Amount = order.Amount, Description = $"خرید پکیج از درگاه - سفارش #{order.Id}", PaymentStatus = PaymentStatus.Success, PaymentDate = DateTime.Now, RefId = verifyResult.RefId, Type = TransactionType.DepositIpg }; _context.Transactions.Add(transaction); await _context.SaveChangesAsync(cancellationToken); // 6. ثبت لاگ تغییر Balance var balanceLog = new UserWalletChangeLog { WalletId = wallet.Id, CurrentBalance = wallet.Balance, ChangeValue = order.Amount, CurrentNetworkBalance = wallet.NetworkBalance, ChangeNerworkValue = 0, CurrentDiscountBalance = wallet.DiscountBalance - order.Amount, // قبل از شارژ DiscountBalance ChangeDiscountValue = 0, IsIncrease = true, RefrenceId = transaction.Id }; await _context.UserWalletChangeLogs.AddAsync(balanceLog, cancellationToken); // 7. ثبت لاگ تغییر DiscountBalance var discountLog = new UserWalletChangeLog { WalletId = wallet.Id, CurrentBalance = wallet.Balance, ChangeValue = 0, CurrentNetworkBalance = wallet.NetworkBalance, ChangeNerworkValue = 0, CurrentDiscountBalance = wallet.DiscountBalance, ChangeDiscountValue = order.Amount, IsIncrease = true, RefrenceId = transaction.Id }; await _context.UserWalletChangeLogs.AddAsync(discountLog, cancellationToken); // 8. به‌روزرسانی Order order.TransactionId = transaction.Id; order.PaymentStatus = PaymentStatus.Success; order.PaymentDate = DateTime.Now; order.PaymentMethod = PaymentMethod.IPG; // 9. تغییر User.PackagePurchaseMethod order.User.PackagePurchaseMethod = PackagePurchaseMethod.DirectPurchase; await _context.SaveChangesAsync(cancellationToken); _logger.LogInformation( "Package purchase verified successfully. " + "OrderId: {OrderId}, UserId: {UserId}, TransactionId: {TransactionId}, RefId: {RefId}", order.Id, order.UserId, transaction.Id, verifyResult.RefId ); return true; } catch (Exception ex) { _logger.LogError( ex, "Error in VerifyPackagePurchaseCommand. OrderId: {OrderId}", request.OrderId ); throw; } } }