diff --git a/spp_registry/README.rst b/spp_registry/README.rst index 4eb0e993..8c2a20e0 100644 --- a/spp_registry/README.rst +++ b/spp_registry/README.rst @@ -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 ~~~~~~~~~~ diff --git a/spp_registry/__manifest__.py b/spp_registry/__manifest__.py index 2ed500e3..4c17061b 100644 --- a/spp_registry/__manifest__.py +++ b/spp_registry/__manifest__.py @@ -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", diff --git a/spp_registry/readme/HISTORY.md b/spp_registry/readme/HISTORY.md index d2f80ecd..c48e1815 100644 --- a/spp_registry/readme/HISTORY.md +++ b/spp_registry/readme/HISTORY.md @@ -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) diff --git a/spp_registry/static/description/index.html b/spp_registry/static/description/index.html index 48cfcf7c..68b3bca4 100644 --- a/spp_registry/static/description/index.html +++ b/spp_registry/static/description/index.html @@ -518,6 +518,20 @@

Changelog

+

19.0.2.2.7

+ +
+

19.0.2.2.4

-
+

19.0.2.2.3

-
+

19.0.2.2.2

  • fix(registry): let an ID type be used again after its ID was removed. @@ -574,7 +588,7 @@

    19.0.2.2.2

    surfacing a database error (#1136)
-
+

19.0.2.2.1

  • feat(registry): registry configuration is consolidated into one @@ -585,7 +599,7 @@

    19.0.2.2.1

    framework refuses a settings save from anyone else (#1009)
-
+

19.0.2.1.4

  • fix(registry): remove the dead @api.constrains("age") @@ -597,7 +611,7 @@

    19.0.2.1.4

    dropped
-
+

19.0.2.1.3

  • fix(registry): show an ID Status column on the group form @@ -608,7 +622,7 @@

    19.0.2.1.3

    (#1110)
-
+

19.0.2.1.1

  • fix(views): add reusable x2many_no_padding JS widget that @@ -618,7 +632,7 @@

    19.0.2.1.1

    don’t bloat the layout (#943).
-
+

19.0.2.0.0

  • Initial migration to OpenSPP2
  • diff --git a/spp_registry/tests/test_phone_number.py b/spp_registry/tests/test_phone_number.py index 580ca661..d8325729 100644 --- a/spp_registry/tests/test_phone_number.py +++ b/spp_registry/tests/test_phone_number.py @@ -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): diff --git a/spp_registry/tests/test_unlink_permissions.py b/spp_registry/tests/test_unlink_permissions.py index 4e75ab7d..45964cf3 100644 --- a/spp_registry/tests/test_unlink_permissions.py +++ b/spp_registry/tests/test_unlink_permissions.py @@ -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 @@ -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):