Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docsource/modules150-160.rst
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ Module coverage 15.0 -> 16.0
+-------------------------------------------------+----------------------+-------------------------------------------------+
| |del| google_spreadsheet | |Obsolete module. |
+-------------------------------------------------+----------------------+-------------------------------------------------+
| hr | | |
| hr | Done | |
+-------------------------------------------------+----------------------+-------------------------------------------------+
| hr_attendance | | |
+-------------------------------------------------+----------------------+-------------------------------------------------+
Expand Down
202 changes: 202 additions & 0 deletions openupgrade_scripts/scripts/hr/16.0.1.1/post-migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
# Copyright 2023 Coop IT Easy (https://coopiteasy.be)
# 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(
Comment thread
remytms marked this conversation as resolved.
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

If the employee is linked to a res.user, we set the partner_id of the
res.user as a work_contact_id.

If the employee is not linked to a res.user. Then we try to match an
existing partner with the same email address. If one is found, then
we assign it as work_contact_id. If several are found, we raise a
warning and we link the first one found. If none are found, then we
create a new partner.
"""
employees = env["hr.employee"].search([])

for employee in employees:
if employee.user_id and employee.user_id.partner_id:
partner = employee.user_id.partner_id
if (
not employee.work_email
and not employee.mobile_phone
or (
employee.work_email == partner.email
and employee.mobile_phone == partner.mobile
)
or (not employee.work_email and employee.mobile_phone == partner.mobile)
or (not employee.mobile_phone and employee.work_email == partner.email)
):
employee.work_contact_id = partner
_logger.info(
"Set work_contact_id of hr.employee(%s) to "
"res.partner(%s) (the res.user partner).",
employee.id,
partner.id,
)
else:
matching_partner = env["res.partner"].search(
[
("email", "=", employee.work_email),
("mobile", "=", employee.mobile_phone),
]
)
nb_matching_partner = len(matching_partner)
if nb_matching_partner == 1:
employee.work_contact_id = matching_partner
_logger.info(
"Found res.partner(%s) that match hr.employee(%s). "
"work_contact_id is set accordingly.",
matching_partner.id,
employee.id,
)
elif nb_matching_partner > 1:
partner = matching_partner[0]
employee.work_contact_id = partner
_logger.warning(
"Several res.partner found for hr.employee(%s): "
"res.partner(%s). "
"Arbitrarily, the res.partner(%s) (the first one) "
"is used for work_contact_id of the hr.employee(%s).",
employee.id,
", ".joins(matching_partner.ids),
partner.id,
employee.id,
)
else:
partner_vals = {
"name": employee.name,
"email": employee.work_email,
"mobile": employee.mobile_phone,
"company_id": employee.company_id.id,
"image_1920": employee.image_1920,
}
partner = env["res.partner"].create(partner_vals)
employee.work_contact_id = partner
_logger.info(
"No res.partner found for hr.employee(%s). "
"A new partner has been created and linked to "
"the employee: res.partner(%s).",
employee.id,
partner.id,
)


def fill_master_department_id(cr):
"""Fill master_department_id based on parent_path"""
openupgrade.logged_query(
cr,
"""
UPDATE hr_department
SET master_department_id = split_part(parent_path, '/', 1)::int
WHERE parent_path is not NULL;
""",
)


@openupgrade.migrate()
def migrate(env, version):
warn_about_dataloss(
env.cr,
"ou_legacy_16_0_hr_plan_hr_plan_activity_type_rel",
"hr_plan_activity_type_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",
)
fill_master_department_id(env.cr)
create_work_contact(env)
openupgrade.load_data(env.cr, "hr", "16.0.1.1/noupdate_changes.xml")
58 changes: 58 additions & 0 deletions openupgrade_scripts/scripts/hr/16.0.1.1/pre-migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Copyright 2023 Coop IT Easy (https://coopiteasy.be)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from openupgradelib import openupgrade

_xmlid_renames = [
(
"hr_contract.access_hr_contract_type_manager",
"hr.access_hr_contract_type_manager",
),
]

_new_fields = [
(
"company_id", # field name
"hr.plan", # module name
False, # SQL table name
"many2one", # field type
False, # SQL field type
"hr", # module name
),
(
"company_id", # field name
"hr.plan.activity.type", # module name
False, # SQL table name
"many2one", # field type
False, # SQL field type
"hr", # module name
),
(
"master_department_id", # field name
"hr.department", # module name
False, # SQL table name
"many2one", # field type
False, # SQL field type
"hr", # module name
),
]


@openupgrade.migrate()
def migrate(env, version):
openupgrade.rename_xmlids(env.cr, _xmlid_renames)
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.
openupgrade.rename_tables(
env.cr,
[
(
"hr_plan_hr_plan_activity_type_rel",
"ou_legacy_16_0_hr_plan_hr_plan_activity_type_rel",
)
],
)
1 change: 1 addition & 0 deletions openupgrade_scripts/scripts/hr/16.0.1.1/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_hr_migration
Loading