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; } = [];
+}