Skip to content

Commit

Permalink
Merge pull request #4719 from ForgeFlow/16.0-ou-imp-hr-TT50283
Browse files Browse the repository at this point in the history
[16.0][OU-IMP] hr: Convert hr_plan_activity_type records without data loss
  • Loading branch information
pedrobaeza authored Jan 24, 2025
2 parents 4fdf815 + c8b7301 commit 51a4bed
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 96 deletions.
141 changes: 49 additions & 92 deletions openupgrade_scripts/scripts/hr/16.0.1.1/post-migration.py
Original file line number Diff line number Diff line change
@@ -1,93 +1,14 @@
# Copyright 2023 Coop IT Easy (https://coopiteasy.be)
# Copyright 2024 Tecnativa - Víctor Martínez
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

import logging

from openupgradelib import openupgrade
from psycopg2.extensions import AsIs

_logger = logging.getLogger(__name__)


def warn_about_dataloss(cr, source_relation_table, relation_comodel_field):
"""Warn user about data loss when migrating data from many2many to
many2one.
:param source_relation_table: The many2many relation table
of the model that will be on the 'one' side of the relation
:param relation_comodel_field: The name of the column containing ids
of the 'many' part of the new relation.
"""
openupgrade.logged_query(
cr,
"""
SELECT DISTINCT %(relation_comodel_field)s
FROM %(source_relation_table)s
WHERE %(relation_comodel_field)s IN (
SELECT %(relation_comodel_field)s
FROM %(source_relation_table)s
GROUP BY %(relation_comodel_field)s
HAVING COUNT(*) > 1
)
""",
{
"source_relation_table": AsIs(source_relation_table),
"relation_comodel_field": AsIs(relation_comodel_field),
},
)
for res in cr.fetchall():
_logger.error(
"hr.plan.activity.type(%s,) is linked to several hr.plan. "
"hr.plan.activity.type can only be linked to one hr.plan. "
"Fix these data before migrating to avoid data loss.",
res[0],
)


def m2m_to_o2m(
env,
model,
field,
source_relation_table,
relation_source_field,
relation_comodel_field,
):
"""Transform many2many relations into one2many (with possible data
loss).
Use rename_tables() in your pre-migrate script to keep the many2many
relation table and give them as 'source_relation_table' argument.
And remove foreign keys constraints with remove_tables_fks().
:param model: The target registery model
:param field: The field that changes from m2m to o2m
:param source_relation_table: The (renamed) many2many relation table
:param relation_source_field: The column name of the 'model' id
in the relation table
:param relation_comodel_field: The column name of the comodel id in
the relation table
"""
columns = env[model]._fields.get(field)
target_table = env[columns.comodel_name]._table
target_field = columns.inverse_name
openupgrade.logged_query(
env.cr,
"""
UPDATE %(target_table)s AS target
SET %(target_field)s=source.%(relation_source_field)s
FROM %(source_relation_table)s AS source
WHERE source.%(relation_comodel_field)s=target.id
""",
{
"target_table": AsIs(target_table),
"target_field": AsIs(target_field),
"source_relation_table": AsIs(source_relation_table),
"relation_source_field": AsIs(relation_source_field),
"relation_comodel_field": AsIs(relation_comodel_field),
},
)


def create_work_contact(env):
"""Create work_contact_id for model hr.employee.base
Expand Down Expand Up @@ -182,21 +103,57 @@ def fill_master_department_id(cr):
)


@openupgrade.migrate()
def migrate(env, version):
warn_about_dataloss(
def _hr_plan_activity_type_m2m_to_o2m(env):
"""Before, the activities in plans (hr.plan) were linked to the
plan_activity_type_ids field with a m2m field, now the field
is an o2m. We define the data in the table hr_plan_activity_type according to the
table ou_legacy_16_0_hr_plan_hr_plan_activity_type_rel that we have defined
previously in pre-migration to ensure that no data is lost.
"""
openupgrade.logged_query(
env.cr,
"ou_legacy_16_0_hr_plan_hr_plan_activity_type_rel",
"hr_plan_activity_type_id",
"""
UPDATE hr_plan_activity_type hpat
SET plan_id = rel.hr_plan_id
FROM ou_legacy_16_0_hr_plan_hr_plan_activity_type_rel rel
WHERE rel.hr_plan_activity_type_id = hpat.id
""",
)
m2m_to_o2m(
env,
"hr.plan",
"plan_activity_type_ids",
"ou_legacy_16_0_hr_plan_hr_plan_activity_type_rel",
"hr_plan_id",
"hr_plan_activity_type_id",
openupgrade.logged_query(
env.cr,
"""
INSERT INTO hr_plan_activity_type (
plan_id,
activity_type_id,
summary,
responsible,
responsible_id,
note,
create_uid,
create_date,
write_uid,
write_date
)
SELECT rel.hr_plan_id,
detail.activity_type_id,
detail.summary,
detail.responsible,
detail.responsible_id,
detail.note,
detail.create_uid,
detail.create_date,
detail.write_uid,
detail.write_date
FROM ou_legacy_16_0_hr_plan_hr_plan_activity_type_rel rel
JOIN hr_plan_activity_type detail ON rel.hr_plan_activity_type_id = detail.id
WHERE detail.plan_id != rel.hr_plan_id
""",
)


@openupgrade.migrate()
def migrate(env, version):
_hr_plan_activity_type_m2m_to_o2m(env)
fill_master_department_id(env.cr)
create_work_contact(env)
openupgrade.load_data(env.cr, "hr", "16.0.1.1/noupdate_changes.xml")
6 changes: 3 additions & 3 deletions openupgrade_scripts/scripts/hr/16.0.1.1/pre-migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ def migrate(env, version):
openupgrade.add_fields(env, _new_fields)
# Backup Many2many relation between hr.plan and hr.plan.activity.type
openupgrade.remove_tables_fks(env.cr, ["hr_plan_hr_plan_activity_type_rel"])
# get_legacy_name cannot be used here, because there is confilct in
# renaming constrains on this table. Waiting for a fix in
# openupgradelib, we will fix a new table name here.
# get_legacy_name cannot be used here, as there is a length limit in table name,
# and it causes a conflict. Waiting for a fix in
# openupgradelib, we will use a new table name here.
openupgrade.rename_tables(
env.cr,
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ hr / hr.employee / work_email (char) : now a

hr / hr.plan / plan_activity_type_ids (many2many): table is now 'False' ('hr_plan_hr_plan_activity_type_rel')
hr / hr.plan / plan_activity_type_ids (many2many): type is now 'one2many' ('many2many')
# DONE: pre-migration and post-migration: move data from many2many table to plan_id colomn in hr.plan.activity.type
# DONE: pre-migration and post-migration: move data from many2many table to plan_id column in hr.plan.activity.type

hr / hr.plan.activity.type / plan_id (many2one) : NEW relation: hr.plan
# DONE: see plan_activity_type_ids from hr.plan
Expand Down

0 comments on commit 51a4bed

Please sign in to comment.