diff --git a/docsource/modules150-160.rst b/docsource/modules150-160.rst index 82a2f9756360..a5919f6c9d35 100644 --- a/docsource/modules150-160.rst +++ b/docsource/modules150-160.rst @@ -164,7 +164,7 @@ Module coverage 15.0 -> 16.0 +-------------------------------------------------+----------------------+-------------------------------------------------+ | |del| google_spreadsheet | | | +-------------------------------------------------+----------------------+-------------------------------------------------+ -| hr | | | +| hr | Done | | +-------------------------------------------------+----------------------+-------------------------------------------------+ | hr_attendance | | | +-------------------------------------------------+----------------------+-------------------------------------------------+ diff --git a/openupgrade_scripts/scripts/hr/16.0.1.1/post-migration.py b/openupgrade_scripts/scripts/hr/16.0.1.1/post-migration.py new file mode 100644 index 000000000000..1683884f55d7 --- /dev/null +++ b/openupgrade_scripts/scripts/hr/16.0.1.1/post-migration.py @@ -0,0 +1,186 @@ +# 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 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""" + # Get employee + openupgrade.logged_query( + env.cr, + """ + SELECT id, name, work_email, mobile_phone, company_id + FROM hr_employee + """, + ) + for employee_values in env.cr.fetchall(): + # Create partner + openupgrade.logged_query( + env.cr, + """ + INSERT INTO res_partner (name, email, mobile, company_id) + VALUES (%s, %s, %s, %s) + RETURNING id + """, + ( + employee_values[1], + employee_values[2], + employee_values[3], + employee_values[4], + ), + ) + partner_values = env.cr.fetchall() + # Update employee + openupgrade.logged_query( + env.cr, + "UPDATE hr_employee SET work_contact_id = %s WHERE id = %s", + (partner_values[0][0], employee_values[0]), + ) + # Create image + openupgrade.logged_query( + env.cr, + """ + SELECT + name, description, res_model, res_field, res_id, + company_id, type, url, public, db_datas, store_fname, + file_size, checksum, mimetype, index_content + FROM ir_attachment + WHERE + res_model = 'hr.employee' + AND res_field = 'image_1920' + AND res_id = %s + """, + (employee_values[0],), + ) + for attachment_values in env.cr.fetchall(): + openupgrade.logged_query( + env.cr, + """ + INSERT INTO ir_attachment ( + name, description, res_model, res_field, res_id, + company_id, type, url, public, db_datas, store_fname, + file_size, checksum, mimetype, index_content + ) VALUES ( + %s, %s, 'res.partner', 'image_1920', %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s + ) + """, + ( + attachment_values[0], + attachment_values[1], + attachment_values[4], + attachment_values[5], + attachment_values[6], + attachment_values[7], + attachment_values[8], + attachment_values[9], + attachment_values[10], + attachment_values[11], + attachment_values[12], + attachment_values[13], + attachment_values[14], + ), + ) + + +@openupgrade.migrate() +def migrate(env, version): + warn_about_dataloss( + env.cr, + openupgrade.get_legacy_name("hr_plan_hr_plan_activity_type_rel"), + "hr_plan_activity_type_id", + ) + m2m_to_o2m( + env, + "hr.plan", + "plan_activity_type_ids", + openupgrade.get_legacy_name("hr_plan_hr_plan_activity_type_rel"), + "hr_plan_id", + "hr_plan_activity_type_id", + ) + openupgrade.load_data(env.cr, "hr", "16.0.1.1/noupdate_changes.xml") diff --git a/openupgrade_scripts/scripts/hr/16.0.1.1/pre-migration.py b/openupgrade_scripts/scripts/hr/16.0.1.1/pre-migration.py new file mode 100644 index 000000000000..728748b2a890 --- /dev/null +++ b/openupgrade_scripts/scripts/hr/16.0.1.1/pre-migration.py @@ -0,0 +1,32 @@ +# 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 + +_moved_fields = [ + "__last_update", + "_order", + "display_name", + "name", +] + +_xmlid_renames = [ + ( + "hr_contract.access_hr_contract_type_manager", + "hr.access_hr_contract_type_manager", + ), +] + + +@openupgrade.migrate() +def migrate(env, version): + openupgrade.update_module_moved_models( + env.cr, "hr.contract.type", "hr_contract", "hr" + ) + openupgrade.update_module_moved_fields( + env.cr, "hr.contract.type", _moved_fields, "hr_contract", "hr" + ) + openupgrade.rename_xmlids(env.cr, _xmlid_renames) + # Backup Many2many relation between hr.plan and hr.plan.activity.type + openupgrade.remove_tables_fks(env.cr, ["hr_plan_hr_plan_activity_type_rel"]) + openupgrade.rename_tables(env.cr, [("hr_plan_hr_plan_activity_type_rel", None)]) diff --git a/openupgrade_scripts/scripts/hr/16.0.1.1/upgrade_analysis_work.txt b/openupgrade_scripts/scripts/hr/16.0.1.1/upgrade_analysis_work.txt new file mode 100644 index 000000000000..829537542f74 --- /dev/null +++ b/openupgrade_scripts/scripts/hr/16.0.1.1/upgrade_analysis_work.txt @@ -0,0 +1,75 @@ +---Models in module 'hr'--- +model hr.contract.type (moved from hr_contract) +# DONE: pre-migration: moved from hr_contract to hr + +---Fields in module 'hr'--- +hr / hr.contract.type / __last_update (datetime) : previously in module hr_contract +hr / hr.contract.type / _order : previously in module hr_contract +hr / hr.contract.type / display_name (char) : previously in module hr_contract +hr / hr.contract.type / name (char) : previously in module hr_contract +# DONE: pre-migration: moved from hr_contract to hr + +hr / hr.contract.type / sequence (integer) : NEW +# NOTHING TO DO + +hr / hr.department / master_department_id (many2one): NEW relation: hr.department, isfunction: function, stored +hr / hr.department / parent_path (char) : NEW +hr / hr.department / plan_ids (one2many) : NEW relation: hr.plan +# NOTHING TO DO + +hr / hr.employee / mobile_phone (char) : now a function +hr / hr.employee / work_contact_id (many2one) : NEW relation: res.partner +hr / hr.employee / work_email (char) : now a function +# TODO: post-migration: create work_contact_id for each employee + +hr / hr.job / active (boolean) : NEW hasdefault: default +hr / hr.job / contract_type_id (many2one) : NEW relation: hr.contract.type +hr / hr.job / state (selection) : DEL required, selection_keys: ['open', 'recruit'] +# NOTHING TO DO: hr.job does not work with state anymore. + +hr / hr.plan / company_id (many2one) : NEW relation: res.company, hasdefault: default +hr / hr.plan / department_id (many2one) : NEW relation: hr.department +# NOTHING TO DO + +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 + +hr / hr.plan.activity.type / company_id (many2one) : NEW relation: res.company, hasdefault: default +# NOTHING TO DO: not a required field so no default to set + +hr / hr.plan.activity.type / plan_id (many2one) : NEW relation: hr.plan +# DONE: see plan_activity_type_ids from hr.plan + +hr / res.users / create_employee (boolean) : NEW hasdefault: default +hr / res.users / create_employee_id (many2one) : NEW relation: hr.employee +# NOTHING TO DO + +hr / resource.resource / employee_id (one2many) : NEW relation: hr.employee +# NOTHING TO DO + +---XML records in module 'hr'--- +NEW ir.actions.act_window: hr.hr_contract_type_action +# NOTHING TO DO + +NEW ir.actions.server: hr.action_hr_employee_create_user +# NOTHING TO DO + +NEW ir.model.access: hr.access_hr_contract_type_manager [renamed from hr_contract module] +# DONE: pre-migration: renamed + +NEW ir.rule: hr.hr_plan_activity_type_company_rule (noupdate) +NEW ir.rule: hr.hr_plan_company_rule (noupdate) +# NOTHING TO DO + +NEW ir.ui.menu: hr.menu_config_employee +NEW ir.ui.menu: hr.menu_config_recruitment +NEW ir.ui.menu: hr.menu_view_hr_contract_type +DEL ir.ui.menu: hr.menu_config_plan_types +DEL ir.ui.menu: hr.menu_human_resources_configuration_employee +NEW ir.ui.view: hr.hr_contract_type_view_form +NEW ir.ui.view: hr.hr_contract_type_view_tree +NEW ir.ui.view: hr.view_employee_form_smartbutton +NEW ir.ui.view: hr.view_users_simple_form +NEW ir.ui.view: hr.view_users_simple_form_inherit_hr +# NOTHING TO DO