From 66c9f75e979fb59b2c2fba29d3126053a301480b Mon Sep 17 00:00:00 2001 From: Juanjo Date: Tue, 3 Sep 2024 11:02:49 +0200 Subject: [PATCH] [REF] project_timeline: Use dedicated fields for timeline planning The fields `date_assign` and `date_end` can't be used, as they are automatically rewritten on certain flow events (user assignation and stage changed to finished one), so we need dedicated fields for the planning. A previous change switches `date_assign` to `date_start`, but it didn't change demo data, and better to use a consistent naming, prefixing both fields with `planned_`. This includes the migration scripts for preserving previous data, and automations to fill planned data from the previous fields. It also pre-fills planning information from assignation date/close date as a best effort pre-planning for existing tasks. TT50618 Co-Authored-By: Pedro M. Baeza --- project_timeline/README.rst | 7 +- project_timeline/__init__.py | 2 +- project_timeline/__manifest__.py | 4 +- project_timeline/demo/project_task_demo.xml | 76 +++++++++---------- project_timeline/hooks.py | 19 +++-- .../migrations/14.0.2.0.0/post-migration.py | 16 ++++ .../migrations/14.0.2.0.0/pre-migration.py | 11 +++ project_timeline/models/project_task.py | 42 ++++++++-- project_timeline/readme/CONTRIBUTORS.rst | 1 + project_timeline/readme/USAGE.rst | 6 +- .../static/description/index.html | 7 +- .../tests/test_project_timeline.py | 24 ++++-- project_timeline/views/project_task_view.xml | 32 ++++++-- 13 files changed, 177 insertions(+), 70 deletions(-) create mode 100644 project_timeline/migrations/14.0.2.0.0/post-migration.py create mode 100644 project_timeline/migrations/14.0.2.0.0/pre-migration.py diff --git a/project_timeline/README.rst b/project_timeline/README.rst index b50da8536a..c94fca4f65 100644 --- a/project_timeline/README.rst +++ b/project_timeline/README.rst @@ -45,7 +45,11 @@ To view the timeline: * Click on the timeline view icon. * You will see the tasks or projects in the new view. -The Task timeline uses the Start Date and End Date fields, in the Extra Info tab. +The Task timeline uses the "Planned Start Date" and "Planned End Date" fields, in the +"Extra Info" tab. + +When a user is assigned, and there's no planned start date, current datetime is filled +there, and the same happens for the end one when the task is put in a done stage. Bug Tracker =========== @@ -79,6 +83,7 @@ Contributors * Pedro M. Baeza * Carlos Dauden * Alexandre Díaz + * Juan José Seguí * `Open Source Integrators `_: diff --git a/project_timeline/__init__.py b/project_timeline/__init__.py index adb73323b1..650ad125b7 100644 --- a/project_timeline/__init__.py +++ b/project_timeline/__init__.py @@ -1,4 +1,4 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from .hooks import populate_date_start +from .hooks import post_init_hook from . import models diff --git a/project_timeline/__manifest__.py b/project_timeline/__manifest__.py index 77c3a2ff51..85e586a806 100644 --- a/project_timeline/__manifest__.py +++ b/project_timeline/__manifest__.py @@ -6,7 +6,7 @@ { "name": "Project timeline", "summary": "Timeline view for projects", - "version": "14.0.1.5.0", + "version": "14.0.2.0.0", "category": "Project Management", "website": "https://github.com/OCA/project", "author": "Tecnativa, Onestein, Odoo Community Association (OCA)", @@ -18,5 +18,5 @@ "views/project_task_view.xml", ], "demo": ["demo/project_project_demo.xml", "demo/project_task_demo.xml"], - "post_init_hook": "populate_date_start", + "post_init_hook": "post_init_hook", } diff --git a/project_timeline/demo/project_task_demo.xml b/project_timeline/demo/project_task_demo.xml index becf2c6765..e837256bfd 100644 --- a/project_timeline/demo/project_task_demo.xml +++ b/project_timeline/demo/project_task_demo.xml @@ -4,191 +4,191 @@ diff --git a/project_timeline/hooks.py b/project_timeline/hooks.py index 8f289c38c0..bbfab6a3f2 100644 --- a/project_timeline/hooks.py +++ b/project_timeline/hooks.py @@ -1,16 +1,19 @@ # Copyright 2021 Open Source Integrators - Daniel Reis +# Copyright 2024 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -def populate_date_start(cr, registry): - """ - The date_start was introduced to be used instead of date_assign. - To keep same behaviour on upgrade, initialize it - to have the same data as before. - """ +def post_init_hook(cr, registry): + """Pre-fill planned dates with existing data for having a "best effort" planning.""" cr.execute( "UPDATE project_task " - "SET date_start = date_assign " - "WHERE date_start IS NULL " + "SET planned_date_start = date_assign " + "WHERE planned_date_start IS NULL " "AND date_assign IS NOT NULL" ) + cr.execute( + "UPDATE project_task " + "SET planned_date_end = date_end " + "WHERE planned_date_end IS NULL " + "AND date_end IS NOT NULL" + ) diff --git a/project_timeline/migrations/14.0.2.0.0/post-migration.py b/project_timeline/migrations/14.0.2.0.0/post-migration.py new file mode 100644 index 0000000000..fc7c520fe8 --- /dev/null +++ b/project_timeline/migrations/14.0.2.0.0/post-migration.py @@ -0,0 +1,16 @@ +# Copyright 2024 Tecnativa - Juan José Seguí +# Copyright 2024 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openupgradelib import openupgrade + + +@openupgrade.migrate() +def migrate(env, version): + openupgrade.logged_query( + env.cr, + """UPDATE project_task + SET planned_date_end = date_end + WHERE planned_date_end IS NULL AND date_end IS NOT NULL; + """, + ) diff --git a/project_timeline/migrations/14.0.2.0.0/pre-migration.py b/project_timeline/migrations/14.0.2.0.0/pre-migration.py new file mode 100644 index 0000000000..30154ce114 --- /dev/null +++ b/project_timeline/migrations/14.0.2.0.0/pre-migration.py @@ -0,0 +1,11 @@ +# Copyright 2024 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openupgradelib import openupgrade + + +@openupgrade.migrate() +def migrate(env, version): + openupgrade.rename_fields( + env, [("project.task", "project_task", "date_start", "planned_date_start")] + ) diff --git a/project_timeline/models/project_task.py b/project_timeline/models/project_task.py index 38de489147..ad66693f90 100644 --- a/project_timeline/models/project_task.py +++ b/project_timeline/models/project_task.py @@ -3,15 +3,45 @@ # Copyright 2021 Open Source Integrators - Daniel Reis # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import fields, models +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError class ProjectTask(models.Model): _inherit = "project.task" - date_start = fields.Datetime("Start Date") + planned_date_start = fields.Datetime( + compute="_compute_planned_date_start", + store=True, + readonly=False, + ) + planned_date_end = fields.Datetime( + compute="_compute_planned_date_end", + store=True, + readonly=False, + ) - def update_date_end(self, stage_id): - res = super().update_date_end(stage_id) - res.pop("date_end", None) - return res + @api.depends("date_assign") + def _compute_planned_date_start(self): + """Put the assignation date as the planned start if not other value is + previously set. + """ + for record in self.filtered( + lambda x: not x.planned_date_start and x.date_assign + ): + record.planned_date_start = record.date_assign + + @api.depends("date_end") + def _compute_planned_date_end(self): + """Put the done date as the planned end if not other value is previously set.""" + for record in self.filtered(lambda x: not x.planned_date_end and x.date_end): + record.planned_date_end = record.date_end + + @api.constrains("planned_date_start", "planned_date_end") + def _check_planned_dates(self): + for task in self: + if task.planned_date_start and task.planned_date_end: + if task.planned_date_end < task.planned_date_start: + raise ValidationError( + _("The end date must be after the start date.") + ) diff --git a/project_timeline/readme/CONTRIBUTORS.rst b/project_timeline/readme/CONTRIBUTORS.rst index b314a14016..b073352c3d 100644 --- a/project_timeline/readme/CONTRIBUTORS.rst +++ b/project_timeline/readme/CONTRIBUTORS.rst @@ -8,6 +8,7 @@ * Pedro M. Baeza * Carlos Dauden * Alexandre Díaz + * Juan José Seguí * `Open Source Integrators `_: diff --git a/project_timeline/readme/USAGE.rst b/project_timeline/readme/USAGE.rst index 1357433890..698d4a528a 100644 --- a/project_timeline/readme/USAGE.rst +++ b/project_timeline/readme/USAGE.rst @@ -4,4 +4,8 @@ To view the timeline: * Click on the timeline view icon. * You will see the tasks or projects in the new view. -The Task timeline uses the Start Date and End Date fields, in the Extra Info tab. +The Task timeline uses the "Planned Start Date" and "Planned End Date" fields, in the +"Extra Info" tab. + +When a user is assigned, and there's no planned start date, current datetime is filled +there, and the same happens for the end one when the task is put in a done stage. diff --git a/project_timeline/static/description/index.html b/project_timeline/static/description/index.html index e84adbc7fd..35a7d5b281 100644 --- a/project_timeline/static/description/index.html +++ b/project_timeline/static/description/index.html @@ -1,4 +1,3 @@ - @@ -393,7 +392,10 @@

