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: 13 additions & 0 deletions spp_registry/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,19 @@ Dependencies
Changelog
=========

19.0.2.2.7
~~~~~~~~~~

- test(registry): make two tests hold when other modules are installed
alongside spp_registry, as on every full stack. The unparseable-phone
fallback test builds its record with ``new()`` instead of
``create()``, because ``spp_base_common`` overrides ``create()`` to
refuse a number containing letters before the registry compute is
reached; the unlink-permission tests pin the starter bundles'
admin-only registry switch off for their transaction, because it is
shipped on and enforced server-side and would refuse the manager the
registry rule allows. No behaviour change (#443)

19.0.2.2.4
~~~~~~~~~~

Expand Down
2 changes: 1 addition & 1 deletion spp_registry/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{
"name": "OpenSPP Registry",
"category": "OpenSPP/Core",
"version": "19.0.2.2.4",
"version": "19.0.2.2.7",
"sequence": 1,
"author": "OpenSPP.org",
"website": "https://github.com/OpenSPP/OpenSPP2",
Expand Down
4 changes: 4 additions & 0 deletions spp_registry/readme/HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### 19.0.2.2.7

- test(registry): make two tests hold when other modules are installed alongside spp_registry, as on every full stack. The unparseable-phone fallback test builds its record with `new()` instead of `create()`, because `spp_base_common` overrides `create()` to refuse a number containing letters before the registry compute is reached; the unlink-permission tests pin the starter bundles' admin-only registry switch off for their transaction, because it is shipped on and enforced server-side and would refuse the manager the registry rule allows. No behaviour change (#443)

### 19.0.2.2.4

- fix(registry): refuse a date of birth in the future on every write path. `_birthdate_onchange` only runs in the form UI, so ORM `create`/`write`, CSV/Excel import and API writes (XML-RPC, API v2, DCI) all persisted a future `birthdate` — which the non-stored `age` compute then rendered as a negative number in views, exports and API reads. A stored-field constraint now enforces it server-side, comparing against the user's own today so a registrar east of UTC is not refused a birth recorded earlier that local day, and naming the record and the offending value so a bad row in a bulk import can be found. The onchange is kept as the friendlier silent-reset UX in the form (#362)
Expand Down
28 changes: 21 additions & 7 deletions spp_registry/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,20 @@ <h2><a class="toc-backref" href="#toc-entry-1">Changelog</a></h2>
</div>
</div>
<div class="section" id="section-1">
<h1>19.0.2.2.7</h1>
<ul class="simple">
<li>test(registry): make two tests hold when other modules are installed
alongside spp_registry, as on every full stack. The unparseable-phone
fallback test builds its record with <tt class="docutils literal">new()</tt> instead of
<tt class="docutils literal">create()</tt>, because <tt class="docutils literal">spp_base_common</tt> overrides <tt class="docutils literal">create()</tt> to
refuse a number containing letters before the registry compute is
reached; the unlink-permission tests pin the starter bundles’
admin-only registry switch off for their transaction, because it is
shipped on and enforced server-side and would refuse the manager the
registry rule allows. No behaviour change (#443)</li>
</ul>
</div>
<div class="section" id="section-2">
<h1>19.0.2.2.4</h1>
<ul class="simple">
<li>fix(registry): refuse a date of birth in the future on every write
Expand All @@ -538,7 +552,7 @@ <h1>19.0.2.2.4</h1>
<tt class="docutils literal">SELECT id, display_name, birthdate FROM res_partner WHERE birthdate &gt; CURRENT_DATE;</tt></li>
</ul>
</div>
<div class="section" id="section-2">
<div class="section" id="section-3">
<h1>19.0.2.2.3</h1>
<ul class="simple">
<li>fix(registry): repair the stored <tt class="docutils literal">status</tt>/<tt class="docutils literal">is_ended</tt> computes on
Expand All @@ -562,7 +576,7 @@ <h1>19.0.2.2.3</h1>
<tt class="docutils literal">CREATE INDEX CONCURRENTLY IF NOT EXISTS spp_group_membership__ended_date_index ON spp_group_membership (ended_date) WHERE ended_date IS NOT NULL;</tt></li>
</ul>
</div>
<div class="section" id="section-3">
<div class="section" id="section-4">
<h1>19.0.2.2.2</h1>
<ul class="simple">
<li>fix(registry): let an ID type be used again after its ID was removed.
Expand All @@ -574,7 +588,7 @@ <h1>19.0.2.2.2</h1>
surfacing a database error (#1136)</li>
</ul>
</div>
<div class="section" id="section-4">
<div class="section" id="section-5">
<h1>19.0.2.2.1</h1>
<ul class="simple">
<li>feat(registry): registry configuration is consolidated into one
Expand All @@ -585,7 +599,7 @@ <h1>19.0.2.2.1</h1>
framework refuses a settings save from anyone else (#1009)</li>
</ul>
</div>
<div class="section" id="section-5">
<div class="section" id="section-6">
<h1>19.0.2.1.4</h1>
<ul class="simple">
<li>fix(registry): remove the dead <tt class="docutils literal"><span class="pre">&#64;api.constrains(&quot;age&quot;)</span></tt>
Expand All @@ -597,7 +611,7 @@ <h1>19.0.2.1.4</h1>
dropped</li>
</ul>
</div>
<div class="section" id="section-6">
<div class="section" id="section-7">
<h1>19.0.2.1.3</h1>
<ul class="simple">
<li>fix(registry): show an ID <strong>Status</strong> column on the group form
Expand All @@ -608,7 +622,7 @@ <h1>19.0.2.1.3</h1>
(#1110)</li>
</ul>
</div>
<div class="section" id="section-7">
<div class="section" id="section-8">
<h1>19.0.2.1.1</h1>
<ul class="simple">
<li>fix(views): add reusable <tt class="docutils literal">x2many_no_padding</tt> JS widget that
Expand All @@ -618,7 +632,7 @@ <h1>19.0.2.1.1</h1>
don’t bloat the layout (#943).</li>
</ul>
</div>
<div class="section" id="section-8">
<div class="section" id="section-9">
<h1>19.0.2.0.0</h1>
<ul class="simple">
<li>Initial migration to OpenSPP2</li>
Expand Down
7 changes: 6 additions & 1 deletion spp_registry/tests/test_phone_number.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,13 @@ def test_unparseable_phone_falls_back_to_original(self):
Worth flagging: this means ``phone_sanitized`` can hold an
un-E164'd value when parsing fails. If you'd rather it be empty,
the compute needs to filter the fallback explicitly.

The record is built with ``new()`` rather than ``create()``: this
pins the compute of the registry layer alone, and ``spp_base_common``
(installed on every full stack) overrides ``create()`` to refuse a
number containing letters before the compute is ever reached.
"""
rec = self.PhoneNumber.create({"partner_id": self.individual_a.id, "phone_no": "abcxyz"})
rec = self.PhoneNumber.new({"partner_id": self.individual_a.id, "phone_no": "abcxyz"})
self.assertEqual(rec.phone_sanitized, "abcxyz")

def test_phone_validation_unavailable_returns_original(self):
Expand Down
11 changes: 11 additions & 0 deletions spp_registry/tests/test_unlink_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from odoo.exceptions import AccessError
from odoo.tests import tagged

from ..models.res_config_settings import _LEGACY_KEYS
from .common import RegistryCommon


Expand All @@ -21,6 +22,16 @@ class TestRegistrantUnlinkPermissions(RegistryCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
# These tests pin spp_registry's own rule (officer blocked, manager
# allowed). The starter bundles layer a stricter switch on top —
# registrant create/write/unlink for admins only, shipped ON and
# enforced server-side since #411 — which would refuse the manager
# here whenever such a bundle is installed in the same database. Pin
# it off for this transaction; the guard reads the parameter live and
# the change rolls back with the test (precedent: spp_mis_demo_v2's
# access-control tests, OP#1142).
for key in _LEGACY_KEYS:
cls.env["ir.config_parameter"].sudo().set_param(key, "False")
cls.target = cls.Partner.create({"name": "Deletable Partner", "is_registrant": True, "is_group": False})

def _target_for(self, user):
Expand Down
Loading