diff --git a/docsource/modules150-160.rst b/docsource/modules150-160.rst index b0f5266d47e8..bb54156f8193 100644 --- a/docsource/modules150-160.rst +++ b/docsource/modules150-160.rst @@ -640,7 +640,7 @@ Module coverage 15.0 -> 16.0 +-------------------------------------------------+----------------------+-------------------------------------------------+ | product_matrix | | | +-------------------------------------------------+----------------------+-------------------------------------------------+ -| project | | | +| project | Done | | +-------------------------------------------------+----------------------+-------------------------------------------------+ | |del| project_account | | | +-------------------------------------------------+----------------------+-------------------------------------------------+ diff --git a/openupgrade_scripts/scripts/project/16.0.1.2/post-migration.py b/openupgrade_scripts/scripts/project/16.0.1.2/post-migration.py new file mode 100644 index 000000000000..10877ae3633e --- /dev/null +++ b/openupgrade_scripts/scripts/project/16.0.1.2/post-migration.py @@ -0,0 +1,18 @@ +# Copyright 2023 Trần Trường Sơn +# Copyright 2023 Rémy Taymans +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openupgradelib import openupgrade + +_translations_to_delete = [ + "mail_template_data_project_task", + "project_manager_all_project_tasks_rule", + "project_message_user_assigned", + "rating_project_request_email_template", +] + + +@openupgrade.migrate() +def migrate(env, version): + openupgrade.load_data(env.cr, "project", "16.0.1.2/noupdate_changes.xml") + openupgrade.delete_record_translations(env.cr, "project", _translations_to_delete) diff --git a/openupgrade_scripts/scripts/project/16.0.1.2/pre-migration.py b/openupgrade_scripts/scripts/project/16.0.1.2/pre-migration.py new file mode 100644 index 000000000000..163f7e94956e --- /dev/null +++ b/openupgrade_scripts/scripts/project/16.0.1.2/pre-migration.py @@ -0,0 +1,170 @@ +# Copyright 2023 Trần Trường Sơn +# Copyright 2023 Rémy Taymans +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openupgradelib import openupgrade + +_new_fields = [ + ( + "is_closed", # Field name + "project.task", # Model name + "project_task", # Table name + "boolean", # Odoo Field type (in lower case) + False, # [Optional] SQL type (if custom fields) + "project", # Module name + False, # [Optional] Default value + ), + ( + "ancestor_id", # Field name + "project.task", # Model name + "project_task", # Table name + "many2one", # Odoo Field type (in lower case) + False, # [Optional] SQL type (if custom fields) + "project", # Module name + False, # [Optional] Default value + ), + ( + "is_analytic_account_id_changed", # Field name + "project.task", # Model name + "project_task", # Table name + "boolean", # Odoo Field type (in lower case) + False, # [Optional] SQL type (if custom fields) + "project", # Module name + False, # [Optional] Default value + ), + ( + "allow_milestones", # Field name + "project.project", # Model name + "project_project", # Table name + "boolean", # Odoo Field type (in lower case) + False, # [Optional] SQL type (if custom fields) + "project", # Module name + False, # [Optional] Default value + ), +] + + +def _set_task_type_fold_if_is_closed(env): + """Field `is_closed` on project.task.type is removed. The field + `fold` can be used instead. + """ + openupgrade.logged_query( + env.cr, + """ + UPDATE project_task_type + SET fold = TRUE + WHERE is_closed = TRUE; + """, + ) + + +def _fill_project_task_is_closed(env): + """Field `is_closed` on project.task is now a stored field.""" + openupgrade.logged_query( + env.cr, + """ + UPDATE project_task task + SET is_closed = stage.fold + FROM project_task_type stage + WHERE task.stage_id = stage.id; + """, + ) + + +def _fill_project_last_update_status_if_null(env): + """In some cases, the user can go to the DB and reset the + `last_update_status` field to NULL. In version 16.0 it is necessary + to reset it to `to_define` because it has a `required` attribute. + """ + openupgrade.logged_query( + env.cr, + """ + UPDATE project_project project + SET last_update_status = 'to_define' + WHERE last_update_status IS NULL; + """, + ) + + +def _compute_project_task_ancestor_id(env): + """ + New column at version 16.0. valid as the ancestor of the current task + """ + openupgrade.logged_query( + env.cr, + """ + WITH RECURSIVE task_ancestors AS ( + SELECT id, parent_id, id AS ancestor_id + FROM project_task + WHERE parent_id IS NULL + + UNION ALL + + SELECT pt.id, pt.parent_id, ta.ancestor_id + FROM project_task pt + INNER JOIN task_ancestors ta ON pt.parent_id = ta.id + ) + UPDATE project_task pt + SET ancestor_id = ta.ancestor_id + FROM task_ancestors ta + WHERE pt.id = ta.id; + + UPDATE project_task pt + SET ancestor_id = NULL + WHERE id = ancestor_id; + """, + ) + + +def _compute_project_task_is_analytic_account_id_changed(env): + """ + `is_analytic_account_id_changed` is a new field at version 16.0. + It has a value of False if you have the same admin account as the project, + otherwise it will have a value of True + """ + openupgrade.logged_query( + env.cr, + """ + UPDATE project_task task + SET is_analytic_account_id_changed = CASE + WHEN project_id IS NOT NULL + AND task.project_id = project.id + AND task.analytic_account_id != project.analytic_account_id + THEN TRUE + ELSE FALSE + END + FROM project_project as project; + """, + ) + + +def _fill_project_allow_milestones(env): + """New field allow_milestones on project.project depends on the + value of the configuration (based on a group) + project.group_project_milestone. + Previously, milestone where visible by default on a project. To keep + this behaviour with existing project, allow_milestones need to be + set to True. + """ + openupgrade.logged_query( + env.cr, + """ + UPDATE project_project project + SET allow_milestones = true + """, + ) + + +@openupgrade.migrate() +def migrate(env, version): + openupgrade.add_fields(env, _new_fields) + _set_task_type_fold_if_is_closed(env) + _fill_project_task_is_closed(env) + _fill_project_last_update_status_if_null(env) + _compute_project_task_ancestor_id(env) + _compute_project_task_is_analytic_account_id_changed(env) + + # Remove SQL view project_task_burndown_chart_report not used anymore in Odoo v16.0 + openupgrade.logged_query( + env.cr, "DROP VIEW IF EXISTS project_task_burndown_chart_report CASCADE" + ) diff --git a/openupgrade_scripts/scripts/project/16.0.1.2/tests/__init__.py b/openupgrade_scripts/scripts/project/16.0.1.2/tests/__init__.py new file mode 100644 index 000000000000..b631ae4cb2b4 --- /dev/null +++ b/openupgrade_scripts/scripts/project/16.0.1.2/tests/__init__.py @@ -0,0 +1 @@ +from . import test_project_migration diff --git a/openupgrade_scripts/scripts/project/16.0.1.2/tests/test_project_migration.py b/openupgrade_scripts/scripts/project/16.0.1.2/tests/test_project_migration.py new file mode 100644 index 000000000000..e4e2a7e179d5 --- /dev/null +++ b/openupgrade_scripts/scripts/project/16.0.1.2/tests/test_project_migration.py @@ -0,0 +1,13 @@ +from odoo.tests import TransactionCase + + +class TestProjectMigration(TransactionCase): + def test_project_allow_milestones(self): + """Test that the allow_milestones field on a project is correctly set. + On a database with demo data, project.group_project_milestone + option is set to true. So allow_milestones should be true on + projects. + """ + projects = self.env["project.project"].search([]) + for project in projects: + self.assertTrue(project.allow_milestones) diff --git a/openupgrade_scripts/scripts/project/16.0.1.2/upgrade_analysis_work.txt b/openupgrade_scripts/scripts/project/16.0.1.2/upgrade_analysis_work.txt new file mode 100644 index 000000000000..caa4d8615f6b --- /dev/null +++ b/openupgrade_scripts/scripts/project/16.0.1.2/upgrade_analysis_work.txt @@ -0,0 +1,101 @@ +---Models in module 'project'--- +obsolete model project.delete.wizard [transient] +# NOTHING TO DO: wizard removed + +---Fields in module 'project'--- +project / account.analytic.tag / task_ids (many2many) : DEL relation: project.task +project / project.task / analytic_tag_ids (many2many) : DEL relation: account.analytic.tag +# NOTHING TO DO: lost feature + +project / project.milestone / task_ids (one2many) : NEW relation: project.task +project / project.project / task_properties_definition (properties_definition): NEW +project / project.task / task_properties (properties) : NEW hasdefault: compute +project / res.company / analytic_plan_id (many2one) : NEW relation: account.analytic.plan, hasdefault: compute +# NOTHING TO DO: new features + +project / project.tags / project_ids (many2many) : NEW relation: project.project +project / project.tags / task_ids (many2many) : NEW relation: project.task +# NOTHING TO DO: reverse relation that already exists on project.project and project.task + +pad_project / project.project / description_pad (char) : DEL +pad_project / project.project / use_pads (boolean) : DEL +pad_project / project.task / description_pad (char) : DEL +# TODO: Module pad_project has been removed + +project / project.project / allow_milestones (boolean) : NEW hasdefault: default +# DONE: pre-migration: create field and set default value. + +project / project.project / last_update_status (selection): not a function anymore +project / project.project / last_update_status (selection): now required +project / project.project / last_update_status (selection): selection_keys is now '['at_risk', 'off_track', 'on_hold', 'on_track', 'to_define']' ('['at_risk', 'off_track', 'on_hold', 'on_track']') +# DONE: pre-migration: Set value of last_update_status to 'to_define' where field is empty + +project / project.task.type / is_closed (boolean) : DEL +# DONE: pre-migration: Field removed, field 'fold' should be used instead. Moving values from 'is_closed' to 'fold'. + +project / project.task / is_closed (boolean) : is now stored +# DONE: pre-migration: Add new column & set value for it + +project / project.task / ancestor_id (many2one) : NEW relation: project.task, isfunction: function, stored +project / project.task / is_analytic_account_id_changed (boolean): NEW isfunction: function, stored +# DONE: pre-migration: pre-compute value for new computed fields + +project / project.task / is_blocked (boolean) : NEW isfunction: function, stored +project / project.task / milestone_id (many2one) : NEW relation: project.milestone, hasdefault: compute +# TODO (speed improvement): pre-migration: pre-compute value for new computed fields + + +---XML records in module 'project'--- +NEW digest.tip: project.digest_tip_project_1 +NEW ir.actions.act_window: project.action_send_mail_project_project +NEW ir.actions.act_window: project.action_send_mail_project_task +NEW ir.actions.act_window: project.action_view_task_from_milestone +NEW ir.actions.act_window: project.open_view_project_all_config_group_stage +NEW ir.actions.act_window: project.project_sharing_project_task_action_sub_task +NEW ir.actions.act_window: project.project_task_action_sub_task +DEL ir.actions.act_window: project.project_milestone_all +NEW ir.actions.act_window.view: project.open_view_all_task_list_calendar +NEW ir.actions.act_window.view: project.open_view_all_task_list_kanban +NEW ir.actions.act_window.view: project.open_view_all_task_list_tree +NEW ir.actions.act_window.view: project.open_view_project_all_config_group_stage_kanban_action_view +NEW ir.actions.act_window.view: project.open_view_project_all_config_group_stage_tree_action_view +NEW ir.actions.act_window.view: project.project_all_task_activity_action_view +NEW ir.actions.act_window.view: project.project_all_task_calendar_action_view +NEW ir.actions.act_window.view: project.project_all_task_graph_action_view +NEW ir.actions.act_window.view: project.project_all_task_pivot_action_view +NEW ir.actions.act_window.view: project.project_sharing_subtasks_form_action_view +NEW ir.actions.act_window.view: project.project_sharing_subtasks_kanban_action_view +NEW ir.actions.act_window.view: project.project_sharing_subtasks_tree_action_view +NEW ir.actions.act_window.view: project.project_task_form_action_view +NEW ir.actions.act_window.view: project.project_task_kanban_action_view +NEW ir.actions.act_window.view: project.project_task_tree_action_view +NEW ir.actions.act_window.view: project.rating_rating_action_task_kanban +NEW ir.actions.act_window.view: project.rating_rating_action_view_project_rating_kanban +DEL ir.actions.server: project.unlink_project_action +NEW ir.model.access: project.access_project_task_burndown_chart_report_user +NEW ir.model.access: project.access_report_project_task_user_project_user +DEL ir.model.access: project.access_project_delete_wizard +NEW ir.rule: project.burndown_chart_project_manager_rule (noupdate) +NEW ir.rule: project.burndown_chart_project_user_rule (noupdate) +NEW ir.rule: project.report_project_task_manager_rule (noupdate) +NEW ir.rule: project.report_project_task_user_rule (noupdate) +NEW ir.ui.menu: project.menu_projects_config_group_stage +NEW ir.ui.view: project.rating_rating_project_view_kanban +NEW ir.ui.view: project.task_type_tree_inherited +NEW ir.ui.view: project.view_project_calendar +NEW ir.ui.view: project.view_project_config_kanban +NEW ir.ui.view: project.view_project_task_pivot_inherit +NEW ir.ui.view: project.view_project_task_type_unarchive_wizard +NEW ir.ui.view: project.view_task_all_calendar +NEW ir.ui.view: project.view_task_kanban_inherit_my_task +DEL ir.ui.view: pad_project.project_project_view_form +DEL ir.ui.view: pad_project.res_config_settings_view_form +DEL ir.ui.view: pad_project.view_task_form2_inherit_pad_project +DEL ir.ui.view: project.project_collaborator_view_form +DEL ir.ui.view: project.project_delete_wizard_form +DEL ir.ui.view: project.project_task_burndown_chart_report_view_pivot +NEW mail.message.subtype: project.mt_project_update_create (noupdate) +NEW mail.message.subtype: project.mt_task_progress (noupdate) +NEW mail.message.subtype: project.mt_update_create (noupdate) +NEW res.groups: project.group_project_milestone +# NOTHING TO DO