Usage

  • Click on the timeline view icon.
  • You will see the tasks or projects in the new view.
  • -

    The Task timeline uses the Start Date and End Date fields, in the Extra Info tab.

    +

    The Task timeline uses the “Planned Start Date” and “Planned End Date” fields, in the +“Extra Info” tab.

    +

    When a user is assigned, and there’s no planned start date, current datetime is filled +there, and the same happens for the end one when the task is put in a done stage.

    Bug Tracker

    @@ -423,6 +425,7 @@

    Contributors

  • Pedro M. Baeza
  • Carlos Dauden
  • Alexandre Díaz
  • +
  • Juan José Seguí
  • Open Source Integrators:
      diff --git a/project_timeline/tests/test_project_timeline.py b/project_timeline/tests/test_project_timeline.py index 4478400bc5..11e89790fb 100644 --- a/project_timeline/tests/test_project_timeline.py +++ b/project_timeline/tests/test_project_timeline.py @@ -1,4 +1,5 @@ # Copyright 2018 Onestein +# Copyright 2024 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import fields @@ -6,16 +7,29 @@ class TestProjectTimeline(TransactionCase): - def test_date_end_doesnt_unset(self): + def test_01_flow_filling(self): + task = self.env["project.task"].create({"name": "1"}) + self.assertFalse(task.planned_date_start) + task.user_id = self.env.user.id + self.assertTrue(task.planned_date_start) + self.assertFalse(task.planned_date_end) + task.stage_id = self.ref("project.project_stage_2") + self.assertTrue(task.planned_date_end) + + def test_02_no_filling(self): stage_id = self.ref("project.project_stage_2") task = self.env["project.task"].create( { "name": "1", - "date_assign": "2018-05-01 00:00:00", - "date_end": "2018-05-07 00:00:00", + "planned_date_start": "2018-05-01 00:00:00", + "planned_date_end": "2018-05-07 00:00:00", } ) - task.write({"stage_id": stage_id, "date_end": "2018-10-07 00:00:00"}) + task.user_id = self.env.user.id + self.assertEqual( + task.planned_date_start, fields.Datetime.from_string("2018-05-01") + ) + task.stage_id = stage_id self.assertEqual( - task.date_end, fields.Datetime.from_string("2018-10-07 00:00:00") + task.planned_date_end, fields.Datetime.from_string("2018-05-07") ) diff --git a/project_timeline/views/project_task_view.xml b/project_timeline/views/project_task_view.xml index 23f1508b3a..55b9f7871d 100644 --- a/project_timeline/views/project_task_view.xml +++ b/project_timeline/views/project_task_view.xml @@ -11,8 +11,8 @@ timeline timeline @@ -111,8 +111,28 @@ - - +