Skip to content

Commit e443534

Browse files
Jeremiclaude
andcommitted
docs: add eligibility, entitlements, and payments concept pages
- Create eligibility.md explaining eligibility criteria and managers - Domain-based and CEL-based eligibility configuration - Geographic targeting with administrative areas - Multiple eligibility manager support - Create entitlements.md covering entitlement lifecycle - Cash and in-kind entitlement types - Entitlement states and approval workflow - Calculation methods (fixed, formula, CEL) - Create payments.md documenting payment processing - Payment batches and states - Payment methods (bank, mobile, voucher) - Failure handling and reconciliation - Add learn/index.md and learn/concepts/index.md for navigation - Fix broken doc references in registry.md - Add learn section to main toctree All content based on V2 spp_programs module code. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent aa49e16 commit e443534

7 files changed

Lines changed: 1197 additions & 2 deletions

File tree

docs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ OpenSPP is currently in development, and everything is evolving rapidly thanks t
5454
:hidden: true
5555
5656
getting_started/index
57+
learn/index
5758
tutorial/index
5859
howto/index
5960
technical_reference/index

docs/learn/concepts/eligibility.md

Lines changed: 378 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,378 @@
1+
---
2+
openspp:
3+
doc_status: draft
4+
---
5+
6+
# Eligibility
7+
8+
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.
9+
10+
**For:** All audiences
11+
12+
## What is Eligibility?
13+
14+
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.
15+
16+
**Examples of eligibility criteria:**
17+
18+
| Program Type | Eligibility Criteria |
19+
|-------------|---------------------|
20+
| Old age pension | Age 60 or older |
21+
| Child grant | Households with children under 5 |
22+
| Poverty assistance | PMT score below threshold |
23+
| Disability support | Certified disability status |
24+
| Geographic targeting | Residence in specific districts |
25+
26+
## Why Eligibility Matters
27+
28+
Proper eligibility determination ensures:
29+
30+
| Goal | How Eligibility Helps |
31+
|------|----------------------|
32+
| **Targeting accuracy** | Benefits reach intended populations |
33+
| **Fairness** | Consistent rules applied to all |
34+
| **Accountability** | Clear, auditable selection criteria |
35+
| **Efficiency** | Automated filtering reduces manual work |
36+
| **Budget control** | Predictable beneficiary counts |
37+
38+
## Types of Eligibility Criteria
39+
40+
### Demographic Criteria
41+
42+
Based on individual or household characteristics:
43+
44+
| Criterion | Example Rule |
45+
|-----------|-------------|
46+
| **Age** | `age >= 60` (elderly) or `age < 18` (children) |
47+
| **Gender** | `gender == 'female'` for maternal programs |
48+
| **Disability** | `has_disability == true` |
49+
| **Household size** | `household_size >= 4` (large families) |
50+
| **Dependency ratio** | `dependents / working_adults > 2` |
51+
52+
### Economic Criteria
53+
54+
Based on income, assets, or poverty indicators:
55+
56+
| Criterion | Example Rule |
57+
|-----------|-------------|
58+
| **Income** | `monthly_income < poverty_line` |
59+
| **PMT score** | `pmt_score < 25` (proxy means test) |
60+
| **Asset ownership** | `owns_land == false` |
61+
| **Employment** | `employment_status == 'unemployed'` |
62+
63+
### Geographic Criteria
64+
65+
Based on location:
66+
67+
| Criterion | Example Rule |
68+
|-----------|-------------|
69+
| **Administrative area** | `area_id in target_districts` |
70+
| **Rural/Urban** | `area_type == 'rural'` |
71+
| **Disaster zone** | `area_id in affected_areas` |
72+
73+
### Categorical Criteria
74+
75+
Based on specific conditions or status:
76+
77+
| Criterion | Example Rule |
78+
|-----------|-------------|
79+
| **Orphan status** | `is_orphan == true` |
80+
| **Refugee status** | `registration_type == 'refugee'` |
81+
| **School enrollment** | `enrolled_in_school == true` |
82+
| **Health condition** | `has_chronic_illness == true` |
83+
84+
### Composite Criteria
85+
86+
Combining multiple conditions:
87+
88+
```
89+
# Elderly women in rural areas
90+
age >= 60 AND gender == 'female' AND area_type == 'rural'
91+
92+
# Large poor households with children
93+
household_size >= 5 AND pmt_score < 20 AND has_children_under_5 == true
94+
95+
# Working-age adults without employment
96+
age >= 18 AND age < 60 AND employment_status == 'unemployed'
97+
```
98+
99+
## Eligibility in OpenSPP
100+
101+
### How It Works
102+
103+
```{mermaid}
104+
graph TD
105+
R[Registry Population] --> E[Eligibility Manager]
106+
E --> |Apply criteria| F[Filter registrants]
107+
F --> |Matching| Q[Qualified registrants]
108+
F --> |Not matching| NQ[Not qualified]
109+
Q --> P[Program enrollment]
110+
111+
style R fill:#e3f2fd
112+
style E fill:#fff3e0
113+
style Q fill:#e8f5e9
114+
style NQ fill:#ffebee
115+
```
116+
117+
1. **Registry data** provides the population to evaluate
118+
2. **Eligibility Manager** applies configured criteria
119+
3. **Matching registrants** become eligible for enrollment
120+
4. **Non-matching registrants** are marked as not eligible
121+
122+
### Eligibility Manager
123+
124+
The Eligibility Manager is a configurable component that controls how eligibility is determined. OpenSPP supports multiple eligibility approaches:
125+
126+
| Manager Type | Description | Best For |
127+
|-------------|-------------|----------|
128+
| **Default (Domain-based)** | Uses Odoo domain filters | Simple criteria |
129+
| **CEL Expression** | Uses Common Expression Language | Complex rules |
130+
| **Area-based** | Targets specific administrative areas | Geographic targeting |
131+
| **Custom** | Developer-defined logic | Specialized requirements |
132+
133+
### Domain-Based Eligibility
134+
135+
The default eligibility manager uses Odoo domain syntax:
136+
137+
```python
138+
# Households in specific districts
139+
[('area_id', 'in', [district_1_id, district_2_id])]
140+
141+
# Individuals over 60
142+
[('birthdate', '<=', '1964-01-01')]
143+
144+
# Groups with more than 3 members
145+
[('z_ind_grp_num_individuals', '>=', 3)]
146+
```
147+
148+
**Advantages:**
149+
- Simple to configure
150+
- No coding required
151+
- Fast evaluation
152+
153+
**Limitations:**
154+
- Cannot access related records easily
155+
- Limited to field comparisons
156+
- No complex calculations
157+
158+
### CEL-Based Eligibility
159+
160+
For complex criteria, OpenSPP supports CEL (Common Expression Language):
161+
162+
```cel
163+
# Age-based eligibility
164+
age_years(me.birthdate) >= 60
165+
166+
# Gender and age combined
167+
me.gender == 'female' and age_years(me.birthdate) >= 18
168+
169+
# Household composition check
170+
members.exists(m, age_years(m.birthdate) < 5)
171+
172+
# Using computed metrics
173+
metric('household.pmt_score') < 25
174+
175+
# Complex household criteria
176+
members.filter(m, age_years(m.birthdate) < 18).size() >= 2
177+
```
178+
179+
**CEL Features:**
180+
181+
| Feature | Description | Example |
182+
|---------|-------------|---------|
183+
| **`me`** | Current registrant context | `me.gender == 'female'` |
184+
| **`members`** | Household members (for groups) | `members.size() >= 3` |
185+
| **`age_years()`** | Calculate age from date | `age_years(me.birthdate) >= 60` |
186+
| **`metric()`** | Access computed variables | `metric('pmt_score') < 25` |
187+
| **`exists()`** | Check if any member matches | `members.exists(m, m.has_disability)` |
188+
| **`filter()`** | Get members matching condition | `members.filter(m, m.age < 18)` |
189+
190+
### Geographic Targeting
191+
192+
The area-based eligibility manager simplifies geographic targeting:
193+
194+
| Configuration | Description |
195+
|--------------|-------------|
196+
| **Admin Areas** | Select target districts, villages, etc. |
197+
| **Area Types** | Target by area classification |
198+
| **Nested Areas** | Include child areas automatically |
199+
200+
## Eligibility Workflow
201+
202+
### At Program Level
203+
204+
```{mermaid}
205+
stateDiagram-v2
206+
[*] --> Import: Import eligible registrants
207+
Import --> Draft: Create draft memberships
208+
Draft --> Verify: Verify eligibility
209+
Verify --> Enrolled: Passes criteria
210+
Verify --> NotEligible: Fails criteria
211+
Enrolled --> [*]
212+
NotEligible --> Draft: Re-evaluate
213+
```
214+
215+
1. **Import** - Find registrants matching criteria from registry
216+
2. **Draft** - Create draft program memberships
217+
3. **Verify** - Run eligibility check against current data
218+
4. **Enrolled/Not Eligible** - Update status based on result
219+
220+
### At Cycle Level
221+
222+
Each cycle can also verify eligibility:
223+
224+
1. **Copy from program** - Bring enrolled members into cycle
225+
2. **Verify cycle eligibility** - Re-check against current data
226+
3. **Prepare entitlements** - Only for eligible cycle members
227+
228+
This allows for:
229+
- Removing members who no longer qualify
230+
- Adding newly eligible members
231+
- Updating status based on changed circumstances
232+
233+
## Multiple Eligibility Managers
234+
235+
A program can have multiple eligibility managers that work together:
236+
237+
```{mermaid}
238+
graph LR
239+
R[Registrants] --> E1[Manager 1:<br/>Age filter]
240+
E1 --> E2[Manager 2:<br/>Area filter]
241+
E2 --> E3[Manager 3:<br/>PMT filter]
242+
E3 --> Q[Qualified]
243+
244+
style E1 fill:#e3f2fd
245+
style E2 fill:#fff3e0
246+
style E3 fill:#f3e5f5
247+
```
248+
249+
Managers are applied in sequence—a registrant must pass all managers to qualify.
250+
251+
**Use cases for multiple managers:**
252+
253+
| Scenario | Manager Setup |
254+
|----------|--------------|
255+
| **Layered targeting** | Area → PMT score → Household composition |
256+
| **Phased rollout** | Core criteria → Additional filters per phase |
257+
| **Complex programs** | Different criteria for different benefit components |
258+
259+
## Eligibility Verification
260+
261+
### When to Verify
262+
263+
| Timing | Purpose |
264+
|--------|---------|
265+
| **Initial enrollment** | Determine who qualifies |
266+
| **Each cycle** | Confirm continued eligibility |
267+
| **After data updates** | Reflect changed circumstances |
268+
| **On demand** | Manual re-verification |
269+
270+
### Verification Results
271+
272+
| Result | Meaning | Next Steps |
273+
|--------|---------|------------|
274+
| **Passes** | Meets all criteria | Proceed with enrollment/benefits |
275+
| **Fails** | Doesn't meet criteria | Mark as not eligible |
276+
| **Pending** | Awaiting data | Request missing information |
277+
278+
## Best Practices
279+
280+
### Designing Eligibility Criteria
281+
282+
1. **Start simple** - Begin with core targeting criteria
283+
2. **Be specific** - Clear rules are easier to audit
284+
3. **Consider data availability** - Only use data you have
285+
4. **Plan for updates** - Circumstances change over time
286+
5. **Document rationale** - Record why criteria were chosen
287+
288+
### Configuration Tips
289+
290+
| Tip | Reason |
291+
|-----|--------|
292+
| **Test with sample data** | Verify criteria work as expected |
293+
| **Preview counts** | CEL manager shows matching count |
294+
| **Use progressive refinement** | Add criteria incrementally |
295+
| **Monitor exclusion rates** | High exclusion may indicate issues |
296+
297+
### Common Pitfalls
298+
299+
| Pitfall | Solution |
300+
|---------|----------|
301+
| **Missing data causes exclusion** | Handle null values explicitly |
302+
| **Overly complex criteria** | Simplify or split into multiple managers |
303+
| **Criteria not updated** | Schedule periodic reviews |
304+
| **No audit trail** | Log eligibility decisions |
305+
306+
## Are You Stuck?
307+
308+
### Why are no registrants matching my criteria?
309+
310+
**Check:**
311+
- Are the field names correct?
312+
- Does your data contain the expected values?
313+
- Are you targeting the right type (individual vs. group)?
314+
- Is the domain syntax valid?
315+
316+
**Debug steps:**
317+
1. Start with a minimal criterion
318+
2. Add conditions one at a time
319+
3. Use CEL preview to see match counts
320+
4. Check sample registrant data
321+
322+
### How do I target households with specific member characteristics?
323+
324+
Use CEL expressions with the `members` context:
325+
326+
```cel
327+
# Households with children under 5
328+
members.exists(m, age_years(m.birthdate) < 5)
329+
330+
# Households with 2+ elderly members
331+
members.filter(m, age_years(m.birthdate) >= 60).size() >= 2
332+
333+
# Female-headed households
334+
members.exists(m, m.is_head == true and m.gender == 'female')
335+
```
336+
337+
### Can I combine multiple criteria with OR logic?
338+
339+
Yes, with CEL:
340+
341+
```cel
342+
# Elderly OR disabled
343+
age_years(me.birthdate) >= 60 or me.has_disability == true
344+
```
345+
346+
With domain syntax, you need to use `|` operator:
347+
348+
```python
349+
['|', ('age', '>=', 60), ('has_disability', '=', True)]
350+
```
351+
352+
### How do I handle missing data?
353+
354+
In CEL, use null checks:
355+
356+
```cel
357+
# Only check PMT if it exists
358+
me.pmt_score == null or me.pmt_score < 25
359+
```
360+
361+
In domain syntax:
362+
363+
```python
364+
['|', ('pmt_score', '=', False), ('pmt_score', '<', 25)]
365+
```
366+
367+
## Next Steps
368+
369+
**Learn more about concepts:**
370+
- {doc}`programs` - How eligibility connects to programs
371+
- {doc}`cycles` - Cycle-level eligibility verification
372+
- {doc}`entitlements` - What happens after eligibility is confirmed
373+
374+
**For configuration:**
375+
- See the Configuration Guide for setting up eligibility managers
376+
377+
**For developers:**
378+
- See the Developer Guide for creating custom eligibility managers

0 commit comments

Comments
 (0)