Add inventory management features including Sales, Stock Returns, and Suppliers
- Implement Sale and SaleItem models for tracking sales transactions. - Create StockReturn model to manage stock adjustments for various reasons. - Introduce Supplier model to represent suppliers of products. - Develop InventoryRepository for CRUD operations on products, suppliers, sales, and stock returns. - Implement InventoryService to handle business logic for inventory management. - Update TenantDbContext to include new models and relationships. - Enhance ProfitLossRepository to account for sales, purchases, and stock returns in profit and loss calculations. - Modify Program.cs to register new inventory-related services.
This commit is contained in:
@@ -82,6 +82,16 @@ namespace Fitness_core_BE
|
||||
// Models/BookingInvoice.cs. Deliberately separate from CustomerInvoice (membership-only).
|
||||
public DbSet<BookingInvoice> BookingInvoices => Set<BookingInvoice>();
|
||||
|
||||
// Simple inventory: Products, Suppliers, GRN (stock in), Sales (stock out), Returns
|
||||
// (stock write-offs) -- see each model's own doc comment.
|
||||
public DbSet<Product> Products => Set<Product>();
|
||||
public DbSet<Supplier> Suppliers => Set<Supplier>();
|
||||
public DbSet<GoodsReceivedNote> GoodsReceivedNotes => Set<GoodsReceivedNote>();
|
||||
public DbSet<GoodsReceivedNoteItem> GoodsReceivedNoteItems => Set<GoodsReceivedNoteItem>();
|
||||
public DbSet<Sale> Sales => Set<Sale>();
|
||||
public DbSet<SaleItem> SaleItems => Set<SaleItem>();
|
||||
public DbSet<StockReturn> StockReturns => Set<StockReturn>();
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
@@ -191,6 +201,11 @@ namespace Fitness_core_BE
|
||||
modelBuilder.Entity<BookingInvoice>().Ignore(i => i.Client);
|
||||
modelBuilder.Entity<TimeBankCard>().Ignore(t => t.Client);
|
||||
modelBuilder.Entity<TimeBankCardUsageLog>().Ignore(l => l.Client);
|
||||
modelBuilder.Entity<Product>().Ignore(p => p.Client);
|
||||
modelBuilder.Entity<Supplier>().Ignore(s => s.Client);
|
||||
modelBuilder.Entity<GoodsReceivedNote>().Ignore(g => g.Client);
|
||||
modelBuilder.Entity<Sale>().Ignore(s => s.Client);
|
||||
modelBuilder.Entity<StockReturn>().Ignore(r => r.Client);
|
||||
|
||||
// A session's capacity is enforced by counting non-cancelled bookings against it at
|
||||
// booking time, not by a unique index -- multiple guests/members can share one slot
|
||||
@@ -286,6 +301,45 @@ namespace Fitness_core_BE
|
||||
modelBuilder.Entity<BookingInvoice>()
|
||||
.HasIndex(i => new { i.FKClientId, i.IssuedAt });
|
||||
|
||||
// Inventory: GRN/Sale items cascade with their header; Return/GRN/Sale restrict
|
||||
// deleting a Product/Supplier that already has history (there's no delete endpoint
|
||||
// for either, but Restrict keeps the data model honest either way).
|
||||
modelBuilder.Entity<Product>()
|
||||
.HasIndex(p => new { p.FKClientId, p.Name });
|
||||
modelBuilder.Entity<Supplier>()
|
||||
.HasIndex(s => new { s.FKClientId, s.Name });
|
||||
modelBuilder.Entity<GoodsReceivedNote>()
|
||||
.HasIndex(g => new { g.FKClientId, g.ReceivedAt });
|
||||
modelBuilder.Entity<GoodsReceivedNote>()
|
||||
.HasOne(g => g.Supplier).WithMany()
|
||||
.HasForeignKey(g => g.FKSupplierId).OnDelete(DeleteBehavior.Restrict);
|
||||
modelBuilder.Entity<GoodsReceivedNoteItem>()
|
||||
.HasOne(i => i.Grn).WithMany(g => g.Items)
|
||||
.HasForeignKey(i => i.FKGrnId).OnDelete(DeleteBehavior.Cascade);
|
||||
modelBuilder.Entity<GoodsReceivedNoteItem>()
|
||||
.HasOne(i => i.Product).WithMany()
|
||||
.HasForeignKey(i => i.FKProductId).OnDelete(DeleteBehavior.Restrict);
|
||||
modelBuilder.Entity<Sale>()
|
||||
.HasIndex(s => new { s.FKClientId, s.SoldAt });
|
||||
modelBuilder.Entity<SaleItem>()
|
||||
.HasOne(i => i.Sale).WithMany(s => s.Items)
|
||||
.HasForeignKey(i => i.FKSaleId).OnDelete(DeleteBehavior.Cascade);
|
||||
modelBuilder.Entity<SaleItem>()
|
||||
.HasOne(i => i.Product).WithMany()
|
||||
.HasForeignKey(i => i.FKProductId).OnDelete(DeleteBehavior.Restrict);
|
||||
modelBuilder.Entity<StockReturn>()
|
||||
.HasIndex(r => new { r.FKClientId, r.ReturnedAt });
|
||||
modelBuilder.Entity<StockReturn>()
|
||||
.HasOne(r => r.Product).WithMany()
|
||||
.HasForeignKey(r => r.FKProductId).OnDelete(DeleteBehavior.Restrict);
|
||||
// Optional traceability links -- most returns have neither.
|
||||
modelBuilder.Entity<StockReturn>()
|
||||
.HasOne(r => r.Sale).WithMany()
|
||||
.HasForeignKey(r => r.FKSaleId).OnDelete(DeleteBehavior.Restrict);
|
||||
modelBuilder.Entity<StockReturn>()
|
||||
.HasOne(r => r.Grn).WithMany()
|
||||
.HasForeignKey(r => r.FKGrnId).OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
modelBuilder.Entity<UnlinkedDeviceEnrollment>()
|
||||
.HasIndex(e => new { e.FKDeviceId, e.DeviceEmployeeNo, e.LinkedAt });
|
||||
|
||||
|
||||
Reference in New Issue
Block a user