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
|
||||
builder.Services.AddScoped<MaterialService>();
|
||||
builder.Services.AddScoped<SupplierService>();
|
||||
builder.Services.AddScoped<StockItemService>();
|
||||
builder.Services.AddScoped<JobService>();
|
||||
builder.Services.AddScoped<CutListPackingService>();
|
||||
builder.Services.AddScoped<ReportService>();
|
||||
builder.Services.AddScoped<PurchaseItemService>();
|
||||
builder.Services.AddScoped<CatalogService>();
|
||||
|
||||
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