289 lines
10 KiB
C#
289 lines
10 KiB
C#
using MediatR;
|
|
using CMSMicroservice.Application.Common.Interfaces.Repositories;
|
|
using CMSMicroservice.Application.Features.InventoryItems.Commands;
|
|
using CMSMicroservice.Domain.Entities;
|
|
using CMSMicroservice.Domain.Enums;
|
|
|
|
namespace CMSMicroservice.Application.Features.InventoryItems.Handlers;
|
|
|
|
/// <summary>
|
|
/// Handler برای ایجاد آیتم موجودی جدید
|
|
/// </summary>
|
|
public class CreateInventoryItemCommandHandler : IRequestHandler<CreateInventoryItemCommand, long>
|
|
{
|
|
private readonly IInventoryItemRepository _repository;
|
|
private readonly IStockMovementRepository _stockMovementRepository;
|
|
|
|
public CreateInventoryItemCommandHandler(
|
|
IInventoryItemRepository repository,
|
|
IStockMovementRepository stockMovementRepository)
|
|
{
|
|
_repository = repository;
|
|
_stockMovementRepository = stockMovementRepository;
|
|
}
|
|
|
|
public async Task<long> Handle(CreateInventoryItemCommand request, CancellationToken cancellationToken)
|
|
{
|
|
// بررسی اینکه حداقل یکی از Product یا DiscountProduct تعریف شده باشد
|
|
if (request.ProductId == null && request.DiscountProductId == null)
|
|
{
|
|
throw new ArgumentException("Either ProductId or DiscountProductId must be provided");
|
|
}
|
|
|
|
// بررسی اینکه هر دو ProductId و DiscountProductId تعریف نشده باشند
|
|
if (request.ProductId != null && request.DiscountProductId != null)
|
|
{
|
|
throw new ArgumentException("Only one of ProductId or DiscountProductId can be provided");
|
|
}
|
|
|
|
// بررسی وجود آیتم موجودی قبلی برای همین محصول در همین انبار
|
|
InventoryItem? existingItem = null;
|
|
if (request.ProductId.HasValue)
|
|
{
|
|
existingItem = await _repository.GetByProductIdAsync(request.ProductId.Value, request.WarehouseId, cancellationToken);
|
|
}
|
|
else if (request.DiscountProductId.HasValue)
|
|
{
|
|
existingItem = await _repository.GetByDiscountProductIdAsync(request.DiscountProductId.Value, request.WarehouseId, cancellationToken);
|
|
}
|
|
|
|
if (existingItem != null)
|
|
{
|
|
throw new InvalidOperationException("Inventory item already exists for this product in this warehouse");
|
|
}
|
|
|
|
var productType = request.ProductId.HasValue ? ProductType.RegularProduct : ProductType.DiscountProduct;
|
|
|
|
var inventoryItem = new InventoryItem
|
|
{
|
|
ProductId = request.ProductId,
|
|
DiscountProductId = request.DiscountProductId,
|
|
ProductType = productType,
|
|
WarehouseId = request.WarehouseId,
|
|
Quantity = request.Quantity,
|
|
LowStockThreshold = request.MinQuantity,
|
|
MaxStockLevel = request.MaxQuantity,
|
|
ReservedQuantity = 0
|
|
};
|
|
|
|
var createdItem = await _repository.AddAsync(inventoryItem, cancellationToken);
|
|
|
|
// ثبت حرکت موجودی اولیه اگر موجودی اولیه بیشتر از صفر باشد
|
|
if (request.Quantity > 0)
|
|
{
|
|
var stockMovement = new StockMovement
|
|
{
|
|
InventoryItemId = createdItem.Id,
|
|
MovementType = StockMovementType.InitialStock,
|
|
Quantity = request.Quantity,
|
|
Note = "Initial stock creation",
|
|
ReferenceNumber = $"INIT-{createdItem.Id}"
|
|
};
|
|
|
|
await _stockMovementRepository.AddAsync(stockMovement, cancellationToken);
|
|
}
|
|
|
|
return createdItem.Id;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handler برای آپدیت آیتم موجودی
|
|
/// </summary>
|
|
public class UpdateInventoryItemCommandHandler : IRequestHandler<UpdateInventoryItemCommand, bool>
|
|
{
|
|
private readonly IInventoryItemRepository _repository;
|
|
|
|
public UpdateInventoryItemCommandHandler(IInventoryItemRepository repository)
|
|
{
|
|
_repository = repository;
|
|
}
|
|
|
|
public async Task<bool> Handle(UpdateInventoryItemCommand request, CancellationToken cancellationToken)
|
|
{
|
|
var inventoryItem = await _repository.GetByIdAsync(request.Id, cancellationToken);
|
|
if (inventoryItem == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (request.WarehouseId.HasValue && request.WarehouseId.Value != inventoryItem.WarehouseId)
|
|
{
|
|
inventoryItem.WarehouseId = request.WarehouseId.Value;
|
|
}
|
|
|
|
if (request.Quantity.HasValue)
|
|
{
|
|
inventoryItem.Quantity = request.Quantity.Value;
|
|
}
|
|
|
|
if (request.MinQuantity.HasValue)
|
|
{
|
|
inventoryItem.LowStockThreshold = request.MinQuantity.Value;
|
|
}
|
|
|
|
if (request.MaxQuantity.HasValue)
|
|
{
|
|
inventoryItem.MaxStockLevel = request.MaxQuantity.Value;
|
|
}
|
|
|
|
await _repository.UpdateAsync(inventoryItem, cancellationToken);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handler برای آپدیت موجودی
|
|
/// </summary>
|
|
public class UpdateInventoryQuantityCommandHandler : IRequestHandler<UpdateInventoryQuantityCommand, bool>
|
|
{
|
|
private readonly IInventoryItemRepository _repository;
|
|
|
|
public UpdateInventoryQuantityCommandHandler(IInventoryItemRepository repository)
|
|
{
|
|
_repository = repository;
|
|
}
|
|
|
|
public async Task<bool> Handle(UpdateInventoryQuantityCommand request, CancellationToken cancellationToken)
|
|
{
|
|
var inventoryItem = await _repository.GetByIdAsync(request.Id, cancellationToken);
|
|
if (inventoryItem == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var quantityChange = request.NewQuantity - inventoryItem.Quantity;
|
|
var movementType = quantityChange >= 0 ? StockMovementType.AdjustmentPlus : StockMovementType.AdjustmentMinus;
|
|
|
|
var result = await _repository.UpdateQuantityAsync(
|
|
request.Id,
|
|
quantityChange,
|
|
movementType,
|
|
note: request.Note,
|
|
referenceNumber: request.ReferenceNumber,
|
|
performedByUserId: request.PerformedByUserId,
|
|
cancellationToken: cancellationToken);
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handler برای رزرو موجودی
|
|
/// </summary>
|
|
public class ReserveInventoryCommandHandler : IRequestHandler<ReserveInventoryCommand, bool>
|
|
{
|
|
private readonly IInventoryItemRepository _repository;
|
|
|
|
public ReserveInventoryCommandHandler(IInventoryItemRepository repository)
|
|
{
|
|
_repository = repository;
|
|
}
|
|
|
|
public async Task<bool> Handle(ReserveInventoryCommand request, CancellationToken cancellationToken)
|
|
{
|
|
return await _repository.ReserveQuantityAsync(
|
|
request.Id,
|
|
request.Quantity,
|
|
referenceNumber: request.ReferenceNumber,
|
|
orderId: request.OrderId,
|
|
discountOrderId: request.DiscountOrderId,
|
|
performedByUserId: request.PerformedByUserId,
|
|
cancellationToken: cancellationToken);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handler برای آزاد کردن موجودی رزرو شده
|
|
/// </summary>
|
|
public class ReleaseReservedInventoryCommandHandler : IRequestHandler<ReleaseReservedInventoryCommand, bool>
|
|
{
|
|
private readonly IInventoryItemRepository _repository;
|
|
|
|
public ReleaseReservedInventoryCommandHandler(IInventoryItemRepository repository)
|
|
{
|
|
_repository = repository;
|
|
}
|
|
|
|
public async Task<bool> Handle(ReleaseReservedInventoryCommand request, CancellationToken cancellationToken)
|
|
{
|
|
return await _repository.ReleaseReservedQuantityAsync(
|
|
request.Id,
|
|
request.Quantity,
|
|
referenceNumber: request.ReferenceNumber,
|
|
orderId: request.OrderId,
|
|
discountOrderId: request.DiscountOrderId,
|
|
performedByUserId: request.PerformedByUserId,
|
|
cancellationToken: cancellationToken);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handler برای کم کردن موجودی
|
|
/// </summary>
|
|
public class ReduceInventoryCommandHandler : IRequestHandler<ReduceInventoryCommand, bool>
|
|
{
|
|
private readonly IInventoryItemRepository _repository;
|
|
|
|
public ReduceInventoryCommandHandler(IInventoryItemRepository repository)
|
|
{
|
|
_repository = repository;
|
|
}
|
|
|
|
public async Task<bool> Handle(ReduceInventoryCommand request, CancellationToken cancellationToken)
|
|
{
|
|
return await _repository.UpdateQuantityAsync(
|
|
request.Id,
|
|
-request.Quantity,
|
|
StockMovementType.Sale,
|
|
referenceNumber: request.ReferenceNumber,
|
|
orderId: request.OrderId,
|
|
discountOrderId: request.DiscountOrderId,
|
|
performedByUserId: request.PerformedByUserId,
|
|
cancellationToken: cancellationToken);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handler برای اضافه کردن موجودی
|
|
/// </summary>
|
|
public class IncreaseInventoryCommandHandler : IRequestHandler<IncreaseInventoryCommand, bool>
|
|
{
|
|
private readonly IInventoryItemRepository _repository;
|
|
|
|
public IncreaseInventoryCommandHandler(IInventoryItemRepository repository)
|
|
{
|
|
_repository = repository;
|
|
}
|
|
|
|
public async Task<bool> Handle(IncreaseInventoryCommand request, CancellationToken cancellationToken)
|
|
{
|
|
return await _repository.UpdateQuantityAsync(
|
|
request.Id,
|
|
request.Quantity,
|
|
StockMovementType.Restock,
|
|
note: request.Note,
|
|
referenceNumber: request.ReferenceNumber,
|
|
performedByUserId: request.PerformedByUserId,
|
|
cancellationToken: cancellationToken);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handler برای حذف آیتم موجودی
|
|
/// </summary>
|
|
public class DeleteInventoryItemCommandHandler : IRequestHandler<DeleteInventoryItemCommand, bool>
|
|
{
|
|
private readonly IInventoryItemRepository _repository;
|
|
|
|
public DeleteInventoryItemCommandHandler(IInventoryItemRepository repository)
|
|
{
|
|
_repository = repository;
|
|
}
|
|
|
|
public async Task<bool> Handle(DeleteInventoryItemCommand request, CancellationToken cancellationToken)
|
|
{
|
|
await _repository.DeleteAsync(request.Id, cancellationToken);
|
|
return true;
|
|
}
|
|
} |