Files
CMS/src/CMSMicroservice.Application/InventoryItemCQ/Commands/ReduceInventory/ReduceInventoryCommandHandler.cs
T
2026-02-22 21:38:20 +03:30

93 lines
3.5 KiB
C#

using CMSMicroservice.Application.Common.Exceptions;
using CMSMicroservice.Domain.Entities;
using CMSMicroservice.Domain.Enums;
namespace CMSMicroservice.Application.InventoryItemCQ.Commands.ReduceInventory;
public class ReduceInventoryCommandHandler : IRequestHandler<ReduceInventoryCommand, ReduceInventoryResponseDto>
{
private readonly IApplicationDbContext _context;
public ReduceInventoryCommandHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task<ReduceInventoryResponseDto> 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 };
}
}