Skip to content
Open
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
13 changes: 7 additions & 6 deletions spp_registrant_gis/views/res_partner_views.xml
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!-- Add coordinates field to Individual Profile tab -->
<!-- Add coordinates field to Individual Profile tab.
Location renders AFTER Financial Information so the profile order
is: Contact → Phones → Financial → Location (#942 item 1). -->
<record id="view_individuals_form_gis" model="ir.ui.view">
<field name="name">spp_registrant_gis.view_individuals_form_gis</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="spp_registry.view_individuals_form" />
<field name="arch" type="xml">
<!-- Add GPS coordinates after phone numbers section -->
<xpath
expr="//page[@name='profile']//group[@name='phone_section']"
expr="//page[@name='profile']//group[@name='financial_section']"
position="after"
>
<separator string="Location" />
Expand All @@ -19,15 +20,15 @@
</field>
</record>

<!-- Add coordinates field to Group Profile tab -->
<!-- Add coordinates field to Group Profile tab.
Same ordering as the individual form. -->
<record id="view_groups_form_gis" model="ir.ui.view">
<field name="name">spp_registrant_gis.view_groups_form_gis</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="spp_registry.view_individuals_form" />
<field name="arch" type="xml">
<!-- Add GPS coordinates after phone numbers section -->
<xpath
expr="//page[@name='group_profile']//group[@name='group_phone_section']"
expr="//page[@name='group_profile']//group[@name='group_financial_section']"
position="after"
>
<separator string="Location" />
Expand Down
41 changes: 41 additions & 0 deletions spp_registry/models/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,47 @@ def _compute_force_recompute_canary(self):
"Group Members",
)

# True when the group-membership-type vocabulary has at least one code.
# Used by views to hide the "Group Role" column entirely when the
# vocabulary is empty (otherwise the column shows blank tag cells with
# nothing pickable).
has_group_membership_type_codes = fields.Boolean(
compute="_compute_has_group_membership_type_codes",
)

# True when the group-type vocabulary has at least one code. Used to
# hide the Group Type form field when there's nothing to pick.
has_group_type_codes = fields.Boolean(
compute="_compute_has_group_type_codes",
)

def _compute_has_group_membership_type_codes(self):
# sudo() so non-admin readers can still resolve the column-visibility
# flag; we only return a boolean, no vocabulary content leaks.
has_codes = bool(
self.env["spp.vocabulary.code"] # nosemgrep: odoo-sudo-without-context
.sudo()
.search_count(
[("vocabulary_id.namespace_uri", "=", "urn:openspp:vocab:group-membership-type")],
limit=1,
)
)
Comment on lines +72 to +79
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The search_count method in Odoo does not accept a limit argument. Passing limit=1 will result in a TypeError at runtime. To efficiently check for the existence of at least one record, use search() with limit=1 instead. Note: This non-deterministic search (using limit=1 without order) is acceptable here but should be acknowledged as technical debt to be addressed if the context changes.

Suggested change
has_codes = bool(
self.env["spp.vocabulary.code"] # nosemgrep: odoo-sudo-without-context
.sudo()
.search_count(
[("vocabulary_id.namespace_uri", "=", "urn:openspp:vocab:group-membership-type")],
limit=1,
)
)
has_codes = bool(
self.env["spp.vocabulary.code"] # nosemgrep: odoo-sudo-without-context
.sudo()
.search(
[("vocabulary_id.namespace_uri", "=", "urn:openspp:vocab:group-membership-type")],
limit=1,
)
)
References
  1. A non-deterministic database search (using search with limit=1 but no order) can be acceptable if the practical context makes it functionally deterministic, but it should be acknowledged as technical debt.

for rec in self:
rec.has_group_membership_type_codes = has_codes

def _compute_has_group_type_codes(self):
# sudo(): same rationale as above — we only expose a boolean.
has_codes = bool(
self.env["spp.vocabulary.code"] # nosemgrep: odoo-sudo-without-context
.sudo()
.search_count(
[("vocabulary_id.namespace_uri", "=", "urn:openspp:vocab:group-type")],
limit=1,
)
)
Comment on lines +85 to +92
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The search_count method does not support the limit parameter. This will cause a TypeError. Use search() with limit=1 to perform an efficient existence check. This non-deterministic search is acceptable but should be acknowledged as technical debt to be addressed if the context changes.

Suggested change
has_codes = bool(
self.env["spp.vocabulary.code"] # nosemgrep: odoo-sudo-without-context
.sudo()
.search_count(
[("vocabulary_id.namespace_uri", "=", "urn:openspp:vocab:group-type")],
limit=1,
)
)
has_codes = bool(
self.env["spp.vocabulary.code"] # nosemgrep: odoo-sudo-without-context
.sudo()
.search(
[("vocabulary_id.namespace_uri", "=", "urn:openspp:vocab:group-type")],
limit=1,
)
)
References
  1. A non-deterministic database search (using search with limit=1 but no order) can be acceptable if the practical context makes it functionally deterministic, but it should be acknowledged as technical debt.

for rec in self:
rec.has_group_type_codes = has_codes

