refactor: strip supplier/pricing from StockItemService and stock-items API
This commit is contained in:
@@ -11,12 +11,10 @@ namespace CutList.Web.Controllers;
|
|||||||
public class StockItemsController : ControllerBase
|
public class StockItemsController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly StockItemService _stockItemService;
|
private readonly StockItemService _stockItemService;
|
||||||
private readonly SupplierService _supplierService;
|
|
||||||
|
|
||||||
public StockItemsController(StockItemService stockItemService, SupplierService supplierService)
|
public StockItemsController(StockItemService stockItemService)
|
||||||
{
|
{
|
||||||
_stockItemService = stockItemService;
|
_stockItemService = stockItemService;
|
||||||
_supplierService = supplierService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -120,34 +118,6 @@ public class StockItemsController : ControllerBase
|
|||||||
return Ok(items.Select(MapToDto).ToList());
|
return Ok(items.Select(MapToDto).ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{id}/offerings")]
|
|
||||||
public async Task<ActionResult<List<OfferingDto>>> GetOfferings(int id)
|
|
||||||
{
|
|
||||||
var item = await _stockItemService.GetByIdAsync(id);
|
|
||||||
if (item == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
var offerings = await _supplierService.GetOfferingsForStockItemAsync(id);
|
|
||||||
return Ok(offerings.Select(MapOfferingToDto).ToList());
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{id}/pricing")]
|
|
||||||
public async Task<ActionResult<StockPricingDto>> GetPricing(int id)
|
|
||||||
{
|
|
||||||
var item = await _stockItemService.GetByIdAsync(id);
|
|
||||||
if (item == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
var avgCost = await _stockItemService.GetAverageCostAsync(id);
|
|
||||||
var lastPrice = await _stockItemService.GetLastPurchasePriceAsync(id);
|
|
||||||
|
|
||||||
return Ok(new StockPricingDto
|
|
||||||
{
|
|
||||||
AverageCost = avgCost,
|
|
||||||
LastPurchasePrice = lastPrice
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{id}/transactions")]
|
[HttpGet("{id}/transactions")]
|
||||||
public async Task<ActionResult<List<StockTransactionDto>>> GetTransactions(int id, [FromQuery] int? limit = null)
|
public async Task<ActionResult<List<StockTransactionDto>>> GetTransactions(int id, [FromQuery] int? limit = null)
|
||||||
{
|
{
|
||||||
@@ -164,7 +134,7 @@ public class StockItemsController : ControllerBase
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var transaction = await _stockItemService.AddStockAsync(id, dto.Quantity, dto.SupplierId, dto.UnitPrice, dto.Notes);
|
var transaction = await _stockItemService.AddStockAsync(id, dto.Quantity, dto.Notes);
|
||||||
return Ok(MapTransactionToDto(transaction));
|
return Ok(MapTransactionToDto(transaction));
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException)
|
catch (InvalidOperationException)
|
||||||
@@ -250,23 +220,7 @@ public class StockItemsController : ControllerBase
|
|||||||
Type = t.Type.ToString(),
|
Type = t.Type.ToString(),
|
||||||
JobId = t.JobId,
|
JobId = t.JobId,
|
||||||
JobNumber = t.Job?.JobNumber,
|
JobNumber = t.Job?.JobNumber,
|
||||||
SupplierId = t.SupplierId,
|
|
||||||
SupplierName = t.Supplier?.Name,
|
|
||||||
UnitPrice = t.UnitPrice,
|
|
||||||
Notes = t.Notes,
|
Notes = t.Notes,
|
||||||
CreatedAt = t.CreatedAt
|
CreatedAt = t.CreatedAt
|
||||||
};
|
};
|
||||||
|
|
||||||
private static OfferingDto MapOfferingToDto(SupplierOffering o) => new()
|
|
||||||
{
|
|
||||||
Id = o.Id,
|
|
||||||
SupplierId = o.SupplierId,
|
|
||||||
SupplierName = o.Supplier?.Name,
|
|
||||||
StockItemId = o.StockItemId,
|
|
||||||
PartNumber = o.PartNumber,
|
|
||||||
SupplierDescription = o.SupplierDescription,
|
|
||||||
Price = o.Price,
|
|
||||||
Notes = o.Notes,
|
|
||||||
IsActive = o.IsActive
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,6 @@ public class StockTransactionDto
|
|||||||
public string Type { get; set; } = string.Empty;
|
public string Type { get; set; } = string.Empty;
|
||||||
public int? JobId { get; set; }
|
public int? JobId { get; set; }
|
||||||
public string? JobNumber { get; set; }
|
public string? JobNumber { get; set; }
|
||||||
public int? SupplierId { get; set; }
|
|
||||||
public string? SupplierName { get; set; }
|
|
||||||
public decimal? UnitPrice { get; set; }
|
|
||||||
public string? Notes { get; set; }
|
public string? Notes { get; set; }
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
}
|
}
|
||||||
@@ -47,8 +44,6 @@ public class StockTransactionDto
|
|||||||
public class AddStockDto
|
public class AddStockDto
|
||||||
{
|
{
|
||||||
public int Quantity { get; set; }
|
public int Quantity { get; set; }
|
||||||
public int? SupplierId { get; set; }
|
|
||||||
public decimal? UnitPrice { get; set; }
|
|
||||||
public string? Notes { get; set; }
|
public string? Notes { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,9 +65,3 @@ public class ScrapStockDto
|
|||||||
public int Quantity { get; set; }
|
public int Quantity { get; set; }
|
||||||
public string? Notes { get; set; }
|
public string? Notes { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StockPricingDto
|
|
||||||
{
|
|
||||||
public decimal? AverageCost { get; set; }
|
|
||||||
public decimal? LastPurchasePrice { get; set; }
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -57,8 +57,6 @@ public class StockItemService
|
|||||||
|
|
||||||
return await context.StockItems
|
return await context.StockItems
|
||||||
.Include(s => s.Material)
|
.Include(s => s.Material)
|
||||||
.Include(s => s.SupplierOfferings)
|
|
||||||
.ThenInclude(o => o.Supplier)
|
|
||||||
.FirstOrDefaultAsync(s => s.Id == id);
|
.FirstOrDefaultAsync(s => s.Id == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +110,7 @@ public class StockItemService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stock transaction methods
|
// Stock transaction methods
|
||||||
public async Task<StockTransaction> AddStockAsync(int stockItemId, int quantity, int? supplierId = null, decimal? unitPrice = null, string? notes = null)
|
public async Task<StockTransaction> AddStockAsync(int stockItemId, int quantity, string? notes = null)
|
||||||
{
|
{
|
||||||
await using var context = _factory.CreateDbContext();
|
await using var context = _factory.CreateDbContext();
|
||||||
|
|
||||||
@@ -124,8 +122,6 @@ public class StockItemService
|
|||||||
StockItemId = stockItemId,
|
StockItemId = stockItemId,
|
||||||
Quantity = quantity,
|
Quantity = quantity,
|
||||||
Type = StockTransactionType.Received,
|
Type = StockTransactionType.Received,
|
||||||
SupplierId = supplierId,
|
|
||||||
UnitPrice = unitPrice,
|
|
||||||
Notes = notes,
|
Notes = notes,
|
||||||
CreatedAt = DateTime.UtcNow
|
CreatedAt = DateTime.UtcNow
|
||||||
};
|
};
|
||||||
@@ -139,34 +135,6 @@ public class StockItemService
|
|||||||
return transaction;
|
return transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<decimal?> GetAverageCostAsync(int stockItemId)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
|
|
||||||
var transactions = await context.StockTransactions
|
|
||||||
.Where(t => t.StockItemId == stockItemId && t.Type == StockTransactionType.Received && t.UnitPrice.HasValue)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
if (transactions.Count == 0)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var totalCost = transactions.Sum(t => t.Quantity * t.UnitPrice!.Value);
|
|
||||||
var totalQty = transactions.Sum(t => t.Quantity);
|
|
||||||
|
|
||||||
return totalQty > 0 ? totalCost / totalQty : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<decimal?> GetLastPurchasePriceAsync(int stockItemId)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
|
|
||||||
return await context.StockTransactions
|
|
||||||
.Where(t => t.StockItemId == stockItemId && t.Type == StockTransactionType.Received && t.UnitPrice.HasValue)
|
|
||||||
.OrderByDescending(t => t.CreatedAt)
|
|
||||||
.Select(t => t.UnitPrice)
|
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<StockTransaction> UseStockAsync(int stockItemId, int quantity, int? jobId = null, string? notes = null)
|
public async Task<StockTransaction> UseStockAsync(int stockItemId, int quantity, int? jobId = null, string? notes = null)
|
||||||
{
|
{
|
||||||
await using var context = _factory.CreateDbContext();
|
await using var context = _factory.CreateDbContext();
|
||||||
@@ -251,7 +219,6 @@ public class StockItemService
|
|||||||
|
|
||||||
var query = context.StockTransactions
|
var query = context.StockTransactions
|
||||||
.Include(t => t.Job)
|
.Include(t => t.Job)
|
||||||
.Include(t => t.Supplier)
|
|
||||||
.Where(t => t.StockItemId == stockItemId)
|
.Where(t => t.StockItemId == stockItemId)
|
||||||
.OrderByDescending(t => t.CreatedAt)
|
.OrderByDescending(t => t.CreatedAt)
|
||||||
.AsQueryable();
|
.AsQueryable();
|
||||||
|
|||||||
Reference in New Issue
Block a user