diff --git a/spp_change_request_v2/README.rst b/spp_change_request_v2/README.rst index cec371c0..99b63c96 100644 --- a/spp_change_request_v2/README.rst +++ b/spp_change_request_v2/README.rst @@ -853,6 +853,20 @@ Before declaring a new CR type complete: Changelog ========= +19.0.3.1.12 +~~~~~~~~~~~ + +- fix(change_request): auto-apply-on-approve runs through the public + ``action_apply`` again. Requiring change-request manager rights to + apply meant auto-apply was routed to the internal mechanism instead, + so the approver could be a validator — but ``action_apply`` is the + extension point modules override to hang post-apply work off an apply, + and bypassing it left those overrides silently not running on + approval: no error, just missing side effects. Auto-apply now calls + ``action_apply`` under ``sudo()``, which the manager gate already + exempts. ``sudo()`` sets superuser mode without changing the user, so + the applying user is still recorded as the approver. + 19.0.3.1.11 ~~~~~~~~~~~ diff --git a/spp_change_request_v2/__manifest__.py b/spp_change_request_v2/__manifest__.py index f34e3557..d3d91b88 100644 --- a/spp_change_request_v2/__manifest__.py +++ b/spp_change_request_v2/__manifest__.py @@ -1,6 +1,6 @@ { "name": "OpenSPP Change Request V2", - "version": "19.0.3.1.11", + "version": "19.0.3.1.12", "sequence": 50, "category": "OpenSPP", "summary": "Configuration-driven change request system with UX improvements, conflict detection and duplicate prevention", diff --git a/spp_change_request_v2/models/change_request.py b/spp_change_request_v2/models/change_request.py index 6a703e54..81d9e481 100644 --- a/spp_change_request_v2/models/change_request.py +++ b/spp_change_request_v2/models/change_request.py @@ -1093,10 +1093,16 @@ def _on_approve(self): self._create_log("approved") if self.request_type_id.auto_apply_on_approve: # Auto-apply is authorized by the approval workflow itself, so it - # goes through the internal mechanism rather than the manager-gated - # public action_apply (the approver may be a validator, not a - # manager). - self._apply_change_request() + # runs with sudo: ``action_apply``'s manager gate exempts + # ``env.su``, which lets the approver be a validator rather than a + # manager. Going through the public entry point rather than the + # internal mechanism keeps ``action_apply`` the single extension + # point for apply -- downstream modules override it to hang + # post-apply work off the apply, and routing around it left those + # overrides silently not running on approval. ``sudo()`` sets + # ``su`` without changing ``uid``, so ``applied_by_id`` still + # records the real approver. + self.sudo().action_apply() # nosemgrep: odoo-sudo-without-context def _on_reject(self, reason): super()._on_reject(reason) @@ -1448,9 +1454,16 @@ def action_apply(self): roles cannot (e.g. ``spp.group.membership``), so it must be gated server-side to managers: the XML button ``groups=`` is NOT an authorization boundary because Odoo object methods are callable over - RPC. Superuser (sudo) callers and the auto-apply-on-approve path (which - invokes ``_apply_change_request`` directly, already authorized by the - approval workflow) are unaffected. + RPC. Superuser (``env.su``) callers are exempt, and + auto-apply-on-approve is one of them: ``_on_approve`` reaches this + method through ``sudo()``, already authorized by the approval workflow + itself, so the approver may be a validator rather than a manager. + + This is also the extension point for apply, so an override runs on both + paths -- under ``su`` when auto-applied on approval, and as the manager + who clicked Apply on the manual path. ``sudo()`` sets ``su`` without + changing ``uid``, so ``self.env.user`` is the approver either way and + ``applied_by_id`` records them, not the superuser. """ if not (self.env.su or self.env.user.has_group("spp_change_request_v2.group_cr_manager")): raise AccessError(_("Only Change Request managers can apply change requests.")) diff --git a/spp_change_request_v2/readme/HISTORY.md b/spp_change_request_v2/readme/HISTORY.md index 54cd843e..5e160703 100644 --- a/spp_change_request_v2/readme/HISTORY.md +++ b/spp_change_request_v2/readme/HISTORY.md @@ -1,3 +1,7 @@ +### 19.0.3.1.12 + +- fix(change_request): auto-apply-on-approve runs through the public `action_apply` again. Requiring change-request manager rights to apply meant auto-apply was routed to the internal mechanism instead, so the approver could be a validator — but `action_apply` is the extension point modules override to hang post-apply work off an apply, and bypassing it left those overrides silently not running on approval: no error, just missing side effects. Auto-apply now calls `action_apply` under `sudo()`, which the manager gate already exempts. `sudo()` sets superuser mode without changing the user, so the applying user is still recorded as the approver. + ### 19.0.3.1.11 - fix(change_request): field-mapping transform expressions are evaluated again. `_eval_expression` passed `nocopy=True` to `safe_eval`, which takes no such argument in Odoo 19, so every expression raised `TypeError`; the blanket fallback swallowed it and the **untransformed** value was written to the registrant. A configured transform was therefore ignored, reported only as a warning in the log. **Behaviour change:** request types that already have an Expression transform configured will start transforming values on upgrade, having silently passed the raw value through until now. diff --git a/spp_change_request_v2/static/description/index.html b/spp_change_request_v2/static/description/index.html index 705cc88b..c8d57bc4 100644 --- a/spp_change_request_v2/static/description/index.html +++ b/spp_change_request_v2/static/description/index.html @@ -1339,6 +1339,21 @@