-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tax free childcare #1004
base: master
Are you sure you want to change the base?
Tax free childcare #1004
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
from policyengine_uk.model_api import * | ||
|
||
|
||
class child_age_eligible(Variable): | ||
value_type = bool | ||
entity = Person | ||
label = "Child age eligibility requirements" | ||
documentation = "Whether this person meets the age and disability requirements for eligibility" | ||
definition_period = YEAR | ||
|
||
def formula(person, period, parameters): | ||
""" | ||
Calculate age eligibility based on age and disability conditions. | ||
|
||
Returns: | ||
bool: True if eligible (under 12, or under 17 with disability), False otherwise | ||
""" | ||
# Get the benefit unit the person belongs to | ||
benunit = person.benunit | ||
|
||
# Get person's characteristics | ||
age = person("age", period) | ||
|
||
# Check disability conditions | ||
gc = parameters(period).gov.dwp.pension_credit.guarantee_credit | ||
standard_disability_benefits = gc.child.disability.eligibility | ||
severe_disability_benefits = gc.child.disability.severe.eligibility | ||
|
||
is_disabled = (add(person, period, standard_disability_benefits) | | ||
add(person, period, severe_disability_benefits)) > 0 | ||
|
||
# Check age conditions | ||
basic_age_condition = (age < 12) | ||
age_under_17 = (age < 17) | ||
|
||
# Combine conditions | ||
eligible = basic_age_condition | (age_under_17 & is_disabled) | ||
|
||
return benunit.any(eligible) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since this is a person level variable we do not need to add the we want to return |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
from policyengine_uk.model_api import * | ||
|
||
|
||
class meets_income_requirements(Variable): | ||
value_type = bool | ||
entity = Person | ||
label = "Income requirements and calculations" | ||
documentation = "Whether this person meets the income requirements for tax-free childcare based on age and income thresholds" | ||
definition_period = YEAR | ||
|
||
def formula(person, period): | ||
""" | ||
Calculate if a person meets income requirements based on their age and income. | ||
|
||
Returns: | ||
bool: True if they meet the income conditions for their age group | ||
""" | ||
# Get person's characteristics | ||
age = person("age", period) | ||
|
||
# Calculate eligible income | ||
total_income = person("total_income", period) | ||
# Extract investment incomes to subtract | ||
investment_income = add( | ||
person, | ||
period, | ||
[ | ||
"private_pension_income", | ||
"savings_interest_income", | ||
"dividend_income", | ||
"property_income", | ||
] | ||
) | ||
|
||
yearly_eligible_income = total_income - investment_income | ||
|
||
# Income thresholds by age group | ||
quarterly_income = yearly_eligible_income / 4 | ||
|
||
# Age >= 21 | ||
meets_adult_condition = ( | ||
(age >= 21) & | ||
(quarterly_income >= 2379) | ||
) | ||
|
||
# Age 18-20 | ||
meets_young_adult_condition = ( | ||
(age >= 18) & | ||
(age <= 20) & | ||
(quarterly_income >= 1788) | ||
) | ||
|
||
# Age < 18 | ||
meets_youth_condition = ( | ||
(age < 18) & | ||
(quarterly_income >= 1331) | ||
) | ||
|
||
# Combine all conditions | ||
return ( | ||
meets_adult_condition | | ||
meets_young_adult_condition | | ||
meets_youth_condition | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
from policyengine_uk.model_api import * | ||
|
||
|
||
class incompatibilities_childcare_eligible(Variable): | ||
value_type = bool | ||
entity = Person | ||
label = "Tax-Free Childcare Exclusions" | ||
documentation = "Whether the person's benefit unit meets the incompatibility conditions for tax-free childcare (not receiving WTC, CTC, or UC)" | ||
definition_period = YEAR | ||
|
||
def formula(person, period, parameters): | ||
""" | ||
Calculate eligibility based on incompatible benefits. | ||
|
||
Returns: | ||
bool: True if eligible (no incompatible benefits received), False if receiving any incompatible benefits | ||
""" | ||
# Get the benefit unit the person belongs to | ||
benunit = person.benunit | ||
|
||
# Check if receiving any of the mutually exclusive benefits | ||
has_wtc = benunit("working_tax_credit", period) > 0 | ||
has_ctc = benunit("child_tax_credit", period) > 0 | ||
has_uc = benunit("universal_credit", period) > 0 | ||
|
||
# Returns True when person's benefit unit does NOT receive any of these benefits | ||
return ~( | ||
has_wtc | | ||
has_ctc | | ||
has_uc | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
from policyengine_uk.model_api import * | ||
|
||
class childcare_work_condition(Variable): | ||
value_type = bool | ||
entity = Person | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar question for each of the files - do we want to compute this for each person or for the entire Benefit Unit? |
||
label = "Work conditions for tax-free childcare" | ||
documentation = "Whether the person/couple meets work requirements for tax-free childcare" | ||
definition_period = YEAR | ||
def formula(person, period, parameters): | ||
""" | ||
Calculate if person meets work conditions for: | ||
- Single working adult | ||
- Couple where either both work or one works and other has disability/incapacity | ||
""" | ||
benunit = person.benunit | ||
is_adult = person("is_adult", period) | ||
|
||
# Basic work status | ||
in_work = person("in_work", period) | ||
|
||
# Get disability/incapacity conditions like we did in childcare age eligibility | ||
gc = parameters(period).gov.dwp.pension_credit.guarantee_credit | ||
standard_disability_benefits = gc.child.disability.eligibility | ||
severe_disability_benefits = gc.child.disability.severe.eligibility | ||
|
||
is_disabled = (add(person, period, standard_disability_benefits) | | ||
add(person, period, severe_disability_benefits)) > 0 | ||
|
||
has_incapacity = person("incapacity_benefit", period) > 0 | ||
|
||
# Build conditions | ||
# Single adult conditions | ||
is_single = benunit.sum(is_adult) == 1 | ||
single_working = is_single & in_work | ||
|
||
# Couple conditions | ||
is_couple = benunit.sum(is_adult) == 2 | ||
partner_in_work = in_work | ||
partner_has_condition = (is_disabled | has_incapacity) | ||
|
||
couple_both_working = is_couple & in_work & partner_in_work | ||
is_partner_working_with_disabled_person = is_couple & partner_in_work & (is_disabled | has_incapacity) | ||
is_person_working_with_disabled_partner = is_couple & in_work & partner_has_condition | ||
|
||
return ( | ||
single_working | | ||
couple_both_working | | ||
is_person_working_with_disabled_partner | | ||
is_partner_working_with_disabled_person | ||
) |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add a class Use underscores when naming files instead of "-" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
from policyengine_uk.model_api import * | ||
|
||
|
||
def formula(benunit, period, parameters, parents_contribution): | ||
# Define tax-free childcare parameters | ||
p = { | ||
"standard_child": { | ||
"yearly_max": 2000 | ||
}, | ||
"disabled_child": { | ||
"yearly_max": 4000 | ||
}, | ||
"government_contribution": 2/8 | ||
} | ||
|
||
# Check eligibility conditions | ||
meets_age_condition = benunit("child_age_eligible", period) | ||
meets_income_condition = benunit.any(benunit.members("meets_income_requirements", period)) | ||
is_eligible = meets_age_condition & meets_income_condition & benunit("incompatibilities_childcare_eligible", period) | ||
|
||
# Determine the maximum eligible childcare cost for a single child | ||
max_amount = 0 | ||
for child in benunit.members("is_child", period): | ||
if is_eligible[child]: | ||
if child("is_disabled", period): | ||
max_amount = p["disabled_child"]["yearly_max"] # Only consider disabled child's max | ||
else: | ||
max_amount = p["standard_child"]["yearly_max"] # Only consider standard child's max | ||
|
||
# Calculate the government contribution | ||
government_contribution = min(parents_contribution * p["government_contribution"], max_amount) | ||
|
||
return government_contribution |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want to parameterize values such as "12" and "17" - in general we try to avoid hard coding any values that could be adjusted through a parameter reform.