using CMSMicroservice.Application.Common.Exceptions; using CMSMicroservice.Domain.Entities; using CMSMicroservice.Domain.Enums; namespace CMSMicroservice.Application.InventoryItemCQ.Commands.ReduceInventory; public class ReduceInventoryCommandHandler : IRequestHandler { private readonly IApplicationDbContext _context; public ReduceInventoryCommandHandler(IApplicationDbContext context) { _context = context; } public async Task Handle(ReduceInventoryCommand request, CancellationToken cancellationToken) { var item = await _context.InventoryItems .FirstOrDefaultAsync(i => i.Id == request.Id, cancellationToken); if (item == null) { throw new NotFoundException(nameof(Domain.Entities.InventoryItem), request.Id); } var previousQuantity = item.Quantity; if (request.FromReserved) { // کم کردن از موجودی رزرو شده if (item.ReservedQuantity < request.Quantity) { throw new InvalidOperationException($"Insufficient reserved stock. Reserved: {item.ReservedQuantity}, Requested: {request.Quantity}"); } item.ReservedQuantity -= request.Quantity; item.Quantity -= request.Quantity; } else { // کم کردن مستقیم از موجودی if (item.AvailableQuantity < request.Quantity) { throw new InvalidOperationException($"Insufficient available stock. Available: {item.AvailableQuantity}, Requested: {request.Quantity}"); } item.Quantity -= request.Quantity; } item.LastSoldAt = DateTime.UtcNow; // ثبت حرکت موجودی var stockMovement = new StockMovement { InventoryItemId = item.Id, MovementType = request.MovementType, Quantity = -request.Quantity, // منفی — CHECK constraint: QuantityAfter = QuantityBefore + Quantity QuantityBefore = previousQuantity, QuantityAfter = item.Quantity, Note = request.Note ?? request.MovementType.ToString(), ReferenceNumber = request.ReferenceNumber ?? $"SALE-{DateTime.UtcNow:yyyyMMddHHmmss}", OrderId = request.OrderId, DiscountOrderId = request.DiscountOrderId, PerformedByUserId = request.PerformedByUserId }; await _context.StockMovements.AddAsync(stockMovement, cancellationToken); // همگام‌سازی با Product.RemainingCount یا DiscountProduct.RemainingCount if (item.ProductType == ProductType.RegularProduct && item.ProductId.HasValue) { var product = await _context.Products.FindAsync(new object[] { item.ProductId.Value }, cancellationToken); if (product != null) { product.RemainingCount = item.Quantity; } } else if (item.ProductType == ProductType.DiscountProduct && item.DiscountProductId.HasValue) { var discountProduct = await _context.DiscountProducts.FindAsync( new object[] { item.DiscountProductId.Value }, cancellationToken); if (discountProduct != null) { discountProduct.RemainingCount = item.Quantity; } } await _context.SaveChangesAsync(cancellationToken); return new ReduceInventoryResponseDto { Success = true }; } }