Skip to content

Commit 05ab60c

Browse files
committed
feat(spp_mis_demo_v2): add compliance criteria to demo programs
Add compliance managers to Cash Transfer (per_capita_income < poverty_line) and Conditional Child Grant (per_capita_income < income_threshold with program-level override to 2000). Santos story demonstrates compliance failure triggering graduation (non_compliant cycle membership), while Dela Cruz demonstrates compliance passing on the same program. - Configure compliance CEL expressions on 2 of 7 programs - Add program constant override for income_threshold via spp.cel.program.parameter - Mark Santos cycle membership as non_compliant after payment creation - Add CCG eligibility flag to 4 household blueprints (bp_01, bp_04, bp_06, bp_28) - Add Santos Universal Child Grant enrollment for partial exit story - Update wizard view, translations, and USE_CASES.md to v3 spec - Add 12 new tests for compliance configuration and behavior
1 parent 25198e6 commit 05ab60c

10 files changed

Lines changed: 980 additions & 827 deletions

spp_mis_demo_v2/docs/USE_CASES.md

Lines changed: 483 additions & 792 deletions
Large diffs are not rendered by default.

spp_mis_demo_v2/i18n/fr.po

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,8 @@ msgstr ""
138138

139139
#. module: spp_mis_demo_v2
140140
#: model_terms:ir.ui.view,arch_db:spp_mis_demo_v2.view_mis_demo_wizard_form
141-
msgid "<strong>Social Protection Programs (6):</strong>"
142-
msgstr "<strong>Programmes de protection sociale (6) :</strong>"
141+
msgid "<strong>Social Protection Programs (7):</strong>"
142+
msgstr "<strong>Programmes de protection sociale (7) :</strong>"
143143

144144
#. module: spp_mis_demo_v2
145145
#: model_terms:ir.ui.view,arch_db:spp_mis_demo_v2.view_mis_demo_wizard_form

spp_mis_demo_v2/i18n/spp_mis_demo_v2.pot

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ msgstr ""
110110

111111
#. module: spp_mis_demo_v2
112112
#: model_terms:ir.ui.view,arch_db:spp_mis_demo_v2.view_mis_demo_wizard_form
113-
msgid "<strong>Social Protection Programs (6):</strong>"
113+
msgid "<strong>Social Protection Programs (7):</strong>"
114114
msgstr ""
115115

116116
#. module: spp_mis_demo_v2

