diff --git a/PepApi.Core/Controllers/NestsController.cs b/PepApi.Core/Controllers/NestsController.cs index 76a347a..c730c78 100644 --- a/PepApi.Core/Controllers/NestsController.cs +++ b/PepApi.Core/Controllers/NestsController.cs @@ -160,6 +160,52 @@ public class NestsController : ControllerBase if (string.IsNullOrWhiteSpace(search)) return BadRequest(new { message = "Search term is required" }); + var result = await SearchPartsInternalAsync(search, year, customer, limit); + return Ok(result); + } + + /// + /// Batch search for parts across nests by multiple part names. + /// Returns results grouped by search term. + /// + [HttpPost("parts/search/batch")] + public async Task> SearchPartsBatch( + [FromBody] BatchPartSearchRequest request) + { + if (request.SearchTerms == null || request.SearchTerms.Count == 0) + return BadRequest(new { message = "At least one search term is required" }); + + var results = new List(); + + foreach (var searchTerm in request.SearchTerms.Distinct()) + { + if (string.IsNullOrWhiteSpace(searchTerm)) + continue; + + var result = await SearchPartsInternalAsync( + searchTerm, + request.Year, + request.Customer, + request.LimitPerTerm); + + results.Add(result); + } + + return Ok(new BatchPartSearchResponse + { + TotalSearchTerms = results.Count, + TotalMatches = results.Sum(r => r.TotalMatches), + TotalNests = results.SelectMany(r => r.Results).Select(r => r.NestName).Distinct().Count(), + Results = results + }); + } + + private async Task SearchPartsInternalAsync( + string search, + int? year, + string? customer, + int limit) + { var searchUpper = search.Trim().ToUpper(); // Get nest headers - filter by year only if specified @@ -191,14 +237,15 @@ public class NestsController : ControllerBase if (!nests.Any()) { - return Ok(new PartSearchResponse + return new PartSearchResponse { SearchTerm = search, Year = year, TotalMatches = 0, TotalNests = 0, + ResultsReturned = 0, Results = [] - }); + }; } var nestKeys = nests.Select(n => (n.NestName, n.CopyID)).ToHashSet(); @@ -221,6 +268,22 @@ public class NestsController : ControllerBase .Where(p => nestKeys.Contains((p.NestName, p.CopyID))) .ToList(); + // Get material descriptions for materials used in matching nests + var materialNumbers = nests + .Select(n => n.Material) + .Where(m => !string.IsNullOrWhiteSpace(m)) + .Distinct() + .ToList(); + + var materialDescriptions = await _db.MaterialHeaders + .Where(m => materialNumbers.Contains(m.Material)) + .Select(m => new { m.Material, m.Description }) + .ToListAsync(); + + var materialDescriptionLookup = materialDescriptions + .GroupBy(m => m.Material) + .ToDictionary(g => g.Key, g => g.First().Description); + // Group by nest and part name var nestLookup = nests.ToDictionary(n => (n.NestName, n.CopyID)); @@ -229,6 +292,9 @@ public class NestsController : ControllerBase .Select(g => { var nest = nestLookup[(g.Key.NestName, g.Key.CopyID)]; + var materialDesc = nest.Material != null && materialDescriptionLookup.TryGetValue(nest.Material, out var desc) + ? desc + : ""; return new PartSearchResult { PartName = g.Key.Drawing ?? "", @@ -238,6 +304,7 @@ public class NestsController : ControllerBase Comments = nest.Comments ?? "", MaterialNumber = int.TryParse(nest.Material, out var num) ? num : 0, MaterialGrade = nest.MatGrade ?? "", + MaterialDescription = materialDesc, Thickness = nest.MatThick, DateProgrammed = nest.DateProgrammed!.Value, DateLastModified = nest.ModifiedDate ?? nest.DateProgrammed!.Value, @@ -252,7 +319,7 @@ public class NestsController : ControllerBase var limitedResults = limit > 0 ? allResults.Take(limit).ToList() : allResults; - return Ok(new PartSearchResponse + return new PartSearchResponse { SearchTerm = search, Year = year, @@ -260,7 +327,7 @@ public class NestsController : ControllerBase TotalNests = allResults.Select(r => r.NestName).Distinct().Count(), ResultsReturned = limitedResults.Count, Results = limitedResults - }); + }; } private async Task GetNestPathAsync(string nestName, int? year = null) diff --git a/PepApi.Core/Models/PartSearchResult.cs b/PepApi.Core/Models/PartSearchResult.cs index 793787d..29a1c31 100644 --- a/PepApi.Core/Models/PartSearchResult.cs +++ b/PepApi.Core/Models/PartSearchResult.cs @@ -9,6 +9,7 @@ public class PartSearchResult public required string Comments { get; set; } public int MaterialNumber { get; set; } public required string MaterialGrade { get; set; } + public required string MaterialDescription { get; set; } public double Thickness { get; set; } public DateTime DateProgrammed { get; set; } public DateTime DateLastModified { get; set; } @@ -26,3 +27,19 @@ public class PartSearchResponse public int ResultsReturned { get; set; } public List Results { get; set; } = []; } + +public class BatchPartSearchRequest +{ + public required List SearchTerms { get; set; } + public string? Customer { get; set; } + public int? Year { get; set; } + public int LimitPerTerm { get; set; } = 100; +} + +public class BatchPartSearchResponse +{ + public int TotalSearchTerms { get; set; } + public int TotalMatches { get; set; } + public int TotalNests { get; set; } + public List Results { get; set; } = []; +}