Skip to content

Commit 8da1e4d

Browse files
Tahzeergitbook-bot
authored andcommitted
GITBOOK-1632: Add Registry Connector Interface Docs
1 parent 3d15034 commit 8da1e4d

File tree

3 files changed

+322
-2
lines changed

3 files changed

+322
-2
lines changed

SUMMARY.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@
138138
* [Agency app APIs](pbms/developer-zone/api-reference/agency-app-apis.md)
139139
* [Staff portal APIs (for Odoo)](pbms/developer-zone/api-reference/staff-portal-apis-for-odoo.md)
140140
* [Tech Guides](pbms/developer-zone/tech-guides/README.md)
141-
* [Registry Connectors](pbms/developer-zone/tech-guides/registry-connectors.md)
141+
* [Registry Addon](pbms/developer-zone/tech-guides/registry-addon.md)
142+
* [Registry Connector](pbms/developer-zone/tech-guides/registry-connectors.md)
142143
* [Eligibility Summary view](pbms/developer-zone/tech-guides/eligibility-summary-view.md)
143144
* [Entitlement Summary view](pbms/developer-zone/tech-guides/entitlement-summary-view.md)
144145
* [Previous Generation](pbms/previous-generation/README.md)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
layout:
3+
width: default
4+
title:
5+
visible: true
6+
description:
7+
visible: false
8+
tableOfContents:
9+
visible: true
10+
outline:
11+
visible: true
12+
pagination:
13+
visible: true
14+
metadata:
15+
visible: true
16+
---
17+
18+
# Registry Addon
19+
20+
This guide provides details on implementing the [Registry Addon Odoo](https://github.com/OpenG2P/openg2p-pbms-odoo-extensions) Module for integration with PBMS Odoo.

pbms/developer-zone/tech-guides/registry-connectors.md

Lines changed: 300 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,304 @@ layout:
1515
visible: true
1616
---
1717

18-
# Registry Connectors
18+
# Registry Connector
1919

20+
This guide provides details on implementing the [Registry Connectors Interface](https://github.com/OpenG2P/openg2p-pbms-bg-tasks-extensions) for integration with PBMS Background Tasks.
21+
22+
## Overview
23+
24+
The `RegistryInterface` defines a standardized contract for interacting with various **G2P Registries** within the PBMS. It ensures consistent behavior across different registry integrations, including eligibility checks, summary computation, entitlement processing, and beneficiary search functionalities.
25+
26+
Custom implementations of this interface allow developers to integrate new registry types (for example, `farmer`, `student`, or `worker` registries) without modifying the PBMS core logic.
27+
28+
**Interface Code:** [Registry Interface](https://app.gitbook.com/u/21UJpMbIpqP7PKcbN5AOu80ESpo1) in OpenG2P PBMS Background Tasks Extensions\
29+
**Example Implementation:** [`farmer` Implementation](https://github.com/OpenG2P/openg2p-pbms-bg-tasks-extensions/blob/3.0/openg2p-bg-task-registry-adapters/src/openg2p_bg_task_registry_adapters/computations/registry_farmer.py), [`student` Implementation](https://github.com/OpenG2P/openg2p-pbms-bg-tasks-extensions/blob/3.0/openg2p-bg-task-registry-adapters/src/openg2p_bg_task_registry_adapters/computations/registry_student.py)
30+
31+
## Key components of Registry Connector Interface
32+
33+
The `RegistryInterface` defines methods for summary, eligibility and entitlement computation, registry access, and query construction. See the attached Key details of the same are mentioned below
34+
35+
### Computations
36+
37+
**`get_summary`**
38+
39+
**Purpose:** Asynchronously retrieves summary statistics for a given beneficiary list.\
40+
Used primarily in background tasks or async workflows.
41+
42+
**Arguments:**
43+
44+
* `beneficiary_list_id (str)`: The ID of the beneficiary list to summarize.
45+
* `bg_task_session (AsyncSession)`: Async SQLAlchemy session for background operations.
46+
* `formated (bool, optional)`: Whether to return formatted summary data. Defaults to `False`.
47+
48+
**Returns:**\
49+
`BeneficiaryListSummaryPayload` — Contains computed summary metrics for the list.
50+
51+
***
52+
53+
**`get_summary_sync`**
54+
55+
**Purpose:** Retrieves summary statistics synchronously for a beneficiary list (non-async execution).
56+
57+
**Arguments:**
58+
59+
* `beneficiary_list_id (str)`: The beneficiary list identifier.
60+
* `bg_task_session (Session)`: SQLAlchemy synchronous session.
61+
62+
**Returns:** `BeneficiaryListSummaryPayload`
63+
64+
***
65+
66+
**`compute_eligibility_statistics`**
67+
68+
**Purpose:** Computes and updates eligibility statistics for a given list of beneficiaries.
69+
70+
**Arguments:**
71+
72+
* `beneficiary_list_details (List[BeneficiaryListDetails])`: Details of beneficiaries in the list.
73+
* `base_summary`: Type or class of base\_summary - e.g., `BeneficiaryListSummary` or custom model implementation
74+
* `sr_session (Session)`: Session connected to the source registry database.
75+
* `bg_task_session (Session)`: Session connected to the PBMS background task database.
76+
77+
**Returns:** None - Updates the summary table in place.
78+
79+
***
80+
81+
**`compute_entitlement_statistics`**
82+
83+
**Purpose:** Calculates entitlement statistics for the given beneficiary list and updates the relevant fields.
84+
85+
**Arguments:**
86+
87+
* `beneficiary_list_id (str)`: ID of the beneficiary list.
88+
* `bg_task_session (Session)`: Background task DB session.
89+
* `sr_session (Session)`: Registry DB session.
90+
91+
**Returns:** None - Updates the computed statistics in database
92+
93+
***
94+
95+
### Registry Methods
96+
97+
**`get_registrants_by_ids`**
98+
99+
**Purpose:** Fetches registrant records from the registry database based on their IDs.
100+
101+
**Arguments:**
102+
103+
* `registrant_ids (List[str])`: List of registrant IDs to fetch.
104+
* `sr_session (Session)`: Registry database session.
105+
106+
**Returns:** `List[G2PRegistry]` - List of registry entries.
107+
108+
***
109+
110+
**`get_is_registant_entitled`**
111+
112+
**Purpose:** Checks whether a specific registrant is entitled based on a dynamically generated SQL query.
113+
114+
**Arguments:**
115+
116+
* `registrant_id (str)`: ID of the registrant.
117+
* `sql_query (str)`: SQL query representing eligibility rules.
118+
* `sr_session (Session)`: Registry session.
119+
120+
**Returns:** `bool` - `True` if entitled, otherwise `False`.
121+
122+
***
123+
124+
**`get_entitlement_multiplier`**
125+
126+
**Purpose:** Retrieves the multiplier value used in entitlement computation for a specific registrant.
127+
128+
**Arguments:**
129+
130+
* `multiplier (str)`: Field or SQL expression to compute multiplier.
131+
* `registrant_id (str)`: ID of the registrant.
132+
* `sr_session (Session)`: Registry session.
133+
134+
**Returns:** `int` - The computed multiplier value.
135+
136+
***
137+
138+
**`search_beneficiaries`**
139+
140+
**Purpose:** Searches for beneficiaries based on a search query and pagination parameters.
141+
142+
**Arguments:**
143+
144+
* `bg_task_session (AsyncSession)`: Async background session.
145+
* `sr_session (AsyncSession)`: Async registry session.
146+
* `beneficiary_list_id (str)`: Beneficiary list identifier.
147+
* `target_registry (str)`: Registry name or identifier.
148+
* `search_query`: _\[Placeholder: Expected structure or type, e.g., dict or SQL clause]_
149+
* `page (int)`: Page number for pagination (default: `1`).
150+
* `page_size (int)`: Results per page (default: `10`).
151+
* `order_by (str)`: Sorting order (default: `"id asc"`).
152+
153+
**Returns:** `BeneficiarySearchResponsePayload` - Paginated list of beneficiaries matching the query.
154+
155+
***
156+
157+
### SQL Query Constructors (Utility Methods)
158+
159+
These helper methods generate SQL Alchemy-compatible `TextClause` objects to perform parameterized queries on registry data. 
160+
161+
{% hint style="info" %}
162+
Custom implementations can directly use these methods by passing `target_registry`, given that table naming conventions are followed for registries.
163+
{% endhint %}
164+
165+
**`construct_multiplier_sql_query`**
166+
167+
**Purpose:** Constructs a query to retrieve multiplier values for entitlement calculations.
168+
169+
**Arguments:**
170+
171+
* `multiplier (str)`: Column name representing the multiplier.
172+
* `target_registry (str)`: Registry name.
173+
174+
**Returns:** `TextClause` - SQL query for retrieving multiplier values.
175+
176+
***
177+
178+
**`construct_beneficiary_search_sql_query`**
179+
180+
**Purpose:** Builds a SQL query for paginated beneficiary search with dynamic filters.
181+
182+
**Arguments:**
183+
184+
* `registrant_ids (List[str])`: List of registrant IDs to include.
185+
* `target_registry (str)`: Target registry table.
186+
* `where_clause (str)`: Additional SQL conditions.
187+
* `order_by (str)`: Sorting criteria.
188+
* `page_size (int)`: Number of records per page.
189+
* `page (int)`: Page number.
190+
191+
**Returns:** `Tuple[TextClause, Dict[str, Any]]` - Query and its parameters.
192+
193+
***
194+
195+
**`construct_beneficiary_search_count_sql_query`**
196+
197+
**Purpose:** Builds a SQL query to count total search results (for pagination).
198+
199+
**Arguments:**
200+
201+
* `registrant_ids (List[str])`: List of registrant IDs.
202+
* `target_registry (str)`: Registry table name.
203+
* `where_clause (str)`: SQL filtering conditions.
204+
205+
**Returns:** `Tuple[TextClause, Dict[str, Any]]` - Count query and parameters.
206+
207+
***
208+
209+
**`construct_get_is_registrant_entitled_sql_query`**
210+
211+
**Purpose:** Generates a SQL query to check if a registrant meets entitlement conditions.
212+
213+
**Arguments:**
214+
215+
* `registrant_id (str)`: The registrant’s unique ID.
216+
* `target_registry (str)`: Registry name.
217+
* `sql_query (str)`: Base eligibility SQL.
218+
219+
**Returns:** `TextClause` - SQL query ready for execution with parameters.
220+
221+
***
222+
223+
## Data Models, Schemas and Dependencies
224+
225+
To implement this interface, the following models and schemas are typically imported from the G2P [PBMS](https://app.gitbook.com/u/21UJpMbIpqP7PKcbN5AOu80ESpo1) and [PBMS Background Task](https://github.com/OpenG2P/openg2p-pbms-bg-tasks/tree/3.0/openg2p-bg-task-models/src/openg2p_bg_task_models) ecosystem:
226+
227+
* `G2PRegistry`: Core registry ORM model.
228+
* `BeneficiaryListDetails`: Details of beneficiaries linked to lists.
229+
* `BeneficiaryListSummaryPayload`: Schema for summary statistics.
230+
* `BeneficiarySearchResponsePayload`: Schema for search results.
231+
* `Disbursement`: Disbursement data schema.
232+
233+
_Additional dependencies include `sqlalchemy`, `sqlalchemy.ext.asyncio`, and `abc` for abstract base class definition._
234+
235+
{% hint style="info" %}
236+
New data models and schemas created during custom implementation are expected to inherit their corresponding parent model/schema
237+
{% endhint %}
238+
239+
## Example Implementation Workflow
240+
241+
The [`RegistryFarmer` class](https://github.com/OpenG2P/openg2p-pbms-bg-tasks-extensions/blob/3.0/openg2p-bg-task-registry-adapters/src/openg2p_bg_task_registry_adapters/computations/registry_farmer.py) demonstrates a **custom implementation** of the `RegistryInterface`, tailored for integrating with a [**Farmer Registry**](https://github.com/OpenG2P/openg2p-pbms-bg-tasks-extensions/blob/3.0/openg2p-bg-task-registry-adapters/src/openg2p_bg_task_registry_adapters/models/registry_farmer.py) data source.
242+
243+
Below is the typical workflow for building a similar registry connector:
244+
245+
### Define a Custom Registry Class and Update Factory
246+
247+
Create a class (e.g., `RegistryFarmer`) that **inherits from** `RegistryInterface`.\
248+
This ensures the connector implements all abstract methods required by the PBMS framework — including summaries, searches, and entitlement computations.
249+
250+
```python
251+
class RegistryFarmer(RegistryInterface):
252+
```
253+
254+
Update the `/factory/registry_factory.py` file to include this new registry class
255+
256+
```python
257+
class RegistryFactory:
258+
"""Get the appropriate summary computation class based on the registrant type"""
259+
260+
@staticmethod
261+
def get_registry_class(
262+
target_registry,
263+
) -> RegistryInterface:
264+
if target_registry == G2PRegistryType.FARMER.value:
265+
return RegistryFarmer()
266+
267+
# add multiple interfaces using elif blocks
268+
269+
else:
270+
raise BGTaskException(code=BGTaskErrorCodes.INVALID_REQUEST)
271+
```
272+
273+
### Create Custom Schema (`/schemas`) and Model Definitions (`/models`)
274+
275+
Define a pydantic schema to structure registry-specific summary data. Each registry schema extends the base `BeneficiaryListSummaryPayload` to ensure the payload integrates seamlessly with existing response models.
276+
277+
```python
278+
# /schemas/beneficiary_list_summary_farmer.py
279+
from typing import Optional
280+
from pydantic import BaseModel
281+
from .beneficiary_list_summary import BeneficiaryListSummaryPayload
282+
283+
class BeneficiaryListSummaryFarmer(BaseModel):
284+
# ... registry-specific stats ...
285+
# computaion logic is expected in registry connector implementation
286+
287+
class BeneficiaryListSummaryFarmerPayload(BeneficiaryListSummaryPayload):
288+
registry_summary: BeneficiaryListSummaryFarmer
289+
```
290+
291+
Extend the base SQLAlchemy model `BeneficiaryListSummary` to persist registry-specific statistics. The inheritance ensures all common fields (e.g., `beneficiary_list_id`, timestamps) are available automatically.
292+
293+
```python
294+
# /models/beneficiary_list_summary_farmer.py
295+
from openg2p_bg_task_models.models import BeneficiaryListSummary
296+
from sqlalchemy import JSON, Float, String
297+
from sqlalchemy.orm import mapped_column
298+
299+
class BeneficiaryListSummaryFarmer(BeneficiaryListSummary):
300+
__tablename__ = "beneficiary_list_summary_farmer"
301+
302+
land_holding_mean = mapped_column(Float, default=0)
303+
annual_income_mean = mapped_column(Float, default=0)
304+
average_entitlement_female = mapped_column(JSON, nullable=True)
305+
average_entitlement_male = mapped_column(JSON, nullable=True)
306+
# ... other numeric/statistical columns ...
307+
# computaion logic is expected in registry connector implementation
308+
```
309+
310+
After new model creation you are expected to update the migration script in [`migrate.py`](https://github.com/OpenG2P/openg2p-pbms-bg-tasks-extensions/blob/3.0/openg2p-bg-task-registry-adapters/src/openg2p_bg_task_registry_adapters/migrate.py) with the new models.
311+
312+
Implement the computation and registry methods, you can use the SQL utility methods provided in the interface by passing `target_registry` string to get a `TextClause` SQL query. Refer the Code Anatomy for Registry Connector Interface below to populate your custom interface with the current interface template.
313+
314+
<table data-full-width="false"><thead><tr><th>Method Name</th><th width="82">Type</th><th>Purpose</th><th width="148">Key Arguments</th><th>Returns</th><th>Implementation Notes</th></tr></thead><tbody><tr><td><code>get_summary</code></td><td>Async</td><td>Retrieves summary statistics for a given beneficiary list asynchronously.</td><td><code>beneficiary_list_id: str</code>, <code>bg_task_session: AsyncSession</code>, <code>formated: bool</code></td><td><code>BeneficiaryListSummaryPayload</code></td><td>Used in API calls; fetches formatted summary metrics from summary table.</td></tr><tr><td><code>get_summary_sync</code></td><td>Sync</td><td>Same as <code>get_summary</code> but executed synchronously (for Celery or background tasks).</td><td><code>beneficiary_list_id: str</code>, <code>bg_task_session: Session</code></td><td><code>BeneficiaryListSummaryPayload</code></td><td>Ideal for heavy computation where async isn’t needed.</td></tr><tr><td><code>compute_eligibility_statistics</code></td><td>Sync</td><td>Computes eligibility-based summary metrics for beneficiaries.</td><td><code>beneficiary_list_details: List[BeneficiaryListDetails]</code>, <code>base_summary</code>, <code>sr_session</code>, <code>bg_task_session</code></td><td>None</td><td>Uses NumPy for percentile and mean computations; updates summary model.</td></tr><tr><td><code>compute_entitlement_statistics</code></td><td>Sync</td><td>Computes entitlement statistics (e.g., payment distribution by gender).</td><td><code>beneficiary_list_id: str</code>, <code>bg_task_session: Session</code>, <code>sr_session: Session</code></td><td>None</td><td>Groups entitlements by <code>benefit_code_id</code>; calculates mean, Q1, Q2, Q3.</td></tr><tr><td><code>get_registrants_by_ids</code></td><td>Sync</td><td>Fetches registrant data from the registry database.</td><td><code>registrant_ids: List[str]</code>, <code>sr_session: Session</code></td><td><code>List[G2PRegistry]</code></td><td>Uses chunked loading (<code>yield_per(500)</code>) for performance on large datasets.</td></tr><tr><td><code>get_is_registant_entitled</code></td><td>Sync</td><td>Checks if a registrant satisfies entitlement criteria using a SQL query.</td><td><code>registrant_id: str</code>, <code>sql_query: str</code>, <code>sr_session: Session</code></td><td><code>bool</code></td><td>Constructs validated dynamic SQL using <code>construct_get_is_registrant_entitled_sql_query</code>.</td></tr><tr><td><code>get_entitlement_multiplier</code></td><td>Sync</td><td>Retrieves multiplier value for entitlement scaling.</td><td><code>multiplier: str</code>, <code>registrant_id: str</code>, <code>sr_session: Session</code></td><td><code>int</code></td><td>Executes a SQL query; defaults to <code>1</code> if not found or multiplier is <code>"none"</code>.</td></tr><tr><td><code>search_beneficiaries</code></td><td>Async</td><td>Performs paginated and filtered beneficiary searches.</td><td><code>bg_task_session: AsyncSession</code>, <code>sr_session: AsyncSession</code>, <code>beneficiary_list_id: str</code>, <code>target_registry: str</code>, <code>search_query</code>, <code>page</code>, <code>page_size</code>, <code>order_by</code></td><td><code>BeneficiarySearchResponsePayload</code></td><td>Builds dynamic SQL queries with <code>construct_beneficiary_search_sql_query</code> and applies caching.</td></tr><tr><td><code>construct_multiplier_sql_query</code></td><td>Utility</td><td>Builds SQL query to fetch multiplier column from registry table.</td><td><code>multiplier: str</code>, <code>target_registry: str</code></td><td><code>TextClause</code></td><td>Returns a prepared SQLAlchemy <code>text()</code> object.</td></tr><tr><td><code>construct_beneficiary_search_sql_query</code></td><td>Utility</td><td>Constructs SQL for paginated search with WHERE and ORDER BY.</td><td><code>registrant_ids: List[str]</code>, <code>target_registry: str</code>, <code>where_clause: str</code>, <code>order_by: str</code>, <code>page_size: int</code>, <code>page: int</code></td><td><code>(TextClause, Dict[str, Any])</code></td><td>Replaces curly quotes in filters; dynamically injects pagination params.</td></tr><tr><td><code>construct_beneficiary_search_count_sql_query</code></td><td>Utility</td><td>Builds SQL query to count total search results.</td><td><code>registrant_ids: List[str]</code>, <code>target_registry: str</code>, <code>where_clause: str</code></td><td><code>(TextClause, Dict[str, Any])</code></td><td>Mirrors main query but replaces <code>SELECT *</code> with <code>SELECT COUNT(*)</code>.</td></tr><tr><td><code>construct_get_is_registrant_entitled_sql_query</code></td><td>Utility</td><td>Prepares validated entitlement SQL query with a dynamic <code>WHERE</code> clause.</td><td><code>registrant_id: str</code>, <code>target_registry: str</code>, <code>sql_query: str</code></td><td><code>TextClause</code></td><td>Validates SQL starts with <code>SELECT</code>; appends correct registry table reference.</td></tr></tbody></table>
315+
316+
After pushing this custom adapter code to GitHub, you can proceed to create a custom Docker image for your setup. Simply follow the existing [Docker creation guide](../pbms-docker.md#background-tasks) for **PBMS Background Tasks**, updating the path for the extensions package.
317+
318+
This approach ensures your environment remains consistent with the PBMS deployment standards while allowing flexibility to integrate your custom logic and components seamlessly.

0 commit comments

Comments
 (0)