spp_mis_demo_v2/models/demo_programs.py

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"use_logic_studio": True,
4949
"logic_name": "Child Benefit Eligibility",
5050
"expression_type": "filter",
51-
"stories": ["carlos_elena_morales"],
51+
"stories": ["carlos_elena_morales", "maria_santos"],
5252
"demo_points": [
5353
"Household-based program",
5454
"Child-focused eligibility",
@@ -62,17 +62,19 @@
6262
"name": "Conditional Child Grant",
6363
"description": "Monthly grant for households with pregnant women and children aged 0-2. "
6464
"Targets the critical first 1,000 days of life to support nutrition and "
65-
"health-seeking behavior. Compliance requires prenatal visits, health "
66-
"checkups, and immunizations.",
65+
"health-seeking behavior. Compliance enforces an income cap to ensure "
66+
"benefits reach low-income families.",
6767
"target_type": "group",
6868
"entitlement_amount": 10.0,
6969
"entitlement_formula": "first_1000_days_grant",
7070
"cycle_duration": 30, # Monthly
7171
# CEL: Households with children under 2 (first 1,000 days)
7272
# Pattern: Member age check via members.exists()
7373
"cel_expression": "r.is_group == true and members.exists(m, age_years(m.birthdate) < 2)",
74-
# Compliance: prenatal visits, health checkups, immunizations
75-
"compliance_cel_expression": "members.exists(m, age_years(m.birthdate) <= 2)",
74+
# Compliance: Income cap — per-capita income must stay below threshold
75+
"compliance_cel_expression": "per_capita_income < income_threshold",
76+
# Override income_threshold from default 5000 to 2000 for this program
77+
"program_constants": {"income_threshold": "2000"},
7678
# Link to Logic Pack
7779
"logic_pack": "child_benefit",
7880
"use_logic_studio": True,
@@ -82,9 +84,9 @@
8284
"demo_points": [
8385
"Conditional cash transfer",
8486
"First 1,000 days targeting (0-2 years)",
85-
"Health visit and immunization compliance",
87+
"Income-cap compliance (per_capita_income < income_threshold)",
8688
"Compliance manager with CEL expression",
87-
"CEL: members.exists() for eligibility and compliance",
89+
"CEL: members.exists() for eligibility, per_capita_income for compliance",
8890
"Logic Pack: child_benefit",
8991
],
9092
},
@@ -105,7 +107,7 @@
105107
"use_logic_studio": True,
106108
"logic_name": "Social Pension Eligibility",
107109
"expression_type": "filter",
108-
"stories": ["rosa_garcia"],
110+
"stories": ["rosa_garcia", "manuel_gloria_elderly"],
109111
"demo_points": [
110112
"Individual targeting",
111113
"Age-based eligibility",
@@ -151,14 +153,17 @@
151153
"id": "cash_transfer_program",
152154
"name": "Cash Transfer Program",
153155
"description": "Regular cash transfers to low-income households. "
154-
"Fixed monthly amount using cash_transfer_amount constant.",
156+
"Fixed monthly amount using cash_transfer_amount constant. "
157+
"Compliance rechecks per-capita income each cycle.",
155158
"target_type": "group",
156159
"entitlement_amount": 150.0,
157160
"entitlement_formula": "cash_transfer_amount", # Uses constant
158161
"cycle_duration": 30,
159162
# CEL: Income below poverty line and household size >= 2
160163
# Pattern: Constant comparison using activated variables
161164
"cel_expression": "r.is_group == true and hh_total_income < poverty_line and hh_size >= 2",
165+
# Compliance: Per-capita income must remain below poverty line each cycle
166+
"compliance_cel_expression": "per_capita_income < poverty_line",
162167
# Link to Logic Pack
163168
"logic_pack": "cash_transfer_basic",
164169
"use_logic_studio": True,
@@ -168,7 +173,8 @@
168173
"demo_points": [
169174
"Regular cash disbursements",
170175
"Income-based eligibility",
171-
"Graduation pathway (Maria Santos)",
176+
"Per-capita income compliance (per_capita_income < poverty_line)",
177+
"Graduation via compliance failure (Maria Santos)",
172178
"Uses poverty_line constant",
173179
"Uses hh_total_income aggregate",
174180
"Logic Pack: cash_transfer_basic",
@@ -216,7 +222,7 @@
216222
# No Logic Pack - demonstrates simple inline CEL
217223
"logic_pack": None,
218224
"use_logic_studio": False,
219-
"stories": ["rosa_garcia", "fatima_al_rahman"],
225+
"stories": ["rosa_garcia", "fatima_al_rahman", "pedro_reyes", "ana_mendoza", "maria_santos", "ibrahim_hassan"],
220226
"demo_points": [
221227
"In-kind entitlements",
222228
"Multi-program enrollment",
@@ -268,18 +274,31 @@ def get_programs_by_pack(pack_code):
268274

269275
# Story-to-program enrollment mapping with journey details
270276
STORY_ENROLLMENTS = {
271-
# Story 1: Maria Santos - Success story with graduation from Cash Transfer
277+
# Story 1: Maria Santos - Cash Transfer (graduated via compliance failure) +
278+
# Universal Child Grant (active) + Food Assistance (individual)
272279
"maria_santos": [
273280
{
274281
"program": "Cash Transfer Program",
275-
"enrolled_days_back": 150,
276-
"graduated_days_back": 30, # Successfully graduated from the program
282+
"enrolled_days_back": 180,
283+
"graduated_days_back": 30, # Exited after compliance failure
277284
"payments": [
285+
{"amount": 150, "days_back": 150, "status": "paid"},
278286
{"amount": 150, "days_back": 120, "status": "paid"},
279287
{"amount": 150, "days_back": 90, "status": "paid"},
280-
{"amount": 150, "days_back": 60, "status": "paid"},
281288
],
282-
}
289+
# Compliance failure: income improved, per_capita_income exceeded poverty_line
290+
# Cycle membership will be set to non_compliant after payments are created
291+
"non_compliant_cycle": {"days_back": 30},
292+
},
293+
{
294+
"program": "Universal Child Grant",
295+
"enrolled_days_back": 150,
296+
},
297+
{
298+
"program": "Food Assistance",
299+
"enrolled_days_back": 120,
300+
"enroll_individual": True, # Enroll head member, not the group
301+
},
283302
],
284303
# Story 2: Juan Dela Cruz - Cash Transfer with GRM issue
285304
"juan_dela_cruz": [
@@ -335,7 +354,12 @@ def get_programs_by_pack(pack_code):
335354
{"amount": 400, "days_back": 50, "status": "paid"}, # Tier 2 (score 85)
336355
{"amount": 400, "days_back": 35, "status": "paid"},
337356
],
338-
}
357+
},
358+
{
359+
"program": "Food Assistance",
360+
"enrolled_days_back": 50,
361+
"enroll_individual": True, # Enroll head member, not the group
362+
},
339363
],
340364
# Story 8: Teresa Villanueva - Food Assistance
341365
"fatima_al_rahman": [
@@ -344,7 +368,21 @@ def get_programs_by_pack(pack_code):
344368
"enrolled_days_back": 30,
345369
}
346370
],
347-
# Story 9: David Martinez - Disability Support Grant (NEW)
371+
# Pedro Reyes - Food Assistance (individual)
372+
"pedro_reyes": [
373+
{
374+
"program": "Food Assistance",
375+
"enrolled_days_back": 90,
376+
}
377+
],
378+
# Ana Mendoza - Food Assistance (individual)
379+
"ana_mendoza": [
380+
{
381+
"program": "Food Assistance",
382+
"enrolled_days_back": 70,
383+
}
384+
],
385+
# Story 9: David Martinez - Disability Support Grant
348386
"david_sofia_martinez": [
349387
{
350388
"program": "Disability Support Grant",
@@ -356,6 +394,20 @@ def get_programs_by_pack(pack_code):
356394
],
357395
}
358396
],
397+
# Manuel Pangilinan - Elderly Social Pension (individual, age 75)
398+
"manuel_gloria_elderly": [
399+
{
400+
"program": "Elderly Social Pension",
401+
"enrolled_days_back": 200,
402+
"enroll_individual": True, # Enroll head member, not the group
403+
"payments": [
404+
{"amount": 100, "days_back": 170, "status": "paid"},
405+
{"amount": 100, "days_back": 140, "status": "paid"},
406+
{"amount": 100, "days_back": 110, "status": "paid"},
407+
{"amount": 100, "days_back": 80, "status": "paid"},
408+
],
409+
}
410+
],
359411
# Background stories
360412
"ahmed_said": [
361413
{

spp_mis_demo_v2/models/household_blueprints.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
# Program IDs matching DEMO_PROGRAMS in demo_programs.py
1818
_UCG = "universal_child_grant"
19+
_CCG = "conditional_child_grant"
1920
_ESP = "elderly_social_pension"
2021
_ERF = "emergency_relief_fund"
2122
_CTP = "cash_transfer_program"
@@ -38,7 +39,7 @@
3839
{"role": "spouse", "gender": "female", "age_range": (23, 33)},
3940
{"role": "child", "gender": "any", "age_range": (1, 4)},
4041
],
41-
"eligibility": {_UCG: True, _CTP: True, _ERF: False, _DSG: False},
42+
"eligibility": {_UCG: True, _CCG: True, _CTP: True, _ERF: False, _DSG: False},
4243
},
4344
{
4445
"id": "bp_02_young_couple_2children_rural_vlow",
@@ -84,7 +85,7 @@
8485
{"role": "child", "gender": "any", "age_range": (4, 8)},
8586
{"role": "child", "gender": "any", "age_range": (8, 12)},
8687
],
87-
"eligibility": {_UCG: True, _CTP: True, _ERF: False, _DSG: False},
88+
"eligibility": {_UCG: True, _CCG: True, _CTP: True, _ERF: False, _DSG: False},
8889
},
8990
{
9091
"id": "bp_05_single_father_1child_periurban_mod",
@@ -112,7 +113,7 @@
112113
{"role": "child", "gender": "any", "age_range": (0, 1)},
113114
{"role": "child", "gender": "any", "age_range": (1, 3)},
114115
],
115-
"eligibility": {_UCG: True, _CTP: True, _ERF: True, _DSG: False},
116+
"eligibility": {_UCG: True, _CCG: True, _CTP: True, _ERF: True, _DSG: False},
116117
},
117118
# =========================================================================
118119
# Middle-age Families (6 blueprints, ~150 households)
@@ -442,7 +443,7 @@
442443
{"role": "child", "gender": "any", "age_range": (5, 10), "is_disabled": True},
443444
{"role": "elderly", "gender": "any", "age_range": (68, 80)},
444445
],
445-
"eligibility": {_UCG: True, _ESP: True, _CTP: True, _ERF: True, _DSG: True},
446+
"eligibility": {_UCG: True, _CCG: True, _ESP: True, _CTP: True, _ERF: True, _DSG: True},
446447
},
447448
]
448449

0 commit comments

Comments
 (0)