diff --git a/OpenNest.Reporting/NestReportBuilder.cs b/OpenNest.Reporting/NestReportBuilder.cs index 03c4c3c..fa88bf9 100644 --- a/OpenNest.Reporting/NestReportBuilder.cs +++ b/OpenNest.Reporting/NestReportBuilder.cs @@ -27,7 +27,13 @@ public static class NestReportBuilder return item; } - for (var index = 0; index < nest.Plates.Count; index++) + // The editor can leave unused stock at the end of a job. Exclude those placeholders + // from report pages and totals without changing plate numbers or the live nest. + var plateCount = nest.Plates.Count; + while (plateCount > 0 && nest.Plates[plateCount - 1]?.Parts.Count == 0) + plateCount--; + + for (var index = 0; index < plateCount; index++) { var number = index + 1; var plate = nest.Plates[index]; diff --git a/OpenNest.Tests/Reporting/NestPdfWriterTests.cs b/OpenNest.Tests/Reporting/NestPdfWriterTests.cs index c96c08b..dc9220a 100644 --- a/OpenNest.Tests/Reporting/NestPdfWriterTests.cs +++ b/OpenNest.Tests/Reporting/NestPdfWriterTests.cs @@ -79,6 +79,7 @@ public sealed class NestPdfWriterTests : IDisposable public void Write_EmptyAndDemandOnlyJobsProduceExplicitSummaryOnlyReports() { var nest = new Nest("Empty test") { Units = Units.Millimeters }; + nest.Plates.Add(new Plate(24, 48) { Quantity = 1 }); var empty = ReportPdf.Text(WriteReport(nest, "empty.pdf"), 1); Assert.Contains("No plates in this job.", empty); Assert.Contains("No parts in this job.", empty); @@ -91,6 +92,21 @@ public sealed class NestPdfWriterTests : IDisposable Assert.Contains("Page 1 of 1", demand); } + [SkippableFact] + public void Write_TrailingEmptyStockDoesNotAddPagesOrCountTowardTotals() + { + var nest = NestReportTestData.CreateMultiPlateNest(); + var expected = ReportPdf.Pages(WriteReport(nest, "without-empty-stock.pdf")); + nest.Plates.Add(new Plate(24, 48) { Quantity = 5 }); + nest.Plates.Add(new Plate(30, 60) { Quantity = 2 }); + var before = NestReportBuilderTests.Fingerprint(nest); + + var actual = ReportPdf.Pages(WriteReport(nest)); + + Assert.Equal(expected, actual); + Assert.Equal(before, NestReportBuilderTests.Fingerprint(nest)); + } + [Fact] public void Write_TabbedLeadInPartStrokesEachOpenContourSeparately() { diff --git a/docs/nest-reports.md b/docs/nest-reports.md index 5717cba..b0de29a 100644 --- a/docs/nest-reports.md +++ b/docs/nest-reports.md @@ -31,6 +31,8 @@ the selected plate, or certify that a layout passed geometry/pre-post checks. - Recount nested quantities from placements times sheet copies exactly once using checked wide integers. Include unplaced demand; report shortage and extra separately. Cached `Quantity.Nested` is not authoritative. +- Omit trailing empty stock plates from report pages, layout counts and physical + sheet totals. Keep the live nest and remaining plate numbers unchanged. - Distinguish distinct layouts from physical sheets. Per-sheet quantities do not include copies; total quantities do. Utilization uses net part area divided by full sheet area, excluding cutoffs.