def write(self, values):
res = super().write(values)
self._validate_unique_membership_types()
Expand Down
22 changes: 21 additions & 1 deletion spp_registry/models/group_membership.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,29 @@ class SPPGroupMembership(models.Model):
)
membership_type_ids = fields.Many2many(
"spp.vocabulary.code",
string="Membership Types",
string="Group Role",
domain="[('namespace_uri', '=', 'urn:openspp:vocab:group-membership-type')]",
)
# True when the group-membership-type vocabulary has at least one code.
# Drives column_invisible on the standalone Group Membership tree view
# (the embedded lists on the registrant forms read this from
# `parent.has_group_membership_type_codes` on res.partner instead).
has_group_membership_type_codes = fields.Boolean(
compute="_compute_has_group_membership_type_codes",
)

def _compute_has_group_membership_type_codes(self):
has_codes = bool(
self.env["spp.vocabulary.code"] # nosemgrep: odoo-sudo-without-context
.sudo()
.search_count(
[("vocabulary_id.namespace_uri", "=", "urn:openspp:vocab:group-membership-type")],
limit=1,
)
)
Comment on lines +42 to +49
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

In Odoo, search_count does not accept a limit argument. This implementation will fail with a TypeError. Please use search() with limit=1 for an optimized existence check. This approach is non-deterministic without an explicit order and should be acknowledged as technical debt to be addressed if the context changes.

Suggested change
has_codes = bool(
self.env["spp.vocabulary.code"] # nosemgrep: odoo-sudo-without-context
.sudo()
.search_count(
[("vocabulary_id.namespace_uri", "=", "urn:openspp:vocab:group-membership-type")],
limit=1,
)
)
has_codes = bool(
self.env["spp.vocabulary.code"] # nosemgrep: odoo-sudo-without-context
.sudo()
.search(
[("vocabulary_id.namespace_uri", "=", "urn:openspp:vocab:group-membership-type")],
limit=1,
)
)
References
  1. A non-deterministic database search (using search with limit=1 but no order) can be acceptable if the practical context makes it functionally deterministic, but it should be acknowledged as technical debt.

for rec in self:
rec.has_group_membership_type_codes = has_codes

start_date = fields.Datetime(default=lambda self: fields.Datetime.now())
ended_date = fields.Datetime()
status = fields.Selection(
Expand Down
9 changes: 4 additions & 5 deletions spp_registry/views/group_membership_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
<field name="priority">1</field>
<field name="arch" type="xml">
<list>
<field name="has_group_membership_type_codes" column_invisible="1" />
<field name="group" />
<field name="individual" />
<field
name="membership_type_ids"
string="Membership Types"
string="Group Role"
widget="many2many_tags"
options="{'no_create_edit':True,'no_open':True}"
column_invisible="not has_group_membership_type_codes"
/>
<field name="start_date" />
<field name="ended_date" />
Expand Down Expand Up @@ -52,10 +54,7 @@
/>
</h1>
<div class="o_row">
<label
for="membership_type_ids"
string="Membership Types:"
/>
<label for="membership_type_ids" string="Group Role:" />
<field
name="membership_type_ids"
widget="many2many_tags"
Expand Down
4 changes: 3 additions & 1 deletion spp_registry/views/group_membership_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
</xpath>
<xpath expr="//div[@name='group_members_section']" position="inside">
<separator string="Group Members" />
<field name="has_group_membership_type_codes" invisible="1" />
<field name="group_membership_ids" readonly="disabled" nolabel="1">
<list editable="top" default_order='status asc,ended_date asc'>
<button
Expand All @@ -34,9 +35,10 @@
<field name="individual_gender" string="Sex" />
<field
name="membership_type_ids"
string="Membership Types"
string="Group Role"
widget="many2many_tags"
options="{'no_open':True, 'no_create_edit':True, 'no_create':True, 'no_quick_create':True}"
column_invisible="not parent.has_group_membership_type_codes"
/>
<field name="start_date" />
<field name="ended_date" string="End date" />
Expand Down
4 changes: 3 additions & 1 deletion spp_registry/views/individual_membership_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
</xpath>
<xpath expr="//div[@name='membership_section']" position="inside">
<separator string="Group Membership" />
<field name="has_group_membership_type_codes" invisible="1" />
<field name="individual_membership_ids" readonly="disabled" nolabel="1">
<list editable="top">
<button
Expand All @@ -32,9 +33,10 @@
/>
<field
name="membership_type_ids"
string="Membership Types"
string="Group Role"
widget="many2many_tags"
options="{'no_open':True, 'no_create_edit':True}"
column_invisible="not parent.has_group_membership_type_codes"
/>
<field name="start_date" />
<field name="ended_date" />
Expand Down
5 changes: 5 additions & 0 deletions spp_registry/views/individual_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -582,11 +582,16 @@
readonly="disabled"
help="Name of the group (e.g., Household, Family)"
/>
<field
name="has_group_type_codes"
invisible="1"
/>
<field
name="group_type_id"
string="Group Type"
options="{'no_open':True, 'no_create_edit':True,'no_create':True}"
readonly="disabled"
invisible="not has_group_type_codes"
help="Type of group classification"
/>
</group>
Expand Down
2 changes: 1 addition & 1 deletion spp_registry_group_hierarchy/views/group_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
/>
</h1>
<div class="o_row">
<label for="membership_type_ids" string="Role:" />
<label for="membership_type_ids" string="Group Role:" />
<field
name="membership_type_ids"
widget="many2many_tags"
Expand Down
Loading