You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When a work item (WI) or household item (HI) has invoiced budget lines, the expected subsidy payback calculation should use the actual invoice cost, not the projected cost derived from confidence margins. Currently, multiple services compute payback incorrectly for invoiced lines.
Affected Areas
1. Household Item Subsidy Payback Service
householdItemSubsidyPaybackService.ts passes supportsInvoices: false to the factory, so all HI budget lines are treated as non-invoiced and payback is always computed from projected costs (plannedAmount +/- confidence margin). Since EPIC-04 Story 4.9 added HI invoice support (migration 0011: household_item_budget_id on invoices), HI payback should now use actual invoice costs when available.
2. Subsidy Payback Factory Invoice Query
subsidyPaybackServiceFactory.ts hardcodes work_item_budget_id in the invoice aggregation query (line 91). Even if HI payback is changed to supportsInvoices: true, the factory would still query the wrong column. The invoice query column needs to be configurable per entity type.
3. Budget Overview totalReductions
budgetOverviewService.ts computes totalReductions (the aggregate subsidy reduction stat) using plannedAmount for percentage subsidies regardless of whether the line has invoices (lines 220, 427). When a budget line has invoices, the reduction should be calculated from actualCost instead.
Expected Behavior
When a budget line has linked invoices:
The subsidy payback calculation should use the sum of invoice amounts (actual cost) as the base for percentage subsidy reductions, resulting in minPayback === maxPayback === actualCost * rate
Fixed subsidies are unaffected (amount is constant regardless of cost)
This applies to both WI and HI payback calculations on detail pages, as well as the budget overview aggregate
Actual Behavior
HI subsidy payback always uses projected cost (confidence margin applied to plannedAmount), never actual invoice cost
Budget overview totalReductions uses plannedAmount for percentage subsidies even when the line is fully invoiced
The per-WI payback endpoint correctly handles invoices, but HI payback does not
Acceptance Criteria
AC 1: Given a household item with a budget line linked to an invoice, when the HI subsidy payback is calculated, then the payback amount uses the actual invoice cost (not the projected cost from confidence margins), and minPayback === maxPayback for that line
AC 2: Given a work item with a budget line linked to an invoice, when the WI subsidy payback is calculated, then the payback amount uses the actual invoice cost (existing behavior preserved -- regression test)
AC 3: Given a budget line linked to invoices (WI or HI), when the budget overview totalReductions is computed for a percentage subsidy, then the reduction uses the actual invoice cost instead of plannedAmount
AC 4: Given a household item with mixed budget lines (some invoiced, some not), when the HI subsidy payback is calculated, then invoiced lines use actual cost and non-invoiced lines use projected cost with confidence margins
AC 5: Given the subsidy payback factory, when configured for household items with supportsInvoices: true, then the invoice query uses household_item_budget_id (not work_item_budget_id) to aggregate invoice amounts
AC 6: Given the BudgetCostOverview component on the HI detail page, when all budget lines are invoiced, then the expected payback displays a single value (not a range), consistent with the WI detail page behavior
Notes
The subsidyPaybackServiceFactory.ts invoice query column must be parameterized (e.g., via a new config field invoiceBudgetIdColumn)
The budgetBreakdownService.ts and budgetOverviewService.ts payback calculation (lines 458-529) already correctly handle invoiced lines for the aggregate payback -- only totalReductions is affected
The per-WI payback endpoint already works correctly for invoiced lines (AC 2 is a regression guard)
Problem
When a work item (WI) or household item (HI) has invoiced budget lines, the expected subsidy payback calculation should use the actual invoice cost, not the projected cost derived from confidence margins. Currently, multiple services compute payback incorrectly for invoiced lines.
Affected Areas
1. Household Item Subsidy Payback Service
householdItemSubsidyPaybackService.tspassessupportsInvoices: falseto the factory, so all HI budget lines are treated as non-invoiced and payback is always computed from projected costs (plannedAmount +/- confidence margin). Since EPIC-04 Story 4.9 added HI invoice support (migration 0011:household_item_budget_idon invoices), HI payback should now use actual invoice costs when available.2. Subsidy Payback Factory Invoice Query
subsidyPaybackServiceFactory.tshardcodeswork_item_budget_idin the invoice aggregation query (line 91). Even if HI payback is changed tosupportsInvoices: true, the factory would still query the wrong column. The invoice query column needs to be configurable per entity type.3. Budget Overview
totalReductionsbudgetOverviewService.tscomputestotalReductions(the aggregate subsidy reduction stat) usingplannedAmountfor percentage subsidies regardless of whether the line has invoices (lines 220, 427). When a budget line has invoices, the reduction should be calculated fromactualCostinstead.Expected Behavior
When a budget line has linked invoices:
minPayback === maxPayback === actualCost * rateActual Behavior
plannedAmount), never actual invoice costtotalReductionsusesplannedAmountfor percentage subsidies even when the line is fully invoicedAcceptance Criteria
minPayback === maxPaybackfor that linetotalReductionsis computed for a percentage subsidy, then the reduction uses the actual invoice cost instead ofplannedAmountsupportsInvoices: true, then the invoice query useshousehold_item_budget_id(notwork_item_budget_id) to aggregate invoice amountsBudgetCostOverviewcomponent on the HI detail page, when all budget lines are invoiced, then the expected payback displays a single value (not a range), consistent with the WI detail page behaviorNotes
subsidyPaybackServiceFactory.tsinvoice query column must be parameterized (e.g., via a new config fieldinvoiceBudgetIdColumn)budgetBreakdownService.tsandbudgetOverviewService.tspayback calculation (lines 458-529) already correctly handle invoiced lines for the aggregate payback -- onlytotalReductionsis affected