Implement Inventory Management Service with CRUD operations for warehouses and inventory items, stock operations, and bulk processing capabilities.
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 1m48s
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 1m48s
This commit is contained in:
+289
@@ -0,0 +1,289 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user