Add GetNextSerialSequence functionality to Stock services and repository
This commit is contained in:
@@ -28,5 +28,7 @@ public interface IStockRepository
|
|||||||
|
|
||||||
// Serial numbers
|
// Serial numbers
|
||||||
Task<bool> SerialNumberExistsAsync(Guid itemId, string serialNumber);
|
Task<bool> SerialNumberExistsAsync(Guid itemId, string serialNumber);
|
||||||
|
/// <summary>One past the highest numeric suffix among the item's existing serials that start with <paramref name="prefix"/> (1 if none).</summary>
|
||||||
|
Task<int> GetNextSerialSequenceAsync(Guid itemId, string prefix);
|
||||||
Task AddItemSerialNumberAsync(ItemSerialNumber serial);
|
Task AddItemSerialNumberAsync(ItemSerialNumber serial);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,14 @@ public class StockController(StockService service, ICurrentUserService currentUs
|
|||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Next free number for auto-generated serials (e.g. after ...-0005 the answer is 6).</summary>
|
||||||
|
[HttpGet("serials/next-sequence")]
|
||||||
|
public async Task<IActionResult> GetNextSerialSequence([FromQuery] Guid itemId, [FromQuery] string prefix = "")
|
||||||
|
{
|
||||||
|
var next = await service.GetNextSerialSequenceAsync(itemId, prefix);
|
||||||
|
return Ok(new { next });
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet("movements")]
|
[HttpGet("movements")]
|
||||||
public async Task<IActionResult> GetMovements(
|
public async Task<IActionResult> GetMovements(
|
||||||
[FromQuery] Guid? locationId,
|
[FromQuery] Guid? locationId,
|
||||||
|
|||||||
@@ -107,6 +107,26 @@ public class StockRepository(AppDBContext db) : IStockRepository
|
|||||||
public Task<bool> SerialNumberExistsAsync(Guid itemId, string serialNumber) =>
|
public Task<bool> SerialNumberExistsAsync(Guid itemId, string serialNumber) =>
|
||||||
db.ItemSerialNumbers.AnyAsync(s => s.FK_ItemId == itemId && s.SerialNumber == serialNumber);
|
db.ItemSerialNumbers.AnyAsync(s => s.FK_ItemId == itemId && s.SerialNumber == serialNumber);
|
||||||
|
|
||||||
|
public async Task<int> GetNextSerialSequenceAsync(Guid itemId, string prefix)
|
||||||
|
{
|
||||||
|
// Only serials of the form <prefix><digits> count; anything else (a supplier's own serial that
|
||||||
|
// happens to start with the prefix) is ignored for numbering.
|
||||||
|
var serials = await db.ItemSerialNumbers
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(s => s.FK_ItemId == itemId && s.SerialNumber.StartsWith(prefix))
|
||||||
|
.Select(s => s.SerialNumber)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var max = 0L;
|
||||||
|
foreach (var serial in serials)
|
||||||
|
{
|
||||||
|
var suffix = serial[prefix.Length..];
|
||||||
|
if (suffix.Length is > 0 and <= 9 && suffix.All(char.IsDigit) && long.TryParse(suffix, out var n))
|
||||||
|
max = Math.Max(max, n);
|
||||||
|
}
|
||||||
|
return (int)max + 1;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task AddItemSerialNumberAsync(ItemSerialNumber serial) =>
|
public async Task AddItemSerialNumberAsync(ItemSerialNumber serial) =>
|
||||||
await db.ItemSerialNumbers.AddAsync(serial);
|
await db.ItemSerialNumbers.AddAsync(serial);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,10 @@ public class StockService(
|
|||||||
b.Quantity, b.Item.ReorderLevel!.Value)).ToList();
|
b.Quantity, b.Item.ReorderLevel!.Value)).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>The next unused sequence number for generating serials like "<prefix>0001" for an item.</summary>
|
||||||
|
public Task<int> GetNextSerialSequenceAsync(Guid itemId, string prefix) =>
|
||||||
|
repo.GetNextSerialSequenceAsync(itemId, prefix ?? string.Empty);
|
||||||
|
|
||||||
public async Task<StockTotalResponse?> GetItemTotalAsync(Guid itemId)
|
public async Task<StockTotalResponse?> GetItemTotalAsync(Guid itemId)
|
||||||
{
|
{
|
||||||
var item = await itemRepo.GetByIdAsync(itemId);
|
var item = await itemRepo.GetByIdAsync(itemId);
|
||||||
|
|||||||
Reference in New Issue
Block a user