From 546037b61cd0e7acb9d4b1bdfa25fa217db7bf4e Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Thu, 14 May 2026 11:36:34 -0400 Subject: [PATCH] Fix stock capital period handling --- .../tests/test_stock_capital_periods.py | 49 +++++++++++++++++++ .../gov/dwp/esa_income_assessable_capital.py | 1 + .../housing_benefit_assessable_capital.py | 3 +- .../dwp/income_support_assessable_capital.py | 1 + .../gov/dwp/jsa_income_assessable_capital.py | 1 + .../pension_credit_assessable_capital.py | 3 +- .../household_uc_reported_capital.py | 1 + .../universal_credit/uc_assessable_capital.py | 5 +- .../universal_credit/uc_reported_capital.py | 1 + .../student_loans/student_loan_balance.py | 1 + .../wealth/gross_financial_wealth.py | 1 + .../household/wealth/net_financial_wealth.py | 1 + .../variables/household/wealth/savings.py | 1 + .../household/wealth/total_wealth.py | 1 + uv.lock | 2 +- 15 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 policyengine_uk/tests/test_stock_capital_periods.py diff --git a/policyengine_uk/tests/test_stock_capital_periods.py b/policyengine_uk/tests/test_stock_capital_periods.py new file mode 100644 index 000000000..d36c3068b --- /dev/null +++ b/policyengine_uk/tests/test_stock_capital_periods.py @@ -0,0 +1,49 @@ +from policyengine_uk import Simulation + + +def test_uc_capital_stocks_are_not_prorated_in_monthly_calculations(): + situation = { + "people": {"person": {"age": {"2026": 30}}}, + "benunits": { + "benunit": { + "members": ["person"], + "would_claim_uc": {"2026": True}, + } + }, + "households": { + "household": { + "members": ["person"], + "savings": {"2026": 12_000}, + "other_residential_property_value": {"2026": 12_000}, + "corporate_wealth": {"2026": 12_000}, + } + }, + } + simulation = Simulation(situation=situation) + + assert simulation.calculate("savings", "2026-01")[0] == 12_000 + assert simulation.calculate("corporate_wealth", "2026-01")[0] == 12_000 + assert simulation.calculate("uc_assessable_capital", "2026-01")[0] == 36_000 + assert not simulation.calculate("is_uc_eligible", "2026-01")[0] + + +def test_pension_credit_capital_stocks_are_not_prorated_monthly(): + situation = { + "people": {"person": {"age": {"2026": 70}}}, + "benunits": {"benunit": {"members": ["person"]}}, + "households": { + "household": { + "members": ["person"], + "savings": {"2026": 12_000}, + "owned_land": {"2026": 12_000}, + "corporate_wealth": {"2026": 12_000}, + } + }, + } + simulation = Simulation(situation=situation) + + assert simulation.calculate("savings", "2026-01")[0] == 12_000 + assert ( + simulation.calculate("pension_credit_assessable_capital", "2026-01")[0] + == 36_000 + ) diff --git a/policyengine_uk/variables/gov/dwp/esa_income_assessable_capital.py b/policyengine_uk/variables/gov/dwp/esa_income_assessable_capital.py index d159eb3dc..473bcdfeb 100644 --- a/policyengine_uk/variables/gov/dwp/esa_income_assessable_capital.py +++ b/policyengine_uk/variables/gov/dwp/esa_income_assessable_capital.py @@ -15,6 +15,7 @@ class esa_income_assessable_capital(Variable): ) definition_period = YEAR unit = GBP + quantity_type = STOCK def formula(benunit, period, parameters): ESA = parameters(period).gov.dwp.ESA.income diff --git a/policyengine_uk/variables/gov/dwp/housing_benefit/housing_benefit_assessable_capital.py b/policyengine_uk/variables/gov/dwp/housing_benefit/housing_benefit_assessable_capital.py index 060b18377..c978c5f69 100644 --- a/policyengine_uk/variables/gov/dwp/housing_benefit/housing_benefit_assessable_capital.py +++ b/policyengine_uk/variables/gov/dwp/housing_benefit/housing_benefit_assessable_capital.py @@ -11,13 +11,14 @@ class housing_benefit_assessable_capital(Variable): ) definition_period = YEAR unit = GBP + quantity_type = STOCK def formula(benunit, period, parameters): household = benunit.household person = benunit.members any_over_SP_age = benunit.any(person("is_SP_age", period)) p = parameters(period).gov.dwp.housing_benefit.means_test.capital - household_capital = add(household, period, p.sources) + household_capital = sum(household(source, period) for source in p.sources) benunit_adults = add(benunit, period, ["is_adult"]) household_adults = benunit.max( person.household.sum(person.household.members("is_adult", period)) diff --git a/policyengine_uk/variables/gov/dwp/income_support_assessable_capital.py b/policyengine_uk/variables/gov/dwp/income_support_assessable_capital.py index 8ff591249..e497c670f 100644 --- a/policyengine_uk/variables/gov/dwp/income_support_assessable_capital.py +++ b/policyengine_uk/variables/gov/dwp/income_support_assessable_capital.py @@ -14,6 +14,7 @@ class income_support_assessable_capital(Variable): ) definition_period = YEAR unit = GBP + quantity_type = STOCK def formula(benunit, period, parameters): IS = parameters(period).gov.dwp.income_support diff --git a/policyengine_uk/variables/gov/dwp/jsa_income_assessable_capital.py b/policyengine_uk/variables/gov/dwp/jsa_income_assessable_capital.py index 403e24f2c..2483cc994 100644 --- a/policyengine_uk/variables/gov/dwp/jsa_income_assessable_capital.py +++ b/policyengine_uk/variables/gov/dwp/jsa_income_assessable_capital.py @@ -15,6 +15,7 @@ class jsa_income_assessable_capital(Variable): ) definition_period = YEAR unit = GBP + quantity_type = STOCK def formula(benunit, period, parameters): JSA = parameters(period).gov.dwp.JSA.income diff --git a/policyengine_uk/variables/gov/dwp/pension_credit/pension_credit_assessable_capital.py b/policyengine_uk/variables/gov/dwp/pension_credit/pension_credit_assessable_capital.py index b8627bffb..9f4c1fde9 100644 --- a/policyengine_uk/variables/gov/dwp/pension_credit/pension_credit_assessable_capital.py +++ b/policyengine_uk/variables/gov/dwp/pension_credit/pension_credit_assessable_capital.py @@ -13,12 +13,13 @@ class pension_credit_assessable_capital(Variable): ) definition_period = YEAR unit = GBP + quantity_type = STOCK def formula(benunit, period, parameters): household = benunit.household person = benunit.members p = parameters(period).gov.dwp.pension_credit.income.capital - household_capital = add(household, period, p.sources) + household_capital = sum(household(source, period) for source in p.sources) any_pension_age = benunit.any(person("is_SP_age", period)) benunit_pension_age_adults = benunit.sum(person("is_SP_age", period)) household_pension_age_adults = benunit.max( diff --git a/policyengine_uk/variables/gov/dwp/universal_credit/household_uc_reported_capital.py b/policyengine_uk/variables/gov/dwp/universal_credit/household_uc_reported_capital.py index 7e654cf6e..2909c5caa 100644 --- a/policyengine_uk/variables/gov/dwp/universal_credit/household_uc_reported_capital.py +++ b/policyengine_uk/variables/gov/dwp/universal_credit/household_uc_reported_capital.py @@ -7,6 +7,7 @@ class household_uc_reported_capital(Variable): label = "Household Universal Credit capital explicitly reported by benunits" definition_period = YEAR unit = GBP + quantity_type = STOCK def formula(household, period, parameters): person = household.members diff --git a/policyengine_uk/variables/gov/dwp/universal_credit/uc_assessable_capital.py b/policyengine_uk/variables/gov/dwp/universal_credit/uc_assessable_capital.py index da4f42bed..eef9c8f72 100644 --- a/policyengine_uk/variables/gov/dwp/universal_credit/uc_assessable_capital.py +++ b/policyengine_uk/variables/gov/dwp/universal_credit/uc_assessable_capital.py @@ -11,11 +11,14 @@ class uc_assessable_capital(Variable): ) definition_period = YEAR unit = GBP + quantity_type = STOCK def formula(benunit, period, parameters): household = benunit.household p = parameters(period).gov.dwp.universal_credit.means_test - household_capital = add(household, period, p.capital.sources) + household_capital = sum( + household(source, period) for source in p.capital.sources + ) benunit_adults = add(benunit, period, ["is_adult"]) household_reported_capital = household("household_uc_reported_capital", period) household_unreported_adults = household( diff --git a/policyengine_uk/variables/gov/dwp/universal_credit/uc_reported_capital.py b/policyengine_uk/variables/gov/dwp/universal_credit/uc_reported_capital.py index d8c751904..f7bde48ec 100644 --- a/policyengine_uk/variables/gov/dwp/universal_credit/uc_reported_capital.py +++ b/policyengine_uk/variables/gov/dwp/universal_credit/uc_reported_capital.py @@ -12,4 +12,5 @@ class uc_reported_capital(Variable): ) definition_period = YEAR unit = GBP + quantity_type = STOCK default_value = -1 diff --git a/policyengine_uk/variables/gov/hmrc/student_loans/student_loan_balance.py b/policyengine_uk/variables/gov/hmrc/student_loans/student_loan_balance.py index 71a431b2a..0c91e5b35 100644 --- a/policyengine_uk/variables/gov/hmrc/student_loans/student_loan_balance.py +++ b/policyengine_uk/variables/gov/hmrc/student_loans/student_loan_balance.py @@ -11,4 +11,5 @@ class student_loan_balance(Variable): ) definition_period = YEAR unit = GBP + quantity_type = STOCK default_value = 0 diff --git a/policyengine_uk/variables/household/wealth/gross_financial_wealth.py b/policyengine_uk/variables/household/wealth/gross_financial_wealth.py index f62c2338e..eb2d5e884 100644 --- a/policyengine_uk/variables/household/wealth/gross_financial_wealth.py +++ b/policyengine_uk/variables/household/wealth/gross_financial_wealth.py @@ -7,4 +7,5 @@ class gross_financial_wealth(Variable): definition_period = YEAR value_type = float unit = GBP + quantity_type = STOCK uprating = "gov.economic_assumptions.indices.obr.per_capita.gdp" diff --git a/policyengine_uk/variables/household/wealth/net_financial_wealth.py b/policyengine_uk/variables/household/wealth/net_financial_wealth.py index 254518afa..4831b2432 100644 --- a/policyengine_uk/variables/household/wealth/net_financial_wealth.py +++ b/policyengine_uk/variables/household/wealth/net_financial_wealth.py @@ -7,4 +7,5 @@ class net_financial_wealth(Variable): definition_period = YEAR value_type = float unit = GBP + quantity_type = STOCK uprating = "gov.economic_assumptions.indices.obr.per_capita.gdp" diff --git a/policyengine_uk/variables/household/wealth/savings.py b/policyengine_uk/variables/household/wealth/savings.py index d0aea30af..e2ea67ccb 100644 --- a/policyengine_uk/variables/household/wealth/savings.py +++ b/policyengine_uk/variables/household/wealth/savings.py @@ -8,4 +8,5 @@ class savings(Variable): definition_period = YEAR value_type = float unit = GBP + quantity_type = STOCK uprating = "gov.economic_assumptions.indices.obr.per_capita.gdp" diff --git a/policyengine_uk/variables/household/wealth/total_wealth.py b/policyengine_uk/variables/household/wealth/total_wealth.py index 93eac33c6..7a1367090 100644 --- a/policyengine_uk/variables/household/wealth/total_wealth.py +++ b/policyengine_uk/variables/household/wealth/total_wealth.py @@ -7,6 +7,7 @@ class total_wealth(Variable): definition_period = YEAR value_type = float unit = GBP + quantity_type = STOCK adds = [ "property_wealth", diff --git a/uv.lock b/uv.lock index a99714ab0..e2700d7ca 100644 --- a/uv.lock +++ b/uv.lock @@ -1584,7 +1584,7 @@ wheels = [ [[package]] name = "policyengine-uk" -version = "2.88.12" +version = "2.88.15" source = { editable = "." } dependencies = [ { name = "microdf-python", marker = "python_full_version >= '3.11'" },