diff --git a/Api.SeaHavenIndustries.Tests/UpliftQueueReadTests.cs b/Api.SeaHavenIndustries.Tests/UpliftQueueReadTests.cs index 39372fc..f5b0a5d 100644 --- a/Api.SeaHavenIndustries.Tests/UpliftQueueReadTests.cs +++ b/Api.SeaHavenIndustries.Tests/UpliftQueueReadTests.cs @@ -672,6 +672,32 @@ public sealed class UpliftQueueReadTests total.AutoApprovedTotal.Should().Be(0m); } + [Fact] + public async Task Exposure_AutoApprovedSumsGrantedAmountsPerCreationPath() + { + using var context = NewContext(); + var (vendor, workOrder) = await SeedWorkOrderAsync(context, "WO-A", "SITE-A", "HVAC"); + var dispatch = await SeedDispatchAsync(context, vendor, workOrder, "DIS-A"); + context.DispatchUpliftRequests.AddRange( + // Vendor-portal rows (createdby null) store the requested new NTE total: + // 1000 -> 1500 grants 500, then 1500 -> 1800 grants 300. + Request(dispatch, "NoApprovalRequired", new DateTime(2026, 3, 1), decided: new DateTime(2026, 3, 2), requested: 1500m, currentNte: 1000m), + Request(dispatch, "NoApprovalRequired", new DateTime(2026, 3, 3), decided: new DateTime(2026, 3, 4), requested: 1800m, currentNte: 1500m), + // Work-order-path rows (createdby set) store the granted increment: 200. + Request(dispatch, "NoApprovalRequired", new DateTime(2026, 3, 5), decided: new DateTime(2026, 3, 6), requested: 200m, currentNte: 1800m, createdBy: "user-7")); + await context.SaveChangesAsync(); + var data = new UpliftDataService(context); + + var exposure = await data.GetApprovedExposureForWorkOrdersAsync( + new[] { workOrder.Id }, CancellationToken.None); + + // Granted exposure is 500 + 300 + 200; summing raw RequestedNTE would + // double-count whole NTE totals and report 3500. + var total = exposure.Should().ContainSingle(e => e.WorkOrderId == workOrder.Id).Subject; + total.AutoApprovedTotal.Should().Be(1000m); + total.AdminApprovedTotal.Should().Be(0m); + } + // --- Read authorization (tier roles) --- [Fact] diff --git a/SeaHaven.DataServices/Implementation/UpliftDataService.cs b/SeaHaven.DataServices/Implementation/UpliftDataService.cs index 5ebb82e..50249d9 100644 --- a/SeaHaven.DataServices/Implementation/UpliftDataService.cs +++ b/SeaHaven.DataServices/Implementation/UpliftDataService.cs @@ -361,15 +361,17 @@ namespace SeaHaven.DataServices.Implementation .Select(g => new { DispatchId = g.Key, - AutoApproved = g.Where(x => x.Status == "NoApprovalRequired") - .Sum(x => (decimal?)x.RequestedNTE), // The two creation paths store different meanings in RequestedNTE. // Vendor-portal rows store the requested new NTE total, so the // granted amount is RequestedNTE - CurrentNTE; work-order-path rows // store the granted increment directly. Vendor sessions have no // identity user, so createdby is null only on vendor-portal rows. Summing // granted amounts keeps sequential approvals from double-counting whole - // NTE totals. + // NTE totals. This applies to both buckets. + AutoApproved = g.Where(x => x.Status == "NoApprovalRequired") + .Sum(x => (decimal?)(x.createdby == null + ? x.RequestedNTE - (x.CurrentNTE ?? 0m) + : x.RequestedNTE)), AdminApproved = g.Where(x => x.Status == "Approved") .Sum(x => (decimal?)(x.createdby == null ? x.RequestedNTE - (x.CurrentNTE ?? 0m)