93 lines
3.5 KiB
C#
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 };
|
|
}
|
|
}
|