From bba297076ea35b747c50bdc250ad06e803f7909c Mon Sep 17 00:00:00 2001 From: emjay0921 Date: Wed, 22 Jul 2026 10:45:32 +0800 Subject: [PATCH] feat(farmer_demo): seed large commercial farm with idle land for CEL demo (#1119) --- .../models/farmer_blueprints.py | 37 +++++++++++++++++++ .../tests/test_seeded_farm_generator.py | 20 ++++++++++ 2 files changed, 57 insertions(+) diff --git a/spp_farmer_registry_demo/models/farmer_blueprints.py b/spp_farmer_registry_demo/models/farmer_blueprints.py index fa43a84b9..02ce93dab 100644 --- a/spp_farmer_registry_demo/models/farmer_blueprints.py +++ b/spp_farmer_registry_demo/models/farmer_blueprints.py @@ -619,6 +619,43 @@ _AQUACULTURE: False, }, }, + # ========================================================================= + # Edge Cases — Targeting Exclusion (1 blueprint, 1 farm) + # OP#1119: EC1 — a large commercial farm (50 ha, well above the 5 ha + # smallholder threshold) that ALSO has idle/fallow land. Scenario 5 + # (Climate Resilience) needs this so the CEL + # `r.is_group == true and is_smallholder and farm_size_idle > 0` can be + # shown rejecting it on is_smallholder even though farm_size_idle > 0. + # All eligibility is False — it is the deliberate rejection example. + # ========================================================================= + { + "id": "bp_22_ec1_large_commercial_idle", + "label": "EC1 — Large commercial farm, 50ha with idle land (targeting exclusion)", + "count": 1, + "zone": "rural", + "farm_type": "crop", + "size_range": (50.0, 50.0), + "idle_pct": 0.1, # 5 ha fallow/idle — the positive Climate signal it can't use (not a smallholder) + "experience_range": (20, 30), + "head_gender": "male", + "members": [ + {"role": "head", "gender": "male", "age_range": (45, 60)}, + {"role": "spouse", "gender": "female", "age_range": (42, 58)}, + ], + "activities": [ + {"type": "crop", "species_code": "rice_irrigated", "area_pct": 0.5}, + {"type": "crop", "species_code": "maize", "area_pct": 0.3}, + ], + "land_tenure": "self", + "land_use": "cultivation", + "eligibility": { + _INPUT_SUBSIDY: False, + _EQUIPMENT_GRANT: False, + _LIVESTOCK: False, + _CLIMATE: False, + _AQUACULTURE: False, + }, + }, ] diff --git a/spp_farmer_registry_demo/tests/test_seeded_farm_generator.py b/spp_farmer_registry_demo/tests/test_seeded_farm_generator.py index a965a2b1b..5b5b2960c 100644 --- a/spp_farmer_registry_demo/tests/test_seeded_farm_generator.py +++ b/spp_farmer_registry_demo/tests/test_seeded_farm_generator.py @@ -1036,6 +1036,26 @@ def test_generate_all_farms_idle_land(self): self.assertAlmostEqual(details.farm_size_idle, 1.0, places=1) self.assertAlmostEqual(details.farm_size_under_crops, 3.0, places=1) + def test_1119_ec1_large_commercial_not_smallholder_with_idle(self): + """OP#1119: the EC1 blueprint seeds a large commercial farm that is NOT + a smallholder yet has idle land > 0 — the contrast case for Scenario 5, + where the Climate Resilience CEL (is_smallholder AND farm_size_idle > 0) + rejects it on is_smallholder despite the idle land.""" + from odoo.addons.spp_farmer_registry_demo.models.farmer_blueprints import ( + FARMER_BLUEPRINTS, + ) + + ec1 = next((bp for bp in FARMER_BLUEPRINTS if bp["id"] == "bp_22_ec1_large_commercial_idle"), None) + self.assertIsNotNone(ec1, "EC1 large-commercial blueprint must exist") + + gen = self._make_generator() + farm = gen.generate_all_farms([ec1])[0]["group"] + + threshold = float(self.env["ir.config_parameter"].sudo().get_param("spp.farmer.smallholder_threshold", "5.0")) + self.assertGreater(farm.farm_total_size, threshold, "EC1 must be above the smallholder threshold") + self.assertFalse(farm.is_smallholder, "EC1 must not be a smallholder") + self.assertGreater(farm.farm_size_idle, 0.0, "EC1 must have idle/fallow land > 0") + def test_generate_all_farms_assigns_areas(self): """Farms should be assigned to demo areas if any exist.""" gen = self._make_generator()