Programs - Gary-Community-Ventures/benefits-api GitHub Wiki
Programs
Programs are the main thing that is displayed to the user on the results page. Text like the name, description, and apply link are handled in the admin, while rules for eligibility and value are handled in code. There are 2 methods for calculating eligibility and value.
- Write our own rules
- Use Policy Engine
This section will discuss programming the rules for a program, and how add/edit a program in the admin.
Admin
The Admin allows non developers to edit program information without the help of a developer.
Creating a program
- Go to the "Translation Admin".
- Go to "Programs".
- Click "Add New".
- Enter the "Name abbreviated" that corresponds to the calculator for the program (you may need to ask a developer for this).
-
Add all of the text for the program by clicking the links, and replacing the placeholder text with the desired text.
- Translation documentation
- Documentation for each field can be found in the Translation admin section.
-
Click "Edit in Main Admin"
- Update the fields
- Documentation for each field can be found in the Main Admin section.
Updating a program
Translation admin
To edit any of the text in the translation admin:
- Go to the "Translation Admin".
- Go to "Programs".
- Search the name of the program.
- Select "Go to".
- Select the field to update.
The translations can also be accessed through the main admin by clicking on the hamburger menu in the "Translate" column
Main Admin
- Go to "Programs.
- Search the name of the program.
- Click on the name.
- Update the fields.
What things mean
Translation admin
The following translated text can be edited in the translation admin:
- Name: The name that is displayed to the user
- Description: The description that is displayed to the user
- Short description: Deprecated
- Learn more link: Deprecated
- Apply button link: The link that will take the user to the application. This is a translation, because there can be different links for different languages
- Value type: Deprecated
- Estimated delivery time: Deprecated
- Estimated application time: The estimated amount of time it would take for the user to apply
- Website description: The description on the page that lists all of the MFB benefits
- Estimated value: If this value is not empty, then the program value will be set to this value. Can be text
Main admin
The following things can be edited in the main admin:
- White label: The white label to show this program in
- Name abbreviated: The rules to use
- External name: Syncs programs across environments
- Legal status required: The citizenship statuses that are eligible for this program
- Documents: The documents that are needed to apply for this program
- Active: Only active programs are showed to the user
- Low confidence: Display a flag to the user that reads "Low Confidence"
- Fpl: The year that the program should be calculated for. For the custom calculators, this is used for choosing what FPL year to use. For the Policy Engine calculators, this is used to determine which period to use.
- Category: The category that the program is in
Other program related features
The following can be added to a program.
- Navigator: An organization that will help the user apply the program.
- Warning message: An additional message to display to the user under certain conditions.
- Translation override: Override translated text of the program under certain conditions.
Development
Base classes are provided for both writing custom rules, and using rules from Policy Engine.
Custom rules
Create a new folder with the name of the new program in one of the state (or federal) folders in /programs/programs/. In that folder add the files __init__.py
and calculator.py
.
To create a program calculator in the calculator.py
, create a new class that inherits from ProgramCalculator
in /programs/programs/calc.py.
The following methods and attributes can be overridden:
household_eligible
(method): Eligibility rules that apply to the whole household.- An
Eligibility
object is passed as a parameter. To add a condition, calle.condition(bool)
. A program will be marked as eligible if all of the conditions areTrue
. There is an additional condition that at least one household member must be eligible.
- An
member_eligible
(method): Eligibility rules that apply to individual household members.- An
MemberEligibility
object is passed as a parameter. To add a condition, calle.condition(bool)
. A member will be marked as eligible if all of the conditions areTrue
.
- An
household_value
(method): The household value of the program if eligible.member_value
(method): The value of the program for each eligible household member.amount
(attribute): The value returned byhousehold_value
if it is not overridden.member_amount
(attribute): The value returned bymember_value
if it is not overridden.dependencies
(attribute): A list of fields needed so that the program does not through an error when run. If the screen is missing one of these fields, then the program will be skipped. Syntax:Screen
andHouseholdMember
fields:{field}
IncomeStream
fields:income_{field}
Expense
fields:expense_{field}
Import and add the calculator to the dictionary in the __init__.py
file in the corresponding state folders /programs/programs/. The key used is matched to the name_abbreviated
of a program.
Policy Engine rules
Policy Engine is the open source rules engine and API that MFB uses for some of it's benefits.
How Policy Engine works
Policy Engine is a fork of OpenFisca, so the best documentation for Policy Engine is the OpenFisca documentation, but here is a way too brief overview of how it works:
- Variables: Calculations are broken down into nodes (or variables) that depend on 0 or more other variables to calculate it's value. For example,
snap_net_income
subtracts thesnap_deductions
variable from thesnap_gross_income
variable. Variables can be overridden to set leaf variables (variables that don't depend on other variables; e.g.age
), override a calculation (this can be useful if there is a bug that needs to be fixed urgently), or to use custom rules. - Periods: Benefits change every year, and periods are the way to select which year (or month in some cases) to calculate a variable for.
- Entities: Entities control who is included in a variable. For example, some benefits (like WIC) are calculated for each member of the household individually, while other benefits (like SNAP) are calculated for the household as a whole.
- Parameters: Instead of hard coding numbers into variables (like income limit), parameters are used so that changes over time can be tracked.
Issues and pull requests can be filed in the policyengine-us GitHub repo for bugs/benefit updates in Policy Engine
Integrating with Policy Engine
Two base classes are provided to interact with the Policy Engine API.
The PolicyEngineScreenInput
, in /programs/programs/policyengine/calculators/dependencies/base.py, base class is used to transform the screen data into a variable in Policy Engine. There are 4 classes to inherit from depending on what entity the variable is in:
Household
TaxUnit
SpmUnit
Member
The following methods and attributes can be overridden:
value
(method): Transforms the screen data into the Policy Engine variable.- By default,
value
returnsNone
. Which means that Policy Engine will calculate the variable and return the result (used for output variables) value
can also return a static value.
- By default,
field
(attribute): The name of the variable whose value is set.dependencies
(attribute): A list of fields needed so that the program does not through an error when run. If the screen is missing one of these fields, then the program will be skipped. Syntax:Screen
andHouseholdMember
fields:{field}
IncomeStream
fields:income_{field}
Expense
fields:expense_{field}
The PolicyEngineCalulator
, in /programs/programs/policyengine/calculators/base.py, base class is used to transform the Policy Engine API response into the program eligibility. There are 3 classes to inherit from depending on what entity the the benefit is in:
PolicyEngineSpmCalulator
PolicyEngineTaxUnitCalulator
PolicyEngineMembersCalculator
The following methods and attributes can be overridden:
household_value
(method): The value of the benefit for the whole household.- Used in classes inherited from
PolicyEngineSpmCalulator
andPolicyEngineTaxUnitCalulator
. - If the value is greater than 0, then the benefit is eligible.
- Use
self.sim.value
to access the variables from the Policy Engine API.
- Used in classes inherited from
member_value
(method): The value of the benefit for each member.- Used in classes inherited from
PolicyEngineMembersCalculator
. - If the value is greater than 0, then the benefit is eligible.
- Use
self.sim.value
to access the variables from the Policy Engine API (pass in themember.id
as the second parameter).
- Used in classes inherited from
pe_inputs
(attribute): A list of dependency classes inherited fromPolicyEngineScreenInput
that represents all of the variables needed to calculate the value.pe_outputs
(attribute): A list of dependency classes inherited fromPolicyEngineScreenInput
that represents the variables that Policy Engine needs to calculate.- The output dependencies should all have a value of
None
.
- The output dependencies should all have a value of
pe_name
(attribute): The name of the variable that will be used as the value if nohousehold_value
ormember_value
is provided.
The POLICY_ENGINE_CLIENT_ID
and POLICY_ENGINE_CLIENT_SECRET
environment variables need to be set in order to use the Policy Engine API.
Debugging
Printing variables to the console can be a useful tool for debugging. The following techniques can be used to print the variables:
To print the value of a specific dependency, add print(self.sim.value(self.pe_category, self.pe_sub_category, "[variable_name]", self.pe_period)
to the household_value
method, or add print(self.sim.value(self.pe_category, str(member.id), "[variable_name]", self.pe_period)
to the member_value
method. Replace [varibale_name]
with the name of the variable to print.
To print all of the variables, add print(self.data)
to the end of the __init__
method in PrivateApiSim
in /programs/programs/policyengine/engines.py. Additionally, more variables can be logged by adding "[variable_name]": {"[period]": None}
to the raw_input
in the pe_input
function in /programs/programs/policyengine/policy_engine.py. Replace [variable_name]
with the name of the variable, and [period]
with the period to compute the variable for.
Brief technical overview
- Program calculators are in the state (and federal) folders in /programs/programs.
- The
ProgramCalculator
base class is located in /programs/programs/calc.py. - The calculators are run in /programs/models.py in the
eligibility
method on theProgram
model. Program
is used ineligibility_results
to return the API response for the results page.- How programs are imported/exported is controlled by the
ProgramDataController
class in /programs/models.py.