Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

G2P-2555: Status & description update and error handling with empty d… #153

Merged
merged 4 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions g2p_registry_base/models/reg_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ class G2PRegistrantID(models.Model):
expiry_date = fields.Date()
id_type_as_str = fields.Char(related="id_type.name")

status = fields.Selection([("invalid", "Invalid"), ("valid", "Valid")], required=True)

description = fields.Char()

def _compute_display_name(self):
res = super()._compute_display_name()
for rec in self:
Expand Down
34 changes: 30 additions & 4 deletions g2p_registry_base/tests/test_reg_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ def test_01_display_name(self):
id_type = self.id_type_model.create({"name": "Test ID Type", "id_validation": "[0-9]+"})

reg_id = self.reg_id_model.create(
{"partner_id": partner.id, "id_type": id_type.id, "value": "123456"}
{
"partner_id": partner.id,
"id_type": id_type.id,
"value": "123456",
"status": "valid",
"description": "Due to API",
}
)

# Call the _compute_display_name method
Expand All @@ -35,7 +41,13 @@ def test_02_create_registrant_id(self):
id_type = self.id_type_model.create({"name": "Test ID Type", "id_validation": "[0-9]+"})

reg_id = self.reg_id_model.create(
{"partner_id": partner.id, "id_type": id_type.id, "value": "123456"}
{
"partner_id": partner.id,
"id_type": id_type.id,
"value": "123456",
"status": "valid",
"description": "Due to API",
}
)
self.assertEqual(reg_id.value, "123456", "Registrant ID value is not as expected.")

Expand All @@ -44,15 +56,29 @@ def test_03_invalid_id_value(self):
id_type = self.id_type_model.create({"name": "Test ID Type", "id_validation": "[0-9]+"})

with self.assertRaises(ValidationError) as context:
self.reg_id_model.create({"partner_id": partner.id, "id_type": id_type.id, "value": "abc"})
self.reg_id_model.create(
{
"partner_id": partner.id,
"id_type": id_type.id,
"value": "abc",
"status": "valid",
"description": "Due to API",
}
)

self.assertIn("The provided Test ID Type ID 'abc' is invalid.", str(context.exception))

def test_04_name_search(self):
partner = self.partner_model.create({"name": "Test Partner", "is_registrant": True})
id_type = self.id_type_model.create({"name": "Test ID Type"})
reg_id = self.reg_id_model.create(
{"partner_id": partner.id, "id_type": id_type.id, "value": "Test Value"}
{
"partner_id": partner.id,
"id_type": id_type.id,
"value": "Test Value",
"status": "valid",
"description": "Due to API",
}
)
search_result = self.reg_id_model._name_search("Test Partner")
self.assertIn(reg_id.id, search_result, "Expected record not found in search result")
Expand Down
4 changes: 4 additions & 0 deletions g2p_registry_base/views/reg_id_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
<field name="partner_id" options="{'no_open':True,'no_create_edit':True,'no_create':True}" />
<field name="id_type" options="{'no_open':True,'no_create_edit':True,'no_create':True}" />
<field name="value" />
<field name="status" />
<field name="description" />
</tree>
</field>
</record>
Expand All @@ -24,6 +26,8 @@
<search string="Search Registrant IDs">
<field name="partner_id" />
<field name="value" />
<field name="status" />
<field name="description" />
<group expand="0" string="Group By">
<filter string="Registrant" name="grp_registrant" context="{'group_by': 'partner_id'}" />
</group>
Expand Down
7 changes: 6 additions & 1 deletion g2p_registry_group/tests/test_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,12 @@ def test_02_add_id(self):
"name": "Testing ID Type",
}
)
vals = {"id_type": id_type.id, "value": "112233445566778899"}
vals = {
"id_type": id_type.id,
"value": "112233445566778899",
"status": "valid",
"description": "Due to API",
}

self.group_1.write({"reg_ids": [(0, 0, vals)]})
expected_value = "112233445566778899"
Expand Down
7 changes: 6 additions & 1 deletion g2p_registry_individual/tests/test_individuals.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,12 @@ def test_04_add_id(self):
"name": "Testing ID Type",
}
)
vals = {"id_type": id_type.id, "value": "112233445566778899"}
vals = {
"id_type": id_type.id,
"value": "112233445566778899",
"status": "valid",
"description": "Due to API",
}

self.registrant_1.write({"reg_ids": [(0, 0, vals)]})
expected_value = "112233445566778899"
Expand Down
7 changes: 7 additions & 0 deletions g2p_registry_individual/views/individuals_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,13 @@
/>
<field name="value" string="ID Number" />
<field name="expiry_date" />
<field name="status" readonly="1" widget="badge" decoration-info="1" />
<field
name="description"
readonly="1"
widget="badge"
decoration-warning="1"
/>
</tree>
</field>
</page>
Expand Down
80 changes: 73 additions & 7 deletions g2p_registry_rest_api/routers/individual.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@

from fastapi import APIRouter, Depends

from odoo import fields
from odoo.api import Environment

from odoo.addons.fastapi.dependencies import odoo_env

from ..exceptions.base_exception import G2PApiValidationError
from ..exceptions.error_codes import G2PErrorCodes
from ..schemas.individual import IndividualInfoRequest, IndividualInfoResponse, UpdateIndividualInfoRequest
from ..schemas.individual import (
IndividualInfoRequest,
IndividualInfoResponse,
UpdateIndividualInfoRequest,
UpdateIndividualInfoResponse,
)

individual_router = APIRouter(tags=["individual"])

Expand Down Expand Up @@ -92,7 +98,7 @@ async def get_ids(
if not include_id_type:
_handle_error(G2PErrorCodes.G2P_REQ_010, "Record is not present in the database.")

domain = [("is_registrant", "=", True), ("is_group", "=", False)]
domain = [("is_registrant", "=", True), ("is_group", "=", False), ("active", "=", True)]
if include_id_type:
domain.append(("reg_ids.id_type", "=", include_id_type))

Expand All @@ -115,12 +121,12 @@ async def get_ids(
_handle_error(G2PErrorCodes.G2P_REQ_010, "An error occurred while getting IDs.")


@individual_router.put("/update_individual", responses={200: {"model": IndividualInfoResponse}})
@individual_router.put("/update_individual", responses={200: {"model": UpdateIndividualInfoResponse}})
async def update_individual(
requests: list[UpdateIndividualInfoRequest],
env: Annotated[Environment, Depends(odoo_env)],
id_type: str | None = "",
) -> list[IndividualInfoResponse]:
) -> list[UpdateIndividualInfoResponse]:
"""
Update an individual
"""
Expand All @@ -134,7 +140,14 @@ async def update_individual(
partner_rec = (
env["res.partner"]
.sudo()
.search([("reg_ids.value", "=", _id), ("reg_ids.id_type", "=", id_type)], limit=1)
.search(
[
("reg_ids.value", "=", _id),
("reg_ids.id_type", "=", id_type),
("active", "=", True),
],
limit=1,
)
)
if not partner_rec:
_handle_error(
Expand All @@ -144,12 +157,65 @@ async def update_individual(

# Update the individual
indv_rec = env["process_individual.rest.mixin"]._process_individual(request)

logging.info("Individual Api: Updating Individual Record", indv_rec)

for reg_id in indv_rec["reg_ids"]:
id_type = reg_id[2].get("id_type")
value = reg_id[2].get("value")
status = reg_id[2].get("status")
description = reg_id[2].get("description")

id_rec = (
env["g2p.reg.id"]
.sudo()
.search(
[
("value", "=", value),
("id_type", "=", id_type),
],
limit=1,
)
)
if id_rec:
# Search for the partner
partner_rec = (
env["res.partner"]
.sudo()
.search(
[
("reg_ids.value", "=", value),
("reg_ids.id_type", "=", id_type),
("active", "=", True),
],
limit=1,
)
)

indv_rec.pop("reg_ids")

if partner_rec:
partner_rec.update(
{
"reg_ids": [
(
fields.Command.update(
id_rec.id,
{
"partner_id": partner_rec.id,
"id_type": id_type,
"value": value,
"status": status,
"description": description,
},
)
)
]
}
)

partner_rec.write(indv_rec)

results.append(IndividualInfoResponse.model_validate(partner_rec))
results.append(UpdateIndividualInfoResponse.model_validate(partner_rec))

else:
logging.error("ID & ID type is required for update individual")
Expand Down
22 changes: 14 additions & 8 deletions g2p_registry_rest_api/routers/process_individual_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,24 @@ class ProcessIndividualMixin(models.AbstractModel):

def _process_individual(self, individual):
indv_rec = {
"name": individual.name,
"registration_date": individual.registration_date,
"name": individual.name if individual.name else None,
"registration_date": individual.registration_date if individual.registration_date else None,
"is_registrant": True,
"is_group": False,
"email": individual.email,
"given_name": individual.given_name,
"family_name": individual.family_name,
"addl_name": individual.addl_name,
"birthdate": individual.birthdate or False,
"birth_place": individual.birth_place or False,
"email": individual.email if individual.email else None,
"given_name": individual.given_name if individual.given_name else None,
"family_name": individual.family_name if individual.family_name else None,
"addl_name": individual.addl_name if individual.addl_name else None,
"birthdate": individual.birthdate if individual.birthdate else None,
"birth_place": individual.birth_place if individual.birth_place else None,
"address": individual.address if individual.address else None,
"image_1920": individual.image_1920 if individual.image_1920 else None,
}

filtered_none = {key: value for key, value in indv_rec.items() if value is not None}
indv_rec.clear()
indv_rec.update(filtered_none)

ids = []
ids_info = individual
ids = ProcessIndividualMixin._process_ids(self, ids_info)
Expand Down Expand Up @@ -61,6 +65,8 @@ def _process_ids(self, ids_info):
"id_type": id_type_id[0].id,
"value": rec.value,
"expiry_date": rec.expiry_date,
"status": rec.status if rec.status else None,
"description": rec.description if rec.description else None,
},
)
)
Expand Down
24 changes: 21 additions & 3 deletions g2p_registry_rest_api/schemas/individual.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from datetime import date
from datetime import date, datetime

from pydantic import field_validator
from pydantic import Field, field_validator

from .registrant import RegistrantInfoRequest, RegistrantInfoResponse

Expand All @@ -27,11 +27,29 @@ class IndividualInfoRequest(RegistrantInfoRequest):
addl_name: str | None = None
family_name: str | None = None
gender: str | None
birthdate: date | None
birthdate: str = Field(
None, description="Date of birth in YYYY-MM-DD format", json_schema_extra={"examples": ["2000-01-01"]}
)
birth_place: str | None
is_group: bool = False

@field_validator("birthdate")
@classmethod
def parse_dob(cls, v):
if v is None or v == "":
return None
return datetime.strptime(v, "%Y-%m-%d").date()


class UpdateIndividualInfoRequest(IndividualInfoRequest):
updateId: str
image_1920: bytes | None = None
given_name: str | None
name: str | None


class UpdateIndividualInfoResponse(IndividualInfoResponse):
id: int | None = None
given_name: str | None = None
name: str | None = None
family_name: str | None = None
Loading
Loading