Skip to content

Expected payback uses projected cost instead of actual invoice cost for invoiced budget lines #592

@steilerDev

Description

@steilerDev

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.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)
  • Related: EPIC-04 Story 4.9 (PR feat(invoices): add invoice linking for household item budget lines (#413) #414) added HI invoice linking

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions