Skip to content

[17.0][MIG] project_task_recurring_activity: Migration to 17.0#1671

Open
CristianoMafraJunior wants to merge 12 commits intoOCA:17.0from
Escodoo:17.0-mig-project_task_recurring_activity
Open

[17.0][MIG] project_task_recurring_activity: Migration to 17.0#1671
CristianoMafraJunior wants to merge 12 commits intoOCA:17.0from
Escodoo:17.0-mig-project_task_recurring_activity

Conversation

@CristianoMafraJunior
Copy link
Member

@Escodoo MIGOCA-50

Migrated project_task_recurring_activity to Odoo 17 compatibility, removing legacy recurrence API dependencies (next_recurrence_date, _get_recurring_fields, planned_hours, etc.).
Updated project_task.xml for V17: recurring activities are no longer inserted in the old recurrence page (V16), but injected into the current task form layout.

Refactored models/project_task.py:

  • removed old logic tied to next_recurrence_date;
  • updated call_create_recurring_tasks() to use V17 recurrence flow via _create_next_occurrence();
  • preserved propagation of custom_activity_ids to newly created recurring tasks.

Refactored models/project_task_recurrence.py:

  • replaced _get_recurring_fields override with _get_recurring_fields_to_copy;
  • added compatibility helpers for manual and cron creation (create_recurring_tasks and _cron_create_recurring_tasks);
  • cron now uses business date (date_deadline) instead of create_date, avoiding freezegun-related instability.

Refactored models/recurring_activity.py:

  • removed references to recurrence_id.next_recurrence_date;
  • activity date_deadline is now computed from task date context (with safe fallback).

Updated tests/test_project_recurrence.py:

  • replaced planned_hours with allocated_hours;
  • removed assertions relying on legacy fields not present in V17;
  • aligned task/activity count expectations with Odoo 17 recurrence behavior;
  • removed brittle assertions based on create_date (DB/server real time).

Copy link
Contributor

@alexey-pelykh alexey-pelykh left a comment

Choose a reason for hiding this comment

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

Thanks for working on this! A few things I noticed: the next_recurrence_date field has string="next_date" which looks like an internal reference rather than a user-visible label — should be something like "Next Recurrence Date". Also, project_task_recurrence.py and recurring_activity.py are missing license headers (other files have them). codecov/patch is failing which suggests some paths aren't covered by tests.

days_after_task_creation_date = fields.Integer()
next_recurrence_date = fields.Date(
string="next_date", compute="_compute_next_recurrence_date", store=True
)
Copy link
Contributor

Choose a reason for hiding this comment

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

string="next_date" looks like an internal name. Consider a proper label like "Next Recurrence Date".

Copy link
Contributor

@alexey-pelykh alexey-pelykh left a comment

Choose a reason for hiding this comment

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

Thank you for the migration work on project_task_recurring_activity to 17.0. The overall approach of adapting to V17's _create_next_occurrence flow looks reasonable. However, there are several issues that need to be addressed before this can be merged.


Critical / Blocking

  1. Missing license headers (project_task_recurrence.py, recurring_activity.py): OCA modules require AGPL-3 license headers on every Python source file. Two model files are missing them.

  2. Security: Access rules too permissive (ir.model.access.csv): The recurring.activity model grants read/write/create/unlink to ALL users (empty group_id:id column). This should be restricted to at minimum project.group_project_user or project.group_project_recurring_tasks.

  3. Mutable default on field (project_task_recurrence.py:7): fields.Date(default=fields.Date.today()) evaluates today() at class definition time (module load), so every record will get the date the server started, not the date of creation. Use default=fields.Date.today (without parentheses) or default=lambda self: fields.Date.today().

  4. _cron_create_recurring_tasks scans all recurrences (project_task_recurrence.py:17): self.search([]).filtered("task_ids") loads every recurrence record into memory. This is an unbounded query that will degrade as the database grows. Use a domain filter, e.g., self.search([('task_ids', '!=', False)]).

  5. f-string inside _() translation function (recurring_activity.py:84-87): Using an f-string inside _() breaks Odoo's translation extraction. The _() function requires a static string at extraction time. Use % formatting or .format() with _() containing only a static template string.


Moderate

  1. next_recurrence_date field string (recurring_activity.py:44-46): string="next_date" looks like an internal identifier, not a user-facing label. Should be something like "Next Recurrence Date".

  2. Translation files are stale (i18n/es.po, i18n/it.po): The .po files reference Project-Id-Version: Odoo Server 14.0 and contain entries for fields like __last_update which was removed in V16+. The .pot file references Odoo Server 16.0. These should be regenerated for 17.0, and stale field references removed.

  3. _get_next_date logic is confusing (recurring_activity.py:53-58): The conditional days + 1 if days == 0 else days means that setting 0 days actually results in 1 day offset, which is non-obvious. Consider documenting this behavior or using a minimum constraint on the field instead.

  4. custom_activity_ids as stored computed Many2many (project_task.py:12-14): This field is compute="_compute_activity_ids", store=True, copy=True but it simply mirrors recurring_activity_ids.ids. A stored computed field that is also copyable is unusual -- when a task is copied, does the compute fire and overwrite the copy? This interaction should be verified.

  5. create override uses self._forming_activity_data(item, item.custom_activity_ids) (project_task.py:60-65): But custom_activity_ids on the newly created task is a computed field that mirrors recurring_activity_ids. If the task was just created as a recurrence copy, this may re-create activities that were already copied. Verify there is no duplication of recurring_activity_ids on recurrence creation.

  6. Inconsistent XML indentation (data/recurring_activity.xml): The cron record uses mixed indentation (8 spaces for <record> children, then 12 spaces for <field name="nextcall">). Follow consistent indentation.


Minor / Suggestions

  1. recurring_activity.xml form view: readonly="0" attributes on user_id, summary, and description fields in the form view may be unnecessary if the fields are not readonly by default at the model level (they are store=True, readonly=False already).

  2. Test assertion messages: Some assertion messages are generic ("Must be equal to 0", "Must be equal to 1"). More descriptive messages would help debugging test failures.

  3. Unused import in tests (test_project_recurrence.py:5): from odoo import _, fields -- the _ import is used inside assertRaisesRegex, which is fine, but note that this makes the test dependent on the exact translated string. Consider matching on a substring instead.

  4. delta_time method (recurring_activity.py:98-99): This is a trivial (new - old).days wrapper that is only used in tests. Consider whether it needs to be on the model at all, or can be a test helper.

  5. Usage documentation (readme/USAGE.md): Still references "In tab Recurrence" but per the PR description, the V17 migration moved the fields out of the old recurrence page. The documentation should reflect the actual V17 location.


Review posted via CorporateHub OCA review campaign

@CristianoMafraJunior CristianoMafraJunior force-pushed the 17.0-mig-project_task_recurring_activity branch from 9e522ea to 3aa418c Compare March 2, 2026 14:14
@CristianoMafraJunior CristianoMafraJunior force-pushed the 17.0-mig-project_task_recurring_activity branch from 3aa418c to 439d07d Compare March 2, 2026 14:24
groups="project.group_project_recurring_tasks"
invisible="not recurring_task"
/>
<field

Choose a reason for hiding this comment

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

If you add a label, remove the default field label with nolabel="1" or it will be duplicated. On the other hand, the tree looks too small.

Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants