diff --git a/CutList.Web/Data/ApplicationDbContext.cs b/CutList.Web/Data/ApplicationDbContext.cs index 2a70362..06ace95 100644 --- a/CutList.Web/Data/ApplicationDbContext.cs +++ b/CutList.Web/Data/ApplicationDbContext.cs @@ -11,13 +11,15 @@ public class ApplicationDbContext : DbContext } public DbSet Materials => Set(); - public DbSet MaterialStockLengths => Set(); + public DbSet MaterialDimensions => Set(); public DbSet Suppliers => Set(); public DbSet StockItems => Set(); public DbSet SupplierOfferings => Set(); + public DbSet StockTransactions => Set(); public DbSet CuttingTools => Set(); - public DbSet Projects => Set(); - public DbSet ProjectParts => Set(); + public DbSet Jobs => Set(); + public DbSet JobParts => Set(); + public DbSet JobStocks => Set(); protected override void OnModelCreating(ModelBuilder modelBuilder) { @@ -27,25 +29,119 @@ public class ApplicationDbContext : DbContext modelBuilder.Entity(entity => { entity.HasKey(e => e.Id); - entity.Property(e => e.Shape).HasMaxLength(50).IsRequired(); + entity.Property(e => e.Shape) + .HasMaxLength(50) + .IsRequired() + .HasConversion( + v => v.ToString(), // Enum to string (uses enum name) + v => Enum.Parse(v)); // String to enum entity.Property(e => e.Size).HasMaxLength(100).IsRequired(); + entity.Property(e => e.Type) + .HasMaxLength(20) + .HasConversion( + v => v.ToString(), + v => Enum.Parse(v)); + entity.Property(e => e.Grade).HasMaxLength(50); entity.Property(e => e.Description).HasMaxLength(255); entity.Property(e => e.CreatedAt).HasDefaultValueSql("GETUTCDATE()"); }); - // MaterialStockLength - modelBuilder.Entity(entity => + // MaterialDimensions - TPH inheritance + modelBuilder.Entity(entity => { entity.HasKey(e => e.Id); - entity.Property(e => e.LengthInches).HasPrecision(10, 4); - entity.Property(e => e.Notes).HasMaxLength(255); + // 1:1 relationship with Material entity.HasOne(e => e.Material) - .WithMany(m => m.StockLengths) - .HasForeignKey(e => e.MaterialId) + .WithOne(m => m.Dimensions) + .HasForeignKey(e => e.MaterialId) .OnDelete(DeleteBehavior.Cascade); - entity.HasIndex(e => new { e.MaterialId, e.LengthInches }).IsUnique(); + // TPH discriminator + entity.HasDiscriminator("DimensionType") + .HasValue("RoundBar") + .HasValue("RoundTube") + .HasValue("FlatBar") + .HasValue("SquareBar") + .HasValue("SquareTube") + .HasValue("RectangularTube") + .HasValue("Angle") + .HasValue("Channel") + .HasValue("IBeam") + .HasValue("Pipe"); + }); + + // Configure each dimension type's properties + modelBuilder.Entity(entity => + { + entity.Property(e => e.Diameter).HasPrecision(10, 4); + entity.HasIndex(e => e.Diameter); + }); + + modelBuilder.Entity(entity => + { + entity.Property(e => e.OuterDiameter).HasPrecision(10, 4); + entity.Property(e => e.Wall).HasColumnName("Wall").HasPrecision(10, 4); + entity.HasIndex(e => e.OuterDiameter); + }); + + modelBuilder.Entity(entity => + { + entity.Property(e => e.Width).HasColumnName("Width").HasPrecision(10, 4); + entity.Property(e => e.Thickness).HasColumnName("Thickness").HasPrecision(10, 4); + entity.HasIndex(e => e.Width); + }); + + modelBuilder.Entity(entity => + { + entity.Property(e => e.Size).HasColumnName("Size").HasPrecision(10, 4); + entity.HasIndex(e => e.Size); + }); + + modelBuilder.Entity(entity => + { + entity.Property(e => e.Size).HasColumnName("Size").HasPrecision(10, 4); + entity.Property(e => e.Wall).HasColumnName("Wall").HasPrecision(10, 4); + entity.HasIndex(e => e.Size); + }); + + modelBuilder.Entity(entity => + { + entity.Property(e => e.Width).HasColumnName("Width").HasPrecision(10, 4); + entity.Property(e => e.Height).HasColumnName("Height").HasPrecision(10, 4); + entity.Property(e => e.Wall).HasColumnName("Wall").HasPrecision(10, 4); + entity.HasIndex(e => e.Width); + }); + + modelBuilder.Entity(entity => + { + entity.Property(e => e.Leg1).HasPrecision(10, 4); + entity.Property(e => e.Leg2).HasPrecision(10, 4); + entity.Property(e => e.Thickness).HasColumnName("Thickness").HasPrecision(10, 4); + entity.HasIndex(e => e.Leg1); + }); + + modelBuilder.Entity(entity => + { + entity.Property(e => e.Height).HasColumnName("Height").HasPrecision(10, 4); + entity.Property(e => e.Flange).HasPrecision(10, 4); + entity.Property(e => e.Web).HasPrecision(10, 4); + entity.HasIndex(e => e.Height); + }); + + modelBuilder.Entity(entity => + { + entity.Property(e => e.Height).HasColumnName("Height").HasPrecision(10, 4); + entity.Property(e => e.WeightPerFoot).HasPrecision(10, 4); + entity.HasIndex(e => e.Height); + }); + + modelBuilder.Entity(entity => + { + entity.Property(e => e.NominalSize).HasPrecision(10, 4); + entity.Property(e => e.Wall).HasColumnName("Wall").HasPrecision(10, 4); + entity.Property(e => e.Schedule).HasMaxLength(20); + entity.HasIndex(e => e.NominalSize); }); // Supplier @@ -63,6 +159,7 @@ public class ApplicationDbContext : DbContext entity.HasKey(e => e.Id); entity.Property(e => e.LengthInches).HasPrecision(10, 4); entity.Property(e => e.Name).HasMaxLength(100); + entity.Property(e => e.Notes).HasMaxLength(255); entity.Property(e => e.CreatedAt).HasDefaultValueSql("GETUTCDATE()"); entity.HasOne(e => e.Material) @@ -73,6 +170,30 @@ public class ApplicationDbContext : DbContext entity.HasIndex(e => new { e.MaterialId, e.LengthInches }).IsUnique(); }); + // StockTransaction + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id); + entity.Property(e => e.Notes).HasMaxLength(500); + entity.Property(e => e.UnitPrice).HasPrecision(10, 2); + entity.Property(e => e.CreatedAt).HasDefaultValueSql("GETUTCDATE()"); + + entity.HasOne(e => e.StockItem) + .WithMany(s => s.Transactions) + .HasForeignKey(e => e.StockItemId) + .OnDelete(DeleteBehavior.Cascade); + + entity.HasOne(e => e.Job) + .WithMany() + .HasForeignKey(e => e.JobId) + .OnDelete(DeleteBehavior.SetNull); + + entity.HasOne(e => e.Supplier) + .WithMany() + .HasForeignKey(e => e.SupplierId) + .OnDelete(DeleteBehavior.SetNull); + }); + // SupplierOffering modelBuilder.Entity(entity => { @@ -103,38 +224,63 @@ public class ApplicationDbContext : DbContext entity.Property(e => e.KerfInches).HasPrecision(6, 4); }); - // Project - modelBuilder.Entity(entity => + // Job + modelBuilder.Entity(entity => { entity.HasKey(e => e.Id); - entity.Property(e => e.Name).HasMaxLength(100).IsRequired(); + entity.Property(e => e.JobNumber).HasMaxLength(20).IsRequired(); + entity.Property(e => e.Name).HasMaxLength(100); entity.Property(e => e.Customer).HasMaxLength(100); entity.Property(e => e.CreatedAt).HasDefaultValueSql("GETUTCDATE()"); + entity.HasIndex(e => e.JobNumber).IsUnique(); + entity.HasOne(e => e.CuttingTool) - .WithMany(t => t.Projects) + .WithMany(t => t.Jobs) .HasForeignKey(e => e.CuttingToolId) .OnDelete(DeleteBehavior.SetNull); }); - // ProjectPart - modelBuilder.Entity(entity => + // JobPart + modelBuilder.Entity(entity => { entity.HasKey(e => e.Id); entity.Property(e => e.Name).HasMaxLength(100); entity.Property(e => e.LengthInches).HasPrecision(10, 4); - entity.HasOne(e => e.Project) + entity.HasOne(e => e.Job) .WithMany(p => p.Parts) - .HasForeignKey(e => e.ProjectId) + .HasForeignKey(e => e.JobId) .OnDelete(DeleteBehavior.Cascade); entity.HasOne(e => e.Material) - .WithMany(m => m.ProjectParts) + .WithMany(m => m.JobParts) .HasForeignKey(e => e.MaterialId) .OnDelete(DeleteBehavior.Restrict); }); + // JobStock + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id); + entity.Property(e => e.LengthInches).HasPrecision(10, 4); + + entity.HasOne(e => e.Job) + .WithMany(j => j.Stock) + .HasForeignKey(e => e.JobId) + .OnDelete(DeleteBehavior.Cascade); + + entity.HasOne(e => e.Material) + .WithMany() + .HasForeignKey(e => e.MaterialId) + .OnDelete(DeleteBehavior.Restrict); + + entity.HasOne(e => e.StockItem) + .WithMany() + .HasForeignKey(e => e.StockItemId) + .OnDelete(DeleteBehavior.SetNull); + }); + // Seed default cutting tools modelBuilder.Entity().HasData( new CuttingTool { Id = 1, Name = "Bandsaw", KerfInches = 0.0625m, IsDefault = true, IsActive = true }, diff --git a/CutList.Web/Data/Entities/Material.cs b/CutList.Web/Data/Entities/Material.cs index 93efd84..d17cc4e 100644 --- a/CutList.Web/Data/Entities/Material.cs +++ b/CutList.Web/Data/Entities/Material.cs @@ -3,16 +3,36 @@ namespace CutList.Web.Data.Entities; public class Material { public int Id { get; set; } - public string Shape { get; set; } = string.Empty; + public MaterialShape Shape { get; set; } + + /// + /// Material type (Steel, Aluminum, Stainless, etc.) + /// + public MaterialType Type { get; set; } + + /// + /// Grade or specification (e.g., "A36", "Hot Roll", "304", "6061-T6") + /// + public string? Grade { get; set; } + public string Size { get; set; } = string.Empty; public string? Description { get; set; } public bool IsActive { get; set; } = true; public DateTime CreatedAt { get; set; } = DateTime.UtcNow; public DateTime? UpdatedAt { get; set; } - public ICollection StockItems { get; set; } = new List(); - public ICollection StockLengths { get; set; } = new List(); - public ICollection ProjectParts { get; set; } = new List(); + /// + /// Sort order based on primary dimension (stored as thousandths of an inch for numeric sorting). + /// + public int SortOrder { get; set; } - public string DisplayName => $"{Shape} - {Size}"; + public ICollection StockItems { get; set; } = new List(); + public ICollection JobParts { get; set; } = new List(); + + /// + /// Optional parsed dimensions for decimal-based searching. + /// + public MaterialDimensions? Dimensions { get; set; } + + public string DisplayName => $"{Shape.GetDisplayName()} - {Size}"; } diff --git a/CutList.Web/Data/Entities/StockItem.cs b/CutList.Web/Data/Entities/StockItem.cs index 95d17d3..6aeba92 100644 --- a/CutList.Web/Data/Entities/StockItem.cs +++ b/CutList.Web/Data/Entities/StockItem.cs @@ -6,10 +6,13 @@ public class StockItem public int MaterialId { get; set; } public decimal LengthInches { get; set; } public string? Name { get; set; } + public int QuantityOnHand { get; set; } = 0; + public string? Notes { get; set; } public bool IsActive { get; set; } = true; public DateTime CreatedAt { get; set; } = DateTime.UtcNow; public DateTime? UpdatedAt { get; set; } public Material Material { get; set; } = null!; public ICollection SupplierOfferings { get; set; } = new List(); + public ICollection Transactions { get; set; } = new List(); } diff --git a/CutList.Web/Migrations/ApplicationDbContextModelSnapshot.cs b/CutList.Web/Migrations/ApplicationDbContextModelSnapshot.cs index 93115b3..03e4a70 100644 --- a/CutList.Web/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/CutList.Web/Migrations/ApplicationDbContextModelSnapshot.cs @@ -84,78 +84,7 @@ namespace CutList.Web.Migrations }); }); - modelBuilder.Entity("CutList.Web.Data.Entities.Material", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime2") - .HasDefaultValueSql("GETUTCDATE()"); - - b.Property("Description") - .HasMaxLength(255) - .HasColumnType("nvarchar(255)"); - - b.Property("IsActive") - .HasColumnType("bit"); - - b.Property("Shape") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.Property("Size") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("nvarchar(100)"); - - b.Property("UpdatedAt") - .HasColumnType("datetime2"); - - b.HasKey("Id"); - - b.ToTable("Materials"); - }); - - modelBuilder.Entity("CutList.Web.Data.Entities.MaterialStockLength", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("IsActive") - .HasColumnType("bit"); - - b.Property("LengthInches") - .HasPrecision(10, 4) - .HasColumnType("decimal(10,4)"); - - b.Property("MaterialId") - .HasColumnType("int"); - - b.Property("Notes") - .HasMaxLength(255) - .HasColumnType("nvarchar(255)"); - - b.Property("Quantity") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.HasIndex("MaterialId", "LengthInches") - .IsUnique(); - - b.ToTable("MaterialStockLengths"); - }); - - modelBuilder.Entity("CutList.Web.Data.Entities.Project", b => + modelBuilder.Entity("CutList.Web.Data.Entities.Job", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -175,8 +104,12 @@ namespace CutList.Web.Migrations b.Property("CuttingToolId") .HasColumnType("int"); - b.Property("Name") + b.Property("JobNumber") .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Name") .HasMaxLength(100) .HasColumnType("nvarchar(100)"); @@ -190,10 +123,13 @@ namespace CutList.Web.Migrations b.HasIndex("CuttingToolId"); - b.ToTable("Projects"); + b.HasIndex("JobNumber") + .IsUnique(); + + b.ToTable("Jobs"); }); - modelBuilder.Entity("CutList.Web.Data.Entities.ProjectPart", b => + modelBuilder.Entity("CutList.Web.Data.Entities.JobPart", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -201,6 +137,9 @@ namespace CutList.Web.Migrations SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + b.Property("JobId") + .HasColumnType("int"); + b.Property("LengthInches") .HasPrecision(10, 4) .HasColumnType("decimal(10,4)"); @@ -213,9 +152,6 @@ namespace CutList.Web.Migrations .HasMaxLength(100) .HasColumnType("nvarchar(100)"); - b.Property("ProjectId") - .HasColumnType("int"); - b.Property("Quantity") .HasColumnType("int"); @@ -224,11 +160,133 @@ namespace CutList.Web.Migrations b.HasKey("Id"); + b.HasIndex("JobId"); + b.HasIndex("MaterialId"); - b.HasIndex("ProjectId"); + b.ToTable("JobParts"); + }); - b.ToTable("ProjectParts"); + modelBuilder.Entity("CutList.Web.Data.Entities.JobStock", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("IsCustomLength") + .HasColumnType("bit"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("LengthInches") + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)"); + + b.Property("MaterialId") + .HasColumnType("int"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("Quantity") + .HasColumnType("int"); + + b.Property("SortOrder") + .HasColumnType("int"); + + b.Property("StockItemId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("JobId"); + + b.HasIndex("MaterialId"); + + b.HasIndex("StockItemId"); + + b.ToTable("JobStocks"); + }); + + modelBuilder.Entity("CutList.Web.Data.Entities.Material", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasDefaultValueSql("GETUTCDATE()"); + + b.Property("Description") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Grade") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Shape") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Size") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("SortOrder") + .HasColumnType("int"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("UpdatedAt") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.ToTable("Materials"); + }); + + modelBuilder.Entity("CutList.Web.Data.Entities.MaterialDimensions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DimensionType") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("nvarchar(21)"); + + b.Property("MaterialId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("MaterialId") + .IsUnique(); + + b.ToTable("MaterialDimensions"); + + b.HasDiscriminator("DimensionType").HasValue("MaterialDimensions"); + + b.UseTphMappingStrategy(); }); modelBuilder.Entity("CutList.Web.Data.Entities.StockItem", b => @@ -258,6 +316,13 @@ namespace CutList.Web.Migrations .HasMaxLength(100) .HasColumnType("nvarchar(100)"); + b.Property("Notes") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("QuantityOnHand") + .HasColumnType("int"); + b.Property("UpdatedAt") .HasColumnType("datetime2"); @@ -269,6 +334,53 @@ namespace CutList.Web.Migrations b.ToTable("StockItems"); }); + modelBuilder.Entity("CutList.Web.Data.Entities.StockTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasDefaultValueSql("GETUTCDATE()"); + + b.Property("JobId") + .HasColumnType("int"); + + b.Property("Notes") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Quantity") + .HasColumnType("int"); + + b.Property("StockItemId") + .HasColumnType("int"); + + b.Property("SupplierId") + .HasColumnType("int"); + + b.Property("Type") + .HasColumnType("int"); + + b.Property("UnitPrice") + .HasPrecision(10, 2) + .HasColumnType("decimal(10,2)"); + + b.HasKey("Id"); + + b.HasIndex("JobId"); + + b.HasIndex("StockItemId"); + + b.HasIndex("SupplierId"); + + b.ToTable("StockTransactions"); + }); + modelBuilder.Entity("CutList.Web.Data.Entities.Supplier", b => { b.Property("Id") @@ -345,44 +457,274 @@ namespace CutList.Web.Migrations b.ToTable("SupplierOfferings"); }); - modelBuilder.Entity("CutList.Web.Data.Entities.MaterialStockLength", b => + modelBuilder.Entity("CutList.Web.Data.Entities.AngleDimensions", b => { - b.HasOne("CutList.Web.Data.Entities.Material", "Material") - .WithMany("StockLengths") - .HasForeignKey("MaterialId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); + b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions"); - b.Navigation("Material"); + b.Property("Leg1") + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)"); + + b.Property("Leg2") + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)"); + + b.Property("Thickness") + .ValueGeneratedOnUpdateSometimes() + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)") + .HasColumnName("Thickness"); + + b.HasIndex("Leg1"); + + b.HasDiscriminator().HasValue("Angle"); }); - modelBuilder.Entity("CutList.Web.Data.Entities.Project", b => + modelBuilder.Entity("CutList.Web.Data.Entities.ChannelDimensions", b => + { + b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions"); + + b.Property("Flange") + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)"); + + b.Property("Height") + .ValueGeneratedOnUpdateSometimes() + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)") + .HasColumnName("Height"); + + b.Property("Web") + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)"); + + b.HasIndex("Height"); + + b.HasDiscriminator().HasValue("Channel"); + }); + + modelBuilder.Entity("CutList.Web.Data.Entities.FlatBarDimensions", b => + { + b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions"); + + b.Property("Thickness") + .ValueGeneratedOnUpdateSometimes() + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)") + .HasColumnName("Thickness"); + + b.Property("Width") + .ValueGeneratedOnUpdateSometimes() + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)") + .HasColumnName("Width"); + + b.HasIndex("Width"); + + b.HasDiscriminator().HasValue("FlatBar"); + }); + + modelBuilder.Entity("CutList.Web.Data.Entities.IBeamDimensions", b => + { + b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions"); + + b.Property("Height") + .ValueGeneratedOnUpdateSometimes() + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)") + .HasColumnName("Height"); + + b.Property("WeightPerFoot") + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)"); + + b.HasIndex("Height"); + + b.HasDiscriminator().HasValue("IBeam"); + }); + + modelBuilder.Entity("CutList.Web.Data.Entities.PipeDimensions", b => + { + b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions"); + + b.Property("NominalSize") + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)"); + + b.Property("Schedule") + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Wall") + .ValueGeneratedOnUpdateSometimes() + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)") + .HasColumnName("Wall"); + + b.HasIndex("NominalSize"); + + b.HasDiscriminator().HasValue("Pipe"); + }); + + modelBuilder.Entity("CutList.Web.Data.Entities.RectangularTubeDimensions", b => + { + b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions"); + + b.Property("Height") + .ValueGeneratedOnUpdateSometimes() + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)") + .HasColumnName("Height"); + + b.Property("Wall") + .ValueGeneratedOnUpdateSometimes() + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)") + .HasColumnName("Wall"); + + b.Property("Width") + .ValueGeneratedOnUpdateSometimes() + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)") + .HasColumnName("Width"); + + b.HasIndex("Width"); + + b.HasDiscriminator().HasValue("RectangularTube"); + }); + + modelBuilder.Entity("CutList.Web.Data.Entities.RoundBarDimensions", b => + { + b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions"); + + b.Property("Diameter") + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)"); + + b.HasIndex("Diameter"); + + b.HasDiscriminator().HasValue("RoundBar"); + }); + + modelBuilder.Entity("CutList.Web.Data.Entities.RoundTubeDimensions", b => + { + b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions"); + + b.Property("OuterDiameter") + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)"); + + b.Property("Wall") + .ValueGeneratedOnUpdateSometimes() + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)") + .HasColumnName("Wall"); + + b.HasIndex("OuterDiameter"); + + b.HasDiscriminator().HasValue("RoundTube"); + }); + + modelBuilder.Entity("CutList.Web.Data.Entities.SquareBarDimensions", b => + { + b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions"); + + b.Property("Size") + .ValueGeneratedOnUpdateSometimes() + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)") + .HasColumnName("Size"); + + b.HasIndex("Size"); + + b.HasDiscriminator().HasValue("SquareBar"); + }); + + modelBuilder.Entity("CutList.Web.Data.Entities.SquareTubeDimensions", b => + { + b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions"); + + b.Property("Size") + .ValueGeneratedOnUpdateSometimes() + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)") + .HasColumnName("Size"); + + b.Property("Wall") + .ValueGeneratedOnUpdateSometimes() + .HasPrecision(10, 4) + .HasColumnType("decimal(10,4)") + .HasColumnName("Wall"); + + b.HasIndex("Size"); + + b.HasDiscriminator().HasValue("SquareTube"); + }); + + modelBuilder.Entity("CutList.Web.Data.Entities.Job", b => { b.HasOne("CutList.Web.Data.Entities.CuttingTool", "CuttingTool") - .WithMany("Projects") + .WithMany("Jobs") .HasForeignKey("CuttingToolId") .OnDelete(DeleteBehavior.SetNull); b.Navigation("CuttingTool"); }); - modelBuilder.Entity("CutList.Web.Data.Entities.ProjectPart", b => + modelBuilder.Entity("CutList.Web.Data.Entities.JobPart", b => { + b.HasOne("CutList.Web.Data.Entities.Job", "Job") + .WithMany("Parts") + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.HasOne("CutList.Web.Data.Entities.Material", "Material") - .WithMany("ProjectParts") + .WithMany("JobParts") .HasForeignKey("MaterialId") .OnDelete(DeleteBehavior.Restrict) .IsRequired(); - b.HasOne("CutList.Web.Data.Entities.Project", "Project") - .WithMany("Parts") - .HasForeignKey("ProjectId") + b.Navigation("Job"); + + b.Navigation("Material"); + }); + + modelBuilder.Entity("CutList.Web.Data.Entities.JobStock", b => + { + b.HasOne("CutList.Web.Data.Entities.Job", "Job") + .WithMany("Stock") + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("CutList.Web.Data.Entities.Material", "Material") + .WithMany() + .HasForeignKey("MaterialId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("CutList.Web.Data.Entities.StockItem", "StockItem") + .WithMany() + .HasForeignKey("StockItemId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Job"); + + b.Navigation("Material"); + + b.Navigation("StockItem"); + }); + + modelBuilder.Entity("CutList.Web.Data.Entities.MaterialDimensions", b => + { + b.HasOne("CutList.Web.Data.Entities.Material", "Material") + .WithOne("Dimensions") + .HasForeignKey("CutList.Web.Data.Entities.MaterialDimensions", "MaterialId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("Material"); - - b.Navigation("Project"); }); modelBuilder.Entity("CutList.Web.Data.Entities.StockItem", b => @@ -396,6 +738,31 @@ namespace CutList.Web.Migrations b.Navigation("Material"); }); + modelBuilder.Entity("CutList.Web.Data.Entities.StockTransaction", b => + { + b.HasOne("CutList.Web.Data.Entities.Job", "Job") + .WithMany() + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("CutList.Web.Data.Entities.StockItem", "StockItem") + .WithMany("Transactions") + .HasForeignKey("StockItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("CutList.Web.Data.Entities.Supplier", "Supplier") + .WithMany() + .HasForeignKey("SupplierId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Job"); + + b.Navigation("StockItem"); + + b.Navigation("Supplier"); + }); + modelBuilder.Entity("CutList.Web.Data.Entities.SupplierOffering", b => { b.HasOne("CutList.Web.Data.Entities.StockItem", "StockItem") @@ -417,26 +784,30 @@ namespace CutList.Web.Migrations modelBuilder.Entity("CutList.Web.Data.Entities.CuttingTool", b => { - b.Navigation("Projects"); + b.Navigation("Jobs"); + }); + + modelBuilder.Entity("CutList.Web.Data.Entities.Job", b => + { + b.Navigation("Parts"); + + b.Navigation("Stock"); }); modelBuilder.Entity("CutList.Web.Data.Entities.Material", b => { - b.Navigation("ProjectParts"); + b.Navigation("Dimensions"); + + b.Navigation("JobParts"); b.Navigation("StockItems"); - - b.Navigation("StockLengths"); - }); - - modelBuilder.Entity("CutList.Web.Data.Entities.Project", b => - { - b.Navigation("Parts"); }); modelBuilder.Entity("CutList.Web.Data.Entities.StockItem", b => { b.Navigation("SupplierOfferings"); + + b.Navigation("Transactions"); }); modelBuilder.Entity("CutList.Web.Data.Entities.Supplier", b =>