using CMSMicroservice.Application.Common.Exceptions; using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Domain.Entities; using CMSMicroservice.Domain.Enums; using CMSMicroservice.Domain.Common; using MediatR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using ValidationException = FluentValidation.ValidationException; namespace CMSMicroservice.Application.PackageCQ.Commands.InitiateBasePackagePayment; /// /// Handler برای ثبت اولیه تراکنش و سفارش پکیج پایه /// این Handler فقط Transaction و Order را با وضعیت Pending ایجاد می‌کند /// BFF سپس کاربر را به درگاه PYMS هدایت می‌کند /// public class InitiateBasePackagePaymentCommandHandler : IRequestHandler { private readonly IApplicationDbContext _context; private readonly ILogger _logger; /// /// شناسه پکیج پایه در دیتابیس /// private const long BasePackageId = 4; public InitiateBasePackagePaymentCommandHandler( IApplicationDbContext context, ILogger logger) { _context = context; _logger = logger; } public async Task Handle( InitiateBasePackagePaymentCommand request, CancellationToken cancellationToken) { try { _logger.LogInformation( "Initiating base package payment for UserId: {UserId}", request.UserId); // 1. پیدا کردن کاربر var user = await _context.Users .FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken); if (user == null) { _logger.LogWarning("User not found. UserId: {UserId}", request.UserId); throw new NotFoundException(nameof(User), request.UserId); } // 2. بررسی عدم خرید قبلی پکیج پایه if (user.PackagePurchaseMethod != PackagePurchaseMethod.None) { _logger.LogWarning( "User {UserId} has already purchased base package via {Method}", request.UserId, user.PackagePurchaseMethod); return new InitiateBasePackagePaymentResponseDto { Success = false, Message = "شما قبلاً پکیج پایه را خریداری کرده‌اید." }; } // 3. بررسی عدم وجود سفارش Pending var pendingOrder = await _context.UserOrders .FirstOrDefaultAsync(o => o.UserId == request.UserId && o.PaymentStatus == PaymentStatus.Pending && o.PackageId == BasePackageId, cancellationToken); if (pendingOrder != null) { _logger.LogWarning( "User {UserId} has pending order {OrderId}", request.UserId, pendingOrder.Id); // برگرداندن سفارش موجود برای ادامه پرداخت var existingTransaction = await _context.Transactions .FirstOrDefaultAsync(t => t.Id == pendingOrder.TransactionId, cancellationToken); return new InitiateBasePackagePaymentResponseDto { Success = true, Message = "سفارش قبلی در انتظار پرداخت یافت شد.", OrderId = pendingOrder.Id, TransactionId = existingTransaction?.Id ?? 0, Amount = SystemConstants.BasePackageAmount }; } // 4. پیدا کردن آدرس پیش‌فرض کاربر var defaultAddress = await _context.UserAddresses .Where(a => a.UserId == request.UserId) .OrderByDescending(a => a.Created) .FirstOrDefaultAsync(cancellationToken); if (defaultAddress == null) { _logger.LogWarning("No address found for user {UserId}", request.UserId); throw new ValidationException("لطفاً ابتدا یک آدرس برای خود ثبت کنید."); } // 5. ایجاد Transaction با وضعیت Pending var transaction = new Transaction { Amount = SystemConstants.BasePackageAmount, Description = $"خرید پکیج پایه ۵۶ میلیونی - کاربر #{user.Id}", PaymentStatus = PaymentStatus.Pending, Type = TransactionType.DepositIpg }; _context.Transactions.Add(transaction); await _context.SaveChangesAsync(cancellationToken); _logger.LogInformation( "Created Transaction {TransactionId} with Pending status for UserId {UserId}", transaction.Id, request.UserId); // 6. ایجاد UserOrder با وضعیت Pending var order = new UserOrder { UserId = user.Id, PackageId = BasePackageId, Amount = SystemConstants.BasePackageAmount, PaymentStatus = PaymentStatus.Pending, DeliveryStatus = DeliveryStatus.None, UserAddressId = defaultAddress.Id, PaymentMethod = PaymentMethod.IPG, TransactionId = transaction.Id }; _context.UserOrders.Add(order); await _context.SaveChangesAsync(cancellationToken); _logger.LogInformation( "Created UserOrder {OrderId} for UserId {UserId}, TransactionId: {TransactionId}", order.Id, request.UserId, transaction.Id); return new InitiateBasePackagePaymentResponseDto { Success = true, Message = "تراکنش و سفارش با موفقیت ثبت شد.", OrderId = order.Id, TransactionId = transaction.Id, Amount = SystemConstants.BasePackageAmount }; } catch (Exception ex) { _logger.LogError( ex, "Error in InitiateBasePackagePaymentCommand for UserId: {UserId}", request.UserId); throw; } } }