feat: Migrate MaterialDimensions from TPH to TPC and add Alro catalog seeding
Switch MaterialDimensions inheritance from TPH (single table with discriminator) to TPC (table per concrete type) with individual tables per shape. Add Swagger for dev API exploration, expand SeedController with export/import endpoints and Alro catalog JSON dataset, and include Python scraper for Alro catalog PDFs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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`
|
||||
|
||||
72
CutList.Web/Controllers/Dtos/SeedDataDtos.cs
Normal file
72
CutList.Web/Controllers/Dtos/SeedDataDtos.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace CutList.Web.Controllers.Dtos;
|
||||
|
||||
public class SeedExportData
|
||||
{
|
||||
public DateTime ExportedAt { get; set; }
|
||||
public List<SeedSupplierDto> Suppliers { get; set; } = [];
|
||||
public List<SeedCuttingToolDto> CuttingTools { get; set; } = [];
|
||||
public List<SeedMaterialDto> Materials { get; set; } = [];
|
||||
}
|
||||
|
||||
public class SeedSupplierDto
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
public string? ContactInfo { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
}
|
||||
|
||||
public class SeedCuttingToolDto
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
public decimal KerfInches { get; set; }
|
||||
public bool IsDefault { get; set; }
|
||||
}
|
||||
|
||||
public class SeedMaterialDto
|
||||
{
|
||||
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 SeedDimensionsDto? Dimensions { get; set; }
|
||||
public List<SeedStockItemDto> StockItems { get; set; } = [];
|
||||
}
|
||||
|
||||
public class SeedDimensionsDto
|
||||
{
|
||||
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 string? Schedule { get; set; }
|
||||
}
|
||||
|
||||
public class SeedStockItemDto
|
||||
{
|
||||
public decimal LengthInches { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public int QuantityOnHand { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
public List<SeedSupplierOfferingDto> SupplierOfferings { get; set; } = [];
|
||||
}
|
||||
|
||||
public class SeedSupplierOfferingDto
|
||||
{
|
||||
public string SupplierName { get; set; } = "";
|
||||
public string? PartNumber { get; set; }
|
||||
public string? SupplierDescription { get; set; }
|
||||
public decimal? Price { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
}
|
||||
277
CutList.Web/Controllers/SeedController.cs
Normal file
277
CutList.Web/Controllers/SeedController.cs
Normal file
@@ -0,0 +1,277 @@
|
||||
using CutList.Web.Controllers.Dtos;
|
||||
using CutList.Web.Data;
|
||||
using CutList.Web.Data.Entities;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace CutList.Web.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class SeedController : ControllerBase
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
|
||||
public SeedController(ApplicationDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
[HttpGet("export")]
|
||||
public async Task<ActionResult<SeedExportData>> Export()
|
||||
{
|
||||
var materials = await _context.Materials
|
||||
.Include(m => m.Dimensions)
|
||||
.Include(m => m.StockItems.Where(s => s.IsActive))
|
||||
.ThenInclude(s => s.SupplierOfferings.Where(o => o.IsActive))
|
||||
.Where(m => m.IsActive)
|
||||
.OrderBy(m => m.Shape).ThenBy(m => m.SortOrder)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
|
||||
var suppliers = await _context.Suppliers
|
||||
.Where(s => s.IsActive)
|
||||
.OrderBy(s => s.Name)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
|
||||
var cuttingTools = await _context.CuttingTools
|
||||
.Where(t => t.IsActive)
|
||||
.OrderBy(t => t.Name)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
|
||||
var export = new SeedExportData
|
||||
{
|
||||
ExportedAt = DateTime.UtcNow,
|
||||
Suppliers = suppliers.Select(s => new SeedSupplierDto
|
||||
{
|
||||
Name = s.Name,
|
||||
ContactInfo = s.ContactInfo,
|
||||
Notes = s.Notes
|
||||
}).ToList(),
|
||||
CuttingTools = cuttingTools.Select(t => new SeedCuttingToolDto
|
||||
{
|
||||
Name = t.Name,
|
||||
KerfInches = t.KerfInches,
|
||||
IsDefault = t.IsDefault
|
||||
}).ToList(),
|
||||
Materials = materials.Select(m => new SeedMaterialDto
|
||||
{
|
||||
Shape = m.Shape.ToString(),
|
||||
Type = m.Type.ToString(),
|
||||
Grade = m.Grade,
|
||||
Size = m.Size,
|
||||
Description = m.Description,
|
||||
Dimensions = MapDimensionsToDto(m.Dimensions),
|
||||
StockItems = m.StockItems.OrderBy(s => s.LengthInches).Select(s => new SeedStockItemDto
|
||||
{
|
||||
LengthInches = s.LengthInches,
|
||||
Name = s.Name,
|
||||
QuantityOnHand = s.QuantityOnHand,
|
||||
Notes = s.Notes,
|
||||
SupplierOfferings = s.SupplierOfferings.Select(o => new SeedSupplierOfferingDto
|
||||
{
|
||||
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()
|
||||
};
|
||||
|
||||
return Ok(export);
|
||||
}
|
||||
|
||||
[HttpPost("import")]
|
||||
public async Task<ActionResult> Import([FromBody] SeedExportData data)
|
||||
{
|
||||
var suppliersCreated = 0;
|
||||
var toolsCreated = 0;
|
||||
var materialsCreated = 0;
|
||||
var materialsSkipped = 0;
|
||||
var stockCreated = 0;
|
||||
var offeringsCreated = 0;
|
||||
|
||||
// 1. Suppliers - match by name
|
||||
var supplierMap = new Dictionary<string, Supplier>();
|
||||
foreach (var dto in data.Suppliers)
|
||||
{
|
||||
var existing = await _context.Suppliers.FirstOrDefaultAsync(s => s.Name == dto.Name);
|
||||
if (existing != null)
|
||||
{
|
||||
supplierMap[dto.Name] = existing;
|
||||
}
|
||||
else
|
||||
{
|
||||
var supplier = new Supplier
|
||||
{
|
||||
Name = dto.Name,
|
||||
ContactInfo = dto.ContactInfo,
|
||||
Notes = dto.Notes,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
_context.Suppliers.Add(supplier);
|
||||
supplierMap[dto.Name] = supplier;
|
||||
suppliersCreated++;
|
||||
}
|
||||
}
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// 2. Cutting tools - match by name
|
||||
foreach (var dto in data.CuttingTools)
|
||||
{
|
||||
var exists = await _context.CuttingTools.AnyAsync(t => t.Name == dto.Name);
|
||||
if (!exists)
|
||||
{
|
||||
_context.CuttingTools.Add(new CuttingTool
|
||||
{
|
||||
Name = dto.Name,
|
||||
KerfInches = dto.KerfInches,
|
||||
IsDefault = dto.IsDefault
|
||||
});
|
||||
toolsCreated++;
|
||||
}
|
||||
}
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// 3. Materials - match by shape + size + grade
|
||||
foreach (var dto in data.Materials)
|
||||
{
|
||||
if (!Enum.TryParse<MaterialShape>(dto.Shape, out var shape))
|
||||
{
|
||||
materialsSkipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
Enum.TryParse<MaterialType>(dto.Type, out var type);
|
||||
|
||||
var existing = await _context.Materials
|
||||
.Include(m => m.StockItems)
|
||||
.FirstOrDefaultAsync(m => m.Shape == shape && m.Size == dto.Size && m.Grade == dto.Grade && m.IsActive);
|
||||
|
||||
Material material;
|
||||
if (existing != null)
|
||||
{
|
||||
material = existing;
|
||||
materialsSkipped++;
|
||||
}
|
||||
else
|
||||
{
|
||||
material = new Material
|
||||
{
|
||||
Shape = shape,
|
||||
Type = type,
|
||||
Grade = dto.Grade,
|
||||
Size = dto.Size,
|
||||
Description = dto.Description,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
if (dto.Dimensions != null)
|
||||
material.Dimensions = MapDtoToDimensions(shape, dto.Dimensions);
|
||||
|
||||
_context.Materials.Add(material);
|
||||
await _context.SaveChangesAsync();
|
||||
materialsCreated++;
|
||||
}
|
||||
|
||||
// 4. Stock items - match by material + length
|
||||
foreach (var stockDto in dto.StockItems)
|
||||
{
|
||||
var existingStock = material.StockItems
|
||||
.FirstOrDefault(s => s.LengthInches == stockDto.LengthInches && s.IsActive);
|
||||
|
||||
StockItem stockItem;
|
||||
if (existingStock != null)
|
||||
{
|
||||
stockItem = existingStock;
|
||||
}
|
||||
else
|
||||
{
|
||||
stockItem = new StockItem
|
||||
{
|
||||
MaterialId = material.Id,
|
||||
LengthInches = stockDto.LengthInches,
|
||||
Name = stockDto.Name,
|
||||
QuantityOnHand = stockDto.QuantityOnHand,
|
||||
Notes = stockDto.Notes,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
_context.StockItems.Add(stockItem);
|
||||
await _context.SaveChangesAsync();
|
||||
stockCreated++;
|
||||
}
|
||||
|
||||
// 5. Supplier offerings
|
||||
foreach (var offeringDto in stockDto.SupplierOfferings)
|
||||
{
|
||||
if (!supplierMap.TryGetValue(offeringDto.SupplierName, out var supplier))
|
||||
continue;
|
||||
|
||||
var existingOffering = await _context.SupplierOfferings
|
||||
.AnyAsync(o => o.SupplierId == supplier.Id && o.StockItemId == stockItem.Id);
|
||||
|
||||
if (!existingOffering)
|
||||
{
|
||||
_context.SupplierOfferings.Add(new SupplierOffering
|
||||
{
|
||||
SupplierId = supplier.Id,
|
||||
StockItemId = stockItem.Id,
|
||||
PartNumber = offeringDto.PartNumber,
|
||||
SupplierDescription = offeringDto.SupplierDescription,
|
||||
Price = offeringDto.Price,
|
||||
Notes = offeringDto.Notes
|
||||
});
|
||||
offeringsCreated++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
Message = "Import completed",
|
||||
SuppliersCreated = suppliersCreated,
|
||||
CuttingToolsCreated = toolsCreated,
|
||||
MaterialsCreated = materialsCreated,
|
||||
MaterialsSkipped = materialsSkipped,
|
||||
StockItemsCreated = stockCreated,
|
||||
SupplierOfferingsCreated = offeringsCreated
|
||||
});
|
||||
}
|
||||
|
||||
private static SeedDimensionsDto? MapDimensionsToDto(MaterialDimensions? dim) => dim switch
|
||||
{
|
||||
RoundBarDimensions d => new SeedDimensionsDto { Diameter = d.Diameter },
|
||||
RoundTubeDimensions d => new SeedDimensionsDto { OuterDiameter = d.OuterDiameter, Wall = d.Wall },
|
||||
FlatBarDimensions d => new SeedDimensionsDto { Width = d.Width, Thickness = d.Thickness },
|
||||
SquareBarDimensions d => new SeedDimensionsDto { Size = d.Size },
|
||||
SquareTubeDimensions d => new SeedDimensionsDto { Size = d.Size, Wall = d.Wall },
|
||||
RectangularTubeDimensions d => new SeedDimensionsDto { Width = d.Width, Height = d.Height, Wall = d.Wall },
|
||||
AngleDimensions d => new SeedDimensionsDto { Leg1 = d.Leg1, Leg2 = d.Leg2, Thickness = d.Thickness },
|
||||
ChannelDimensions d => new SeedDimensionsDto { Height = d.Height, Flange = d.Flange, Web = d.Web },
|
||||
IBeamDimensions d => new SeedDimensionsDto { Height = d.Height, WeightPerFoot = d.WeightPerFoot },
|
||||
PipeDimensions d => new SeedDimensionsDto { NominalSize = d.NominalSize, Wall = d.Wall, Schedule = d.Schedule },
|
||||
_ => null
|
||||
};
|
||||
|
||||
private static MaterialDimensions? MapDtoToDimensions(MaterialShape shape, SeedDimensionsDto dto) => shape switch
|
||||
{
|
||||
MaterialShape.RoundBar => new RoundBarDimensions { Diameter = dto.Diameter ?? 0 },
|
||||
MaterialShape.RoundTube => new RoundTubeDimensions { OuterDiameter = dto.OuterDiameter ?? 0, Wall = dto.Wall ?? 0 },
|
||||
MaterialShape.FlatBar => new FlatBarDimensions { Width = dto.Width ?? 0, Thickness = dto.Thickness ?? 0 },
|
||||
MaterialShape.SquareBar => new SquareBarDimensions { Size = dto.Size ?? 0 },
|
||||
MaterialShape.SquareTube => new SquareTubeDimensions { Size = dto.Size ?? 0, Wall = dto.Wall ?? 0 },
|
||||
MaterialShape.RectangularTube => new RectangularTubeDimensions { Width = dto.Width ?? 0, Height = dto.Height ?? 0, Wall = dto.Wall ?? 0 },
|
||||
MaterialShape.Angle => new AngleDimensions { Leg1 = dto.Leg1 ?? 0, Leg2 = dto.Leg2 ?? 0, Thickness = dto.Thickness ?? 0 },
|
||||
MaterialShape.Channel => new ChannelDimensions { Height = dto.Height ?? 0, Flange = dto.Flange ?? 0, Web = dto.Web ?? 0 },
|
||||
MaterialShape.IBeam => new IBeamDimensions { Height = dto.Height ?? 0, WeightPerFoot = dto.WeightPerFoot ?? 0 },
|
||||
MaterialShape.Pipe => new PipeDimensions { NominalSize = dto.NominalSize ?? 0, Wall = dto.Wall ?? 0, Schedule = dto.Schedule },
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
31
CutList.Web/Data/SeedData/alro-catalog.json
Normal file
31
CutList.Web/Data/SeedData/alro-catalog.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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": []
|
||||
}
|
||||
962
CutList.Web/Migrations/20260216183131_MaterialDimensionsTPHtoTPT.Designer.cs
generated
Normal file
962
CutList.Web/Migrations/20260216183131_MaterialDimensionsTPHtoTPT.Designer.cs
generated
Normal file
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
962
CutList.Web/Migrations/20260216190925_RenameDimensionTables.Designer.cs
generated
Normal file
962
CutList.Web/Migrations/20260216190925_RenameDimensionTables.Designer.cs
generated
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
678
CutList.Web/Migrations/20260216190925_RenameDimensionTables.cs
Normal file
678
CutList.Web/Migrations/20260216190925_RenameDimensionTables.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
875
CutList.Web/Migrations/20260216191345_DimensionsTPTtoTPC.Designer.cs
generated
Normal file
875
CutList.Web/Migrations/20260216191345_DimensionsTPTtoTPC.Designer.cs
generated
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
172
CutList.Web/Migrations/20260216191345_DimensionsTPTtoTPC.cs
Normal file
172
CutList.Web/Migrations/20260216191345_DimensionsTPTtoTPC.cs
Normal file
@@ -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();
|
||||
|
||||
83
scripts/AlroCatalog/SCRAPE_PLAN.md
Normal file
83
scripts/AlroCatalog/SCRAPE_PLAN.md
Normal file
@@ -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.
|
||||
971
scripts/AlroCatalog/alro-scrape-progress.json
Normal file
971
scripts/AlroCatalog/alro-scrape-progress.json
Normal file
@@ -0,0 +1,971 @@
|
||||
{
|
||||
"completed": [
|
||||
[
|
||||
"Bars",
|
||||
"A-36",
|
||||
"ROUND"
|
||||
]
|
||||
],
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
728
scripts/AlroCatalog/scrape_alro.py
Normal file
728
scripts/AlroCatalog/scrape_alro.py
Normal file
@@ -0,0 +1,728 @@
|
||||
#!/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 (edit GRADE_FILTER below)
|
||||
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 --resume # Resume from 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):
|
||||
"""Main Level 3 extraction. Returns list of raw item dicts."""
|
||||
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 []
|
||||
|
||||
log.info(f" DimA: {len(dim_a_opts)} sizes")
|
||||
|
||||
for a_val, a_text in dim_a_opts:
|
||||
# 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:
|
||||
items.append(_make_item(
|
||||
grade, shape_mapped,
|
||||
a_val, a_text, b_val, b_text, c_val, c_text,
|
||||
l_text,
|
||||
))
|
||||
else:
|
||||
# No DimC — read lengths
|
||||
lengths = await get_select_options(page, ID["dim_length"])
|
||||
for l_val, l_text in lengths:
|
||||
items.append(_make_item(
|
||||
grade, shape_mapped,
|
||||
a_val, a_text, b_val, b_text, None, None,
|
||||
l_text,
|
||||
))
|
||||
else:
|
||||
# No DimB — just DimA + Length
|
||||
lengths = await get_select_options(page, ID["dim_length"])
|
||||
for l_val, l_text in lengths:
|
||||
items.append(_make_item(
|
||||
grade, shape_mapped,
|
||||
a_val, a_text, None, None, None, None,
|
||||
l_text,
|
||||
))
|
||||
|
||||
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}"', {"size": 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',
|
||||
{"size": round(a, 4), "wall": round(b, 4)})
|
||||
if a is not None:
|
||||
return f'{a_txt}"', {"size": 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 "", {}
|
||||
|
||||
|
||||
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:
|
||||
materials[key] = {
|
||||
"shape": shape,
|
||||
"type": "Steel",
|
||||
"grade": grade,
|
||||
"size": size_str,
|
||||
"dimensions": dims,
|
||||
"stockItems": [],
|
||||
}
|
||||
|
||||
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": "",
|
||||
}],
|
||||
})
|
||||
|
||||
sorted_mats = sorted(materials.values(), key=lambda m: (m["shape"], m["grade"], m["size"]))
|
||||
|
||||
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": sorted_mats,
|
||||
}
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# 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
|
||||
resume = "--resume" in sys.argv
|
||||
all_grades = "--all-grades" in sys.argv
|
||||
|
||||
progress = load_progress() if resume else {"completed": [], "items": []}
|
||||
all_items: list[dict] = progress.get("items", [])
|
||||
done_keys: set[tuple] = {tuple(k) for k in progress.get("completed", [])}
|
||||
|
||||
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 resume:
|
||||
log.info(f" Resuming: {len(done_keys)} combos done, {len(all_items)} items")
|
||||
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)
|
||||
|
||||
items = await scrape_dims_panel(
|
||||
page, grade_name, shape_name, shape_mapped,
|
||||
save_discovery=first_item or discover,
|
||||
)
|
||||
first_item = False
|
||||
|
||||
all_items.extend(items)
|
||||
total_scraped += len(items)
|
||||
log.info(f" -> {len(items)} items (total {total_scraped})")
|
||||
|
||||
done_keys.add(combo_key)
|
||||
progress["completed"] = [list(k) for k in done_keys]
|
||||
progress["items"] = all_items
|
||||
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}")
|
||||
log.info(f"Materials: {len(catalog['materials'])}")
|
||||
total_stock = sum(len(m["stockItems"]) for m in catalog["materials"])
|
||||
log.info(f"Stock items: {total_stock}")
|
||||
by_shape: dict[str, int] = {}
|
||||
for m in catalog["materials"]:
|
||||
by_shape[m["shape"]] = by_shape.get(m["shape"], 0) + 1
|
||||
for s, n in sorted(by_shape.items()):
|
||||
log.info(f" {s}: {n}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user