Country Implementation Guide
This guide is the end-to-end spine for building a country-specific PBMS implementation: taking the generic PBMS platform and wiring it to a country's own registry (or a new registry type), its own branding, and its own deployment.
It ties together the focused sub-guides — Registry Database Contract, Registry Add-ons, Registry Connectors, Summary Views and Theme Extension — into one ordered sequence. Read this page first, then dive into the sub-guide referenced at each step.
Throughout, the two registry types that ship with PBMS — farmer and households — are used as the running examples. A new country type (call it <type>) follows the exact same pattern; every place you see farmer / households is a place you add your own type.
How the pieces fit together
A PBMS deployment has three databases and several services:
PBMS core DB — Odoo. Holds programs, eligibility / entitlement / priority rules, and the registry type definitions.
Registry DB (
sr_session) — the source registry PBMS reads. This is where yourg2p_register_<type>view lives (the Registry Database Contract).Bg-task DB — beneficiary lists and computed summaries.
The registry type string (target_registry) is the thread that runs through all of them: you pick it on a rule in Odoo, it names the source table (g2p_register_<type>), and it selects the Python adapter (RegistryFactory.get_registry_class(target_registry)) that runs eligibility, entitlement, search and summary computations. A country implementation is, essentially, defining a new target_registry end to end.
Step 1 — Define the source-registry database view
Start from the data. Your country registry must be exposed in the registry DB as a table/view named g2p_register_<type>, with an internal_record_id primary column and the standard columns the adapter will read.
This is specified in full — including the exact columns for farmer and households — in the Registry Database Contract. Do this first: the table name and column names you settle on here are referenced by every later step.
CREATE VIEW g2p_register_farmer AS
SELECT
r.registry_pk::varchar AS internal_record_id,
r.given_name AS first_name,
r.family_name AS last_name,
r.sex AS gender,
r.age AS estimated_age
-- ...the remaining standard columns
FROM my_country_farmer_registry r;Step 2 — Add the Odoo registry add-on
PBMS core (Odoo) needs a model that mirrors your registry so that program staff can build eligibility / entitlement / priority domains against it. The domain is compiled to SQL that runs on the g2p_register_<type> view, so the Odoo model field names should line up with the view columns.
Follow the Registry Add-ons sub-guide. The pattern, using the shipped g2p_registry_addon module:
Create the concrete model inheriting the abstract
g2p.registry. The model name must beg2p.register.<type>. Seeodoo/extensions/g2p_registry_addon/models/farmer_registry.py:Register it in
models/__init__.py.Register the type → model mapping in the
g2p_registry_type_addonmodule (odoo/extensions/g2p_registry_type_addon/models/registry_type.py). Add your type to bothMODEL_MAPPINGand theG2PRegistryTypeenum:This is what makes your type appear in the Target Registry dropdown on rule definitions (
G2PRegistryType.selection()feedsg2p.eligibility.rule.definition.target_registryand the entitlement / priority equivalents) and what lets Odoo translate a domain to SQL for the right model (get_target_model_name).Add security rules. In
odoo/extensions/g2p_registry_addon/security/ir.model.access.csvadd read/write rows for your model. The model id follows Odoo's conventionmodel_g2p_register_<type>:
Step 3 — Add the bg-task registry adapter
The Python side is the openg2p-bg-task-registry-adapters extension. It contains the adapters that actually run eligibility, entitlement, search and summary computations against your g2p_register_<type> view. This is the Registry Connectors sub-guide.
Declare the SQLAlchemy model for the view, in
.../models/registry_<type>.py, inheriting the baseG2PRegistry(which supplies theinternal_record_idprimary key). Mirror the view columns. Seemodels/registry_farmer.py:Export it from
models/__init__.py.Implement the adapter in
.../computations/registry_<type>.pyas a subclass ofRegistryInterface(interface/registry_interface.py). You must implement the abstract methods:get_summary,get_summary_sync,compute_eligibility_statistics,compute_entitlement_statistics,get_registrants_by_ids,get_is_registant_entitled,get_entitlement_multiplier, andsearch_beneficiaries. The base class already provides the SQL constructors (construct_beneficiary_search_sql_query,construct_multiplier_sql_query, etc.) that buildg2p_register_<type>queries for you — pass yourtarget_registrystring through. UseRegistryFarmer(computations/registry_farmer.py) andRegisterHousehold(computations/register_household.py) as references. Export it fromcomputations/__init__.py.Register it in the factory (
factory/registry_factory.py):Add the type to the adapters' enum (
models/registry_type.py). This is a separate enum from the Odoo one, but the string values must match:Register the summary table in
migrate.py. The registry view is not created by PBMS (it belongs to the source registry), but the per-type summary table is. Add your summary model toget_models()inmigrate.pyso its table is created in the bg-task DB:
Step 4 — Add or extend the summary views
Each registry type has its own summary shape (age quartiles for farmers; household-size and overcrowding quartiles for households). To add a country-specific summary, define its summary ORM model + schema and compute it in your adapter's compute_eligibility_statistics / compute_entitlement_statistics.
The two flavours of summary — eligibility and entitlement — and how they are built and read are covered in the Summary Views sub-guide (eligibility, entitlement). The farmer adapter (computations/registry_farmer.py) is the fullest worked example, including gender-split entitlement statistics.
Step 5 — (Optional) Fork the theme extension for branding
For a country deployment you usually want your own login page, favicon, logo, fonts and company branding. This is the pbms_theme_extension Odoo module. Forking it — login-page templates, favicon/logo assets, fonts, and the res.company / res.users overrides — is covered in the Theme Extension sub-guide. This step is independent of the registry work in steps 1–4 and can be done at any time.
Step 6 — Build the custom Docker images
Your changes live in in-repo modules and extensions, so they are baked into the images at build time from the local source tree. There are three images to rebuild:
Odoo image (
docker/openg2p-pbms-odoo/utils/Dockerfile) — the wholeodoo/extensionstree is copied into the addons path (COPY odoo/extensions ${EXTRA_ADDONS_DIR}/pbms-extensions), so your changes tog2p_registry_addon,g2p_registry_type_addonandpbms_theme_extensionare picked up automatically.Bg-task images (
docker/openg2p-pbms-bg-tasks/bg-task-celery-worker/Dockerfileand.../bg-task-celery-beat/Dockerfile) — install the adapters from local source (COPY extensions/openg2p-bg-task-registry-adapters ... && pip install ...), so your new adapter, model and factory changes ship here.API images (
docker/openg2p-pbms-apis/bene-portal-api/Dockerfileand.../staff-portal-api/Dockerfile) — also install the adapters extension, for the beneficiary-search endpoints.
Build and push them to a registry you control, e.g.:
Step 7 — Point Helm at the custom images and register the target registry
Finally, update the deployment (deployment/charts/openg2p-pbms/).
Point each component at your image. In
values.yamleach service has animage.repository/image.tag. Override them to your custom images:Point PBMS at the registry DB where your
g2p_register_<type>view lives, via theglobal.registryDBblock (see the Registry Database Contract):Register the target registry in Odoo. Once deployed, create/configure programs and set the Target Registry on the eligibility / entitlement / priority rules to your new
<type>. That value flows down tog2p_register_<type>and toRegistryFactory.get_registry_class("<type>"), closing the loop.
End-to-end checklist
2
Odoo model g2p.register.<type>, MODEL_MAPPING, enum, security CSV
odoo/extensions/g2p_registry_addon, g2p_registry_type_addon
3
SQLAlchemy model, adapter, factory, adapters enum, migrate.py
extensions/openg2p-bg-task-registry-adapters
6
Build custom images
docker/
7
Point Helm at images + registry DB, set Target Registry
deployment/charts/openg2p-pbms/values.yaml
Last updated
Was this helpful?