using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Domain.Enums; using MediatR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; namespace CMSMicroservice.Application.OrderManagementCQ.Commands.CancelOrderByAdmin; public class CancelOrderByAdminCommandHandler : IRequestHandler { private readonly IApplicationDbContext _context; private readonly ICurrentUserService _currentUser; private readonly IInventoryService _inventoryService; private readonly ILogger _logger; public CancelOrderByAdminCommandHandler( IApplicationDbContext context, ICurrentUserService currentUser, IInventoryService inventoryService, ILogger logger) { _context = context; _currentUser = currentUser; _inventoryService = inventoryService; _logger = logger; } public async Task Handle(CancelOrderByAdminCommand request, CancellationToken cancellationToken) { // بررسی Admin if (string.IsNullOrEmpty(_currentUser.UserId)) { throw new UnauthorizedAccessException("کاربر احراز هویت نشده است"); } var order = await _context.UserOrders .Include(x => x.User) .ThenInclude(x => x.UserWallets) .Include(x => x.FactorDetails) .FirstOrDefaultAsync(x => x.Id == request.OrderId && !x.IsDeleted, cancellationToken); if (order == null) { throw new KeyNotFoundException($"سفارش با شناسه {request.OrderId} یافت نشد"); } if (order.DeliveryStatus == DeliveryStatus.Cancelled) { throw new InvalidOperationException("این سفارش قبلاً لغو شده است"); } if (order.DeliveryStatus == DeliveryStatus.Delivered) { throw new InvalidOperationException("سفارش تحویل داده شده را نمی‌توان لغو کرد"); } // تغییر وضعیت به لغو شده order.DeliveryStatus = DeliveryStatus.Cancelled; order.DeliveryDescription = $"لغو توسط Admin: {request.CancelReason}"; // بازگشت وجه به کیف پول if (request.RefundToWallet && order.PaymentMethod == PaymentMethod.Wallet) { var wallet = order.User.UserWallets.FirstOrDefault(); if (wallet != null) { var walletLog = new UserWalletHistory { WalletId = wallet.Id, CurrentBalance = wallet.Balance, CurrentNetworkBalance = wallet.NetworkBalance, CurrentDiscountBalance = wallet.DiscountBalance, ChangeValue = order.Amount, ChangeDiscountValue = 0, IsIncrease = true, RefrenceId = order.Id }; wallet.Balance += order.Amount; await _context.UserWalletHistories.AddAsync(walletLog, cancellationToken); _logger.LogInformation( "Refund processed. OrderId: {OrderId}, Amount: {Amount}, UserId: {UserId}", order.Id, order.Amount, order.UserId ); } } await _context.SaveChangesAsync(cancellationToken); // Restore inventory for each item (only if order was not yet delivered) if (order.FactorDetails != null && order.FactorDetails.Any()) { foreach (var item in order.FactorDetails) { var restored = await _inventoryService.ProcessReturnAsync( item.ProductId, ProductType.RegularProduct, item.Count, order.Id, note: $"برگشت موجودی — لغو سفارش #{order.Id} توسط Admin", ct: cancellationToken); if (!restored) { _logger.LogWarning( "Failed to restore inventory for ProductId={ProductId} on cancel OrderId={OrderId}", item.ProductId, order.Id); } } } _logger.LogInformation( "Order cancelled by admin. OrderId: {OrderId}, Reason: {Reason}, Refunded: {Refunded}, Admin: {AdminId}", order.Id, request.CancelReason, request.RefundToWallet, _currentUser.UserId ); return Unit.Value; } }