diff --git a/Distribution/Features/Stock/IStockRepository.cs b/Distribution/Features/Stock/IStockRepository.cs index 9b7c755..dbc9208 100644 --- a/Distribution/Features/Stock/IStockRepository.cs +++ b/Distribution/Features/Stock/IStockRepository.cs @@ -10,6 +10,7 @@ public interface IStockRepository Task> GetBalancesAsync(Guid? locationId, LocationType? locationType, Guid? itemId, int page, int pageSize); Task GetBalancesCountAsync(Guid? locationId, LocationType? locationType, Guid? itemId); Task> GetBalancesByItemAsync(Guid itemId); + Task> GetLowStockAsync(Guid? locationId); Task AddBalanceAsync(StockBalance balance); void UpdateBalance(StockBalance balance); diff --git a/Distribution/Features/Stock/StockController.cs b/Distribution/Features/Stock/StockController.cs index 5680eda..db6ed68 100644 --- a/Distribution/Features/Stock/StockController.cs +++ b/Distribution/Features/Stock/StockController.cs @@ -22,6 +22,13 @@ public class StockController(StockService service, ICurrentUserService currentUs return Ok(result); } + [HttpGet("low-stock")] + public async Task GetLowStock([FromQuery] Guid? locationId) + { + var result = await service.GetLowStockAsync(locationId); + return Ok(result); + } + [HttpGet("balances/{itemId}/total")] public async Task GetItemTotal(Guid itemId) { diff --git a/Distribution/Features/Stock/StockDTOs.cs b/Distribution/Features/Stock/StockDTOs.cs index bf57f0c..a6c79c2 100644 --- a/Distribution/Features/Stock/StockDTOs.cs +++ b/Distribution/Features/Stock/StockDTOs.cs @@ -21,6 +21,14 @@ public record StockTotalResponse( decimal TotalQuantity, List Breakdown); +public record LowStockItemResponse( + Guid ItemId, + string ItemName, + Guid LocationId, + string LocationName, + decimal Quantity, + decimal ReorderLevel); + // Movement public record StockMovementResponse( Guid Id, diff --git a/Distribution/Features/Stock/StockRepository.cs b/Distribution/Features/Stock/StockRepository.cs index 5f236e6..20ba415 100644 --- a/Distribution/Features/Stock/StockRepository.cs +++ b/Distribution/Features/Stock/StockRepository.cs @@ -41,6 +41,17 @@ public class StockRepository(AppDBContext db) : IStockRepository .Where(b => b.FK_ItemId == itemId) .ToListAsync(); + public Task> GetLowStockAsync(Guid? locationId) + { + var query = db.StockBalances + .Include(b => b.Item) + .Where(b => b.LocationType == LocationType.Warehouse + && b.Item.ReorderLevel != null + && b.Quantity < b.Item.ReorderLevel); + if (locationId.HasValue) query = query.Where(b => b.LocationId == locationId.Value); + return query.OrderBy(b => b.Quantity).ToListAsync(); + } + public async Task AddBalanceAsync(StockBalance balance) => await db.StockBalances.AddAsync(balance); diff --git a/Distribution/Features/Stock/StockService.cs b/Distribution/Features/Stock/StockService.cs index 7a56062..cfca6d1 100644 --- a/Distribution/Features/Stock/StockService.cs +++ b/Distribution/Features/Stock/StockService.cs @@ -87,6 +87,15 @@ public class StockService( items.Select(b => MapBalance(b, names.GetValueOrDefault(b.LocationId, "—"))).ToList()); } + public async Task> GetLowStockAsync(Guid? locationId) + { + var balances = await repo.GetLowStockAsync(locationId); + var names = await ResolveLocationNamesAsync(balances.Select(b => (b.LocationId, b.LocationType))); + return balances.Select(b => new LowStockItemResponse( + b.FK_ItemId, b.Item.Name, b.LocationId, names.GetValueOrDefault(b.LocationId, "—"), + b.Quantity, b.Item.ReorderLevel!.Value)).ToList(); + } + public async Task GetItemTotalAsync(Guid itemId) { var item = await itemRepo.GetByIdAsync(itemId);