Eligibility
Contents
Eligibility#
Eligibility determines who qualifies for a social protection program. It's the set of rules that filter the registry population down to those who should receive benefits.
For: All audiences
What is eligibility?#
Eligibility criteria define the conditions a registrant must meet to participate in a program. These criteria translate policy decisions into concrete rules that OpenSPP can evaluate automatically.
Examples of eligibility criteria:
Program Type |
Eligibility criteria |
|---|---|
Old age pension |
Age 60 or older |
Child grant |
Households with children under 5 |
Poverty assistance |
PMT score below threshold |
Disability support |
Certified disability status |
Geographic targeting |
Residence in specific districts |
Why eligibility matters#
Proper eligibility determination ensures:
Goal |
How eligibility helps |
|---|---|
Targeting accuracy |
Benefits reach intended populations |
Fairness |
Consistent rules applied to all |
Accountability |
Clear, auditable selection criteria |
Efficiency |
Automated filtering reduces manual work |
Budget control |
Predictable beneficiary counts |
Types of eligibility criteria#
Demographic criteria#
Based on individual or household characteristics:
Criterion |
Example rule |
|---|---|
Age |
|
Gender |
|
Disability |
|
Household size |
|
Dependency ratio |
|
Economic criteria#
Based on income, assets, or poverty indicators:
Criterion |
Example rule |
|---|---|
Income |
|
PMT score |
|
Asset ownership |
|
Employment |
|
Geographic criteria#
Based on location:
Criterion |
Example rule |
|---|---|
Administrative area |
|
Rural/Urban |
|
Disaster zone |
|
Categorical criteria#
Based on specific conditions or status:
Criterion |
Example rule |
|---|---|
Orphan status |
|
Refugee status |
|
School enrollment |
|
Health condition |
|
Composite criteria#
Combining multiple conditions:
# Elderly women in rural areas
age >= 60 AND gender == 'female' AND area_type == 'rural'
# Large poor households with children
household_size >= 5 AND pmt_score < 20 AND has_children_under_5 == true
# Working-age adults without employment
age >= 18 AND age < 60 AND employment_status == 'unemployed'
Eligibility in OpenSPP#
How it works#
graph TD
R[Registry Population] --> E[Eligibility Manager]
E --> |Apply criteria| F[Filter registrants]
F --> |Matching| Q[Qualified registrants]
F --> |Not matching| NQ[Not qualified]
Q --> P[Program enrollment]
style R fill:#e3f2fd
style E fill:#fff3e0
style Q fill:#e8f5e9
style NQ fill:#ffebee
Registry data provides the population to evaluate
Eligibility Manager applies configured criteria
Matching registrants become eligible for enrollment
Non-matching registrants are marked as not eligible
Eligibility manager#
The Eligibility Manager is a configurable component that controls how eligibility is determined. OpenSPP supports multiple eligibility approaches:
Manager type |
Description |
Best for |
|---|---|---|
Default (Domain-based) |
Uses Odoo domain filters |
Simple criteria |
CEL Expression |
Uses Common Expression Language |
Complex rules |
Area-based |
Targets specific administrative areas |
Geographic targeting |
Custom |
Developer-defined logic |
Specialized requirements |
Domain-based eligibility#
The default eligibility manager uses Odoo domain syntax:
# Households in specific districts
[('area_id', 'in', [district_1_id, district_2_id])]
# Individuals over 60
[('birthdate', '<=', '1964-01-01')]
# Groups with more than 3 members
[('z_ind_grp_num_individuals', '>=', 3)]
Advantages:
Simple to configure
No coding required
Fast evaluation
Limitations:
Cannot access related records easily
Limited to field comparisons
No complex calculations
CEL-based eligibility#
For complex criteria, OpenSPP supports CEL (Common Expression Language):
# Age-based eligibility
age_years(me.birthdate) >= 60
# Gender and age combined
me.gender == 'female' and age_years(me.birthdate) >= 18
# Household composition check
members.exists(m, age_years(m.birthdate) < 5)
# Using computed metrics
metric('household.pmt_score') < 25
# Complex household criteria
members.filter(m, age_years(m.birthdate) < 18).size() >= 2
CEL features:
Feature |
Description |
Example |
|---|---|---|
|
Current registrant context |
|
|
Household members (for groups) |
|
|
Calculate age from date |
|
|
Access computed variables |
|
|
Check if any member matches |
|
|
Get members matching condition |
|
Geographic targeting#
The area-based eligibility manager simplifies geographic targeting:
Configuration |
Description |
|---|---|
Admin areas |
Select target districts, villages, etc. |
Area types |
Target by area classification |
Nested areas |
Include child areas automatically |
Eligibility workflow#
At program level#
stateDiagram-v2
direction LR
[*] --> Import: Import eligible registrants
Import --> Draft: Create draft memberships
Draft --> Verify: Verify eligibility
Verify --> Enrolled: Passes criteria
Verify --> NotEligible: Fails criteria
Enrolled --> [*]
NotEligible --> Draft: Re-evaluate
Import - Find registrants matching criteria from registry
Draft - Create draft program memberships
Verify - Run eligibility check against current data
Enrolled/Not eligible - Update status based on result
At cycle level#
Each cycle can also verify eligibility:
Copy from program - Bring enrolled members into cycle
Verify cycle eligibility - Re-check against current data
Prepare entitlements - Only for eligible cycle members
This allows for:
Removing members who no longer qualify
Adding newly eligible members
Updating status based on changed circumstances
Multiple eligibility managers#
A program can have multiple eligibility managers that work together:
graph LR
R[Registrants] --> E1[Manager 1:<br/>Age filter]
E1 --> E2[Manager 2:<br/>Area filter]
E2 --> E3[Manager 3:<br/>PMT filter]
E3 --> Q[Qualified]
style E1 fill:#e3f2fd
style E2 fill:#fff3e0
style E3 fill:#f3e5f5
Managers are applied in sequence—a registrant must pass all managers to qualify.
Use cases for multiple managers:
Scenario |
Manager setup |
|---|---|
Layered targeting |
Area → PMT score → Household composition |
Phased rollout |
Core criteria → Additional filters per phase |
Complex programs |
Different criteria for different benefit components |
Eligibility verification#
When to verify#
Timing |
Purpose |
|---|---|
Initial enrollment |
Determine who qualifies |
Each cycle |
Confirm continued eligibility |
After data updates |
Reflect changed circumstances |
On demand |
Manual re-verification |
Verification results#
Result |
Meaning |
Next Steps |
|---|---|---|
Passes |
Meets all criteria |
Proceed with enrollment/benefits |
Fails |
Doesn't meet criteria |
Mark as not eligible |
Pending |
Awaiting data |
Request missing information |
Best practices#
Designing eligibility criteria#
Start simple - Begin with core targeting criteria
Be specific - Clear rules are easier to audit
Consider data availability - Only use data you have
Plan for updates - Circumstances change over time
Document rationale - Record why criteria were chosen
Configuration tips#
Tip |
Reason |
|---|---|
Test with sample data |
Verify criteria work as expected |
Preview counts |
CEL manager shows matching count |
Use progressive refinement |
Add criteria incrementally |
Monitor exclusion rates |
High exclusion may indicate issues |
Common pitfalls#
Pitfall |
Solution |
|---|---|
Missing data causes exclusion |
Handle null values explicitly |
Overly complex criteria |
Simplify or split into multiple managers |
Criteria not updated |
Schedule periodic reviews |
No audit trail |
Log eligibility decisions |
Are you stuck?#
Why are no registrants matching my criteria?#
Check:
Are the field names correct?
Does your data contain the expected values?
Are you targeting the right type (individual vs. group)?
Is the domain syntax valid?
Debug steps:
Start with a minimal criterion
Add conditions one at a time
Use CEL preview to see match counts
Check sample registrant data
How do I target households with specific member characteristics?#
Use CEL expressions with the members context:
# Households with children under 5
members.exists(m, age_years(m.birthdate) < 5)
# Households with 2+ elderly members
members.filter(m, age_years(m.birthdate) >= 60).size() >= 2
# Female-headed households
members.exists(m, m.is_head == true and m.gender == 'female')
Can I combine multiple criteria with OR logic?#
Yes, with CEL:
# Elderly OR disabled
age_years(me.birthdate) >= 60 or me.has_disability == true
With domain syntax, you need to use | operator:
['|', ('age', '>=', 60), ('has_disability', '=', True)]
How do I handle missing data?#
In CEL, use null checks:
# Only check PMT if it exists
me.pmt_score == null or me.pmt_score < 25
In domain syntax:
['|', ('pmt_score', '=', False), ('pmt_score', '<', 25)]
Next steps#
Learn more about concepts:
Programs - How eligibility connects to programs
Cycles - Cycle-level eligibility verification
Entitlements - What happens after eligibility is confirmed
For configuration:
See the Configuration Guide for setting up eligibility managers
For developers:
See the Developer Guide for creating custom eligibility managers
openspp.org