From 54b3b274727da79086fe3f3c0b4818289049cf0b Mon Sep 17 00:00:00 2001 From: Daniel Gergely Date: Tue, 17 Mar 2026 15:54:13 +0100 Subject: [PATCH 1/3] [T3059] FIX: last lifecycle event now takes date into account - FIX: take all events, sort by date descending, take first date and calculate state according to this event --- child_compassion/models/project_compassion.py | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/child_compassion/models/project_compassion.py b/child_compassion/models/project_compassion.py index 38c226ca2..3bc517c52 100644 --- a/child_compassion/models/project_compassion.py +++ b/child_compassion/models/project_compassion.py @@ -477,13 +477,25 @@ def _get_months(self): @api.depends("lifecycle_ids", "lifecycle_ids.date") def _compute_last_lifecycle(self): for project in self: - last_info = project.lifecycle_ids[:1] - reactivation_lifecycle = project.lifecycle_ids.filtered( - lambda r, _last=last_info: r.date == _last.date - and r.type == "Reactivation" - )[:1] + if not project.lifecycle_ids: + project.last_lifecycle_id = False + continue + + # Sort lifecycle events by date descending + sorted_events = project.lifecycle_ids.sorted( + key=lambda r: (str(r.date or ''), r.id), + reverse=True + ) + # Take first (newest) event + last_info = sorted_events[0] + + reactivation_lifecycle = sorted_events.filtered( + lambda r: r.date == last_info.date and r.type == "Reactivation" + ) + # If it exists, lifecycle with type 'Reactivation' is determinant - project.last_lifecycle_id = reactivation_lifecycle or last_info + project.last_lifecycle_id = reactivation_lifecycle[0] if reactivation_lifecycle else last_info + @api.depends("lifecycle_ids", "lifecycle_ids.write_date") def _compute_suspension(self): From 6af3b3f998dcce3e38d6c58ae378343e354b6ae2 Mon Sep 17 00:00:00 2001 From: Daniel Gergely Date: Wed, 18 Mar 2026 11:42:58 +0100 Subject: [PATCH 2/3] [T3059] FIX: added post-migration script - FIX: post-migration script should now update the last event date on all projects - FIX: changed the sorting of the lifecycle events in the projects view - FIX: updated module version --- child_compassion/__manifest__.py | 2 +- .../migrations/14.0.1.6.0/post-migration.py | 24 +++++++++++++++++++ child_compassion/models/project_compassion.py | 8 +++---- .../views/project_compassion_view.xml | 4 +++- 4 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 child_compassion/migrations/14.0.1.6.0/post-migration.py diff --git a/child_compassion/__manifest__.py b/child_compassion/__manifest__.py index 7f3aefd60..383dc924f 100644 --- a/child_compassion/__manifest__.py +++ b/child_compassion/__manifest__.py @@ -29,7 +29,7 @@ # pylint: disable=C8101 { "name": "Compassion Children", - "version": "14.0.1.5.0", + "version": "14.0.1.6.0", "category": "Compassion", "author": "Compassion CH", "license": "AGPL-3", diff --git a/child_compassion/migrations/14.0.1.6.0/post-migration.py b/child_compassion/migrations/14.0.1.6.0/post-migration.py new file mode 100644 index 000000000..5a9dee95c --- /dev/null +++ b/child_compassion/migrations/14.0.1.6.0/post-migration.py @@ -0,0 +1,24 @@ +import logging + +from odoo import SUPERUSER_ID, api + +_logger = logging.getLogger(__name__) + + +def migrate(cr, version): + """ + Recompute the lifecycle state & date of an FCP project + """ + + env = api.Environment(cr, SUPERUSER_ID, {}) + + # Fetch all projects: + projects = env["compassion.project"].search([]) + + # Invalidate cache + projects.invalidate_cache(["last_lifecycle_id", "suspension", "suspension"]) + + projects._compute_last_lifecycle() + projects._compute_suspension() + + _logger.info("Successfully recomputed lifecycle states for %s FCPs.", len(projects)) diff --git a/child_compassion/models/project_compassion.py b/child_compassion/models/project_compassion.py index 3bc517c52..3bf1a0a05 100644 --- a/child_compassion/models/project_compassion.py +++ b/child_compassion/models/project_compassion.py @@ -483,8 +483,7 @@ def _compute_last_lifecycle(self): # Sort lifecycle events by date descending sorted_events = project.lifecycle_ids.sorted( - key=lambda r: (str(r.date or ''), r.id), - reverse=True + key=lambda r: (str(r.date or ""), r.id), reverse=True ) # Take first (newest) event last_info = sorted_events[0] @@ -494,8 +493,9 @@ def _compute_last_lifecycle(self): ) # If it exists, lifecycle with type 'Reactivation' is determinant - project.last_lifecycle_id = reactivation_lifecycle[0] if reactivation_lifecycle else last_info - + project.last_lifecycle_id = ( + reactivation_lifecycle[0] if reactivation_lifecycle else last_info + ) @api.depends("lifecycle_ids", "lifecycle_ids.write_date") def _compute_suspension(self): diff --git a/child_compassion/views/project_compassion_view.xml b/child_compassion/views/project_compassion_view.xml index a77a72538..e11488a99 100644 --- a/child_compassion/views/project_compassion_view.xml +++ b/child_compassion/views/project_compassion_view.xml @@ -87,7 +87,9 @@ - + From 3d494a299090dc7403c97b1a7a22ebcb02c0a8cc Mon Sep 17 00:00:00 2001 From: Daniel Gergely Date: Wed, 18 Mar 2026 11:49:51 +0100 Subject: [PATCH 3/3] [T3059] FIX: GCA and pre-commit --- child_compassion/migrations/14.0.1.6.0/post-migration.py | 2 +- child_compassion/models/project_compassion.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/child_compassion/migrations/14.0.1.6.0/post-migration.py b/child_compassion/migrations/14.0.1.6.0/post-migration.py index 5a9dee95c..22c1975f0 100644 --- a/child_compassion/migrations/14.0.1.6.0/post-migration.py +++ b/child_compassion/migrations/14.0.1.6.0/post-migration.py @@ -16,7 +16,7 @@ def migrate(cr, version): projects = env["compassion.project"].search([]) # Invalidate cache - projects.invalidate_cache(["last_lifecycle_id", "suspension", "suspension"]) + projects.invalidate_cache(["last_lifecycle_id", "status", "suspension"]) projects._compute_last_lifecycle() projects._compute_suspension() diff --git a/child_compassion/models/project_compassion.py b/child_compassion/models/project_compassion.py index 3bf1a0a05..d37de91e6 100644 --- a/child_compassion/models/project_compassion.py +++ b/child_compassion/models/project_compassion.py @@ -489,7 +489,8 @@ def _compute_last_lifecycle(self): last_info = sorted_events[0] reactivation_lifecycle = sorted_events.filtered( - lambda r: r.date == last_info.date and r.type == "Reactivation" + lambda r, _last=last_info: r.date == _last.date + and r.type == "Reactivation" ) # If it exists, lifecycle with type 'Reactivation' is determinant