feat: add BomItems and FormPrograms controllers with parse service
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,122 @@
|
|||||||
|
using FabWorks.Api.DTOs;
|
||||||
|
using FabWorks.Core.Data;
|
||||||
|
using FabWorks.Core.Models;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace FabWorks.Api.Controllers
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/exports/{exportId}/bom-items")]
|
||||||
|
public class BomItemsController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly FabWorksDbContext _db;
|
||||||
|
|
||||||
|
public BomItemsController(FabWorksDbContext db) => _db = db;
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult<List<BomItemDto>>> GetByExport(int exportId)
|
||||||
|
{
|
||||||
|
var items = await _db.BomItems
|
||||||
|
.Include(b => b.CutTemplate)
|
||||||
|
.Include(b => b.FormProgram)
|
||||||
|
.Where(b => b.ExportRecordId == exportId)
|
||||||
|
.OrderBy(b => b.SortOrder)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
return items.Select(MapToDto).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<ActionResult<BomItemDto>> Create(int exportId, BomItemDto dto)
|
||||||
|
{
|
||||||
|
var export = await _db.ExportRecords.FindAsync(exportId);
|
||||||
|
if (export == null) return NotFound("Export record not found");
|
||||||
|
|
||||||
|
var item = new BomItem
|
||||||
|
{
|
||||||
|
ExportRecordId = exportId,
|
||||||
|
ItemNo = dto.ItemNo ?? "",
|
||||||
|
PartNo = dto.PartNo ?? "",
|
||||||
|
SortOrder = dto.SortOrder,
|
||||||
|
Qty = dto.Qty,
|
||||||
|
TotalQty = dto.TotalQty,
|
||||||
|
Description = dto.Description ?? "",
|
||||||
|
PartName = dto.PartName ?? "",
|
||||||
|
ConfigurationName = dto.ConfigurationName ?? "",
|
||||||
|
Material = dto.Material ?? ""
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dto.CutTemplate != null)
|
||||||
|
{
|
||||||
|
item.CutTemplate = new CutTemplate
|
||||||
|
{
|
||||||
|
DxfFilePath = dto.CutTemplate.DxfFilePath ?? "",
|
||||||
|
ContentHash = dto.CutTemplate.ContentHash,
|
||||||
|
Thickness = dto.CutTemplate.Thickness,
|
||||||
|
KFactor = dto.CutTemplate.KFactor,
|
||||||
|
DefaultBendRadius = dto.CutTemplate.DefaultBendRadius
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dto.FormProgram != null)
|
||||||
|
{
|
||||||
|
item.FormProgram = new FormProgram
|
||||||
|
{
|
||||||
|
ProgramFilePath = dto.FormProgram.ProgramFilePath ?? "",
|
||||||
|
ContentHash = dto.FormProgram.ContentHash,
|
||||||
|
ProgramName = dto.FormProgram.ProgramName ?? "",
|
||||||
|
Thickness = dto.FormProgram.Thickness,
|
||||||
|
MaterialType = dto.FormProgram.MaterialType ?? "",
|
||||||
|
KFactor = dto.FormProgram.KFactor,
|
||||||
|
BendCount = dto.FormProgram.BendCount,
|
||||||
|
UpperToolNames = dto.FormProgram.UpperToolNames ?? "",
|
||||||
|
LowerToolNames = dto.FormProgram.LowerToolNames ?? "",
|
||||||
|
SetupNotes = dto.FormProgram.SetupNotes ?? ""
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_db.BomItems.Add(item);
|
||||||
|
await _db.SaveChangesAsync();
|
||||||
|
|
||||||
|
return CreatedAtAction(nameof(GetByExport), new { exportId }, MapToDto(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BomItemDto MapToDto(BomItem b) => new()
|
||||||
|
{
|
||||||
|
ID = b.ID,
|
||||||
|
ItemNo = b.ItemNo,
|
||||||
|
PartNo = b.PartNo,
|
||||||
|
SortOrder = b.SortOrder,
|
||||||
|
Qty = b.Qty,
|
||||||
|
TotalQty = b.TotalQty,
|
||||||
|
Description = b.Description,
|
||||||
|
PartName = b.PartName,
|
||||||
|
ConfigurationName = b.ConfigurationName,
|
||||||
|
Material = b.Material,
|
||||||
|
CutTemplate = b.CutTemplate == null ? null : new CutTemplateDto
|
||||||
|
{
|
||||||
|
Id = b.CutTemplate.Id,
|
||||||
|
DxfFilePath = b.CutTemplate.DxfFilePath,
|
||||||
|
ContentHash = b.CutTemplate.ContentHash,
|
||||||
|
Thickness = b.CutTemplate.Thickness,
|
||||||
|
KFactor = b.CutTemplate.KFactor,
|
||||||
|
DefaultBendRadius = b.CutTemplate.DefaultBendRadius
|
||||||
|
},
|
||||||
|
FormProgram = b.FormProgram == null ? null : new FormProgramDto
|
||||||
|
{
|
||||||
|
Id = b.FormProgram.Id,
|
||||||
|
ProgramFilePath = b.FormProgram.ProgramFilePath,
|
||||||
|
ContentHash = b.FormProgram.ContentHash,
|
||||||
|
ProgramName = b.FormProgram.ProgramName,
|
||||||
|
Thickness = b.FormProgram.Thickness,
|
||||||
|
MaterialType = b.FormProgram.MaterialType,
|
||||||
|
KFactor = b.FormProgram.KFactor,
|
||||||
|
BendCount = b.FormProgram.BendCount,
|
||||||
|
UpperToolNames = b.FormProgram.UpperToolNames,
|
||||||
|
LowerToolNames = b.FormProgram.LowerToolNames,
|
||||||
|
SetupNotes = b.FormProgram.SetupNotes
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
using FabWorks.Api.DTOs;
|
||||||
|
using FabWorks.Api.Services;
|
||||||
|
using FabWorks.Core.Data;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace FabWorks.Api.Controllers
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/form-programs")]
|
||||||
|
public class FormProgramsController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly FabWorksDbContext _db;
|
||||||
|
private readonly FormProgramService _formService;
|
||||||
|
|
||||||
|
public FormProgramsController(FabWorksDbContext db, FormProgramService formService)
|
||||||
|
{
|
||||||
|
_db = db;
|
||||||
|
_formService = formService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("by-drawing")]
|
||||||
|
public async Task<ActionResult<List<FormProgramDto>>> GetByDrawing([FromQuery] string drawingNumber)
|
||||||
|
{
|
||||||
|
var programs = await _db.FormPrograms
|
||||||
|
.Include(fp => fp.BomItem)
|
||||||
|
.ThenInclude(b => b.ExportRecord)
|
||||||
|
.Where(fp => fp.BomItem.ExportRecord.DrawingNumber == drawingNumber)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
return programs.Select(fp => new FormProgramDto
|
||||||
|
{
|
||||||
|
Id = fp.Id,
|
||||||
|
ProgramFilePath = fp.ProgramFilePath,
|
||||||
|
ContentHash = fp.ContentHash,
|
||||||
|
ProgramName = fp.ProgramName,
|
||||||
|
Thickness = fp.Thickness,
|
||||||
|
MaterialType = fp.MaterialType,
|
||||||
|
KFactor = fp.KFactor,
|
||||||
|
BendCount = fp.BendCount,
|
||||||
|
UpperToolNames = fp.UpperToolNames,
|
||||||
|
LowerToolNames = fp.LowerToolNames,
|
||||||
|
SetupNotes = fp.SetupNotes
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("parse")]
|
||||||
|
public ActionResult<FormProgramDto> Parse([FromQuery] string filePath)
|
||||||
|
{
|
||||||
|
if (!System.IO.File.Exists(filePath))
|
||||||
|
return NotFound($"File not found: {filePath}");
|
||||||
|
|
||||||
|
var fp = _formService.ParseFromFile(filePath);
|
||||||
|
return new FormProgramDto
|
||||||
|
{
|
||||||
|
ProgramFilePath = fp.ProgramFilePath,
|
||||||
|
ContentHash = fp.ContentHash,
|
||||||
|
ProgramName = fp.ProgramName,
|
||||||
|
Thickness = fp.Thickness,
|
||||||
|
MaterialType = fp.MaterialType,
|
||||||
|
KFactor = fp.KFactor,
|
||||||
|
BendCount = fp.BendCount,
|
||||||
|
UpperToolNames = fp.UpperToolNames,
|
||||||
|
LowerToolNames = fp.LowerToolNames,
|
||||||
|
SetupNotes = fp.SetupNotes
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("{bomItemId}")]
|
||||||
|
public async Task<ActionResult<FormProgramDto>> AttachToItem(int bomItemId, [FromQuery] string filePath)
|
||||||
|
{
|
||||||
|
var bomItem = await _db.BomItems
|
||||||
|
.Include(b => b.FormProgram)
|
||||||
|
.FirstOrDefaultAsync(b => b.ID == bomItemId);
|
||||||
|
|
||||||
|
if (bomItem == null) return NotFound("BOM item not found");
|
||||||
|
|
||||||
|
if (!System.IO.File.Exists(filePath))
|
||||||
|
return NotFound($"File not found: {filePath}");
|
||||||
|
|
||||||
|
var fp = _formService.ParseFromFile(filePath);
|
||||||
|
fp.BomItemId = bomItemId;
|
||||||
|
|
||||||
|
if (bomItem.FormProgram != null)
|
||||||
|
_db.FormPrograms.Remove(bomItem.FormProgram);
|
||||||
|
|
||||||
|
bomItem.FormProgram = fp;
|
||||||
|
await _db.SaveChangesAsync();
|
||||||
|
|
||||||
|
return new FormProgramDto
|
||||||
|
{
|
||||||
|
Id = fp.Id,
|
||||||
|
ProgramFilePath = fp.ProgramFilePath,
|
||||||
|
ContentHash = fp.ContentHash,
|
||||||
|
ProgramName = fp.ProgramName,
|
||||||
|
Thickness = fp.Thickness,
|
||||||
|
MaterialType = fp.MaterialType,
|
||||||
|
KFactor = fp.KFactor,
|
||||||
|
BendCount = fp.BendCount,
|
||||||
|
UpperToolNames = fp.UpperToolNames,
|
||||||
|
LowerToolNames = fp.LowerToolNames,
|
||||||
|
SetupNotes = fp.SetupNotes
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using FabWorks.Core.Models;
|
||||||
|
using FabWorks.Core.PressBrake;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace FabWorks.Api.Services
|
||||||
|
{
|
||||||
|
public class FormProgramService
|
||||||
|
{
|
||||||
|
public FormProgram ParseFromFile(string filePath)
|
||||||
|
{
|
||||||
|
var pgm = FabWorks.Core.PressBrake.Program.Load(filePath);
|
||||||
|
var hash = ComputeFileHash(filePath);
|
||||||
|
|
||||||
|
return new FormProgram
|
||||||
|
{
|
||||||
|
ProgramFilePath = filePath,
|
||||||
|
ContentHash = hash,
|
||||||
|
ProgramName = pgm.ProgName ?? "",
|
||||||
|
Thickness = pgm.MatThick > 0 ? pgm.MatThick : null,
|
||||||
|
MaterialType = pgm.MatType.ToString(),
|
||||||
|
KFactor = pgm.KFactor > 0 ? pgm.KFactor : null,
|
||||||
|
BendCount = pgm.Steps.Count,
|
||||||
|
UpperToolNames = string.Join(", ", pgm.UpperToolSets
|
||||||
|
.Select(t => t.Name).Where(n => !string.IsNullOrEmpty(n)).Distinct()),
|
||||||
|
LowerToolNames = string.Join(", ", pgm.LowerToolSets
|
||||||
|
.Select(t => t.Name).Where(n => !string.IsNullOrEmpty(n)).Distinct()),
|
||||||
|
SetupNotes = pgm.SetupNotes ?? ""
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ComputeFileHash(string filePath)
|
||||||
|
{
|
||||||
|
using var sha = SHA256.Create();
|
||||||
|
using var stream = File.OpenRead(filePath);
|
||||||
|
var bytes = sha.ComputeHash(stream);
|
||||||
|
return BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user