refactor: remove stock-transaction service methods, endpoints, and DTOs
No job workflow ever called these (receive/use/adjust/scrap/recalculate) - inventory quantity tracking is being removed per docs/superpowers/specs/2026-08-01-remove-inventory-quantity-tracking-design.md.
This commit is contained in:
@@ -310,7 +310,6 @@ public class JobsController : ControllerBase
|
||||
LengthInches = s.LengthInches,
|
||||
LengthFormatted = ArchUnits.FormatFromInches((double)s.LengthInches),
|
||||
Name = s.Name,
|
||||
QuantityOnHand = s.QuantityOnHand,
|
||||
IsActive = s.IsActive
|
||||
}).ToList());
|
||||
}
|
||||
|
||||
@@ -63,7 +63,6 @@ public class StockItemsController : ControllerBase
|
||||
MaterialId = dto.MaterialId,
|
||||
LengthInches = (decimal)lengthInches,
|
||||
Name = dto.Name,
|
||||
QuantityOnHand = dto.QuantityOnHand,
|
||||
Notes = dto.Notes
|
||||
};
|
||||
|
||||
@@ -118,87 +117,6 @@ public class StockItemsController : ControllerBase
|
||||
return Ok(items.Select(MapToDto).ToList());
|
||||
}
|
||||
|
||||
[HttpGet("{id}/transactions")]
|
||||
public async Task<ActionResult<List<StockTransactionDto>>> GetTransactions(int id, [FromQuery] int? limit = null)
|
||||
{
|
||||
var item = await _stockItemService.GetByIdAsync(id);
|
||||
if (item == null)
|
||||
return NotFound();
|
||||
|
||||
var transactions = await _stockItemService.GetTransactionHistoryAsync(id, limit);
|
||||
return Ok(transactions.Select(MapTransactionToDto).ToList());
|
||||
}
|
||||
|
||||
[HttpPost("{id}/receive")]
|
||||
public async Task<ActionResult<StockTransactionDto>> ReceiveStock(int id, AddStockDto dto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transaction = await _stockItemService.AddStockAsync(id, dto.Quantity, dto.Notes);
|
||||
return Ok(MapTransactionToDto(transaction));
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("{id}/use")]
|
||||
public async Task<ActionResult<StockTransactionDto>> UseStock(int id, UseStockDto dto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transaction = await _stockItemService.UseStockAsync(id, dto.Quantity, dto.JobId, dto.Notes);
|
||||
return Ok(MapTransactionToDto(transaction));
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("{id}/adjust")]
|
||||
public async Task<ActionResult<StockTransactionDto>> AdjustStock(int id, AdjustStockDto dto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transaction = await _stockItemService.AdjustStockAsync(id, dto.NewQuantity, dto.Notes);
|
||||
return Ok(MapTransactionToDto(transaction));
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("{id}/scrap")]
|
||||
public async Task<ActionResult<StockTransactionDto>> ScrapStock(int id, ScrapStockDto dto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transaction = await _stockItemService.ScrapStockAsync(id, dto.Quantity, dto.Notes);
|
||||
return Ok(MapTransactionToDto(transaction));
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("{id}/recalculate")]
|
||||
public async Task<ActionResult<object>> RecalculateStock(int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var newQuantity = await _stockItemService.RecalculateQuantityAsync(id);
|
||||
return Ok(new { QuantityOnHand = newQuantity });
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
private static StockItemDto MapToDto(StockItem s) => new()
|
||||
{
|
||||
Id = s.Id,
|
||||
@@ -207,20 +125,7 @@ public class StockItemsController : ControllerBase
|
||||
LengthInches = s.LengthInches,
|
||||
LengthFormatted = ArchUnits.FormatFromInches((double)s.LengthInches),
|
||||
Name = s.Name,
|
||||
QuantityOnHand = s.QuantityOnHand,
|
||||
Notes = s.Notes,
|
||||
IsActive = s.IsActive
|
||||
};
|
||||
|
||||
private static StockTransactionDto MapTransactionToDto(StockTransaction t) => new()
|
||||
{
|
||||
Id = t.Id,
|
||||
StockItemId = t.StockItemId,
|
||||
Quantity = t.Quantity,
|
||||
Type = t.Type.ToString(),
|
||||
JobId = t.JobId,
|
||||
JobNumber = t.Job?.JobNumber,
|
||||
Notes = t.Notes,
|
||||
CreatedAt = t.CreatedAt
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ public class StockItemDto
|
||||
public decimal LengthInches { get; set; }
|
||||
public string LengthFormatted { get; set; } = string.Empty;
|
||||
public string? Name { get; set; }
|
||||
public int QuantityOnHand { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
}
|
||||
@@ -18,7 +17,6 @@ public class CreateStockItemDto
|
||||
public int MaterialId { get; set; }
|
||||
public string Length { get; set; } = string.Empty;
|
||||
public string? Name { get; set; }
|
||||
public int QuantityOnHand { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
}
|
||||
|
||||
@@ -28,40 +26,3 @@ public class UpdateStockItemDto
|
||||
public string? Name { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
}
|
||||
|
||||
public class StockTransactionDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int StockItemId { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
public string Type { get; set; } = string.Empty;
|
||||
public int? JobId { get; set; }
|
||||
public string? JobNumber { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
|
||||
public class AddStockDto
|
||||
{
|
||||
public int Quantity { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
}
|
||||
|
||||
public class UseStockDto
|
||||
{
|
||||
public int Quantity { get; set; }
|
||||
public int? JobId { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
}
|
||||
|
||||
public class AdjustStockDto
|
||||
{
|
||||
public int NewQuantity { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
}
|
||||
|
||||
public class ScrapStockDto
|
||||
{
|
||||
public int Quantity { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
}
|
||||
|
||||
@@ -108,147 +108,4 @@ public class StockItemService
|
||||
|
||||
return await query.AnyAsync();
|
||||
}
|
||||
|
||||
// Stock transaction methods
|
||||
public async Task<StockTransaction> AddStockAsync(int stockItemId, int quantity, string? notes = null)
|
||||
{
|
||||
await using var context = _factory.CreateDbContext();
|
||||
|
||||
var stockItem = await context.StockItems.FindAsync(stockItemId)
|
||||
?? throw new InvalidOperationException($"Stock item {stockItemId} not found");
|
||||
|
||||
var transaction = new StockTransaction
|
||||
{
|
||||
StockItemId = stockItemId,
|
||||
Quantity = quantity,
|
||||
Type = StockTransactionType.Received,
|
||||
Notes = notes,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
stockItem.QuantityOnHand += quantity;
|
||||
stockItem.UpdatedAt = DateTime.UtcNow;
|
||||
|
||||
context.StockTransactions.Add(transaction);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public async Task<StockTransaction> UseStockAsync(int stockItemId, int quantity, int? jobId = null, string? notes = null)
|
||||
{
|
||||
await using var context = _factory.CreateDbContext();
|
||||
|
||||
var stockItem = await context.StockItems.FindAsync(stockItemId)
|
||||
?? throw new InvalidOperationException($"Stock item {stockItemId} not found");
|
||||
|
||||
var transaction = new StockTransaction
|
||||
{
|
||||
StockItemId = stockItemId,
|
||||
Quantity = -quantity,
|
||||
Type = StockTransactionType.Used,
|
||||
JobId = jobId,
|
||||
Notes = notes,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
stockItem.QuantityOnHand -= quantity;
|
||||
stockItem.UpdatedAt = DateTime.UtcNow;
|
||||
|
||||
context.StockTransactions.Add(transaction);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public async Task<StockTransaction> AdjustStockAsync(int stockItemId, int newQuantity, string? notes = null)
|
||||
{
|
||||
await using var context = _factory.CreateDbContext();
|
||||
|
||||
var stockItem = await context.StockItems.FindAsync(stockItemId)
|
||||
?? throw new InvalidOperationException($"Stock item {stockItemId} not found");
|
||||
|
||||
var difference = newQuantity - stockItem.QuantityOnHand;
|
||||
|
||||
var transaction = new StockTransaction
|
||||
{
|
||||
StockItemId = stockItemId,
|
||||
Quantity = difference,
|
||||
Type = StockTransactionType.Adjustment,
|
||||
Notes = notes ?? "Manual adjustment",
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
stockItem.QuantityOnHand = newQuantity;
|
||||
stockItem.UpdatedAt = DateTime.UtcNow;
|
||||
|
||||
context.StockTransactions.Add(transaction);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public async Task<StockTransaction> ScrapStockAsync(int stockItemId, int quantity, string? notes = null)
|
||||
{
|
||||
await using var context = _factory.CreateDbContext();
|
||||
|
||||
var stockItem = await context.StockItems.FindAsync(stockItemId)
|
||||
?? throw new InvalidOperationException($"Stock item {stockItemId} not found");
|
||||
|
||||
var transaction = new StockTransaction
|
||||
{
|
||||
StockItemId = stockItemId,
|
||||
Quantity = -quantity,
|
||||
Type = StockTransactionType.Scrapped,
|
||||
Notes = notes,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
stockItem.QuantityOnHand -= quantity;
|
||||
stockItem.UpdatedAt = DateTime.UtcNow;
|
||||
|
||||
context.StockTransactions.Add(transaction);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public async Task<List<StockTransaction>> GetTransactionHistoryAsync(int stockItemId, int? limit = null)
|
||||
{
|
||||
await using var context = _factory.CreateDbContext();
|
||||
|
||||
var query = context.StockTransactions
|
||||
.Include(t => t.Job)
|
||||
.Where(t => t.StockItemId == stockItemId)
|
||||
.OrderByDescending(t => t.CreatedAt)
|
||||
.AsQueryable();
|
||||
|
||||
if (limit.HasValue)
|
||||
{
|
||||
query = query.Take(limit.Value);
|
||||
}
|
||||
|
||||
return await query.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<int> RecalculateQuantityAsync(int stockItemId)
|
||||
{
|
||||
await using var context = _factory.CreateDbContext();
|
||||
|
||||
var stockItem = await context.StockItems.FindAsync(stockItemId)
|
||||
?? throw new InvalidOperationException($"Stock item {stockItemId} not found");
|
||||
|
||||
var calculatedQuantity = await context.StockTransactions
|
||||
.Where(t => t.StockItemId == stockItemId)
|
||||
.SumAsync(t => t.Quantity);
|
||||
|
||||
if (stockItem.QuantityOnHand != calculatedQuantity)
|
||||
{
|
||||
stockItem.QuantityOnHand = calculatedQuantity;
|
||||
stockItem.UpdatedAt = DateTime.UtcNow;
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
return calculatedQuantity;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user