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; /// /// Handler برای ایجاد آیتم موجودی جدید /// public class CreateInventoryItemCommandHandler : IRequestHandler { private readonly IInventoryItemRepository _repository; private readonly IStockMovementRepository _stockMovementRepository; public CreateInventoryItemCommandHandler( IInventoryItemRepository repository, IStockMovementRepository stockMovementRepository) { _repository = repository; _stockMovementRepository = stockMovementRepository; } public async Task 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; } } /// /// Handler برای آپدیت آیتم موجودی /// public class UpdateInventoryItemCommandHandler : IRequestHandler { private readonly IInventoryItemRepository _repository; public UpdateInventoryItemCommandHandler(IInventoryItemRepository repository) { _repository = repository; } public async Task 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; } } /// /// Handler برای آپدیت موجودی /// public class UpdateInventoryQuantityCommandHandler : IRequestHandler { private readonly IInventoryItemRepository _repository; public UpdateInventoryQuantityCommandHandler(IInventoryItemRepository repository) { _repository = repository; } public async Task 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; } } /// /// Handler برای رزرو موجودی /// public class ReserveInventoryCommandHandler : IRequestHandler { private readonly IInventoryItemRepository _repository; public ReserveInventoryCommandHandler(IInventoryItemRepository repository) { _repository = repository; } public async Task 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); } } /// /// Handler برای آزاد کردن موجودی رزرو شده /// public class ReleaseReservedInventoryCommandHandler : IRequestHandler { private readonly IInventoryItemRepository _repository; public ReleaseReservedInventoryCommandHandler(IInventoryItemRepository repository) { _repository = repository; } public async Task 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); } } /// /// Handler برای کم کردن موجودی /// public class ReduceInventoryCommandHandler : IRequestHandler { private readonly IInventoryItemRepository _repository; public ReduceInventoryCommandHandler(IInventoryItemRepository repository) { _repository = repository; } public async Task 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); } } /// /// Handler برای اضافه کردن موجودی /// public class IncreaseInventoryCommandHandler : IRequestHandler { private readonly IInventoryItemRepository _repository; public IncreaseInventoryCommandHandler(IInventoryItemRepository repository) { _repository = repository; } public async Task 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); } } /// /// Handler برای حذف آیتم موجودی /// public class DeleteInventoryItemCommandHandler : IRequestHandler { private readonly IInventoryItemRepository _repository; public DeleteInventoryItemCommandHandler(IInventoryItemRepository repository) { _repository = repository; } public async Task Handle(DeleteInventoryItemCommand request, CancellationToken cancellationToken) { await _repository.DeleteAsync(request.Id, cancellationToken); return true; } }