feat: delete SupplierService, PurchaseItemService, and their API surface
This commit is contained in:
@@ -1,172 +0,0 @@
|
|||||||
using CutList.Core.Formatting;
|
|
||||||
using CutList.Web.Data.Entities;
|
|
||||||
using CutList.Web.DTOs;
|
|
||||||
using CutList.Web.Services;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace CutList.Web.Controllers;
|
|
||||||
|
|
||||||
[ApiController]
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
public class SuppliersController : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly SupplierService _supplierService;
|
|
||||||
|
|
||||||
public SuppliersController(SupplierService supplierService)
|
|
||||||
{
|
|
||||||
_supplierService = supplierService;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet]
|
|
||||||
public async Task<ActionResult<List<SupplierDto>>> GetAll([FromQuery] bool includeInactive = false)
|
|
||||||
{
|
|
||||||
var suppliers = await _supplierService.GetAllAsync(includeInactive);
|
|
||||||
return Ok(suppliers.Select(MapToDto).ToList());
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
|
||||||
public async Task<ActionResult<SupplierDto>> GetById(int id)
|
|
||||||
{
|
|
||||||
var supplier = await _supplierService.GetByIdAsync(id);
|
|
||||||
if (supplier == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
return Ok(MapToDto(supplier));
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<ActionResult<SupplierDto>> Create(CreateSupplierDto dto)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(dto.Name))
|
|
||||||
return BadRequest("Name is required");
|
|
||||||
|
|
||||||
var supplier = new Supplier
|
|
||||||
{
|
|
||||||
Name = dto.Name,
|
|
||||||
ContactInfo = dto.ContactInfo,
|
|
||||||
Notes = dto.Notes
|
|
||||||
};
|
|
||||||
|
|
||||||
await _supplierService.CreateAsync(supplier);
|
|
||||||
return CreatedAtAction(nameof(GetById), new { id = supplier.Id }, MapToDto(supplier));
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPut("{id}")]
|
|
||||||
public async Task<ActionResult<SupplierDto>> Update(int id, UpdateSupplierDto dto)
|
|
||||||
{
|
|
||||||
var supplier = await _supplierService.GetByIdAsync(id);
|
|
||||||
if (supplier == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
if (dto.Name != null) supplier.Name = dto.Name;
|
|
||||||
if (dto.ContactInfo != null) supplier.ContactInfo = dto.ContactInfo;
|
|
||||||
if (dto.Notes != null) supplier.Notes = dto.Notes;
|
|
||||||
|
|
||||||
await _supplierService.UpdateAsync(supplier);
|
|
||||||
return Ok(MapToDto(supplier));
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpDelete("{id}")]
|
|
||||||
public async Task<IActionResult> Delete(int id)
|
|
||||||
{
|
|
||||||
var supplier = await _supplierService.GetByIdAsync(id);
|
|
||||||
if (supplier == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
await _supplierService.DeleteAsync(id);
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Offerings ---
|
|
||||||
|
|
||||||
[HttpGet("{id}/offerings")]
|
|
||||||
public async Task<ActionResult<List<OfferingDto>>> GetOfferings(int id)
|
|
||||||
{
|
|
||||||
var supplier = await _supplierService.GetByIdAsync(id);
|
|
||||||
if (supplier == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
var offerings = await _supplierService.GetOfferingsForSupplierAsync(id);
|
|
||||||
return Ok(offerings.Select(MapOfferingToDto).ToList());
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("{id}/offerings")]
|
|
||||||
public async Task<ActionResult<OfferingDto>> CreateOffering(int id, CreateOfferingDto dto)
|
|
||||||
{
|
|
||||||
var supplier = await _supplierService.GetByIdAsync(id);
|
|
||||||
if (supplier == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
var exists = await _supplierService.OfferingExistsAsync(id, dto.StockItemId);
|
|
||||||
if (exists)
|
|
||||||
return Conflict("An offering for this supplier and stock item already exists");
|
|
||||||
|
|
||||||
var offering = new SupplierOffering
|
|
||||||
{
|
|
||||||
SupplierId = id,
|
|
||||||
StockItemId = dto.StockItemId,
|
|
||||||
PartNumber = dto.PartNumber,
|
|
||||||
SupplierDescription = dto.SupplierDescription,
|
|
||||||
Price = dto.Price,
|
|
||||||
Notes = dto.Notes
|
|
||||||
};
|
|
||||||
|
|
||||||
await _supplierService.AddOfferingAsync(offering);
|
|
||||||
|
|
||||||
// Reload with includes
|
|
||||||
var created = await _supplierService.GetOfferingByIdAsync(offering.Id);
|
|
||||||
return CreatedAtAction(nameof(GetOfferings), new { id }, MapOfferingToDto(created!));
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPut("{supplierId}/offerings/{offeringId}")]
|
|
||||||
public async Task<ActionResult<OfferingDto>> UpdateOffering(int supplierId, int offeringId, UpdateOfferingDto dto)
|
|
||||||
{
|
|
||||||
var offering = await _supplierService.GetOfferingByIdAsync(offeringId);
|
|
||||||
if (offering == null || offering.SupplierId != supplierId)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
if (dto.PartNumber != null) offering.PartNumber = dto.PartNumber;
|
|
||||||
if (dto.SupplierDescription != null) offering.SupplierDescription = dto.SupplierDescription;
|
|
||||||
if (dto.Price.HasValue) offering.Price = dto.Price;
|
|
||||||
if (dto.Notes != null) offering.Notes = dto.Notes;
|
|
||||||
|
|
||||||
await _supplierService.UpdateOfferingAsync(offering);
|
|
||||||
return Ok(MapOfferingToDto(offering));
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpDelete("{supplierId}/offerings/{offeringId}")]
|
|
||||||
public async Task<IActionResult> DeleteOffering(int supplierId, int offeringId)
|
|
||||||
{
|
|
||||||
var offering = await _supplierService.GetOfferingByIdAsync(offeringId);
|
|
||||||
if (offering == null || offering.SupplierId != supplierId)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
await _supplierService.DeleteOfferingAsync(offeringId);
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static SupplierDto MapToDto(Supplier s) => new()
|
|
||||||
{
|
|
||||||
Id = s.Id,
|
|
||||||
Name = s.Name,
|
|
||||||
ContactInfo = s.ContactInfo,
|
|
||||||
Notes = s.Notes,
|
|
||||||
IsActive = s.IsActive
|
|
||||||
};
|
|
||||||
|
|
||||||
private static OfferingDto MapOfferingToDto(SupplierOffering o) => new()
|
|
||||||
{
|
|
||||||
Id = o.Id,
|
|
||||||
SupplierId = o.SupplierId,
|
|
||||||
SupplierName = o.Supplier?.Name,
|
|
||||||
StockItemId = o.StockItemId,
|
|
||||||
MaterialName = o.StockItem?.Material?.DisplayName,
|
|
||||||
LengthInches = o.StockItem?.LengthInches,
|
|
||||||
LengthFormatted = o.StockItem != null ? ArchUnits.FormatFromInches((double)o.StockItem.LengthInches) : null,
|
|
||||||
PartNumber = o.PartNumber,
|
|
||||||
SupplierDescription = o.SupplierDescription,
|
|
||||||
Price = o.Price,
|
|
||||||
Notes = o.Notes,
|
|
||||||
IsActive = o.IsActive
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
namespace CutList.Web.DTOs;
|
|
||||||
|
|
||||||
public class SupplierDto
|
|
||||||
{
|
|
||||||
public int Id { get; set; }
|
|
||||||
public string Name { get; set; } = string.Empty;
|
|
||||||
public string? ContactInfo { get; set; }
|
|
||||||
public string? Notes { get; set; }
|
|
||||||
public bool IsActive { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CreateSupplierDto
|
|
||||||
{
|
|
||||||
public string Name { get; set; } = string.Empty;
|
|
||||||
public string? ContactInfo { get; set; }
|
|
||||||
public string? Notes { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class UpdateSupplierDto
|
|
||||||
{
|
|
||||||
public string? Name { get; set; }
|
|
||||||
public string? ContactInfo { get; set; }
|
|
||||||
public string? Notes { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class OfferingDto
|
|
||||||
{
|
|
||||||
public int Id { get; set; }
|
|
||||||
public int SupplierId { get; set; }
|
|
||||||
public string? SupplierName { get; set; }
|
|
||||||
public int StockItemId { get; set; }
|
|
||||||
public string? MaterialName { get; set; }
|
|
||||||
public decimal? LengthInches { get; set; }
|
|
||||||
public string? LengthFormatted { get; set; }
|
|
||||||
public string? PartNumber { get; set; }
|
|
||||||
public string? SupplierDescription { get; set; }
|
|
||||||
public decimal? Price { get; set; }
|
|
||||||
public string? Notes { get; set; }
|
|
||||||
public bool IsActive { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CreateOfferingDto
|
|
||||||
{
|
|
||||||
public int StockItemId { get; set; }
|
|
||||||
public string? PartNumber { get; set; }
|
|
||||||
public string? SupplierDescription { get; set; }
|
|
||||||
public decimal? Price { get; set; }
|
|
||||||
public string? Notes { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class UpdateOfferingDto
|
|
||||||
{
|
|
||||||
public string? PartNumber { get; set; }
|
|
||||||
public string? SupplierDescription { get; set; }
|
|
||||||
public decimal? Price { get; set; }
|
|
||||||
public string? Notes { get; set; }
|
|
||||||
}
|
|
||||||
@@ -25,12 +25,10 @@ builder.Services.AddDbContextFactory<ApplicationDbContext>(options =>
|
|||||||
|
|
||||||
// Add application services
|
// Add application services
|
||||||
builder.Services.AddScoped<MaterialService>();
|
builder.Services.AddScoped<MaterialService>();
|
||||||
builder.Services.AddScoped<SupplierService>();
|
|
||||||
builder.Services.AddScoped<StockItemService>();
|
builder.Services.AddScoped<StockItemService>();
|
||||||
builder.Services.AddScoped<JobService>();
|
builder.Services.AddScoped<JobService>();
|
||||||
builder.Services.AddScoped<CutListPackingService>();
|
builder.Services.AddScoped<CutListPackingService>();
|
||||||
builder.Services.AddScoped<ReportService>();
|
builder.Services.AddScoped<ReportService>();
|
||||||
builder.Services.AddScoped<PurchaseItemService>();
|
|
||||||
builder.Services.AddScoped<CatalogService>();
|
builder.Services.AddScoped<CatalogService>();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|||||||
@@ -1,119 +0,0 @@
|
|||||||
using CutList.Web.Data;
|
|
||||||
using CutList.Web.Data.Entities;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace CutList.Web.Services;
|
|
||||||
|
|
||||||
public class PurchaseItemService
|
|
||||||
{
|
|
||||||
private readonly IDbContextFactory<ApplicationDbContext> _factory;
|
|
||||||
|
|
||||||
public PurchaseItemService(IDbContextFactory<ApplicationDbContext> factory)
|
|
||||||
{
|
|
||||||
_factory = factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<List<PurchaseItem>> GetAllAsync(PurchaseItemStatus? status = null)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
|
|
||||||
var query = context.PurchaseItems
|
|
||||||
.Include(p => p.StockItem)
|
|
||||||
.ThenInclude(s => s.Material)
|
|
||||||
.Include(p => p.Supplier)
|
|
||||||
.Include(p => p.Job)
|
|
||||||
.AsQueryable();
|
|
||||||
|
|
||||||
if (status.HasValue)
|
|
||||||
{
|
|
||||||
query = query.Where(p => p.Status == status.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await query
|
|
||||||
.OrderBy(p => p.Status)
|
|
||||||
.ThenByDescending(p => p.CreatedAt)
|
|
||||||
.ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<PurchaseItem?> GetByIdAsync(int id)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
|
|
||||||
return await context.PurchaseItems
|
|
||||||
.Include(p => p.StockItem)
|
|
||||||
.ThenInclude(s => s.Material)
|
|
||||||
.Include(p => p.Supplier)
|
|
||||||
.Include(p => p.Job)
|
|
||||||
.FirstOrDefaultAsync(p => p.Id == id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<PurchaseItem> CreateAsync(PurchaseItem item)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
|
|
||||||
item.CreatedAt = DateTime.UtcNow;
|
|
||||||
context.PurchaseItems.Add(item);
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task CreateBulkAsync(List<PurchaseItem> items)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
item.CreatedAt = now;
|
|
||||||
}
|
|
||||||
context.PurchaseItems.AddRange(items);
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdateAsync(PurchaseItem item)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
|
|
||||||
item.UpdatedAt = DateTime.UtcNow;
|
|
||||||
context.PurchaseItems.Update(item);
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdateStatusAsync(int id, PurchaseItemStatus status)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
|
|
||||||
var item = await context.PurchaseItems.FindAsync(id);
|
|
||||||
if (item != null)
|
|
||||||
{
|
|
||||||
item.Status = status;
|
|
||||||
item.UpdatedAt = DateTime.UtcNow;
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdateSupplierAsync(int id, int? supplierId)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
|
|
||||||
var item = await context.PurchaseItems.FindAsync(id);
|
|
||||||
if (item != null)
|
|
||||||
{
|
|
||||||
item.SupplierId = supplierId;
|
|
||||||
item.UpdatedAt = DateTime.UtcNow;
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteAsync(int id)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
|
|
||||||
var item = await context.PurchaseItems.FindAsync(id);
|
|
||||||
if (item != null)
|
|
||||||
{
|
|
||||||
context.PurchaseItems.Remove(item);
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
using CutList.Web.Data;
|
|
||||||
using CutList.Web.Data.Entities;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace CutList.Web.Services;
|
|
||||||
|
|
||||||
public class SupplierService
|
|
||||||
{
|
|
||||||
private readonly IDbContextFactory<ApplicationDbContext> _factory;
|
|
||||||
|
|
||||||
public SupplierService(IDbContextFactory<ApplicationDbContext> factory)
|
|
||||||
{
|
|
||||||
_factory = factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<List<Supplier>> GetAllAsync(bool includeInactive = false)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
var query = context.Suppliers.AsQueryable();
|
|
||||||
if (!includeInactive)
|
|
||||||
{
|
|
||||||
query = query.Where(s => s.IsActive);
|
|
||||||
}
|
|
||||||
return await query.OrderBy(s => s.Name).ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Supplier?> GetByIdAsync(int id)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
return await context.Suppliers
|
|
||||||
.Include(s => s.Offerings)
|
|
||||||
.ThenInclude(o => o.StockItem)
|
|
||||||
.ThenInclude(si => si.Material)
|
|
||||||
.FirstOrDefaultAsync(s => s.Id == id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Supplier> CreateAsync(Supplier supplier)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
supplier.CreatedAt = DateTime.UtcNow;
|
|
||||||
context.Suppliers.Add(supplier);
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
return supplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdateAsync(Supplier supplier)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
context.Suppliers.Update(supplier);
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteAsync(int id)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
var supplier = await context.Suppliers.FindAsync(id);
|
|
||||||
if (supplier != null)
|
|
||||||
{
|
|
||||||
supplier.IsActive = false;
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Offering management
|
|
||||||
public async Task<List<SupplierOffering>> GetOfferingsForSupplierAsync(int supplierId)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
return await context.SupplierOfferings
|
|
||||||
.Include(o => o.StockItem)
|
|
||||||
.ThenInclude(si => si.Material)
|
|
||||||
.Where(o => o.SupplierId == supplierId && o.IsActive)
|
|
||||||
.OrderBy(o => o.StockItem.Material.Shape)
|
|
||||||
.ThenBy(o => o.StockItem.Material.Size)
|
|
||||||
.ThenBy(o => o.StockItem.LengthInches)
|
|
||||||
.ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<List<SupplierOffering>> GetOfferingsForStockItemAsync(int stockItemId)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
return await context.SupplierOfferings
|
|
||||||
.Include(o => o.Supplier)
|
|
||||||
.Where(o => o.StockItemId == stockItemId && o.IsActive && o.Supplier.IsActive)
|
|
||||||
.OrderBy(o => o.Supplier.Name)
|
|
||||||
.ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<SupplierOffering?> GetOfferingByIdAsync(int id)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
return await context.SupplierOfferings
|
|
||||||
.Include(o => o.StockItem)
|
|
||||||
.ThenInclude(si => si.Material)
|
|
||||||
.Include(o => o.Supplier)
|
|
||||||
.FirstOrDefaultAsync(o => o.Id == id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<SupplierOffering> AddOfferingAsync(SupplierOffering offering)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
context.SupplierOfferings.Add(offering);
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
return offering;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdateOfferingAsync(SupplierOffering offering)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
context.SupplierOfferings.Update(offering);
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteOfferingAsync(int id)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
var offering = await context.SupplierOfferings.FindAsync(id);
|
|
||||||
if (offering != null)
|
|
||||||
{
|
|
||||||
offering.IsActive = false;
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> OfferingExistsAsync(int supplierId, int stockItemId, int? excludeId = null)
|
|
||||||
{
|
|
||||||
await using var context = _factory.CreateDbContext();
|
|
||||||
var query = context.SupplierOfferings.Where(o =>
|
|
||||||
o.SupplierId == supplierId &&
|
|
||||||
o.StockItemId == stockItemId &&
|
|
||||||
o.IsActive);
|
|
||||||
|
|
||||||
if (excludeId.HasValue)
|
|
||||||
{
|
|
||||||
query = query.Where(o => o.Id != excludeId.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await query.AnyAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user