Compare commits
3 Commits
dac2833dd1
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 7d3c92226c | |||
| c31769a746 | |||
| f04bf02c42 |
@@ -88,8 +88,8 @@ dotnet clean CutList.sln
|
||||
- **DisplayName**: "{Shape} - {Size}"
|
||||
- **Relationships**: `Dimensions` (1:1 MaterialDimensions), `StockItems` (1:many), `JobParts` (1:many)
|
||||
|
||||
### MaterialDimensions (TPH Inheritance)
|
||||
Abstract base; derived types per shape: `RoundBarDimensions`, `RoundTubeDimensions`, `FlatBarDimensions`, `SquareBarDimensions`, `SquareTubeDimensions`, `RectangularTubeDimensions`, `AngleDimensions`, `ChannelDimensions`, `IBeamDimensions`, `PipeDimensions`. Each generates its own `SizeString` and `SortOrder`.
|
||||
### MaterialDimensions (TPC Inheritance)
|
||||
Abstract base with TPC (Table Per Concrete type) mapping — each shape gets its own standalone table (`DimAngle`, `DimChannel`, `DimFlatBar`, `DimIBeam`, `DimPipe`, `DimRectangularTube`, `DimRoundBar`, `DimRoundTube`, `DimSquareBar`, `DimSquareTube`) with no base table. Each table has its own `Id` (shared sequence) and `MaterialId` FK. Each generates its own `SizeString` and `SortOrder`.
|
||||
|
||||
### StockItem
|
||||
- `MaterialId`, `LengthInches` (decimal), `QuantityOnHand` (int), `IsActive`
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -5,7 +5,7 @@ public class CatalogData
|
||||
public DateTime ExportedAt { get; set; }
|
||||
public List<CatalogSupplierDto> Suppliers { get; set; } = [];
|
||||
public List<CatalogCuttingToolDto> CuttingTools { get; set; } = [];
|
||||
public List<CatalogMaterialDto> Materials { get; set; } = [];
|
||||
public CatalogMaterialsDto Materials { get; set; } = new();
|
||||
}
|
||||
|
||||
public class CatalogSupplierDto
|
||||
@@ -22,35 +22,91 @@ public class CatalogCuttingToolDto
|
||||
public bool IsDefault { get; set; }
|
||||
}
|
||||
|
||||
public class CatalogMaterialDto
|
||||
public class CatalogMaterialsDto
|
||||
{
|
||||
public List<CatalogAngleDto> Angles { get; set; } = [];
|
||||
public List<CatalogChannelDto> Channels { get; set; } = [];
|
||||
public List<CatalogFlatBarDto> FlatBars { get; set; } = [];
|
||||
public List<CatalogIBeamDto> IBeams { get; set; } = [];
|
||||
public List<CatalogPipeDto> Pipes { get; set; } = [];
|
||||
public List<CatalogRectangularTubeDto> RectangularTubes { get; set; } = [];
|
||||
public List<CatalogRoundBarDto> RoundBars { get; set; } = [];
|
||||
public List<CatalogRoundTubeDto> RoundTubes { get; set; } = [];
|
||||
public List<CatalogSquareBarDto> SquareBars { get; set; } = [];
|
||||
public List<CatalogSquareTubeDto> SquareTubes { get; set; } = [];
|
||||
}
|
||||
|
||||
public abstract class CatalogMaterialBaseDto
|
||||
{
|
||||
public string Shape { get; set; } = "";
|
||||
public string Type { get; set; } = "";
|
||||
public string? Grade { get; set; }
|
||||
public string Size { get; set; } = "";
|
||||
public string? Description { get; set; }
|
||||
public CatalogDimensionsDto? Dimensions { get; set; }
|
||||
public List<CatalogStockItemDto> StockItems { get; set; } = [];
|
||||
}
|
||||
|
||||
public class CatalogDimensionsDto
|
||||
public class CatalogAngleDto : CatalogMaterialBaseDto
|
||||
{
|
||||
public decimal? Diameter { get; set; }
|
||||
public decimal? OuterDiameter { get; set; }
|
||||
public decimal? Width { get; set; }
|
||||
public decimal? Height { get; set; }
|
||||
public decimal? Thickness { get; set; }
|
||||
public decimal? Wall { get; set; }
|
||||
public decimal? Size { get; set; }
|
||||
public decimal? Leg1 { get; set; }
|
||||
public decimal? Leg2 { get; set; }
|
||||
public decimal? Flange { get; set; }
|
||||
public decimal? Web { get; set; }
|
||||
public decimal? WeightPerFoot { get; set; }
|
||||
public decimal? NominalSize { get; set; }
|
||||
public decimal Leg1 { get; set; }
|
||||
public decimal Leg2 { get; set; }
|
||||
public decimal Thickness { get; set; }
|
||||
}
|
||||
|
||||
public class CatalogChannelDto : CatalogMaterialBaseDto
|
||||
{
|
||||
public decimal Height { get; set; }
|
||||
public decimal Flange { get; set; }
|
||||
public decimal Web { get; set; }
|
||||
}
|
||||
|
||||
public class CatalogFlatBarDto : CatalogMaterialBaseDto
|
||||
{
|
||||
public decimal Width { get; set; }
|
||||
public decimal Thickness { get; set; }
|
||||
}
|
||||
|
||||
public class CatalogIBeamDto : CatalogMaterialBaseDto
|
||||
{
|
||||
public decimal Height { get; set; }
|
||||
public decimal WeightPerFoot { get; set; }
|
||||
}
|
||||
|
||||
public class CatalogPipeDto : CatalogMaterialBaseDto
|
||||
{
|
||||
public decimal NominalSize { get; set; }
|
||||
public decimal Wall { get; set; }
|
||||
public string? Schedule { get; set; }
|
||||
}
|
||||
|
||||
public class CatalogRectangularTubeDto : CatalogMaterialBaseDto
|
||||
{
|
||||
public decimal Width { get; set; }
|
||||
public decimal Height { get; set; }
|
||||
public decimal Wall { get; set; }
|
||||
}
|
||||
|
||||
public class CatalogRoundBarDto : CatalogMaterialBaseDto
|
||||
{
|
||||
public decimal Diameter { get; set; }
|
||||
}
|
||||
|
||||
public class CatalogRoundTubeDto : CatalogMaterialBaseDto
|
||||
{
|
||||
public decimal OuterDiameter { get; set; }
|
||||
public decimal Wall { get; set; }
|
||||
}
|
||||
|
||||
public class CatalogSquareBarDto : CatalogMaterialBaseDto
|
||||
{
|
||||
public decimal SideLength { get; set; }
|
||||
}
|
||||
|
||||
public class CatalogSquareTubeDto : CatalogMaterialBaseDto
|
||||
{
|
||||
public decimal SideLength { get; set; }
|
||||
public decimal Wall { get; set; }
|
||||
}
|
||||
|
||||
public class CatalogStockItemDto
|
||||
{
|
||||
public decimal LengthInches { get; set; }
|
||||
|
||||
@@ -47,84 +47,80 @@ public class ApplicationDbContext : DbContext
|
||||
entity.Property(e => e.CreatedAt).HasDefaultValueSql("GETUTCDATE()");
|
||||
});
|
||||
|
||||
// MaterialDimensions - TPH inheritance
|
||||
// MaterialDimensions - TPC inheritance (each shape gets its own table, no base table)
|
||||
modelBuilder.Entity<MaterialDimensions>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id);
|
||||
entity.UseTpcMappingStrategy();
|
||||
|
||||
// 1:1 relationship with Material
|
||||
entity.HasOne(e => e.Material)
|
||||
.WithOne(m => m.Dimensions)
|
||||
.HasForeignKey<MaterialDimensions>(e => e.MaterialId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
// TPH discriminator
|
||||
entity.HasDiscriminator<string>("DimensionType")
|
||||
.HasValue<RoundBarDimensions>("RoundBar")
|
||||
.HasValue<RoundTubeDimensions>("RoundTube")
|
||||
.HasValue<FlatBarDimensions>("FlatBar")
|
||||
.HasValue<SquareBarDimensions>("SquareBar")
|
||||
.HasValue<SquareTubeDimensions>("SquareTube")
|
||||
.HasValue<RectangularTubeDimensions>("RectangularTube")
|
||||
.HasValue<AngleDimensions>("Angle")
|
||||
.HasValue<ChannelDimensions>("Channel")
|
||||
.HasValue<IBeamDimensions>("IBeam")
|
||||
.HasValue<PipeDimensions>("Pipe");
|
||||
});
|
||||
|
||||
// Configure each dimension type's properties
|
||||
modelBuilder.Entity<RoundBarDimensions>(entity =>
|
||||
{
|
||||
entity.ToTable("DimRoundBar");
|
||||
entity.Property(e => e.Diameter).HasPrecision(10, 4);
|
||||
entity.HasIndex(e => e.Diameter);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<RoundTubeDimensions>(entity =>
|
||||
{
|
||||
entity.ToTable("DimRoundTube");
|
||||
entity.Property(e => e.OuterDiameter).HasPrecision(10, 4);
|
||||
entity.Property(e => e.Wall).HasColumnName("Wall").HasPrecision(10, 4);
|
||||
entity.Property(e => e.Wall).HasPrecision(10, 4);
|
||||
entity.HasIndex(e => e.OuterDiameter);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<FlatBarDimensions>(entity =>
|
||||
{
|
||||
entity.Property(e => e.Width).HasColumnName("Width").HasPrecision(10, 4);
|
||||
entity.Property(e => e.Thickness).HasColumnName("Thickness").HasPrecision(10, 4);
|
||||
entity.ToTable("DimFlatBar");
|
||||
entity.Property(e => e.Width).HasPrecision(10, 4);
|
||||
entity.Property(e => e.Thickness).HasPrecision(10, 4);
|
||||
entity.HasIndex(e => e.Width);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<SquareBarDimensions>(entity =>
|
||||
{
|
||||
entity.Property(e => e.Size).HasColumnName("Size").HasPrecision(10, 4);
|
||||
entity.ToTable("DimSquareBar");
|
||||
entity.Property(e => e.Size).HasPrecision(10, 4);
|
||||
entity.HasIndex(e => e.Size);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<SquareTubeDimensions>(entity =>
|
||||
{
|
||||
entity.Property(e => e.Size).HasColumnName("Size").HasPrecision(10, 4);
|
||||
entity.Property(e => e.Wall).HasColumnName("Wall").HasPrecision(10, 4);
|
||||
entity.ToTable("DimSquareTube");
|
||||
entity.Property(e => e.Size).HasPrecision(10, 4);
|
||||
entity.Property(e => e.Wall).HasPrecision(10, 4);
|
||||
entity.HasIndex(e => e.Size);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<RectangularTubeDimensions>(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.ToTable("DimRectangularTube");
|
||||
entity.Property(e => e.Width).HasPrecision(10, 4);
|
||||
entity.Property(e => e.Height).HasPrecision(10, 4);
|
||||
entity.Property(e => e.Wall).HasPrecision(10, 4);
|
||||
entity.HasIndex(e => e.Width);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<AngleDimensions>(entity =>
|
||||
{
|
||||
entity.ToTable("DimAngle");
|
||||
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.Property(e => e.Thickness).HasPrecision(10, 4);
|
||||
entity.HasIndex(e => e.Leg1);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<ChannelDimensions>(entity =>
|
||||
{
|
||||
entity.Property(e => e.Height).HasColumnName("Height").HasPrecision(10, 4);
|
||||
entity.ToTable("DimChannel");
|
||||
entity.Property(e => e.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);
|
||||
@@ -132,15 +128,17 @@ public class ApplicationDbContext : DbContext
|
||||
|
||||
modelBuilder.Entity<IBeamDimensions>(entity =>
|
||||
{
|
||||
entity.Property(e => e.Height).HasColumnName("Height").HasPrecision(10, 4);
|
||||
entity.ToTable("DimIBeam");
|
||||
entity.Property(e => e.Height).HasPrecision(10, 4);
|
||||
entity.Property(e => e.WeightPerFoot).HasPrecision(10, 4);
|
||||
entity.HasIndex(e => e.Height);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<PipeDimensions>(entity =>
|
||||
{
|
||||
entity.ToTable("DimPipe");
|
||||
entity.Property(e => e.NominalSize).HasPrecision(10, 4);
|
||||
entity.Property(e => e.Wall).HasColumnName("Wall").HasPrecision(10, 4);
|
||||
entity.Property(e => e.Wall).HasPrecision(10, 4);
|
||||
entity.Property(e => e.Schedule).HasMaxLength(20);
|
||||
entity.HasIndex(e => e.NominalSize);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"exportedAt": "2026-02-16T17:09:52.843008+00:00",
|
||||
"suppliers": [
|
||||
{
|
||||
"name": "Alro Steel"
|
||||
}
|
||||
],
|
||||
"cuttingTools": [
|
||||
{
|
||||
"name": "Bandsaw",
|
||||
"kerfInches": 0.0625,
|
||||
"isDefault": true
|
||||
},
|
||||
{
|
||||
"name": "Chop Saw",
|
||||
"kerfInches": 0.125,
|
||||
"isDefault": false
|
||||
},
|
||||
{
|
||||
"name": "Cold Cut Saw",
|
||||
"kerfInches": 0.0625,
|
||||
"isDefault": false
|
||||
},
|
||||
{
|
||||
"name": "Hacksaw",
|
||||
"kerfInches": 0.0625,
|
||||
"isDefault": false
|
||||
}
|
||||
],
|
||||
"materials": {
|
||||
"angles": [],
|
||||
"channels": [],
|
||||
"flatBars": [],
|
||||
"iBeams": [],
|
||||
"pipes": [],
|
||||
"rectangularTubes": [],
|
||||
"roundBars": [],
|
||||
"roundTubes": [],
|
||||
"squareBars": [],
|
||||
"squareTubes": []
|
||||
}
|
||||
}
|
||||
+13461
-15259
File diff suppressed because it is too large
Load Diff
+962
@@ -0,0 +1,962 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using CutList.Web.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace CutList.Web.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20260216183131_MaterialDimensionsTPHtoTPT")]
|
||||
partial class MaterialDimensionsTPHtoTPT
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.11")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.CuttingTool", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<bool>("IsDefault")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<decimal>("KerfInches")
|
||||
.HasPrecision(6, 4)
|
||||
.HasColumnType("decimal(6,4)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CuttingTools");
|
||||
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = 1,
|
||||
IsActive = true,
|
||||
IsDefault = true,
|
||||
KerfInches = 0.0625m,
|
||||
Name = "Bandsaw"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 2,
|
||||
IsActive = true,
|
||||
IsDefault = false,
|
||||
KerfInches = 0.125m,
|
||||
Name = "Chop Saw"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 3,
|
||||
IsActive = true,
|
||||
IsDefault = false,
|
||||
KerfInches = 0.0625m,
|
||||
Name = "Cold Cut Saw"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 4,
|
||||
IsActive = true,
|
||||
IsDefault = false,
|
||||
KerfInches = 0.0625m,
|
||||
Name = "Hacksaw"
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.Job", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<string>("Customer")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<int?>("CuttingToolId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("JobNumber")
|
||||
.IsRequired()
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<DateTime?>("LockedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("OptimizationResultJson")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime?>("OptimizedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CuttingToolId");
|
||||
|
||||
b.HasIndex("JobNumber")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Jobs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.JobPart", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("JobId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("LengthInches")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<int>("MaterialId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("JobId");
|
||||
|
||||
b.HasIndex("MaterialId");
|
||||
|
||||
b.ToTable("JobParts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.JobStock", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("IsCustomLength")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<int>("JobId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("LengthInches")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<int>("MaterialId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Priority")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("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<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("nvarchar(255)");
|
||||
|
||||
b.Property<string>("Grade")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Shape")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("Size")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Materials");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.MaterialDimensions", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("MaterialId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("MaterialId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("MaterialDimensions");
|
||||
|
||||
b.UseTptMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.PurchaseItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<int?>("JobId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<int>("StockItemId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("SupplierId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("JobId");
|
||||
|
||||
b.HasIndex("StockItemId");
|
||||
|
||||
b.HasIndex("SupplierId");
|
||||
|
||||
b.ToTable("PurchaseItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.StockItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<decimal>("LengthInches")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<int>("MaterialId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("nvarchar(255)");
|
||||
|
||||
b.Property<int>("QuantityOnHand")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("MaterialId", "LengthInches")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("StockItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.StockTransaction", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<int?>("JobId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("StockItemId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("SupplierId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal?>("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<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("ContactInfo")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Suppliers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.SupplierOffering", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("nvarchar(255)");
|
||||
|
||||
b.Property<string>("PartNumber")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<decimal?>("Price")
|
||||
.HasPrecision(10, 2)
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<int>("StockItemId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("SupplierDescription")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("nvarchar(255)");
|
||||
|
||||
b.Property<int>("SupplierId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("StockItemId");
|
||||
|
||||
b.HasIndex("SupplierId", "StockItemId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("SupplierOfferings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.AngleDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Leg1")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Leg2")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Thickness")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Leg1");
|
||||
|
||||
b.ToTable("AngleDimensions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.ChannelDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Flange")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Height")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Web")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Height");
|
||||
|
||||
b.ToTable("ChannelDimensions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.FlatBarDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Thickness")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Width")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Width");
|
||||
|
||||
b.ToTable("FlatBarDimensions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.IBeamDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Height")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("WeightPerFoot")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Height");
|
||||
|
||||
b.ToTable("IBeamDimensions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.PipeDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("NominalSize")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<string>("Schedule")
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<decimal?>("Wall")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("NominalSize");
|
||||
|
||||
b.ToTable("PipeDimensions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RectangularTubeDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Height")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Wall")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Width")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Width");
|
||||
|
||||
b.ToTable("RectangularTubeDimensions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RoundBarDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Diameter")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Diameter");
|
||||
|
||||
b.ToTable("RoundBarDimensions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RoundTubeDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("OuterDiameter")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Wall")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("OuterDiameter");
|
||||
|
||||
b.ToTable("RoundTubeDimensions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.SquareBarDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Size")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Size");
|
||||
|
||||
b.ToTable("SquareBarDimensions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.SquareTubeDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Size")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Wall")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Size");
|
||||
|
||||
b.ToTable("SquareTubeDimensions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.Job", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.CuttingTool", "CuttingTool")
|
||||
.WithMany("Jobs")
|
||||
.HasForeignKey("CuttingToolId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.Navigation("CuttingTool");
|
||||
});
|
||||
|
||||
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("JobParts")
|
||||
.HasForeignKey("MaterialId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
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");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.PurchaseItem", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.Job", "Job")
|
||||
.WithMany()
|
||||
.HasForeignKey("JobId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("CutList.Web.Data.Entities.StockItem", "StockItem")
|
||||
.WithMany()
|
||||
.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.StockItem", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.Material", "Material")
|
||||
.WithMany("StockItems")
|
||||
.HasForeignKey("MaterialId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
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")
|
||||
.WithMany("SupplierOfferings")
|
||||
.HasForeignKey("StockItemId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CutList.Web.Data.Entities.Supplier", "Supplier")
|
||||
.WithMany("Offerings")
|
||||
.HasForeignKey("SupplierId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("StockItem");
|
||||
|
||||
b.Navigation("Supplier");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.AngleDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.AngleDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.ChannelDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.ChannelDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.FlatBarDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.FlatBarDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.IBeamDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.IBeamDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.PipeDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.PipeDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RectangularTubeDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.RectangularTubeDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RoundBarDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.RoundBarDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RoundTubeDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.RoundTubeDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.SquareBarDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.SquareBarDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.SquareTubeDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.SquareTubeDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.CuttingTool", b =>
|
||||
{
|
||||
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("Dimensions");
|
||||
|
||||
b.Navigation("JobParts");
|
||||
|
||||
b.Navigation("StockItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.StockItem", b =>
|
||||
{
|
||||
b.Navigation("SupplierOfferings");
|
||||
|
||||
b.Navigation("Transactions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.Supplier", b =>
|
||||
{
|
||||
b.Navigation("Offerings");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,353 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace CutList.Web.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class MaterialDimensionsTPHtoTPT : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
// 1. Create the new TPT tables first (before dropping any columns)
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AngleDimensions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false),
|
||||
Leg1 = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false),
|
||||
Leg2 = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false),
|
||||
Thickness = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AngleDimensions", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AngleDimensions_MaterialDimensions_Id",
|
||||
column: x => x.Id,
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ChannelDimensions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false),
|
||||
Height = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false),
|
||||
Flange = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false),
|
||||
Web = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ChannelDimensions", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_ChannelDimensions_MaterialDimensions_Id",
|
||||
column: x => x.Id,
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "FlatBarDimensions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false),
|
||||
Width = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false),
|
||||
Thickness = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_FlatBarDimensions", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_FlatBarDimensions_MaterialDimensions_Id",
|
||||
column: x => x.Id,
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "IBeamDimensions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false),
|
||||
Height = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false),
|
||||
WeightPerFoot = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_IBeamDimensions", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_IBeamDimensions_MaterialDimensions_Id",
|
||||
column: x => x.Id,
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PipeDimensions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false),
|
||||
NominalSize = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false),
|
||||
Wall = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: true),
|
||||
Schedule = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PipeDimensions", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_PipeDimensions_MaterialDimensions_Id",
|
||||
column: x => x.Id,
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "RectangularTubeDimensions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false),
|
||||
Width = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false),
|
||||
Height = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false),
|
||||
Wall = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_RectangularTubeDimensions", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_RectangularTubeDimensions_MaterialDimensions_Id",
|
||||
column: x => x.Id,
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "RoundBarDimensions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false),
|
||||
Diameter = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_RoundBarDimensions", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_RoundBarDimensions_MaterialDimensions_Id",
|
||||
column: x => x.Id,
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "RoundTubeDimensions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false),
|
||||
OuterDiameter = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false),
|
||||
Wall = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_RoundTubeDimensions", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_RoundTubeDimensions_MaterialDimensions_Id",
|
||||
column: x => x.Id,
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "SquareBarDimensions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false),
|
||||
Size = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_SquareBarDimensions", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_SquareBarDimensions_MaterialDimensions_Id",
|
||||
column: x => x.Id,
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "SquareTubeDimensions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false),
|
||||
Size = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false),
|
||||
Wall = table.Column<decimal>(type: "decimal(10,4)", precision: 10, scale: 4, nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_SquareTubeDimensions", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_SquareTubeDimensions_MaterialDimensions_Id",
|
||||
column: x => x.Id,
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
// 2. Migrate existing data from the TPH table into the new TPT tables
|
||||
migrationBuilder.Sql(@"
|
||||
INSERT INTO RoundBarDimensions (Id, Diameter)
|
||||
SELECT Id, ISNULL(Diameter, 0) FROM MaterialDimensions WHERE DimensionType = 'RoundBar';
|
||||
|
||||
INSERT INTO RoundTubeDimensions (Id, OuterDiameter, Wall)
|
||||
SELECT Id, ISNULL(OuterDiameter, 0), ISNULL(Wall, 0) FROM MaterialDimensions WHERE DimensionType = 'RoundTube';
|
||||
|
||||
INSERT INTO FlatBarDimensions (Id, Width, Thickness)
|
||||
SELECT Id, ISNULL(Width, 0), ISNULL(Thickness, 0) FROM MaterialDimensions WHERE DimensionType = 'FlatBar';
|
||||
|
||||
INSERT INTO SquareBarDimensions (Id, Size)
|
||||
SELECT Id, ISNULL(Size, 0) FROM MaterialDimensions WHERE DimensionType = 'SquareBar';
|
||||
|
||||
INSERT INTO SquareTubeDimensions (Id, Size, Wall)
|
||||
SELECT Id, ISNULL(Size, 0), ISNULL(Wall, 0) FROM MaterialDimensions WHERE DimensionType = 'SquareTube';
|
||||
|
||||
INSERT INTO RectangularTubeDimensions (Id, Width, Height, Wall)
|
||||
SELECT Id, ISNULL(Width, 0), ISNULL(Height, 0), ISNULL(Wall, 0) FROM MaterialDimensions WHERE DimensionType = 'RectangularTube';
|
||||
|
||||
INSERT INTO AngleDimensions (Id, Leg1, Leg2, Thickness)
|
||||
SELECT Id, ISNULL(Leg1, 0), ISNULL(Leg2, 0), ISNULL(Thickness, 0) FROM MaterialDimensions WHERE DimensionType = 'Angle';
|
||||
|
||||
INSERT INTO ChannelDimensions (Id, Height, Flange, Web)
|
||||
SELECT Id, ISNULL(Height, 0), ISNULL(Flange, 0), ISNULL(Web, 0) FROM MaterialDimensions WHERE DimensionType = 'Channel';
|
||||
|
||||
INSERT INTO IBeamDimensions (Id, Height, WeightPerFoot)
|
||||
SELECT Id, ISNULL(Height, 0), ISNULL(WeightPerFoot, 0) FROM MaterialDimensions WHERE DimensionType = 'IBeam';
|
||||
|
||||
INSERT INTO PipeDimensions (Id, NominalSize, Wall, Schedule)
|
||||
SELECT Id, ISNULL(NominalSize, 0), Wall, Schedule FROM MaterialDimensions WHERE DimensionType = 'Pipe';
|
||||
");
|
||||
|
||||
// 3. Now drop the old TPH columns and indexes
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_MaterialDimensions_Diameter",
|
||||
table: "MaterialDimensions");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_MaterialDimensions_Height",
|
||||
table: "MaterialDimensions");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_MaterialDimensions_Leg1",
|
||||
table: "MaterialDimensions");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_MaterialDimensions_NominalSize",
|
||||
table: "MaterialDimensions");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_MaterialDimensions_OuterDiameter",
|
||||
table: "MaterialDimensions");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_MaterialDimensions_Size",
|
||||
table: "MaterialDimensions");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_MaterialDimensions_Width",
|
||||
table: "MaterialDimensions");
|
||||
|
||||
migrationBuilder.DropColumn(name: "Diameter", table: "MaterialDimensions");
|
||||
migrationBuilder.DropColumn(name: "DimensionType", table: "MaterialDimensions");
|
||||
migrationBuilder.DropColumn(name: "Flange", table: "MaterialDimensions");
|
||||
migrationBuilder.DropColumn(name: "Height", table: "MaterialDimensions");
|
||||
migrationBuilder.DropColumn(name: "Leg1", table: "MaterialDimensions");
|
||||
migrationBuilder.DropColumn(name: "Leg2", table: "MaterialDimensions");
|
||||
migrationBuilder.DropColumn(name: "NominalSize", table: "MaterialDimensions");
|
||||
migrationBuilder.DropColumn(name: "OuterDiameter", table: "MaterialDimensions");
|
||||
migrationBuilder.DropColumn(name: "Schedule", table: "MaterialDimensions");
|
||||
migrationBuilder.DropColumn(name: "Size", table: "MaterialDimensions");
|
||||
migrationBuilder.DropColumn(name: "Thickness", table: "MaterialDimensions");
|
||||
migrationBuilder.DropColumn(name: "Wall", table: "MaterialDimensions");
|
||||
migrationBuilder.DropColumn(name: "Web", table: "MaterialDimensions");
|
||||
migrationBuilder.DropColumn(name: "WeightPerFoot", table: "MaterialDimensions");
|
||||
migrationBuilder.DropColumn(name: "Width", table: "MaterialDimensions");
|
||||
|
||||
// 4. Create indexes on the new tables
|
||||
migrationBuilder.CreateIndex(name: "IX_AngleDimensions_Leg1", table: "AngleDimensions", column: "Leg1");
|
||||
migrationBuilder.CreateIndex(name: "IX_ChannelDimensions_Height", table: "ChannelDimensions", column: "Height");
|
||||
migrationBuilder.CreateIndex(name: "IX_FlatBarDimensions_Width", table: "FlatBarDimensions", column: "Width");
|
||||
migrationBuilder.CreateIndex(name: "IX_IBeamDimensions_Height", table: "IBeamDimensions", column: "Height");
|
||||
migrationBuilder.CreateIndex(name: "IX_PipeDimensions_NominalSize", table: "PipeDimensions", column: "NominalSize");
|
||||
migrationBuilder.CreateIndex(name: "IX_RectangularTubeDimensions_Width", table: "RectangularTubeDimensions", column: "Width");
|
||||
migrationBuilder.CreateIndex(name: "IX_RoundBarDimensions_Diameter", table: "RoundBarDimensions", column: "Diameter");
|
||||
migrationBuilder.CreateIndex(name: "IX_RoundTubeDimensions_OuterDiameter", table: "RoundTubeDimensions", column: "OuterDiameter");
|
||||
migrationBuilder.CreateIndex(name: "IX_SquareBarDimensions_Size", table: "SquareBarDimensions", column: "Size");
|
||||
migrationBuilder.CreateIndex(name: "IX_SquareTubeDimensions_Size", table: "SquareTubeDimensions", column: "Size");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
// Re-add the TPH columns
|
||||
migrationBuilder.AddColumn<string>(name: "DimensionType", table: "MaterialDimensions", type: "nvarchar(21)", maxLength: 21, nullable: false, defaultValue: "");
|
||||
migrationBuilder.AddColumn<decimal>(name: "Diameter", table: "MaterialDimensions", type: "decimal(10,4)", precision: 10, scale: 4, nullable: true);
|
||||
migrationBuilder.AddColumn<decimal>(name: "Flange", table: "MaterialDimensions", type: "decimal(10,4)", precision: 10, scale: 4, nullable: true);
|
||||
migrationBuilder.AddColumn<decimal>(name: "Height", table: "MaterialDimensions", type: "decimal(10,4)", precision: 10, scale: 4, nullable: true);
|
||||
migrationBuilder.AddColumn<decimal>(name: "Leg1", table: "MaterialDimensions", type: "decimal(10,4)", precision: 10, scale: 4, nullable: true);
|
||||
migrationBuilder.AddColumn<decimal>(name: "Leg2", table: "MaterialDimensions", type: "decimal(10,4)", precision: 10, scale: 4, nullable: true);
|
||||
migrationBuilder.AddColumn<decimal>(name: "NominalSize", table: "MaterialDimensions", type: "decimal(10,4)", precision: 10, scale: 4, nullable: true);
|
||||
migrationBuilder.AddColumn<decimal>(name: "OuterDiameter", table: "MaterialDimensions", type: "decimal(10,4)", precision: 10, scale: 4, nullable: true);
|
||||
migrationBuilder.AddColumn<string>(name: "Schedule", table: "MaterialDimensions", type: "nvarchar(20)", maxLength: 20, nullable: true);
|
||||
migrationBuilder.AddColumn<decimal>(name: "Size", table: "MaterialDimensions", type: "decimal(10,4)", precision: 10, scale: 4, nullable: true);
|
||||
migrationBuilder.AddColumn<decimal>(name: "Thickness", table: "MaterialDimensions", type: "decimal(10,4)", precision: 10, scale: 4, nullable: true);
|
||||
migrationBuilder.AddColumn<decimal>(name: "Wall", table: "MaterialDimensions", type: "decimal(10,4)", precision: 10, scale: 4, nullable: true);
|
||||
migrationBuilder.AddColumn<decimal>(name: "Web", table: "MaterialDimensions", type: "decimal(10,4)", precision: 10, scale: 4, nullable: true);
|
||||
migrationBuilder.AddColumn<decimal>(name: "WeightPerFoot", table: "MaterialDimensions", type: "decimal(10,4)", precision: 10, scale: 4, nullable: true);
|
||||
migrationBuilder.AddColumn<decimal>(name: "Width", table: "MaterialDimensions", type: "decimal(10,4)", precision: 10, scale: 4, nullable: true);
|
||||
|
||||
// Migrate data back to TPH
|
||||
migrationBuilder.Sql(@"
|
||||
UPDATE md SET DimensionType = 'RoundBar', Diameter = rb.Diameter FROM MaterialDimensions md INNER JOIN RoundBarDimensions rb ON md.Id = rb.Id;
|
||||
UPDATE md SET DimensionType = 'RoundTube', OuterDiameter = rt.OuterDiameter, Wall = rt.Wall FROM MaterialDimensions md INNER JOIN RoundTubeDimensions rt ON md.Id = rt.Id;
|
||||
UPDATE md SET DimensionType = 'FlatBar', Width = fb.Width, Thickness = fb.Thickness FROM MaterialDimensions md INNER JOIN FlatBarDimensions fb ON md.Id = fb.Id;
|
||||
UPDATE md SET DimensionType = 'SquareBar', Size = sb.Size FROM MaterialDimensions md INNER JOIN SquareBarDimensions sb ON md.Id = sb.Id;
|
||||
UPDATE md SET DimensionType = 'SquareTube', Size = st.Size, Wall = st.Wall FROM MaterialDimensions md INNER JOIN SquareTubeDimensions st ON md.Id = st.Id;
|
||||
UPDATE md SET DimensionType = 'RectangularTube', Width = rt.Width, Height = rt.Height, Wall = rt.Wall FROM MaterialDimensions md INNER JOIN RectangularTubeDimensions rt ON md.Id = rt.Id;
|
||||
UPDATE md SET DimensionType = 'Angle', Leg1 = a.Leg1, Leg2 = a.Leg2, Thickness = a.Thickness FROM MaterialDimensions md INNER JOIN AngleDimensions a ON md.Id = a.Id;
|
||||
UPDATE md SET DimensionType = 'Channel', Height = c.Height, Flange = c.Flange, Web = c.Web FROM MaterialDimensions md INNER JOIN ChannelDimensions c ON md.Id = c.Id;
|
||||
UPDATE md SET DimensionType = 'IBeam', Height = ib.Height, WeightPerFoot = ib.WeightPerFoot FROM MaterialDimensions md INNER JOIN IBeamDimensions ib ON md.Id = ib.Id;
|
||||
UPDATE md SET DimensionType = 'Pipe', NominalSize = p.NominalSize, Wall = p.Wall, Schedule = p.Schedule FROM MaterialDimensions md INNER JOIN PipeDimensions p ON md.Id = p.Id;
|
||||
");
|
||||
|
||||
// Drop TPT tables
|
||||
migrationBuilder.DropTable(name: "AngleDimensions");
|
||||
migrationBuilder.DropTable(name: "ChannelDimensions");
|
||||
migrationBuilder.DropTable(name: "FlatBarDimensions");
|
||||
migrationBuilder.DropTable(name: "IBeamDimensions");
|
||||
migrationBuilder.DropTable(name: "PipeDimensions");
|
||||
migrationBuilder.DropTable(name: "RectangularTubeDimensions");
|
||||
migrationBuilder.DropTable(name: "RoundBarDimensions");
|
||||
migrationBuilder.DropTable(name: "RoundTubeDimensions");
|
||||
migrationBuilder.DropTable(name: "SquareBarDimensions");
|
||||
migrationBuilder.DropTable(name: "SquareTubeDimensions");
|
||||
|
||||
// Re-create TPH indexes
|
||||
migrationBuilder.CreateIndex(name: "IX_MaterialDimensions_Diameter", table: "MaterialDimensions", column: "Diameter");
|
||||
migrationBuilder.CreateIndex(name: "IX_MaterialDimensions_Height", table: "MaterialDimensions", column: "Height");
|
||||
migrationBuilder.CreateIndex(name: "IX_MaterialDimensions_Leg1", table: "MaterialDimensions", column: "Leg1");
|
||||
migrationBuilder.CreateIndex(name: "IX_MaterialDimensions_NominalSize", table: "MaterialDimensions", column: "NominalSize");
|
||||
migrationBuilder.CreateIndex(name: "IX_MaterialDimensions_OuterDiameter", table: "MaterialDimensions", column: "OuterDiameter");
|
||||
migrationBuilder.CreateIndex(name: "IX_MaterialDimensions_Size", table: "MaterialDimensions", column: "Size");
|
||||
migrationBuilder.CreateIndex(name: "IX_MaterialDimensions_Width", table: "MaterialDimensions", column: "Width");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,962 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using CutList.Web.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace CutList.Web.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20260216190925_RenameDimensionTables")]
|
||||
partial class RenameDimensionTables
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.11")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.CuttingTool", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<bool>("IsDefault")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<decimal>("KerfInches")
|
||||
.HasPrecision(6, 4)
|
||||
.HasColumnType("decimal(6,4)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CuttingTools");
|
||||
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = 1,
|
||||
IsActive = true,
|
||||
IsDefault = true,
|
||||
KerfInches = 0.0625m,
|
||||
Name = "Bandsaw"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 2,
|
||||
IsActive = true,
|
||||
IsDefault = false,
|
||||
KerfInches = 0.125m,
|
||||
Name = "Chop Saw"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 3,
|
||||
IsActive = true,
|
||||
IsDefault = false,
|
||||
KerfInches = 0.0625m,
|
||||
Name = "Cold Cut Saw"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 4,
|
||||
IsActive = true,
|
||||
IsDefault = false,
|
||||
KerfInches = 0.0625m,
|
||||
Name = "Hacksaw"
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.Job", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<string>("Customer")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<int?>("CuttingToolId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("JobNumber")
|
||||
.IsRequired()
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<DateTime?>("LockedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("OptimizationResultJson")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime?>("OptimizedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CuttingToolId");
|
||||
|
||||
b.HasIndex("JobNumber")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Jobs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.JobPart", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("JobId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("LengthInches")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<int>("MaterialId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("JobId");
|
||||
|
||||
b.HasIndex("MaterialId");
|
||||
|
||||
b.ToTable("JobParts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.JobStock", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("IsCustomLength")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<int>("JobId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("LengthInches")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<int>("MaterialId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Priority")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("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<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("nvarchar(255)");
|
||||
|
||||
b.Property<string>("Grade")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Shape")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("Size")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Materials");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.MaterialDimensions", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("MaterialId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("MaterialId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("DimBase", (string)null);
|
||||
|
||||
b.UseTptMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.PurchaseItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<int?>("JobId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<int>("StockItemId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("SupplierId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("JobId");
|
||||
|
||||
b.HasIndex("StockItemId");
|
||||
|
||||
b.HasIndex("SupplierId");
|
||||
|
||||
b.ToTable("PurchaseItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.StockItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<decimal>("LengthInches")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<int>("MaterialId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("nvarchar(255)");
|
||||
|
||||
b.Property<int>("QuantityOnHand")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("MaterialId", "LengthInches")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("StockItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.StockTransaction", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<int?>("JobId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("StockItemId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("SupplierId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal?>("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<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("ContactInfo")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Suppliers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.SupplierOffering", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("nvarchar(255)");
|
||||
|
||||
b.Property<string>("PartNumber")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<decimal?>("Price")
|
||||
.HasPrecision(10, 2)
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<int>("StockItemId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("SupplierDescription")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("nvarchar(255)");
|
||||
|
||||
b.Property<int>("SupplierId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("StockItemId");
|
||||
|
||||
b.HasIndex("SupplierId", "StockItemId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("SupplierOfferings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.AngleDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Leg1")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Leg2")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Thickness")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Leg1");
|
||||
|
||||
b.ToTable("DimAngle", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.ChannelDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Flange")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Height")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Web")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Height");
|
||||
|
||||
b.ToTable("DimChannel", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.FlatBarDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Thickness")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Width")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Width");
|
||||
|
||||
b.ToTable("DimFlatBar", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.IBeamDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Height")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("WeightPerFoot")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Height");
|
||||
|
||||
b.ToTable("DimIBeam", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.PipeDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("NominalSize")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<string>("Schedule")
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<decimal?>("Wall")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("NominalSize");
|
||||
|
||||
b.ToTable("DimPipe", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RectangularTubeDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Height")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Wall")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Width")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Width");
|
||||
|
||||
b.ToTable("DimRectangularTube", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RoundBarDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Diameter")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Diameter");
|
||||
|
||||
b.ToTable("DimRoundBar", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RoundTubeDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("OuterDiameter")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Wall")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("OuterDiameter");
|
||||
|
||||
b.ToTable("DimRoundTube", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.SquareBarDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Size")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Size");
|
||||
|
||||
b.ToTable("DimSquareBar", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.SquareTubeDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Size")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Wall")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Size");
|
||||
|
||||
b.ToTable("DimSquareTube", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.Job", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.CuttingTool", "CuttingTool")
|
||||
.WithMany("Jobs")
|
||||
.HasForeignKey("CuttingToolId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.Navigation("CuttingTool");
|
||||
});
|
||||
|
||||
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("JobParts")
|
||||
.HasForeignKey("MaterialId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
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");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.PurchaseItem", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.Job", "Job")
|
||||
.WithMany()
|
||||
.HasForeignKey("JobId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("CutList.Web.Data.Entities.StockItem", "StockItem")
|
||||
.WithMany()
|
||||
.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.StockItem", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.Material", "Material")
|
||||
.WithMany("StockItems")
|
||||
.HasForeignKey("MaterialId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
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")
|
||||
.WithMany("SupplierOfferings")
|
||||
.HasForeignKey("StockItemId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CutList.Web.Data.Entities.Supplier", "Supplier")
|
||||
.WithMany("Offerings")
|
||||
.HasForeignKey("SupplierId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("StockItem");
|
||||
|
||||
b.Navigation("Supplier");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.AngleDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.AngleDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.ChannelDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.ChannelDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.FlatBarDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.FlatBarDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.IBeamDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.IBeamDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.PipeDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.PipeDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RectangularTubeDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.RectangularTubeDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RoundBarDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.RoundBarDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RoundTubeDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.RoundTubeDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.SquareBarDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.SquareBarDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.SquareTubeDimensions", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.MaterialDimensions", null)
|
||||
.WithOne()
|
||||
.HasForeignKey("CutList.Web.Data.Entities.SquareTubeDimensions", "Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.CuttingTool", b =>
|
||||
{
|
||||
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("Dimensions");
|
||||
|
||||
b.Navigation("JobParts");
|
||||
|
||||
b.Navigation("StockItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.StockItem", b =>
|
||||
{
|
||||
b.Navigation("SupplierOfferings");
|
||||
|
||||
b.Navigation("Transactions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.Supplier", b =>
|
||||
{
|
||||
b.Navigation("Offerings");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,678 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace CutList.Web.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class RenameDimensionTables : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_AngleDimensions_MaterialDimensions_Id",
|
||||
table: "AngleDimensions");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_ChannelDimensions_MaterialDimensions_Id",
|
||||
table: "ChannelDimensions");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_FlatBarDimensions_MaterialDimensions_Id",
|
||||
table: "FlatBarDimensions");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_IBeamDimensions_MaterialDimensions_Id",
|
||||
table: "IBeamDimensions");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_MaterialDimensions_Materials_MaterialId",
|
||||
table: "MaterialDimensions");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_PipeDimensions_MaterialDimensions_Id",
|
||||
table: "PipeDimensions");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_RectangularTubeDimensions_MaterialDimensions_Id",
|
||||
table: "RectangularTubeDimensions");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_RoundBarDimensions_MaterialDimensions_Id",
|
||||
table: "RoundBarDimensions");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_RoundTubeDimensions_MaterialDimensions_Id",
|
||||
table: "RoundTubeDimensions");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_SquareBarDimensions_MaterialDimensions_Id",
|
||||
table: "SquareBarDimensions");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_SquareTubeDimensions_MaterialDimensions_Id",
|
||||
table: "SquareTubeDimensions");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_SquareTubeDimensions",
|
||||
table: "SquareTubeDimensions");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_SquareBarDimensions",
|
||||
table: "SquareBarDimensions");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_RoundTubeDimensions",
|
||||
table: "RoundTubeDimensions");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_RoundBarDimensions",
|
||||
table: "RoundBarDimensions");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_RectangularTubeDimensions",
|
||||
table: "RectangularTubeDimensions");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_PipeDimensions",
|
||||
table: "PipeDimensions");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_MaterialDimensions",
|
||||
table: "MaterialDimensions");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_IBeamDimensions",
|
||||
table: "IBeamDimensions");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_FlatBarDimensions",
|
||||
table: "FlatBarDimensions");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_ChannelDimensions",
|
||||
table: "ChannelDimensions");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_AngleDimensions",
|
||||
table: "AngleDimensions");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "SquareTubeDimensions",
|
||||
newName: "DimSquareTube");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "SquareBarDimensions",
|
||||
newName: "DimSquareBar");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "RoundTubeDimensions",
|
||||
newName: "DimRoundTube");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "RoundBarDimensions",
|
||||
newName: "DimRoundBar");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "RectangularTubeDimensions",
|
||||
newName: "DimRectangularTube");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "PipeDimensions",
|
||||
newName: "DimPipe");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "MaterialDimensions",
|
||||
newName: "DimBase");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "IBeamDimensions",
|
||||
newName: "DimIBeam");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "FlatBarDimensions",
|
||||
newName: "DimFlatBar");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "ChannelDimensions",
|
||||
newName: "DimChannel");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "AngleDimensions",
|
||||
newName: "DimAngle");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_SquareTubeDimensions_Size",
|
||||
table: "DimSquareTube",
|
||||
newName: "IX_DimSquareTube_Size");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_SquareBarDimensions_Size",
|
||||
table: "DimSquareBar",
|
||||
newName: "IX_DimSquareBar_Size");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_RoundTubeDimensions_OuterDiameter",
|
||||
table: "DimRoundTube",
|
||||
newName: "IX_DimRoundTube_OuterDiameter");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_RoundBarDimensions_Diameter",
|
||||
table: "DimRoundBar",
|
||||
newName: "IX_DimRoundBar_Diameter");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_RectangularTubeDimensions_Width",
|
||||
table: "DimRectangularTube",
|
||||
newName: "IX_DimRectangularTube_Width");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_PipeDimensions_NominalSize",
|
||||
table: "DimPipe",
|
||||
newName: "IX_DimPipe_NominalSize");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_MaterialDimensions_MaterialId",
|
||||
table: "DimBase",
|
||||
newName: "IX_DimBase_MaterialId");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_IBeamDimensions_Height",
|
||||
table: "DimIBeam",
|
||||
newName: "IX_DimIBeam_Height");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_FlatBarDimensions_Width",
|
||||
table: "DimFlatBar",
|
||||
newName: "IX_DimFlatBar_Width");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_ChannelDimensions_Height",
|
||||
table: "DimChannel",
|
||||
newName: "IX_DimChannel_Height");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_AngleDimensions_Leg1",
|
||||
table: "DimAngle",
|
||||
newName: "IX_DimAngle_Leg1");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_DimSquareTube",
|
||||
table: "DimSquareTube",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_DimSquareBar",
|
||||
table: "DimSquareBar",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_DimRoundTube",
|
||||
table: "DimRoundTube",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_DimRoundBar",
|
||||
table: "DimRoundBar",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_DimRectangularTube",
|
||||
table: "DimRectangularTube",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_DimPipe",
|
||||
table: "DimPipe",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_DimBase",
|
||||
table: "DimBase",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_DimIBeam",
|
||||
table: "DimIBeam",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_DimFlatBar",
|
||||
table: "DimFlatBar",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_DimChannel",
|
||||
table: "DimChannel",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_DimAngle",
|
||||
table: "DimAngle",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_DimAngle_DimBase_Id",
|
||||
table: "DimAngle",
|
||||
column: "Id",
|
||||
principalTable: "DimBase",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_DimBase_Materials_MaterialId",
|
||||
table: "DimBase",
|
||||
column: "MaterialId",
|
||||
principalTable: "Materials",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_DimChannel_DimBase_Id",
|
||||
table: "DimChannel",
|
||||
column: "Id",
|
||||
principalTable: "DimBase",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_DimFlatBar_DimBase_Id",
|
||||
table: "DimFlatBar",
|
||||
column: "Id",
|
||||
principalTable: "DimBase",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_DimIBeam_DimBase_Id",
|
||||
table: "DimIBeam",
|
||||
column: "Id",
|
||||
principalTable: "DimBase",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_DimPipe_DimBase_Id",
|
||||
table: "DimPipe",
|
||||
column: "Id",
|
||||
principalTable: "DimBase",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_DimRectangularTube_DimBase_Id",
|
||||
table: "DimRectangularTube",
|
||||
column: "Id",
|
||||
principalTable: "DimBase",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_DimRoundBar_DimBase_Id",
|
||||
table: "DimRoundBar",
|
||||
column: "Id",
|
||||
principalTable: "DimBase",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_DimRoundTube_DimBase_Id",
|
||||
table: "DimRoundTube",
|
||||
column: "Id",
|
||||
principalTable: "DimBase",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_DimSquareBar_DimBase_Id",
|
||||
table: "DimSquareBar",
|
||||
column: "Id",
|
||||
principalTable: "DimBase",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_DimSquareTube_DimBase_Id",
|
||||
table: "DimSquareTube",
|
||||
column: "Id",
|
||||
principalTable: "DimBase",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_DimAngle_DimBase_Id",
|
||||
table: "DimAngle");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_DimBase_Materials_MaterialId",
|
||||
table: "DimBase");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_DimChannel_DimBase_Id",
|
||||
table: "DimChannel");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_DimFlatBar_DimBase_Id",
|
||||
table: "DimFlatBar");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_DimIBeam_DimBase_Id",
|
||||
table: "DimIBeam");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_DimPipe_DimBase_Id",
|
||||
table: "DimPipe");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_DimRectangularTube_DimBase_Id",
|
||||
table: "DimRectangularTube");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_DimRoundBar_DimBase_Id",
|
||||
table: "DimRoundBar");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_DimRoundTube_DimBase_Id",
|
||||
table: "DimRoundTube");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_DimSquareBar_DimBase_Id",
|
||||
table: "DimSquareBar");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_DimSquareTube_DimBase_Id",
|
||||
table: "DimSquareTube");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_DimSquareTube",
|
||||
table: "DimSquareTube");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_DimSquareBar",
|
||||
table: "DimSquareBar");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_DimRoundTube",
|
||||
table: "DimRoundTube");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_DimRoundBar",
|
||||
table: "DimRoundBar");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_DimRectangularTube",
|
||||
table: "DimRectangularTube");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_DimPipe",
|
||||
table: "DimPipe");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_DimIBeam",
|
||||
table: "DimIBeam");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_DimFlatBar",
|
||||
table: "DimFlatBar");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_DimChannel",
|
||||
table: "DimChannel");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_DimBase",
|
||||
table: "DimBase");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_DimAngle",
|
||||
table: "DimAngle");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "DimSquareTube",
|
||||
newName: "SquareTubeDimensions");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "DimSquareBar",
|
||||
newName: "SquareBarDimensions");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "DimRoundTube",
|
||||
newName: "RoundTubeDimensions");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "DimRoundBar",
|
||||
newName: "RoundBarDimensions");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "DimRectangularTube",
|
||||
newName: "RectangularTubeDimensions");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "DimPipe",
|
||||
newName: "PipeDimensions");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "DimIBeam",
|
||||
newName: "IBeamDimensions");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "DimFlatBar",
|
||||
newName: "FlatBarDimensions");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "DimChannel",
|
||||
newName: "ChannelDimensions");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "DimBase",
|
||||
newName: "MaterialDimensions");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "DimAngle",
|
||||
newName: "AngleDimensions");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_DimSquareTube_Size",
|
||||
table: "SquareTubeDimensions",
|
||||
newName: "IX_SquareTubeDimensions_Size");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_DimSquareBar_Size",
|
||||
table: "SquareBarDimensions",
|
||||
newName: "IX_SquareBarDimensions_Size");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_DimRoundTube_OuterDiameter",
|
||||
table: "RoundTubeDimensions",
|
||||
newName: "IX_RoundTubeDimensions_OuterDiameter");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_DimRoundBar_Diameter",
|
||||
table: "RoundBarDimensions",
|
||||
newName: "IX_RoundBarDimensions_Diameter");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_DimRectangularTube_Width",
|
||||
table: "RectangularTubeDimensions",
|
||||
newName: "IX_RectangularTubeDimensions_Width");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_DimPipe_NominalSize",
|
||||
table: "PipeDimensions",
|
||||
newName: "IX_PipeDimensions_NominalSize");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_DimIBeam_Height",
|
||||
table: "IBeamDimensions",
|
||||
newName: "IX_IBeamDimensions_Height");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_DimFlatBar_Width",
|
||||
table: "FlatBarDimensions",
|
||||
newName: "IX_FlatBarDimensions_Width");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_DimChannel_Height",
|
||||
table: "ChannelDimensions",
|
||||
newName: "IX_ChannelDimensions_Height");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_DimBase_MaterialId",
|
||||
table: "MaterialDimensions",
|
||||
newName: "IX_MaterialDimensions_MaterialId");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_DimAngle_Leg1",
|
||||
table: "AngleDimensions",
|
||||
newName: "IX_AngleDimensions_Leg1");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_SquareTubeDimensions",
|
||||
table: "SquareTubeDimensions",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_SquareBarDimensions",
|
||||
table: "SquareBarDimensions",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_RoundTubeDimensions",
|
||||
table: "RoundTubeDimensions",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_RoundBarDimensions",
|
||||
table: "RoundBarDimensions",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_RectangularTubeDimensions",
|
||||
table: "RectangularTubeDimensions",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_PipeDimensions",
|
||||
table: "PipeDimensions",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_IBeamDimensions",
|
||||
table: "IBeamDimensions",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_FlatBarDimensions",
|
||||
table: "FlatBarDimensions",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_ChannelDimensions",
|
||||
table: "ChannelDimensions",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_MaterialDimensions",
|
||||
table: "MaterialDimensions",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_AngleDimensions",
|
||||
table: "AngleDimensions",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_AngleDimensions_MaterialDimensions_Id",
|
||||
table: "AngleDimensions",
|
||||
column: "Id",
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_ChannelDimensions_MaterialDimensions_Id",
|
||||
table: "ChannelDimensions",
|
||||
column: "Id",
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_FlatBarDimensions_MaterialDimensions_Id",
|
||||
table: "FlatBarDimensions",
|
||||
column: "Id",
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_IBeamDimensions_MaterialDimensions_Id",
|
||||
table: "IBeamDimensions",
|
||||
column: "Id",
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_MaterialDimensions_Materials_MaterialId",
|
||||
table: "MaterialDimensions",
|
||||
column: "MaterialId",
|
||||
principalTable: "Materials",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_PipeDimensions_MaterialDimensions_Id",
|
||||
table: "PipeDimensions",
|
||||
column: "Id",
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_RectangularTubeDimensions_MaterialDimensions_Id",
|
||||
table: "RectangularTubeDimensions",
|
||||
column: "Id",
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_RoundBarDimensions_MaterialDimensions_Id",
|
||||
table: "RoundBarDimensions",
|
||||
column: "Id",
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_RoundTubeDimensions_MaterialDimensions_Id",
|
||||
table: "RoundTubeDimensions",
|
||||
column: "Id",
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_SquareBarDimensions_MaterialDimensions_Id",
|
||||
table: "SquareBarDimensions",
|
||||
column: "Id",
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_SquareTubeDimensions_MaterialDimensions_Id",
|
||||
table: "SquareTubeDimensions",
|
||||
column: "Id",
|
||||
principalTable: "MaterialDimensions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,875 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using CutList.Web.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace CutList.Web.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20260216191345_DimensionsTPTtoTPC")]
|
||||
partial class DimensionsTPTtoTPC
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.11")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.HasSequence("MaterialDimensionsSequence");
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.CuttingTool", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<bool>("IsDefault")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<decimal>("KerfInches")
|
||||
.HasPrecision(6, 4)
|
||||
.HasColumnType("decimal(6,4)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CuttingTools");
|
||||
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = 1,
|
||||
IsActive = true,
|
||||
IsDefault = true,
|
||||
KerfInches = 0.0625m,
|
||||
Name = "Bandsaw"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 2,
|
||||
IsActive = true,
|
||||
IsDefault = false,
|
||||
KerfInches = 0.125m,
|
||||
Name = "Chop Saw"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 3,
|
||||
IsActive = true,
|
||||
IsDefault = false,
|
||||
KerfInches = 0.0625m,
|
||||
Name = "Cold Cut Saw"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 4,
|
||||
IsActive = true,
|
||||
IsDefault = false,
|
||||
KerfInches = 0.0625m,
|
||||
Name = "Hacksaw"
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.Job", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<string>("Customer")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<int?>("CuttingToolId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("JobNumber")
|
||||
.IsRequired()
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<DateTime?>("LockedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("OptimizationResultJson")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime?>("OptimizedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CuttingToolId");
|
||||
|
||||
b.HasIndex("JobNumber")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Jobs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.JobPart", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("JobId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("LengthInches")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<int>("MaterialId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("JobId");
|
||||
|
||||
b.HasIndex("MaterialId");
|
||||
|
||||
b.ToTable("JobParts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.JobStock", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("IsCustomLength")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<int>("JobId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("LengthInches")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<int>("MaterialId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Priority")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("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<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("nvarchar(255)");
|
||||
|
||||
b.Property<string>("Grade")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Shape")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("Size")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Materials");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.MaterialDimensions", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.HasDefaultValueSql("NEXT VALUE FOR [MaterialDimensionsSequence]");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseSequence(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("MaterialId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("MaterialId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable((string)null);
|
||||
|
||||
b.UseTpcMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.PurchaseItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<int?>("JobId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<int>("StockItemId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("SupplierId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("JobId");
|
||||
|
||||
b.HasIndex("StockItemId");
|
||||
|
||||
b.HasIndex("SupplierId");
|
||||
|
||||
b.ToTable("PurchaseItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.StockItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<decimal>("LengthInches")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<int>("MaterialId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("nvarchar(255)");
|
||||
|
||||
b.Property<int>("QuantityOnHand")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("MaterialId", "LengthInches")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("StockItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.StockTransaction", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<int?>("JobId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("StockItemId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("SupplierId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal?>("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<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("ContactInfo")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("datetime2")
|
||||
.HasDefaultValueSql("GETUTCDATE()");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Suppliers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.SupplierOffering", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("nvarchar(255)");
|
||||
|
||||
b.Property<string>("PartNumber")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<decimal?>("Price")
|
||||
.HasPrecision(10, 2)
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<int>("StockItemId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("SupplierDescription")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("nvarchar(255)");
|
||||
|
||||
b.Property<int>("SupplierId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("StockItemId");
|
||||
|
||||
b.HasIndex("SupplierId", "StockItemId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("SupplierOfferings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.AngleDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Leg1")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Leg2")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Thickness")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Leg1");
|
||||
|
||||
b.ToTable("DimAngle", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.ChannelDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Flange")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Height")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Web")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Height");
|
||||
|
||||
b.ToTable("DimChannel", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.FlatBarDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Thickness")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Width")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Width");
|
||||
|
||||
b.ToTable("DimFlatBar", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.IBeamDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Height")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("WeightPerFoot")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Height");
|
||||
|
||||
b.ToTable("DimIBeam", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.PipeDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("NominalSize")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<string>("Schedule")
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<decimal?>("Wall")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("NominalSize");
|
||||
|
||||
b.ToTable("DimPipe", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RectangularTubeDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Height")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Wall")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Width")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Width");
|
||||
|
||||
b.ToTable("DimRectangularTube", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RoundBarDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Diameter")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Diameter");
|
||||
|
||||
b.ToTable("DimRoundBar", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RoundTubeDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("OuterDiameter")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Wall")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("OuterDiameter");
|
||||
|
||||
b.ToTable("DimRoundTube", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.SquareBarDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Size")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Size");
|
||||
|
||||
b.ToTable("DimSquareBar", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.SquareTubeDimensions", b =>
|
||||
{
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Size")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Wall")
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Size");
|
||||
|
||||
b.ToTable("DimSquareTube", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.Job", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.CuttingTool", "CuttingTool")
|
||||
.WithMany("Jobs")
|
||||
.HasForeignKey("CuttingToolId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.Navigation("CuttingTool");
|
||||
});
|
||||
|
||||
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("JobParts")
|
||||
.HasForeignKey("MaterialId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
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");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.PurchaseItem", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.Job", "Job")
|
||||
.WithMany()
|
||||
.HasForeignKey("JobId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("CutList.Web.Data.Entities.StockItem", "StockItem")
|
||||
.WithMany()
|
||||
.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.StockItem", b =>
|
||||
{
|
||||
b.HasOne("CutList.Web.Data.Entities.Material", "Material")
|
||||
.WithMany("StockItems")
|
||||
.HasForeignKey("MaterialId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
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")
|
||||
.WithMany("SupplierOfferings")
|
||||
.HasForeignKey("StockItemId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CutList.Web.Data.Entities.Supplier", "Supplier")
|
||||
.WithMany("Offerings")
|
||||
.HasForeignKey("SupplierId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("StockItem");
|
||||
|
||||
b.Navigation("Supplier");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.CuttingTool", b =>
|
||||
{
|
||||
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("Dimensions");
|
||||
|
||||
b.Navigation("JobParts");
|
||||
|
||||
b.Navigation("StockItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.StockItem", b =>
|
||||
{
|
||||
b.Navigation("SupplierOfferings");
|
||||
|
||||
b.Navigation("Transactions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.Supplier", b =>
|
||||
{
|
||||
b.Navigation("Offerings");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace CutList.Web.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class DimensionsTPTtoTPC : Migration
|
||||
{
|
||||
private static readonly string[] DimTables =
|
||||
[
|
||||
"DimAngle", "DimChannel", "DimFlatBar", "DimIBeam", "DimPipe",
|
||||
"DimRectangularTube", "DimRoundBar", "DimRoundTube", "DimSquareBar", "DimSquareTube"
|
||||
];
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
// 1. Drop FKs from shape tables to DimBase
|
||||
foreach (var table in DimTables)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: $"FK_{table}_DimBase_Id",
|
||||
table: table);
|
||||
}
|
||||
|
||||
// 2. Add MaterialId column to each shape table (nullable initially)
|
||||
foreach (var table in DimTables)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "MaterialId",
|
||||
table: table,
|
||||
type: "int",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
// 3. Copy MaterialId from DimBase into each shape table
|
||||
foreach (var table in DimTables)
|
||||
{
|
||||
migrationBuilder.Sql(
|
||||
$"UPDATE t SET t.MaterialId = b.MaterialId FROM [{table}] t INNER JOIN [DimBase] b ON t.Id = b.Id");
|
||||
}
|
||||
|
||||
// 4. Make MaterialId non-nullable now that data is populated
|
||||
foreach (var table in DimTables)
|
||||
{
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "MaterialId",
|
||||
table: table,
|
||||
type: "int",
|
||||
nullable: false,
|
||||
oldClrType: typeof(int),
|
||||
oldNullable: true);
|
||||
}
|
||||
|
||||
// 5. Drop DimBase
|
||||
migrationBuilder.DropTable(name: "DimBase");
|
||||
|
||||
// 6. Create shared sequence for unique IDs across all shape tables
|
||||
migrationBuilder.CreateSequence(name: "MaterialDimensionsSequence");
|
||||
|
||||
// 7. Switch Id columns to use the sequence
|
||||
foreach (var table in DimTables)
|
||||
{
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "Id",
|
||||
table: table,
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValueSql: "NEXT VALUE FOR [MaterialDimensionsSequence]",
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int");
|
||||
}
|
||||
|
||||
// 8. Create indexes and FKs for MaterialId on each shape table
|
||||
foreach (var table in DimTables)
|
||||
{
|
||||
migrationBuilder.CreateIndex(
|
||||
name: $"IX_{table}_MaterialId",
|
||||
table: table,
|
||||
column: "MaterialId",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: $"FK_{table}_Materials_MaterialId",
|
||||
table: table,
|
||||
column: "MaterialId",
|
||||
principalTable: "Materials",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
// Drop FKs and indexes from shape tables
|
||||
foreach (var table in DimTables)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: $"FK_{table}_Materials_MaterialId",
|
||||
table: table);
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: $"IX_{table}_MaterialId",
|
||||
table: table);
|
||||
}
|
||||
|
||||
// Remove sequence from Id columns
|
||||
foreach (var table in DimTables)
|
||||
{
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "Id",
|
||||
table: table,
|
||||
type: "int",
|
||||
nullable: false,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int",
|
||||
oldDefaultValueSql: "NEXT VALUE FOR [MaterialDimensionsSequence]");
|
||||
}
|
||||
|
||||
migrationBuilder.DropSequence(name: "MaterialDimensionsSequence");
|
||||
|
||||
// Re-create DimBase
|
||||
migrationBuilder.CreateTable(
|
||||
name: "DimBase",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
MaterialId = table.Column<int>(type: "int", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_DimBase", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_DimBase_Materials_MaterialId",
|
||||
column: x => x.MaterialId,
|
||||
principalTable: "Materials",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_DimBase_MaterialId",
|
||||
table: "DimBase",
|
||||
column: "MaterialId",
|
||||
unique: true);
|
||||
|
||||
// Copy data back to DimBase from all shape tables
|
||||
foreach (var table in DimTables)
|
||||
{
|
||||
migrationBuilder.Sql(
|
||||
$"SET IDENTITY_INSERT [DimBase] ON; INSERT INTO [DimBase] (Id, MaterialId) SELECT Id, MaterialId FROM [{table}]; SET IDENTITY_INSERT [DimBase] OFF;");
|
||||
}
|
||||
|
||||
// Re-add FKs from shape tables to DimBase and drop MaterialId
|
||||
foreach (var table in DimTables)
|
||||
{
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: $"FK_{table}_DimBase_Id",
|
||||
table: table,
|
||||
column: "Id",
|
||||
principalTable: "DimBase",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.DropColumn(name: "MaterialId", table: table);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,8 @@ namespace CutList.Web.Migrations
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.HasSequence("MaterialDimensionsSequence");
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.CuttingTool", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -274,14 +276,10 @@ namespace CutList.Web.Migrations
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
.HasColumnType("int")
|
||||
.HasDefaultValueSql("NEXT VALUE FOR [MaterialDimensionsSequence]");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("DimensionType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(21)
|
||||
.HasColumnType("nvarchar(21)");
|
||||
SqlServerPropertyBuilderExtensions.UseSequence(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("MaterialId")
|
||||
.HasColumnType("int");
|
||||
@@ -291,11 +289,9 @@ namespace CutList.Web.Migrations
|
||||
b.HasIndex("MaterialId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("MaterialDimensions");
|
||||
b.ToTable((string)null);
|
||||
|
||||
b.HasDiscriminator<string>("DimensionType").HasValue("MaterialDimensions");
|
||||
|
||||
b.UseTphMappingStrategy();
|
||||
b.UseTpcMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.PurchaseItem", b =>
|
||||
@@ -527,14 +523,12 @@ namespace CutList.Web.Migrations
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Thickness")
|
||||
.ValueGeneratedOnUpdateSometimes()
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)")
|
||||
.HasColumnName("Thickness");
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Leg1");
|
||||
|
||||
b.HasDiscriminator().HasValue("Angle");
|
||||
b.ToTable("DimAngle", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.ChannelDimensions", b =>
|
||||
@@ -546,10 +540,8 @@ namespace CutList.Web.Migrations
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Height")
|
||||
.ValueGeneratedOnUpdateSometimes()
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)")
|
||||
.HasColumnName("Height");
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Web")
|
||||
.HasPrecision(10, 4)
|
||||
@@ -557,7 +549,7 @@ namespace CutList.Web.Migrations
|
||||
|
||||
b.HasIndex("Height");
|
||||
|
||||
b.HasDiscriminator().HasValue("Channel");
|
||||
b.ToTable("DimChannel", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.FlatBarDimensions", b =>
|
||||
@@ -565,20 +557,16 @@ namespace CutList.Web.Migrations
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Thickness")
|
||||
.ValueGeneratedOnUpdateSometimes()
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)")
|
||||
.HasColumnName("Thickness");
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Width")
|
||||
.ValueGeneratedOnUpdateSometimes()
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)")
|
||||
.HasColumnName("Width");
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Width");
|
||||
|
||||
b.HasDiscriminator().HasValue("FlatBar");
|
||||
b.ToTable("DimFlatBar", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.IBeamDimensions", b =>
|
||||
@@ -586,10 +574,8 @@ namespace CutList.Web.Migrations
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Height")
|
||||
.ValueGeneratedOnUpdateSometimes()
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)")
|
||||
.HasColumnName("Height");
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("WeightPerFoot")
|
||||
.HasPrecision(10, 4)
|
||||
@@ -597,7 +583,7 @@ namespace CutList.Web.Migrations
|
||||
|
||||
b.HasIndex("Height");
|
||||
|
||||
b.HasDiscriminator().HasValue("IBeam");
|
||||
b.ToTable("DimIBeam", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.PipeDimensions", b =>
|
||||
@@ -613,14 +599,12 @@ namespace CutList.Web.Migrations
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<decimal?>("Wall")
|
||||
.ValueGeneratedOnUpdateSometimes()
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)")
|
||||
.HasColumnName("Wall");
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("NominalSize");
|
||||
|
||||
b.HasDiscriminator().HasValue("Pipe");
|
||||
b.ToTable("DimPipe", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RectangularTubeDimensions", b =>
|
||||
@@ -628,26 +612,20 @@ namespace CutList.Web.Migrations
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Height")
|
||||
.ValueGeneratedOnUpdateSometimes()
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)")
|
||||
.HasColumnName("Height");
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Wall")
|
||||
.ValueGeneratedOnUpdateSometimes()
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)")
|
||||
.HasColumnName("Wall");
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Width")
|
||||
.ValueGeneratedOnUpdateSometimes()
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)")
|
||||
.HasColumnName("Width");
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Width");
|
||||
|
||||
b.HasDiscriminator().HasValue("RectangularTube");
|
||||
b.ToTable("DimRectangularTube", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RoundBarDimensions", b =>
|
||||
@@ -660,7 +638,7 @@ namespace CutList.Web.Migrations
|
||||
|
||||
b.HasIndex("Diameter");
|
||||
|
||||
b.HasDiscriminator().HasValue("RoundBar");
|
||||
b.ToTable("DimRoundBar", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.RoundTubeDimensions", b =>
|
||||
@@ -672,14 +650,12 @@ namespace CutList.Web.Migrations
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Wall")
|
||||
.ValueGeneratedOnUpdateSometimes()
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)")
|
||||
.HasColumnName("Wall");
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("OuterDiameter");
|
||||
|
||||
b.HasDiscriminator().HasValue("RoundTube");
|
||||
b.ToTable("DimRoundTube", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.SquareBarDimensions", b =>
|
||||
@@ -687,14 +663,12 @@ namespace CutList.Web.Migrations
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Size")
|
||||
.ValueGeneratedOnUpdateSometimes()
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)")
|
||||
.HasColumnName("Size");
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Size");
|
||||
|
||||
b.HasDiscriminator().HasValue("SquareBar");
|
||||
b.ToTable("DimSquareBar", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.SquareTubeDimensions", b =>
|
||||
@@ -702,20 +676,16 @@ namespace CutList.Web.Migrations
|
||||
b.HasBaseType("CutList.Web.Data.Entities.MaterialDimensions");
|
||||
|
||||
b.Property<decimal>("Size")
|
||||
.ValueGeneratedOnUpdateSometimes()
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)")
|
||||
.HasColumnName("Size");
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<decimal>("Wall")
|
||||
.ValueGeneratedOnUpdateSometimes()
|
||||
.HasPrecision(10, 4)
|
||||
.HasColumnType("decimal(10,4)")
|
||||
.HasColumnName("Wall");
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.HasIndex("Size");
|
||||
|
||||
b.HasDiscriminator().HasValue("SquareTube");
|
||||
b.ToTable("DimSquareTube", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CutList.Web.Data.Entities.Job", b =>
|
||||
|
||||
@@ -10,6 +10,9 @@ builder.Services.AddControllers();
|
||||
builder.Services.AddRazorComponents()
|
||||
.AddInteractiveServerComponents();
|
||||
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
|
||||
// Add Entity Framework
|
||||
builder.Services.AddDbContext<ApplicationDbContext>(options =>
|
||||
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
|
||||
@@ -27,7 +30,12 @@ builder.Services.AddScoped<CatalogService>();
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (!app.Environment.IsDevelopment())
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseExceptionHandler("/Error", createScopeForErrors: true);
|
||||
app.UseHsts();
|
||||
|
||||
@@ -39,6 +39,101 @@ public class CatalogService
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
|
||||
var grouped = materials.GroupBy(m => m.Shape);
|
||||
var materialsDto = new CatalogMaterialsDto();
|
||||
|
||||
foreach (var group in grouped)
|
||||
{
|
||||
foreach (var m in group)
|
||||
{
|
||||
var stockItems = MapStockItems(m, suppliers);
|
||||
|
||||
switch (m.Shape)
|
||||
{
|
||||
case MaterialShape.Angle when m.Dimensions is AngleDimensions d:
|
||||
materialsDto.Angles.Add(new CatalogAngleDto
|
||||
{
|
||||
Type = m.Type.ToString(), Grade = m.Grade, Size = m.Size, Description = m.Description,
|
||||
Leg1 = d.Leg1, Leg2 = d.Leg2, Thickness = d.Thickness,
|
||||
StockItems = stockItems
|
||||
});
|
||||
break;
|
||||
case MaterialShape.Channel when m.Dimensions is ChannelDimensions d:
|
||||
materialsDto.Channels.Add(new CatalogChannelDto
|
||||
{
|
||||
Type = m.Type.ToString(), Grade = m.Grade, Size = m.Size, Description = m.Description,
|
||||
Height = d.Height, Flange = d.Flange, Web = d.Web,
|
||||
StockItems = stockItems
|
||||
});
|
||||
break;
|
||||
case MaterialShape.FlatBar when m.Dimensions is FlatBarDimensions d:
|
||||
materialsDto.FlatBars.Add(new CatalogFlatBarDto
|
||||
{
|
||||
Type = m.Type.ToString(), Grade = m.Grade, Size = m.Size, Description = m.Description,
|
||||
Width = d.Width, Thickness = d.Thickness,
|
||||
StockItems = stockItems
|
||||
});
|
||||
break;
|
||||
case MaterialShape.IBeam when m.Dimensions is IBeamDimensions d:
|
||||
materialsDto.IBeams.Add(new CatalogIBeamDto
|
||||
{
|
||||
Type = m.Type.ToString(), Grade = m.Grade, Size = m.Size, Description = m.Description,
|
||||
Height = d.Height, WeightPerFoot = d.WeightPerFoot,
|
||||
StockItems = stockItems
|
||||
});
|
||||
break;
|
||||
case MaterialShape.Pipe when m.Dimensions is PipeDimensions d:
|
||||
materialsDto.Pipes.Add(new CatalogPipeDto
|
||||
{
|
||||
Type = m.Type.ToString(), Grade = m.Grade, Size = m.Size, Description = m.Description,
|
||||
NominalSize = d.NominalSize, Wall = d.Wall ?? 0, Schedule = d.Schedule,
|
||||
StockItems = stockItems
|
||||
});
|
||||
break;
|
||||
case MaterialShape.RectangularTube when m.Dimensions is RectangularTubeDimensions d:
|
||||
materialsDto.RectangularTubes.Add(new CatalogRectangularTubeDto
|
||||
{
|
||||
Type = m.Type.ToString(), Grade = m.Grade, Size = m.Size, Description = m.Description,
|
||||
Width = d.Width, Height = d.Height, Wall = d.Wall,
|
||||
StockItems = stockItems
|
||||
});
|
||||
break;
|
||||
case MaterialShape.RoundBar when m.Dimensions is RoundBarDimensions d:
|
||||
materialsDto.RoundBars.Add(new CatalogRoundBarDto
|
||||
{
|
||||
Type = m.Type.ToString(), Grade = m.Grade, Size = m.Size, Description = m.Description,
|
||||
Diameter = d.Diameter,
|
||||
StockItems = stockItems
|
||||
});
|
||||
break;
|
||||
case MaterialShape.RoundTube when m.Dimensions is RoundTubeDimensions d:
|
||||
materialsDto.RoundTubes.Add(new CatalogRoundTubeDto
|
||||
{
|
||||
Type = m.Type.ToString(), Grade = m.Grade, Size = m.Size, Description = m.Description,
|
||||
OuterDiameter = d.OuterDiameter, Wall = d.Wall,
|
||||
StockItems = stockItems
|
||||
});
|
||||
break;
|
||||
case MaterialShape.SquareBar when m.Dimensions is SquareBarDimensions d:
|
||||
materialsDto.SquareBars.Add(new CatalogSquareBarDto
|
||||
{
|
||||
Type = m.Type.ToString(), Grade = m.Grade, Size = m.Size, Description = m.Description,
|
||||
SideLength = d.Size,
|
||||
StockItems = stockItems
|
||||
});
|
||||
break;
|
||||
case MaterialShape.SquareTube when m.Dimensions is SquareTubeDimensions d:
|
||||
materialsDto.SquareTubes.Add(new CatalogSquareTubeDto
|
||||
{
|
||||
Type = m.Type.ToString(), Grade = m.Grade, Size = m.Size, Description = m.Description,
|
||||
SideLength = d.Size, Wall = d.Wall,
|
||||
StockItems = stockItems
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new CatalogData
|
||||
{
|
||||
ExportedAt = DateTime.UtcNow,
|
||||
@@ -54,30 +149,7 @@ public class CatalogService
|
||||
KerfInches = t.KerfInches,
|
||||
IsDefault = t.IsDefault
|
||||
}).ToList(),
|
||||
Materials = materials.Select(m => new CatalogMaterialDto
|
||||
{
|
||||
Shape = m.Shape.ToString(),
|
||||
Type = m.Type.ToString(),
|
||||
Grade = m.Grade,
|
||||
Size = m.Size,
|
||||
Description = m.Description,
|
||||
Dimensions = MapDimensions(m.Dimensions),
|
||||
StockItems = m.StockItems.OrderBy(s => s.LengthInches).Select(s => new CatalogStockItemDto
|
||||
{
|
||||
LengthInches = s.LengthInches,
|
||||
Name = s.Name,
|
||||
QuantityOnHand = s.QuantityOnHand,
|
||||
Notes = s.Notes,
|
||||
SupplierOfferings = s.SupplierOfferings.Select(o => new CatalogSupplierOfferingDto
|
||||
{
|
||||
SupplierName = suppliers.FirstOrDefault(sup => sup.Id == o.SupplierId)?.Name ?? "Unknown",
|
||||
PartNumber = o.PartNumber,
|
||||
SupplierDescription = o.SupplierDescription,
|
||||
Price = o.Price,
|
||||
Notes = o.Notes
|
||||
}).ToList()
|
||||
}).ToList()
|
||||
}).ToList()
|
||||
Materials = materialsDto
|
||||
};
|
||||
}
|
||||
|
||||
@@ -89,14 +161,14 @@ public class CatalogService
|
||||
|
||||
try
|
||||
{
|
||||
// 1. Suppliers — upsert by name
|
||||
// 1. Suppliers - upsert by name
|
||||
var supplierMap = await ImportSuppliersAsync(data.Suppliers, result);
|
||||
|
||||
// 2. Cutting tools — upsert by name
|
||||
// 2. Cutting tools - upsert by name
|
||||
await ImportCuttingToolsAsync(data.CuttingTools, result);
|
||||
|
||||
// 3. Materials + stock items + offerings
|
||||
await ImportMaterialsAsync(data.Materials, supplierMap, result);
|
||||
await ImportAllMaterialsAsync(data.Materials, supplierMap, result);
|
||||
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
@@ -173,7 +245,6 @@ public class CatalogService
|
||||
{
|
||||
existing.KerfInches = dto.KerfInches;
|
||||
existing.IsActive = true;
|
||||
// Skip IsDefault changes to avoid conflicts
|
||||
result.CuttingToolsUpdated++;
|
||||
}
|
||||
else
|
||||
@@ -182,7 +253,7 @@ public class CatalogService
|
||||
{
|
||||
Name = dto.Name,
|
||||
KerfInches = dto.KerfInches,
|
||||
IsDefault = false // Never import as default to avoid conflicts
|
||||
IsDefault = false
|
||||
};
|
||||
_context.CuttingTools.Add(tool);
|
||||
existingTools.Add(tool);
|
||||
@@ -198,94 +269,128 @@ public class CatalogService
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private async Task ImportMaterialsAsync(
|
||||
List<CatalogMaterialDto> materials, Dictionary<string, int> supplierMap, ImportResultDto result)
|
||||
private async Task ImportAllMaterialsAsync(
|
||||
CatalogMaterialsDto materials, Dictionary<string, int> supplierMap, ImportResultDto result)
|
||||
{
|
||||
// Pre-load existing materials with their dimensions
|
||||
var existingMaterials = await _context.Materials
|
||||
.Include(m => m.Dimensions)
|
||||
.Include(m => m.StockItems)
|
||||
.ThenInclude(s => s.SupplierOfferings)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var dto in materials)
|
||||
foreach (var dto in materials.Angles)
|
||||
await ImportMaterialAsync(dto, MaterialShape.Angle, existingMaterials, supplierMap, result,
|
||||
() => new AngleDimensions { Leg1 = dto.Leg1, Leg2 = dto.Leg2, Thickness = dto.Thickness },
|
||||
dim => { var d = (AngleDimensions)dim; d.Leg1 = dto.Leg1; d.Leg2 = dto.Leg2; d.Thickness = dto.Thickness; });
|
||||
|
||||
foreach (var dto in materials.Channels)
|
||||
await ImportMaterialAsync(dto, MaterialShape.Channel, existingMaterials, supplierMap, result,
|
||||
() => new ChannelDimensions { Height = dto.Height, Flange = dto.Flange, Web = dto.Web },
|
||||
dim => { var d = (ChannelDimensions)dim; d.Height = dto.Height; d.Flange = dto.Flange; d.Web = dto.Web; });
|
||||
|
||||
foreach (var dto in materials.FlatBars)
|
||||
await ImportMaterialAsync(dto, MaterialShape.FlatBar, existingMaterials, supplierMap, result,
|
||||
() => new FlatBarDimensions { Width = dto.Width, Thickness = dto.Thickness },
|
||||
dim => { var d = (FlatBarDimensions)dim; d.Width = dto.Width; d.Thickness = dto.Thickness; });
|
||||
|
||||
foreach (var dto in materials.IBeams)
|
||||
await ImportMaterialAsync(dto, MaterialShape.IBeam, existingMaterials, supplierMap, result,
|
||||
() => new IBeamDimensions { Height = dto.Height, WeightPerFoot = dto.WeightPerFoot },
|
||||
dim => { var d = (IBeamDimensions)dim; d.Height = dto.Height; d.WeightPerFoot = dto.WeightPerFoot; });
|
||||
|
||||
foreach (var dto in materials.Pipes)
|
||||
await ImportMaterialAsync(dto, MaterialShape.Pipe, existingMaterials, supplierMap, result,
|
||||
() => new PipeDimensions { NominalSize = dto.NominalSize, Wall = dto.Wall, Schedule = dto.Schedule },
|
||||
dim => { var d = (PipeDimensions)dim; d.NominalSize = dto.NominalSize; d.Wall = (decimal?)dto.Wall; d.Schedule = dto.Schedule; });
|
||||
|
||||
foreach (var dto in materials.RectangularTubes)
|
||||
await ImportMaterialAsync(dto, MaterialShape.RectangularTube, existingMaterials, supplierMap, result,
|
||||
() => new RectangularTubeDimensions { Width = dto.Width, Height = dto.Height, Wall = dto.Wall },
|
||||
dim => { var d = (RectangularTubeDimensions)dim; d.Width = dto.Width; d.Height = dto.Height; d.Wall = dto.Wall; });
|
||||
|
||||
foreach (var dto in materials.RoundBars)
|
||||
await ImportMaterialAsync(dto, MaterialShape.RoundBar, existingMaterials, supplierMap, result,
|
||||
() => new RoundBarDimensions { Diameter = dto.Diameter },
|
||||
dim => { var d = (RoundBarDimensions)dim; d.Diameter = dto.Diameter; });
|
||||
|
||||
foreach (var dto in materials.RoundTubes)
|
||||
await ImportMaterialAsync(dto, MaterialShape.RoundTube, existingMaterials, supplierMap, result,
|
||||
() => new RoundTubeDimensions { OuterDiameter = dto.OuterDiameter, Wall = dto.Wall },
|
||||
dim => { var d = (RoundTubeDimensions)dim; d.OuterDiameter = dto.OuterDiameter; d.Wall = dto.Wall; });
|
||||
|
||||
foreach (var dto in materials.SquareBars)
|
||||
await ImportMaterialAsync(dto, MaterialShape.SquareBar, existingMaterials, supplierMap, result,
|
||||
() => new SquareBarDimensions { Size = dto.SideLength },
|
||||
dim => { var d = (SquareBarDimensions)dim; d.Size = dto.SideLength; });
|
||||
|
||||
foreach (var dto in materials.SquareTubes)
|
||||
await ImportMaterialAsync(dto, MaterialShape.SquareTube, existingMaterials, supplierMap, result,
|
||||
() => new SquareTubeDimensions { Size = dto.SideLength, Wall = dto.Wall },
|
||||
dim => { var d = (SquareTubeDimensions)dim; d.Size = dto.SideLength; d.Wall = dto.Wall; });
|
||||
}
|
||||
|
||||
private async Task ImportMaterialAsync(
|
||||
CatalogMaterialBaseDto dto, MaterialShape shape,
|
||||
List<Material> existingMaterials, Dictionary<string, int> supplierMap,
|
||||
ImportResultDto result,
|
||||
Func<MaterialDimensions> createDimensions,
|
||||
Action<MaterialDimensions> updateDimensions)
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
if (!Enum.TryParse<MaterialType>(dto.Type, ignoreCase: true, out var type))
|
||||
{
|
||||
if (!Enum.TryParse<MaterialShape>(dto.Shape, ignoreCase: true, out var shape))
|
||||
{
|
||||
result.Errors.Add($"Material '{dto.Shape} - {dto.Size}': Unknown shape '{dto.Shape}'");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Enum.TryParse<MaterialType>(dto.Type, ignoreCase: true, out var type))
|
||||
{
|
||||
type = MaterialType.Steel; // Default
|
||||
result.Warnings.Add($"Material '{dto.Shape} - {dto.Size}': Unknown type '{dto.Type}', defaulting to Steel");
|
||||
}
|
||||
|
||||
var existing = existingMaterials.FirstOrDefault(
|
||||
m => m.Shape == shape && m.Size.Equals(dto.Size, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
Material material;
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
// Update existing material
|
||||
existing.Type = type;
|
||||
existing.Grade = dto.Grade ?? existing.Grade;
|
||||
existing.Description = dto.Description ?? existing.Description;
|
||||
existing.IsActive = true;
|
||||
existing.UpdatedAt = DateTime.UtcNow;
|
||||
|
||||
// Update dimensions if provided
|
||||
if (dto.Dimensions != null && existing.Dimensions != null)
|
||||
{
|
||||
ApplyDimensionValues(existing.Dimensions, dto.Dimensions);
|
||||
existing.SortOrder = existing.Dimensions.GetSortOrder();
|
||||
}
|
||||
|
||||
material = existing;
|
||||
result.MaterialsUpdated++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create new material with dimensions
|
||||
material = new Material
|
||||
{
|
||||
Shape = shape,
|
||||
Type = type,
|
||||
Grade = dto.Grade,
|
||||
Size = dto.Size,
|
||||
Description = dto.Description,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
if (dto.Dimensions != null)
|
||||
{
|
||||
var dimensions = MaterialService.CreateDimensionsForShape(shape);
|
||||
ApplyDimensionValues(dimensions, dto.Dimensions);
|
||||
material = await _materialService.CreateWithDimensionsAsync(material, dimensions);
|
||||
}
|
||||
else
|
||||
{
|
||||
_context.Materials.Add(material);
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
existingMaterials.Add(material);
|
||||
result.MaterialsCreated++;
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Import stock items for this material
|
||||
await ImportStockItemsAsync(material, dto.StockItems, supplierMap, result);
|
||||
type = MaterialType.Steel;
|
||||
result.Warnings.Add($"Material '{shape} - {dto.Size}': Unknown type '{dto.Type}', defaulting to Steel");
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
var existing = existingMaterials.FirstOrDefault(
|
||||
m => m.Shape == shape && m.Size.Equals(dto.Size, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
Material material;
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
result.Errors.Add($"Material '{dto.Shape} - {dto.Size}': {ex.Message}");
|
||||
existing.Type = type;
|
||||
existing.Grade = dto.Grade ?? existing.Grade;
|
||||
existing.Description = dto.Description ?? existing.Description;
|
||||
existing.IsActive = true;
|
||||
existing.UpdatedAt = DateTime.UtcNow;
|
||||
|
||||
if (existing.Dimensions != null)
|
||||
{
|
||||
updateDimensions(existing.Dimensions);
|
||||
existing.SortOrder = existing.Dimensions.GetSortOrder();
|
||||
}
|
||||
|
||||
material = existing;
|
||||
result.MaterialsUpdated++;
|
||||
}
|
||||
else
|
||||
{
|
||||
material = new Material
|
||||
{
|
||||
Shape = shape,
|
||||
Type = type,
|
||||
Grade = dto.Grade,
|
||||
Size = dto.Size,
|
||||
Description = dto.Description,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
var dimensions = createDimensions();
|
||||
material = await _materialService.CreateWithDimensionsAsync(material, dimensions);
|
||||
existingMaterials.Add(material);
|
||||
result.MaterialsCreated++;
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
await ImportStockItemsAsync(material, dto.StockItems, supplierMap, result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Errors.Add($"Material '{shape} - {dto.Size}': {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,7 +398,6 @@ public class CatalogService
|
||||
Material material, List<CatalogStockItemDto> stockItems,
|
||||
Dictionary<string, int> supplierMap, ImportResultDto result)
|
||||
{
|
||||
// Reload stock items for this material to ensure we have current state
|
||||
var existingStockItems = await _context.StockItems
|
||||
.Include(s => s.SupplierOfferings)
|
||||
.Where(s => s.MaterialId == material.Id)
|
||||
@@ -314,7 +418,6 @@ public class CatalogService
|
||||
existing.Notes = dto.Notes ?? existing.Notes;
|
||||
existing.IsActive = true;
|
||||
existing.UpdatedAt = DateTime.UtcNow;
|
||||
// Don't overwrite QuantityOnHand — preserve actual inventory
|
||||
stockItem = existing;
|
||||
result.StockItemsUpdated++;
|
||||
}
|
||||
@@ -335,7 +438,6 @@ public class CatalogService
|
||||
result.StockItemsCreated++;
|
||||
}
|
||||
|
||||
// Import supplier offerings
|
||||
foreach (var offeringDto in dto.SupplierOfferings)
|
||||
{
|
||||
try
|
||||
@@ -394,67 +496,22 @@ public class CatalogService
|
||||
}
|
||||
}
|
||||
|
||||
private static CatalogDimensionsDto? MapDimensions(MaterialDimensions? dim) => dim switch
|
||||
private static List<CatalogStockItemDto> MapStockItems(Material m, List<Supplier> suppliers)
|
||||
{
|
||||
RoundBarDimensions d => new CatalogDimensionsDto { Diameter = d.Diameter },
|
||||
RoundTubeDimensions d => new CatalogDimensionsDto { OuterDiameter = d.OuterDiameter, Wall = d.Wall },
|
||||
FlatBarDimensions d => new CatalogDimensionsDto { Width = d.Width, Thickness = d.Thickness },
|
||||
SquareBarDimensions d => new CatalogDimensionsDto { Size = d.Size },
|
||||
SquareTubeDimensions d => new CatalogDimensionsDto { Size = d.Size, Wall = d.Wall },
|
||||
RectangularTubeDimensions d => new CatalogDimensionsDto { Width = d.Width, Height = d.Height, Wall = d.Wall },
|
||||
AngleDimensions d => new CatalogDimensionsDto { Leg1 = d.Leg1, Leg2 = d.Leg2, Thickness = d.Thickness },
|
||||
ChannelDimensions d => new CatalogDimensionsDto { Height = d.Height, Flange = d.Flange, Web = d.Web },
|
||||
IBeamDimensions d => new CatalogDimensionsDto { Height = d.Height, WeightPerFoot = d.WeightPerFoot },
|
||||
PipeDimensions d => new CatalogDimensionsDto { NominalSize = d.NominalSize, Wall = d.Wall, Schedule = d.Schedule },
|
||||
_ => null
|
||||
};
|
||||
|
||||
private static void ApplyDimensionValues(MaterialDimensions dimensions, CatalogDimensionsDto dto)
|
||||
{
|
||||
switch (dimensions)
|
||||
return m.StockItems.OrderBy(s => s.LengthInches).Select(s => new CatalogStockItemDto
|
||||
{
|
||||
case RoundBarDimensions rb:
|
||||
if (dto.Diameter.HasValue) rb.Diameter = dto.Diameter.Value;
|
||||
break;
|
||||
case RoundTubeDimensions rt:
|
||||
if (dto.OuterDiameter.HasValue) rt.OuterDiameter = dto.OuterDiameter.Value;
|
||||
if (dto.Wall.HasValue) rt.Wall = dto.Wall.Value;
|
||||
break;
|
||||
case FlatBarDimensions fb:
|
||||
if (dto.Width.HasValue) fb.Width = dto.Width.Value;
|
||||
if (dto.Thickness.HasValue) fb.Thickness = dto.Thickness.Value;
|
||||
break;
|
||||
case SquareBarDimensions sb:
|
||||
if (dto.Size.HasValue) sb.Size = dto.Size.Value;
|
||||
break;
|
||||
case SquareTubeDimensions st:
|
||||
if (dto.Size.HasValue) st.Size = dto.Size.Value;
|
||||
if (dto.Wall.HasValue) st.Wall = dto.Wall.Value;
|
||||
break;
|
||||
case RectangularTubeDimensions rect:
|
||||
if (dto.Width.HasValue) rect.Width = dto.Width.Value;
|
||||
if (dto.Height.HasValue) rect.Height = dto.Height.Value;
|
||||
if (dto.Wall.HasValue) rect.Wall = dto.Wall.Value;
|
||||
break;
|
||||
case AngleDimensions a:
|
||||
if (dto.Leg1.HasValue) a.Leg1 = dto.Leg1.Value;
|
||||
if (dto.Leg2.HasValue) a.Leg2 = dto.Leg2.Value;
|
||||
if (dto.Thickness.HasValue) a.Thickness = dto.Thickness.Value;
|
||||
break;
|
||||
case ChannelDimensions c:
|
||||
if (dto.Height.HasValue) c.Height = dto.Height.Value;
|
||||
if (dto.Flange.HasValue) c.Flange = dto.Flange.Value;
|
||||
if (dto.Web.HasValue) c.Web = dto.Web.Value;
|
||||
break;
|
||||
case IBeamDimensions ib:
|
||||
if (dto.Height.HasValue) ib.Height = dto.Height.Value;
|
||||
if (dto.WeightPerFoot.HasValue) ib.WeightPerFoot = dto.WeightPerFoot.Value;
|
||||
break;
|
||||
case PipeDimensions p:
|
||||
if (dto.NominalSize.HasValue) p.NominalSize = dto.NominalSize.Value;
|
||||
if (dto.Wall.HasValue) p.Wall = dto.Wall.Value;
|
||||
if (dto.Schedule != null) p.Schedule = dto.Schedule;
|
||||
break;
|
||||
}
|
||||
LengthInches = s.LengthInches,
|
||||
Name = s.Name,
|
||||
QuantityOnHand = s.QuantityOnHand,
|
||||
Notes = s.Notes,
|
||||
SupplierOfferings = s.SupplierOfferings.Select(o => new CatalogSupplierOfferingDto
|
||||
{
|
||||
SupplierName = suppliers.FirstOrDefault(sup => sup.Id == o.SupplierId)?.Name ?? "Unknown",
|
||||
PartNumber = o.PartNumber,
|
||||
SupplierDescription = o.SupplierDescription,
|
||||
Price = o.Price,
|
||||
Notes = o.Notes
|
||||
}).ToList()
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
# Alro Steel SmartGrid Scraper — Remaining Steps
|
||||
|
||||
## Status: Script is READY TO RUN
|
||||
|
||||
The scraper at `scripts/AlroCatalog/scrape_alro.py` is complete and tested. Discovery mode confirmed it works correctly against the live site.
|
||||
|
||||
## What's Done
|
||||
1. Script written with correct ASP.NET control IDs (discovered via `--discover` mode)
|
||||
2. Level 1 (main grid) navigation: working
|
||||
3. Level 2 (popup grid) navigation: working
|
||||
4. Level 3 (dims panel) scraping: working — uses cascading dropdowns `ddlDimA` → `ddlDimB` → `ddlDimC` → `ddlLength`
|
||||
5. Grade filter: 11 common grades (A-36, 1018, 1045, 1144, 12L14, etc.)
|
||||
6. Size string normalization: "1-1/2\"" matches O'Neal format
|
||||
7. Progress save/resume: working
|
||||
8. Discovery mode verified: A-36 Round bars → 27 sizes, 80 items (lengths include "20 FT", "Custom Cut List", "Drop/Remnant" — non-stock entries filtered out in catalog builder)
|
||||
|
||||
## Remaining Steps
|
||||
|
||||
### Step 1: Run the full scrape
|
||||
```bash
|
||||
cd C:\Users\aisaacs\Desktop\Projects\CutList
|
||||
python scripts/AlroCatalog/scrape_alro.py
|
||||
```
|
||||
- This scrapes all 3 categories (Bars, Pipe/Tube, Structural) for 11 filtered grades
|
||||
- Takes ~30-60 minutes (cascading dropdown selections with 1.5s delay each)
|
||||
- Progress saved incrementally to `scripts/AlroCatalog/alro-scrape-progress.json`
|
||||
- If interrupted, resume with `python scripts/AlroCatalog/scrape_alro.py --resume`
|
||||
- To scrape ALL grades: `python scripts/AlroCatalog/scrape_alro.py --all-grades`
|
||||
|
||||
### Step 2: Review output
|
||||
- Output: `CutList.Web/Data/SeedData/alro-catalog.json`
|
||||
- Verify material counts, shapes, sizes
|
||||
- Spot-check dimensions against myalro.com
|
||||
- Compare shape coverage to O'Neal catalog
|
||||
|
||||
### Step 3: Post-scrape adjustments (if needed)
|
||||
|
||||
**Dimension mapping for Structural/Pipe shapes**: The `build_size_and_dims()` function handles all shapes but Structural (Angle, Channel, Beam) and Pipe/Tube shapes haven't been tested live yet. After scraping, check the screenshots in `scripts/AlroCatalog/screenshots/` to verify dimension mapping. The first item of each new shape gets a screenshot + HTML dump.
|
||||
|
||||
**Known dimension mapping assumptions:**
|
||||
- Angle: DimA = leg size, DimB = thickness → `"leg1 x leg2 x thickness"` (assumes equal legs)
|
||||
- Channel: DimA = height, DimB = flange → needs verification
|
||||
- IBeam: DimA = depth, DimB = weight/ft → `"W{depth} x {wt}"`
|
||||
- SquareTube: DimA = size, DimB = wall
|
||||
- RectTube: DimA = width, DimB = height, DimC = wall
|
||||
- RoundTube: DimA = OD, DimB = wall
|
||||
- Pipe: DimA = NPS, DimB = schedule
|
||||
|
||||
**If dimension mapping is wrong for a shape**: Edit the `build_size_and_dims()` function in `scrape_alro.py` and re-run just the catalog builder:
|
||||
```python
|
||||
python -c "
|
||||
import json
|
||||
from scripts.AlroCatalog.scrape_alro import build_catalog
|
||||
data = json.load(open('scripts/AlroCatalog/alro-scrape-progress.json'))
|
||||
catalog = build_catalog(data['items'])
|
||||
json.dump(catalog, open('CutList.Web/Data/SeedData/alro-catalog.json', 'w'), indent=2)
|
||||
"
|
||||
```
|
||||
|
||||
### Step 4: Part numbers (optional future enhancement)
|
||||
The current scraper captures sizes and lengths but NOT part numbers. To get part numbers, the script would need to:
|
||||
1. Select DimA + DimB + Length
|
||||
2. Click the "Next >" button (`btnSearch`)
|
||||
3. Capture part number from the results panel
|
||||
4. Click Back
|
||||
|
||||
This adds significant time per item. The catalog works without part numbers — the supplierOfferings have empty partNumber/supplierDescription fields.
|
||||
|
||||
## Key Files
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `scripts/AlroCatalog/scrape_alro.py` | The scraper script |
|
||||
| `scripts/AlroCatalog/alro-scrape-progress.json` | Incremental progress (resume support) |
|
||||
| `scripts/AlroCatalog/screenshots/` | Discovery HTML/screenshots per shape |
|
||||
| `CutList.Web/Data/SeedData/alro-catalog.json` | Final output (same schema as oneals-catalog.json) |
|
||||
| `CutList.Web/Data/SeedData/oneals-catalog.json` | Reference format |
|
||||
|
||||
## Grade Filter (editable in script)
|
||||
Located at line ~50 in `scrape_alro.py`. Current filter:
|
||||
- A-36, 1018 CF, 1018 HR, 1044 HR, 1045 CF, 1045 HR, 1045 TG&P
|
||||
- 1144 CF, 1144 HR, 12L14 CF, A311/Stressproof
|
||||
|
||||
To add/remove grades, edit the `GRADE_FILTER` set in the script.
|
||||
@@ -0,0 +1,976 @@
|
||||
{
|
||||
"completed": [
|
||||
[
|
||||
"Bars",
|
||||
"A-36",
|
||||
"ROUND"
|
||||
],
|
||||
[
|
||||
"Bars",
|
||||
"A-36",
|
||||
"FLAT"
|
||||
]
|
||||
],
|
||||
"items": [
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".188",
|
||||
"dim_a_text": "3/16",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".188",
|
||||
"dim_a_text": "3/16",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".250",
|
||||
"dim_a_text": "1/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".250",
|
||||
"dim_a_text": "1/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".250",
|
||||
"dim_a_text": "1/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".313",
|
||||
"dim_a_text": "5/16",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".313",
|
||||
"dim_a_text": "5/16",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".313",
|
||||
"dim_a_text": "5/16",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".375",
|
||||
"dim_a_text": "3/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".375",
|
||||
"dim_a_text": "3/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".375",
|
||||
"dim_a_text": "3/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".438",
|
||||
"dim_a_text": "7/16",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".438",
|
||||
"dim_a_text": "7/16",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".438",
|
||||
"dim_a_text": "7/16",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".500",
|
||||
"dim_a_text": "1/2",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".500",
|
||||
"dim_a_text": "1/2",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".500",
|
||||
"dim_a_text": "1/2",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".563",
|
||||
"dim_a_text": "9/16",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".563",
|
||||
"dim_a_text": "9/16",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".563",
|
||||
"dim_a_text": "9/16",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".625",
|
||||
"dim_a_text": "5/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".625",
|
||||
"dim_a_text": "5/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".625",
|
||||
"dim_a_text": "5/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".750",
|
||||
"dim_a_text": "3/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".750",
|
||||
"dim_a_text": "3/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".750",
|
||||
"dim_a_text": "3/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".875",
|
||||
"dim_a_text": "7/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".875",
|
||||
"dim_a_text": "7/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": ".875",
|
||||
"dim_a_text": "7/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.000",
|
||||
"dim_a_text": "1",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.000",
|
||||
"dim_a_text": "1",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.000",
|
||||
"dim_a_text": "1",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.125",
|
||||
"dim_a_text": "1 1/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.125",
|
||||
"dim_a_text": "1 1/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.125",
|
||||
"dim_a_text": "1 1/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.250",
|
||||
"dim_a_text": "1 1/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.250",
|
||||
"dim_a_text": "1 1/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.250",
|
||||
"dim_a_text": "1 1/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.375",
|
||||
"dim_a_text": "1 3/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.375",
|
||||
"dim_a_text": "1 3/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.375",
|
||||
"dim_a_text": "1 3/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.500",
|
||||
"dim_a_text": "1 1/2",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.500",
|
||||
"dim_a_text": "1 1/2",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.500",
|
||||
"dim_a_text": "1 1/2",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.625",
|
||||
"dim_a_text": "1 5/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.625",
|
||||
"dim_a_text": "1 5/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.625",
|
||||
"dim_a_text": "1 5/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.750",
|
||||
"dim_a_text": "1 3/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.750",
|
||||
"dim_a_text": "1 3/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.750",
|
||||
"dim_a_text": "1 3/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.875",
|
||||
"dim_a_text": "1 7/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.875",
|
||||
"dim_a_text": "1 7/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "1.875",
|
||||
"dim_a_text": "1 7/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.000",
|
||||
"dim_a_text": "2",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.000",
|
||||
"dim_a_text": "2",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.000",
|
||||
"dim_a_text": "2",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.125",
|
||||
"dim_a_text": "2 1/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.125",
|
||||
"dim_a_text": "2 1/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.125",
|
||||
"dim_a_text": "2 1/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.250",
|
||||
"dim_a_text": "2 1/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.250",
|
||||
"dim_a_text": "2 1/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.250",
|
||||
"dim_a_text": "2 1/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.375",
|
||||
"dim_a_text": "2 3/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.375",
|
||||
"dim_a_text": "2 3/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.375",
|
||||
"dim_a_text": "2 3/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.500",
|
||||
"dim_a_text": "2 1/2",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.500",
|
||||
"dim_a_text": "2 1/2",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.500",
|
||||
"dim_a_text": "2 1/2",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.625",
|
||||
"dim_a_text": "2 5/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.625",
|
||||
"dim_a_text": "2 5/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.625",
|
||||
"dim_a_text": "2 5/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.750",
|
||||
"dim_a_text": "2 3/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.750",
|
||||
"dim_a_text": "2 3/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.750",
|
||||
"dim_a_text": "2 3/4",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.875",
|
||||
"dim_a_text": "2 7/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.875",
|
||||
"dim_a_text": "2 7/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "2.875",
|
||||
"dim_a_text": "2 7/8",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "3.000",
|
||||
"dim_a_text": "3",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Custom Cut List",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "3.000",
|
||||
"dim_a_text": "3",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "Drop/Remnant",
|
||||
"length_inches": null
|
||||
},
|
||||
{
|
||||
"grade": "A-36",
|
||||
"shape": "RoundBar",
|
||||
"dim_a_val": "3.000",
|
||||
"dim_a_text": "3",
|
||||
"dim_b_val": null,
|
||||
"dim_b_text": null,
|
||||
"dim_c_val": null,
|
||||
"dim_c_text": null,
|
||||
"length_text": "20 FT",
|
||||
"length_inches": 240.0
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,790 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Alro Steel SmartGrid Scraper
|
||||
Scrapes myalro.com's SmartGrid for Carbon Steel materials and outputs
|
||||
a catalog JSON matching the O'Neal catalog format.
|
||||
|
||||
Usage:
|
||||
python scrape_alro.py # Scrape filtered grades (resumes from saved progress)
|
||||
python scrape_alro.py --all-grades # Scrape ALL grades (slow)
|
||||
python scrape_alro.py --discover # Scrape first item only, dump HTML/screenshots
|
||||
python scrape_alro.py --fresh # Start fresh, ignoring saved progress
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import logging
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from playwright.async_api import async_playwright, Page, TimeoutError as PwTimeout
|
||||
from playwright_stealth import Stealth
|
||||
|
||||
# ── Logging ──────────────────────────────────────────────────────────
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s [%(levelname)s] %(message)s",
|
||||
datefmt="%H:%M:%S",
|
||||
)
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# ── Paths ────────────────────────────────────────────────────────────
|
||||
SCRIPT_DIR = Path(__file__).parent.resolve()
|
||||
OUTPUT_PATH = (SCRIPT_DIR / "../../CutList.Web/Data/SeedData/alro-catalog.json").resolve()
|
||||
PROGRESS_PATH = SCRIPT_DIR / "alro-scrape-progress.json"
|
||||
SCREENSHOTS_DIR = SCRIPT_DIR / "screenshots"
|
||||
|
||||
# ── Config ───────────────────────────────────────────────────────────
|
||||
BASE_URL = "https://www.myalro.com/SmartGrid.aspx?PT=Steel&Clear=true"
|
||||
DELAY = 5 # seconds between postback clicks
|
||||
TIMEOUT = 15_000 # ms for element waits
|
||||
CS_ROW = 4 # Carbon Steel row index in main grid
|
||||
|
||||
CATEGORIES = ["Bars", "Pipe / Tube", "Structural"]
|
||||
|
||||
# ┌─────────────────────────────────────────────────────────────────┐
|
||||
# │ GRADE FILTER — only these grades will be scraped. │
|
||||
# │ Use --all-grades flag to override and scrape everything. │
|
||||
# │ Grade names must match the gpname attribute exactly. │
|
||||
# └─────────────────────────────────────────────────────────────────┘
|
||||
GRADE_FILTER = {
|
||||
# Common structural / general purpose
|
||||
"A-36",
|
||||
# Mild steel
|
||||
"1018 CF",
|
||||
"1018 HR",
|
||||
# Medium carbon (shafts, gears, pins)
|
||||
"1045 CF",
|
||||
"1045 HR",
|
||||
"1045 TG&P",
|
||||
# Free-machining
|
||||
"1144 CF",
|
||||
"1144 HR",
|
||||
"12L14 CF",
|
||||
# Hot-rolled plate/bar
|
||||
"1044 HR",
|
||||
# Stressproof (high-strength shafting)
|
||||
"A311/Stressproof",
|
||||
}
|
||||
|
||||
# Alro shape column header → our MaterialShape enum
|
||||
SHAPE_MAP = {
|
||||
"ROUND": "RoundBar",
|
||||
"FLAT": "FlatBar",
|
||||
"SQUARE": "SquareBar",
|
||||
"ANGLE": "Angle",
|
||||
"CHANNEL": "Channel",
|
||||
"BEAM": "IBeam",
|
||||
"SQ TUBE": "SquareTube",
|
||||
"SQUARE TUBE": "SquareTube",
|
||||
"REC TUBE": "RectangularTube",
|
||||
"RECT TUBE": "RectangularTube",
|
||||
"RECTANGULAR TUBE": "RectangularTube",
|
||||
"ROUND TUBE": "RoundTube",
|
||||
"RND TUBE": "RoundTube",
|
||||
"PIPE": "Pipe",
|
||||
}
|
||||
|
||||
# ── ASP.NET control IDs ─────────────────────────────────────────
|
||||
_CP = "ctl00_ContentPlaceHolder1"
|
||||
_PU = f"{_CP}_pnlPopUP"
|
||||
ID = dict(
|
||||
main_grid = f"{_CP}_grdMain",
|
||||
popup_grid = f"{_PU}_grdPopUp",
|
||||
popup_window = f"{_PU}_Window",
|
||||
dims_panel = f"{_PU}_upnlDims",
|
||||
back_btn = f"{_PU}_btnBack",
|
||||
# Dimension dropdowns (cascading: A → B → C → Length)
|
||||
dim_a = f"{_PU}_ddlDimA",
|
||||
dim_b = f"{_PU}_ddlDimB",
|
||||
dim_c = f"{_PU}_ddlDimC",
|
||||
dim_length = f"{_PU}_ddlLength",
|
||||
btn_next = f"{_PU}_btnSearch",
|
||||
)
|
||||
|
||||
# Postback targets ($ separators)
|
||||
PB = dict(
|
||||
main_grid = "ctl00$ContentPlaceHolder1$grdMain",
|
||||
popup_grid = "ctl00$ContentPlaceHolder1$pnlPopUP$grdPopUp",
|
||||
back_btn = "ctl00$ContentPlaceHolder1$pnlPopUP$btnBack",
|
||||
popup = "ctl00$ContentPlaceHolder1$pnlPopUP",
|
||||
dim_a = "ctl00$ContentPlaceHolder1$pnlPopUP$ddlDimA",
|
||||
dim_b = "ctl00$ContentPlaceHolder1$pnlPopUP$ddlDimB",
|
||||
dim_c = "ctl00$ContentPlaceHolder1$pnlPopUP$ddlDimC",
|
||||
)
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# Utility helpers
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
def parse_fraction(s: str) -> float | None:
|
||||
"""Parse fraction/decimal string → float. '1-1/4' → 1.25, '.250' → 0.25"""
|
||||
if not s:
|
||||
return None
|
||||
s = s.strip().strip('"\'')
|
||||
# Collapse double spaces from Alro dropdown text ("1 1/4" → "1 1/4")
|
||||
s = re.sub(r"\s+", " ", s)
|
||||
if not s:
|
||||
return None
|
||||
try:
|
||||
return float(s)
|
||||
except ValueError:
|
||||
pass
|
||||
# Mixed fraction: "1-1/4" or "1 1/4"
|
||||
m = re.match(r"^(\d+)[\s-](\d+)/(\d+)$", s)
|
||||
if m:
|
||||
return int(m[1]) + int(m[2]) / int(m[3])
|
||||
m = re.match(r"^(\d+)/(\d+)$", s)
|
||||
if m:
|
||||
return int(m[1]) / int(m[2])
|
||||
m = re.match(r"^(\d+)$", s)
|
||||
if m:
|
||||
return float(m[1])
|
||||
return None
|
||||
|
||||
|
||||
def decimal_to_fraction(value: float) -> str:
|
||||
"""0.25 → '1/4', 1.25 → '1-1/4', 3.0 → '3'"""
|
||||
if value <= 0:
|
||||
return "0"
|
||||
whole = int(value)
|
||||
frac = value - whole
|
||||
if abs(frac) < 0.001:
|
||||
return str(whole)
|
||||
from math import gcd
|
||||
sixteenths = round(frac * 16)
|
||||
if sixteenths == 16:
|
||||
return str(whole + 1)
|
||||
g = gcd(sixteenths, 16)
|
||||
num, den = sixteenths // g, 16 // g
|
||||
frac_s = f"{num}/{den}"
|
||||
return f"{whole}-{frac_s}" if whole else frac_s
|
||||
|
||||
|
||||
def normalize_dim_text(s: str) -> str:
|
||||
"""Normalize dimension text: '1 1/4' → '1-1/4', '3/16' → '3/16'"""
|
||||
s = re.sub(r"\s+", " ", s.strip())
|
||||
# "1 1/4" → "1-1/4" (mixed fraction with space → hyphen)
|
||||
s = re.sub(r"^(\d+)\s+(\d+/\d+)$", r"\1-\2", s)
|
||||
return s
|
||||
|
||||
|
||||
def parse_length_to_inches(text: str) -> float | None:
|
||||
"""Parse length string to inches. \"20'\" → 240, \"240\" → 240"""
|
||||
s = text.strip().upper()
|
||||
s = re.sub(r"\s*(RL|RANDOM.*|LENGTHS?|EA|EACH|STOCK)\s*", "", s).strip()
|
||||
m = re.match(r"^(\d+(?:\.\d+)?)\s*['\u2032]", s)
|
||||
if m:
|
||||
return float(m[1]) * 12
|
||||
m = re.match(r"^(\d+(?:\.\d+)?)\s*FT", s)
|
||||
if m:
|
||||
return float(m[1]) * 12
|
||||
m = re.match(r'^(\d+(?:\.\d+)?)\s*"?\s*$', s)
|
||||
if m:
|
||||
v = float(m[1])
|
||||
return v * 12 if v <= 30 else v
|
||||
return None
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# SmartGrid navigation
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
async def wait_for_update(page: Page, timeout: int = TIMEOUT):
|
||||
"""Wait for ASP.NET partial postback to finish."""
|
||||
try:
|
||||
await page.wait_for_load_state("networkidle", timeout=timeout)
|
||||
except PwTimeout:
|
||||
log.warning(" networkidle timeout – continuing")
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
|
||||
async def do_postback(page: Page, target: str, arg: str):
|
||||
"""Execute a __doPostBack call."""
|
||||
await page.evaluate(f"__doPostBack('{target}', '{arg}')")
|
||||
|
||||
|
||||
async def click_category(page: Page, category: str) -> bool:
|
||||
"""Click a category blue-button for Carbon Steel in the main grid."""
|
||||
log.info(f"Clicking main grid: {category} (row {CS_ROW})")
|
||||
arg = f"{category}${CS_ROW}"
|
||||
link = await page.query_selector(
|
||||
f"#{ID['main_grid']} a[href*=\"'{arg}'\"] img[src*='blue_button']"
|
||||
)
|
||||
if not link:
|
||||
log.error(f" Button not found for {arg}")
|
||||
return False
|
||||
|
||||
parent = await link.evaluate_handle("el => el.parentElement")
|
||||
await parent.as_element().click()
|
||||
|
||||
try:
|
||||
await page.wait_for_selector(f"#{ID['popup_grid']}", state="visible", timeout=TIMEOUT)
|
||||
await wait_for_update(page)
|
||||
return True
|
||||
except PwTimeout:
|
||||
log.error(f" Popup did not appear for {category}")
|
||||
return False
|
||||
|
||||
|
||||
async def scrape_popup_grid(page: Page):
|
||||
"""Parse the popup grid → [(grade_name, grade_id, shape, row_idx, has_btn)]."""
|
||||
headers = await page.eval_on_selector_all(
|
||||
f"#{ID['popup_grid']} tr.DataHeader th",
|
||||
"els => els.map(el => el.textContent.trim())",
|
||||
)
|
||||
log.info(f" Popup columns: {headers}")
|
||||
|
||||
rows = await page.query_selector_all(
|
||||
f"#{ID['popup_grid']} tr.griditemP, #{ID['popup_grid']} tr.gridaltItemP"
|
||||
)
|
||||
combos = []
|
||||
for row_idx, row in enumerate(rows):
|
||||
first_td = await row.query_selector("td[gpid]")
|
||||
if not first_td:
|
||||
continue
|
||||
gid = (await first_td.get_attribute("gpid") or "").strip()
|
||||
gname = (await first_td.get_attribute("gpname") or "").strip()
|
||||
tds = await row.query_selector_all("td")
|
||||
for col_idx, td in enumerate(tds):
|
||||
if col_idx == 0:
|
||||
continue
|
||||
shape = headers[col_idx] if col_idx < len(headers) else ""
|
||||
img = await td.query_selector("img[src*='blue_button']")
|
||||
combos.append((gname, gid, shape, row_idx, img is not None))
|
||||
|
||||
active = sum(1 for c in combos if c[4])
|
||||
log.info(f" {active} active grade/shape combos")
|
||||
return combos
|
||||
|
||||
|
||||
async def click_shape(page: Page, shape: str, row_idx: int) -> bool:
|
||||
"""Click a shape button in the popup grid; wait for dims panel."""
|
||||
arg = f"{shape}${row_idx}"
|
||||
link = await page.query_selector(
|
||||
f"#{ID['popup_grid']} a[href*=\"'{arg}'\"] img[src*='blue_button']"
|
||||
)
|
||||
if not link:
|
||||
try:
|
||||
await do_postback(page, PB["popup_grid"], arg)
|
||||
except Exception:
|
||||
log.warning(f" Could not click shape {arg}")
|
||||
return False
|
||||
else:
|
||||
parent = await link.evaluate_handle("el => el.parentElement")
|
||||
await parent.as_element().click()
|
||||
|
||||
try:
|
||||
# Wait for the DimA dropdown to appear (the real indicator of dims panel loaded)
|
||||
await page.wait_for_selector(f"#{ID['dim_a']}", state="attached", timeout=TIMEOUT)
|
||||
await wait_for_update(page)
|
||||
return True
|
||||
except PwTimeout:
|
||||
# Check if panel has any content at all
|
||||
html = await page.inner_html(f"#{ID['dims_panel']}")
|
||||
if len(html.strip()) > 50:
|
||||
await wait_for_update(page)
|
||||
return True
|
||||
log.warning(f" Dims panel timeout for {arg}")
|
||||
return False
|
||||
|
||||
|
||||
async def click_back(page: Page):
|
||||
"""Click Back to return to the popup grid view."""
|
||||
try:
|
||||
await do_postback(page, PB["back_btn"], "")
|
||||
await wait_for_update(page)
|
||||
await asyncio.sleep(DELAY)
|
||||
except Exception as e:
|
||||
log.warning(f" Back button error: {e}")
|
||||
|
||||
|
||||
async def close_popup(page: Page):
|
||||
"""Close the popup window and return to the main grid."""
|
||||
try:
|
||||
await do_postback(page, PB["popup"], "Close")
|
||||
await wait_for_update(page)
|
||||
await asyncio.sleep(DELAY)
|
||||
except Exception as e:
|
||||
log.warning(f" Close popup error: {e}")
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# Level 3 — Dimension Panel Scraping
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
async def get_select_options(page: Page, sel_id: str):
|
||||
"""Return [(value, text), ...] for a <select>, excluding placeholders."""
|
||||
el = await page.query_selector(f"#{sel_id}")
|
||||
if not el:
|
||||
return []
|
||||
# Check if disabled
|
||||
disabled = await el.get_attribute("disabled")
|
||||
if disabled:
|
||||
return []
|
||||
try:
|
||||
opts = await page.eval_on_selector(
|
||||
f"#{sel_id}",
|
||||
"""el => Array.from(el.options).map(o => ({
|
||||
v: o.value, t: o.text.trim(), d: o.disabled
|
||||
}))""",
|
||||
)
|
||||
except Exception:
|
||||
return []
|
||||
return [
|
||||
(o["v"], o["t"])
|
||||
for o in opts
|
||||
if o["v"] and o["v"] != "-1" and o["t"] and not o["d"]
|
||||
and o["t"].lower() not in ("- select -", "--select--", "select...", "select", "")
|
||||
]
|
||||
|
||||
|
||||
async def scrape_dims_panel(page: Page, grade: str, shape_alro: str,
|
||||
shape_mapped: str, *, save_discovery: bool = False,
|
||||
on_item=None, scraped_dim_a: set[str] | None = None):
|
||||
"""Main Level 3 extraction. Returns list of raw item dicts.
|
||||
|
||||
If on_item callback is provided, it is called with each item dict
|
||||
as soon as it is discovered (for incremental saving).
|
||||
If scraped_dim_a is provided, DimA values in that set are skipped (resume).
|
||||
"""
|
||||
items: list[dict] = []
|
||||
|
||||
if save_discovery:
|
||||
SCREENSHOTS_DIR.mkdir(exist_ok=True)
|
||||
safe = f"{grade}_{shape_alro}".replace(" ", "_").replace("/", "-")
|
||||
await page.screenshot(path=str(SCREENSHOTS_DIR / f"dims_{safe}.png"), full_page=True)
|
||||
html = await page.inner_html(f"#{ID['dims_panel']}")
|
||||
(SCREENSHOTS_DIR / f"dims_{safe}.html").write_text(html, encoding="utf-8")
|
||||
log.info(f" Discovery saved → screenshots/dims_{safe}.*")
|
||||
|
||||
# ── Get DimA options (primary dimension: diameter, width, size, etc.) ──
|
||||
dim_a_opts = await get_select_options(page, ID["dim_a"])
|
||||
if not dim_a_opts:
|
||||
log.warning(f" No DimA options found")
|
||||
try:
|
||||
html = await page.inner_html(f"#{ID['dims_panel']}")
|
||||
if len(html) > 50:
|
||||
SCREENSHOTS_DIR.mkdir(exist_ok=True)
|
||||
safe = f"{grade}_{shape_alro}_nodimopts".replace(" ", "_").replace("/", "-")
|
||||
(SCREENSHOTS_DIR / f"{safe}.html").write_text(html, encoding="utf-8")
|
||||
except Exception as e:
|
||||
log.warning(f" Could not dump dims panel: {e}")
|
||||
return []
|
||||
|
||||
already_done = scraped_dim_a or set()
|
||||
remaining = [(v, t) for v, t in dim_a_opts if v not in already_done]
|
||||
if already_done:
|
||||
log.info(f" DimA: {len(dim_a_opts)} sizes ({len(dim_a_opts) - len(remaining)} already scraped, {len(remaining)} remaining)")
|
||||
else:
|
||||
log.info(f" DimA: {len(dim_a_opts)} sizes")
|
||||
|
||||
# All DimA values already scraped — combo is complete
|
||||
if not remaining:
|
||||
return []
|
||||
|
||||
for a_val, a_text in remaining:
|
||||
# Select DimA → triggers postback → DimB/Length populate
|
||||
await page.select_option(f"#{ID['dim_a']}", a_val)
|
||||
await asyncio.sleep(DELAY)
|
||||
await wait_for_update(page)
|
||||
|
||||
# Check if DimB appeared (secondary dimension: thickness, wall, etc.)
|
||||
dim_b_opts = await get_select_options(page, ID["dim_b"])
|
||||
if dim_b_opts:
|
||||
for b_val, b_text in dim_b_opts:
|
||||
await page.select_option(f"#{ID['dim_b']}", b_val)
|
||||
await asyncio.sleep(DELAY)
|
||||
await wait_for_update(page)
|
||||
|
||||
# Check for DimC (tertiary — rare)
|
||||
dim_c_opts = await get_select_options(page, ID["dim_c"])
|
||||
if dim_c_opts:
|
||||
for c_val, c_text in dim_c_opts:
|
||||
await page.select_option(f"#{ID['dim_c']}", c_val)
|
||||
await asyncio.sleep(DELAY)
|
||||
await wait_for_update(page)
|
||||
|
||||
lengths = await get_select_options(page, ID["dim_length"])
|
||||
for l_val, l_text in lengths:
|
||||
item = _make_item(
|
||||
grade, shape_mapped,
|
||||
a_val, a_text, b_val, b_text, c_val, c_text,
|
||||
l_text,
|
||||
)
|
||||
items.append(item)
|
||||
if on_item:
|
||||
on_item(item)
|
||||
else:
|
||||
# No DimC — read lengths
|
||||
lengths = await get_select_options(page, ID["dim_length"])
|
||||
for l_val, l_text in lengths:
|
||||
item = _make_item(
|
||||
grade, shape_mapped,
|
||||
a_val, a_text, b_val, b_text, None, None,
|
||||
l_text,
|
||||
)
|
||||
items.append(item)
|
||||
if on_item:
|
||||
on_item(item)
|
||||
else:
|
||||
# No DimB — just DimA + Length
|
||||
lengths = await get_select_options(page, ID["dim_length"])
|
||||
for l_val, l_text in lengths:
|
||||
item = _make_item(
|
||||
grade, shape_mapped,
|
||||
a_val, a_text, None, None, None, None,
|
||||
l_text,
|
||||
)
|
||||
items.append(item)
|
||||
if on_item:
|
||||
on_item(item)
|
||||
|
||||
return items
|
||||
|
||||
|
||||
def _make_item(grade, shape, a_val, a_text, b_val, b_text, c_val, c_text, l_text):
|
||||
"""Build a raw item dict from dimension selections."""
|
||||
return {
|
||||
"grade": grade,
|
||||
"shape": shape,
|
||||
"dim_a_val": a_val, # decimal string like ".500"
|
||||
"dim_a_text": a_text, # fraction string like "1/2"
|
||||
"dim_b_val": b_val,
|
||||
"dim_b_text": b_text,
|
||||
"dim_c_val": c_val,
|
||||
"dim_c_text": c_text,
|
||||
"length_text": l_text,
|
||||
"length_inches": parse_length_to_inches(l_text),
|
||||
}
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# Output — build catalog JSON
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
def build_size_and_dims(shape: str, item: dict):
|
||||
"""Return (size_string, dimensions_dict) for a catalog material entry.
|
||||
|
||||
Uses the decimal values from dropdown option values for precision,
|
||||
and fraction text from dropdown option text for display.
|
||||
"""
|
||||
# Use the numeric value from the dropdown (e.g. ".500") for precision
|
||||
a = float(item["dim_a_val"]) if item.get("dim_a_val") else None
|
||||
b = float(item["dim_b_val"]) if item.get("dim_b_val") else None
|
||||
c = float(item["dim_c_val"]) if item.get("dim_c_val") else None
|
||||
|
||||
a_txt = normalize_dim_text(item.get("dim_a_text") or "")
|
||||
b_txt = normalize_dim_text(item.get("dim_b_text") or "")
|
||||
c_txt = normalize_dim_text(item.get("dim_c_text") or "")
|
||||
|
||||
if shape == "RoundBar" and a is not None:
|
||||
return f'{a_txt}"', {"diameter": round(a, 4)}
|
||||
|
||||
if shape == "FlatBar":
|
||||
if a is not None and b is not None:
|
||||
return (f'{a_txt}" x {b_txt}"',
|
||||
{"width": round(a, 4), "thickness": round(b, 4)})
|
||||
if a is not None:
|
||||
return f'{a_txt}"', {"width": round(a, 4), "thickness": 0}
|
||||
|
||||
if shape == "SquareBar" and a is not None:
|
||||
return f'{a_txt}"', {"sideLength": round(a, 4)}
|
||||
|
||||
if shape == "Angle":
|
||||
if a is not None and b is not None:
|
||||
return (f'{a_txt}" x {a_txt}" x {b_txt}"',
|
||||
{"leg1": round(a, 4), "leg2": round(a, 4), "thickness": round(b, 4)})
|
||||
if a is not None:
|
||||
return f'{a_txt}"', {"leg1": round(a, 4), "leg2": round(a, 4), "thickness": 0}
|
||||
|
||||
if shape == "Channel":
|
||||
# Channels may use DimA for combined designation or height
|
||||
if a is not None and b is not None:
|
||||
return (f'{a_txt}" x {b_txt}"',
|
||||
{"height": round(a, 4), "flange": round(b, 4), "web": 0})
|
||||
if a is not None:
|
||||
return a_txt, {"height": round(a, 4), "flange": 0, "web": 0}
|
||||
|
||||
if shape == "IBeam":
|
||||
# DimA might be the W-designation, DimB the weight/ft
|
||||
if a is not None and b is not None:
|
||||
return (f"W{int(a)} x {b}",
|
||||
{"height": round(a, 4), "weightPerFoot": round(b, 4)})
|
||||
if a is not None:
|
||||
return f"W{int(a)}", {"height": round(a, 4), "weightPerFoot": 0}
|
||||
|
||||
if shape == "SquareTube":
|
||||
if a is not None and b is not None:
|
||||
return (f'{a_txt}" x {b_txt}" wall',
|
||||
{"sideLength": round(a, 4), "wall": round(b, 4)})
|
||||
if a is not None:
|
||||
return f'{a_txt}"', {"sideLength": round(a, 4), "wall": 0}
|
||||
|
||||
if shape == "RectangularTube":
|
||||
if a is not None and b is not None and c is not None:
|
||||
return (f'{a_txt}" x {b_txt}" x {c_txt}" wall',
|
||||
{"width": round(a, 4), "height": round(b, 4), "wall": round(c, 4)})
|
||||
if a is not None and b is not None:
|
||||
return (f'{a_txt}" x {b_txt}"',
|
||||
{"width": round(a, 4), "height": round(b, 4), "wall": 0})
|
||||
|
||||
if shape == "RoundTube":
|
||||
if a is not None and b is not None:
|
||||
return (f'{a_txt}" OD x {b_txt}" wall',
|
||||
{"outerDiameter": round(a, 4), "wall": round(b, 4)})
|
||||
if a is not None:
|
||||
return f'{a_txt}" OD', {"outerDiameter": round(a, 4), "wall": 0}
|
||||
|
||||
if shape == "Pipe":
|
||||
sched = b_txt or c_txt or "40"
|
||||
if a is not None:
|
||||
return (f'{a_txt}" NPS Sch {sched}',
|
||||
{"nominalSize": round(a, 4), "schedule": sched})
|
||||
|
||||
# Fallback
|
||||
return a_txt or "", {}
|
||||
|
||||
|
||||
SHAPE_GROUP_KEY = {
|
||||
"Angle": "angles",
|
||||
"Channel": "channels",
|
||||
"FlatBar": "flatBars",
|
||||
"IBeam": "iBeams",
|
||||
"Pipe": "pipes",
|
||||
"RectangularTube": "rectangularTubes",
|
||||
"RoundBar": "roundBars",
|
||||
"RoundTube": "roundTubes",
|
||||
"SquareBar": "squareBars",
|
||||
"SquareTube": "squareTubes",
|
||||
}
|
||||
|
||||
|
||||
def build_catalog(scraped: list[dict]) -> dict:
|
||||
"""Assemble the final catalog JSON from scraped item dicts."""
|
||||
materials: dict[tuple, dict] = {}
|
||||
|
||||
for item in scraped:
|
||||
shape = item.get("shape", "")
|
||||
grade = item.get("grade", "")
|
||||
if not shape or not grade:
|
||||
continue
|
||||
|
||||
size_str, dims = build_size_and_dims(shape, item)
|
||||
key = (shape, grade, size_str)
|
||||
|
||||
if key not in materials:
|
||||
mat = {
|
||||
"type": "Steel",
|
||||
"grade": grade,
|
||||
"size": size_str,
|
||||
"stockItems": [],
|
||||
}
|
||||
mat.update(dims)
|
||||
materials[key] = mat
|
||||
|
||||
length = item.get("length_inches")
|
||||
if length and length > 0:
|
||||
existing = {si["lengthInches"] for si in materials[key]["stockItems"]}
|
||||
if round(length, 4) not in existing:
|
||||
materials[key]["stockItems"].append({
|
||||
"lengthInches": round(length, 4),
|
||||
"quantityOnHand": 0,
|
||||
"supplierOfferings": [{
|
||||
"supplierName": "Alro Steel",
|
||||
"partNumber": "",
|
||||
"supplierDescription": "",
|
||||
}],
|
||||
})
|
||||
|
||||
# Group by shape key
|
||||
grouped: dict[str, list] = {v: [] for v in SHAPE_GROUP_KEY.values()}
|
||||
for (shape, _, _), mat in sorted(materials.items(), key=lambda kv: (kv[0][0], kv[0][1], kv[0][2])):
|
||||
group_key = SHAPE_GROUP_KEY.get(shape)
|
||||
if group_key:
|
||||
grouped[group_key].append(mat)
|
||||
|
||||
return {
|
||||
"exportedAt": datetime.now(timezone.utc).isoformat(),
|
||||
"suppliers": [{"name": "Alro Steel"}],
|
||||
"cuttingTools": [
|
||||
{"name": "Bandsaw", "kerfInches": 0.0625, "isDefault": True},
|
||||
{"name": "Chop Saw", "kerfInches": 0.125, "isDefault": False},
|
||||
{"name": "Cold Cut Saw", "kerfInches": 0.0625, "isDefault": False},
|
||||
{"name": "Hacksaw", "kerfInches": 0.0625, "isDefault": False},
|
||||
],
|
||||
"materials": grouped,
|
||||
}
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# Progress management
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
def load_progress() -> dict:
|
||||
if PROGRESS_PATH.exists():
|
||||
return json.loads(PROGRESS_PATH.read_text(encoding="utf-8"))
|
||||
return {"completed": [], "items": []}
|
||||
|
||||
|
||||
def save_progress(progress: dict):
|
||||
PROGRESS_PATH.write_text(json.dumps(progress, indent=2, ensure_ascii=False), encoding="utf-8")
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# Main
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
async def main():
|
||||
discover = "--discover" in sys.argv
|
||||
fresh = "--fresh" in sys.argv
|
||||
all_grades = "--all-grades" in sys.argv
|
||||
|
||||
progress = {"completed": [], "items": []} if fresh else load_progress()
|
||||
all_items: list[dict] = progress.get("items", [])
|
||||
done_keys: set[tuple] = {tuple(k) for k in progress.get("completed", [])}
|
||||
|
||||
# Build index of saved DimA values per (grade, shape) for partial resume
|
||||
saved_dim_a: dict[tuple[str, str], set[str]] = {}
|
||||
if all_items and not fresh:
|
||||
for item in all_items:
|
||||
key = (item.get("grade", ""), item.get("shape", ""))
|
||||
saved_dim_a.setdefault(key, set()).add(item.get("dim_a_val", ""))
|
||||
|
||||
log.info("Alro Steel SmartGrid Scraper")
|
||||
if all_grades:
|
||||
log.info(" Mode: ALL grades")
|
||||
else:
|
||||
log.info(f" Filtering to {len(GRADE_FILTER)} grades: {', '.join(sorted(GRADE_FILTER))}")
|
||||
if fresh:
|
||||
log.info(" Fresh start — ignoring saved progress")
|
||||
elif done_keys:
|
||||
log.info(f" Resuming: {len(done_keys)} combos done, {len(all_items)} items saved")
|
||||
if discover:
|
||||
log.info(" Discovery mode — will scrape first item then stop")
|
||||
|
||||
async with Stealth().use_async(async_playwright()) as pw:
|
||||
browser = await pw.chromium.launch(headless=False)
|
||||
ctx = await browser.new_context(
|
||||
viewport={"width": 1280, "height": 900},
|
||||
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
||||
locale="en-US",
|
||||
timezone_id="America/Indiana/Indianapolis",
|
||||
)
|
||||
page = await ctx.new_page()
|
||||
|
||||
log.info(f"Navigating to SmartGrid …")
|
||||
await page.goto(BASE_URL, wait_until="networkidle", timeout=30_000)
|
||||
await asyncio.sleep(2)
|
||||
|
||||
if not await page.query_selector(f"#{ID['main_grid']}"):
|
||||
log.error("Main grid not found! Saving screenshot.")
|
||||
SCREENSHOTS_DIR.mkdir(exist_ok=True)
|
||||
await page.screenshot(path=str(SCREENSHOTS_DIR / "error_no_grid.png"))
|
||||
await browser.close()
|
||||
return
|
||||
|
||||
log.info("Main grid loaded")
|
||||
total_scraped = 0
|
||||
first_item = True
|
||||
|
||||
for category in CATEGORIES:
|
||||
log.info(f"\n{'=' * 60}")
|
||||
log.info(f" Category: {category}")
|
||||
log.info(f"{'=' * 60}")
|
||||
|
||||
if not await click_category(page, category):
|
||||
continue
|
||||
await asyncio.sleep(DELAY)
|
||||
|
||||
combos = await scrape_popup_grid(page)
|
||||
|
||||
for grade_name, grade_id, shape_name, row_idx, has_btn in combos:
|
||||
if not has_btn:
|
||||
continue
|
||||
|
||||
# Grade filter
|
||||
if not all_grades and grade_name not in GRADE_FILTER:
|
||||
continue
|
||||
|
||||
shape_upper = shape_name.upper().strip()
|
||||
shape_mapped = SHAPE_MAP.get(shape_upper)
|
||||
if shape_mapped is None:
|
||||
log.info(f" Skip unmapped shape: {shape_name}")
|
||||
continue
|
||||
|
||||
combo_key = (category, grade_name, shape_name)
|
||||
if combo_key in done_keys:
|
||||
log.info(f" Skip (done): {grade_name} / {shape_name}")
|
||||
continue
|
||||
|
||||
log.info(f"\n -- {grade_name} / {shape_name} -> {shape_mapped} --")
|
||||
|
||||
if not await click_shape(page, shape_name, row_idx):
|
||||
await click_back(page)
|
||||
await asyncio.sleep(DELAY)
|
||||
continue
|
||||
|
||||
await asyncio.sleep(DELAY)
|
||||
|
||||
combo_count = 0
|
||||
def on_item_discovered(item):
|
||||
nonlocal total_scraped, combo_count
|
||||
all_items.append(item)
|
||||
total_scraped += 1
|
||||
combo_count += 1
|
||||
progress["items"] = all_items
|
||||
save_progress(progress)
|
||||
|
||||
# Pass already-scraped DimA values so partial combos resume correctly
|
||||
already = saved_dim_a.get((grade_name, shape_mapped), set())
|
||||
|
||||
items = await scrape_dims_panel(
|
||||
page, grade_name, shape_name, shape_mapped,
|
||||
save_discovery=first_item or discover,
|
||||
on_item=on_item_discovered,
|
||||
scraped_dim_a=already,
|
||||
)
|
||||
first_item = False
|
||||
|
||||
log.info(f" -> {combo_count} items (total {total_scraped})")
|
||||
|
||||
done_keys.add(combo_key)
|
||||
progress["completed"] = [list(k) for k in done_keys]
|
||||
save_progress(progress)
|
||||
|
||||
await click_back(page)
|
||||
await asyncio.sleep(DELAY)
|
||||
|
||||
if discover:
|
||||
log.info("\nDiscovery done. Check: scripts/AlroCatalog/screenshots/")
|
||||
await browser.close()
|
||||
return
|
||||
|
||||
await close_popup(page)
|
||||
await asyncio.sleep(DELAY)
|
||||
|
||||
await browser.close()
|
||||
|
||||
# ── Build output ──
|
||||
log.info(f"\n{'=' * 60}")
|
||||
log.info(f"Building catalog from {len(all_items)} items …")
|
||||
catalog = build_catalog(all_items)
|
||||
|
||||
OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||
OUTPUT_PATH.write_text(json.dumps(catalog, indent=2, ensure_ascii=False), encoding="utf-8")
|
||||
|
||||
log.info(f"Written: {OUTPUT_PATH}")
|
||||
total_mats = sum(len(v) for v in catalog["materials"].values())
|
||||
total_stock = sum(len(m["stockItems"]) for v in catalog["materials"].values() for m in v)
|
||||
log.info(f"Materials: {total_mats}")
|
||||
log.info(f"Stock items: {total_stock}")
|
||||
for shape_key, mats in sorted(catalog["materials"].items()):
|
||||
if mats:
|
||||
log.info(f" {shape_key}: {len(mats)}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -17,7 +17,6 @@ Param(
|
||||
[string]$InstallDir = "C:\Services\CutListWeb",
|
||||
[string]$Urls = "http://*:5270",
|
||||
[switch]$OpenFirewall,
|
||||
[int]$PublishTimeoutSeconds = 180,
|
||||
[int]$ServiceStopTimeoutSeconds = 30,
|
||||
[int]$ServiceStartTimeoutSeconds = 30
|
||||
)
|
||||
@@ -103,6 +102,7 @@ function Create-Service($name, $bin, $urls) {
|
||||
sc.exe create $name binPath= "$binPath" start= auto DisplayName= "$name" | Out-Null
|
||||
# Set recovery to restart on failure
|
||||
sc.exe failure $name reset= 86400 actions= restart/60000/restart/60000/restart/60000 | Out-Null
|
||||
sc.exe description $name 'CutList bin packing web application' | Out-Null
|
||||
}
|
||||
|
||||
function Start-ServiceSafe($name) {
|
||||
|
||||
Reference in New Issue
Block a user