diff --git a/l10n_us_ca_hr_payroll/__manifest__.py b/l10n_us_ca_hr_payroll/__manifest__.py index b4dd1c3a..eeeeb590 100755 --- a/l10n_us_ca_hr_payroll/__manifest__.py +++ b/l10n_us_ca_hr_payroll/__manifest__.py @@ -28,5 +28,5 @@ USA::California Payroll Rules. 'data/rules.xml', 'data/final.xml', ], - 'installable': True + 'installable': False } diff --git a/l10n_us_fl_hr_payroll/__manifest__.py b/l10n_us_fl_hr_payroll/__manifest__.py index 4c1312d4..354fdc7d 100755 --- a/l10n_us_fl_hr_payroll/__manifest__.py +++ b/l10n_us_fl_hr_payroll/__manifest__.py @@ -23,5 +23,5 @@ USA::Florida Payroll Rules. 'data/rules.xml', 'data/final.xml', ], - 'installable': True + 'installable': False } diff --git a/l10n_us_hr_payroll/migrations/12.0.2020.1.0/post-migration.py b/l10n_us_hr_payroll/migrations/12.0.2020.1.0/post-migration.py new file mode 100644 index 00000000..752751db --- /dev/null +++ b/l10n_us_hr_payroll/migrations/12.0.2020.1.0/post-migration.py @@ -0,0 +1,52 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from odoo.addons.l10n_us_hr_payroll.migrations.data import FIELDS_CONTRACT_TO_US_PAYROLL_FORMS_2020 +from odoo.addons.l10n_us_hr_payroll.migrations.helper import field_exists, \ + temp_field_exists, \ + remove_temp_field, \ + temp_field_values + + +from odoo import SUPERUSER_ID +from odoo.api import Environment + + +import logging +_logger = logging.getLogger(__name__) + + +def migrate(cr, installed_version): + fields_to_move = [f for f in FIELDS_CONTRACT_TO_US_PAYROLL_FORMS_2020 if temp_field_exists(cr, 'hr_contract', f)] + if not fields_to_move: + _logger.warn(' migration aborted because no temporary fields exist...') + return + + env = Environment(cr, SUPERUSER_ID, {}) + new_structure = env.ref('l10n_us_hr_payroll.structure_type_employee') + + # We will assume all contracts without a struct (because we deleted it), or with one like US_xx_EMP, need config + contracts = env['hr.contract'].search([ + '|', + ('struct_id', '=', False), + ('struct_id.code', '=like', 'US_%'), + ]) + _logger.warn('Migrating Contracts: ' + str(contracts)) + for contract in contracts: + _logger.warn('Migrating contract: ' + str(contract) + ' for employee: ' + str(contract.employee_id)) + # Could we somehow detect the state off of the current/orphaned salary structure? + old_struct_code = contract.struct_id.code + temp_values = temp_field_values(cr, 'hr_contract', contract.id, fields_to_move) + # Resolve mapping to the new field names. + values = {FIELDS_CONTRACT_TO_US_PAYROLL_FORMS_2020[k]: v for k, v in temp_values.items()} + values.update({ + 'name': 'MIG: ' + str(contract.name), + 'employee_id': contract.employee_id.id, + }) + us_payroll_config = env['hr.contract.us_payroll_config'].create(values) + contract.write({ + 'struct_id': new_structure.id, + 'us_payroll_config_id': us_payroll_config.id, + }) + + for field in fields_to_move: + remove_temp_field(cr, 'hr_contract', field) diff --git a/l10n_us_hr_payroll/migrations/12.0.2020.1.0/pre-migration.py b/l10n_us_hr_payroll/migrations/12.0.2020.1.0/pre-migration.py new file mode 100644 index 00000000..420181e4 --- /dev/null +++ b/l10n_us_hr_payroll/migrations/12.0.2020.1.0/pre-migration.py @@ -0,0 +1,29 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from odoo.addons.l10n_us_hr_payroll.migrations.data import FIELDS_CONTRACT_TO_US_PAYROLL_FORMS_2020, \ + XMLIDS_TO_REMOVE_2020, \ + XMLIDS_TO_RENAME_2020 +from odoo.addons.l10n_us_hr_payroll.migrations.helper import field_exists, \ + temp_field_exists, \ + make_temp_field, \ + remove_xmlid, \ + rename_xmlid + + +def migrate(cr, installed_version): + # Add temporary columns for all hr_contract fields that move to hr_contract_us_payroll_config + fields_to_move = [f for f in FIELDS_CONTRACT_TO_US_PAYROLL_FORMS_2020 if field_exists(cr, 'hr_contract', f)] + # Prevent error if repeatedly running and already copied. + fields_to_move = [f for f in fields_to_move if not temp_field_exists(cr, 'hr_contract', f)] + for field in fields_to_move: + make_temp_field(cr, 'hr_contract', field) + + # Need to migrate XMLIDs.. + for xmlid in XMLIDS_TO_REMOVE_2020: + remove_xmlid(cr, xmlid) + + for from_xmlid, to_xmlid in XMLIDS_TO_RENAME_2020.items(): + rename_xmlid(cr, from_xmlid, to_xmlid) + + # Need to remove views as they don't work anymore. + cr.execute("DELETE FROM ir_ui_view as v WHERE v.id in (SELECT t.res_id FROM ir_model_data as t WHERE t.model = 'ir.ui.view' and (t.module = 'l10n_us_hr_payroll' or t.module like 'l10n_us_%_hr_payroll'))") diff --git a/l10n_us_hr_payroll/migrations/__init__.py b/l10n_us_hr_payroll/migrations/__init__.py new file mode 100644 index 00000000..0358305d --- /dev/null +++ b/l10n_us_hr_payroll/migrations/__init__.py @@ -0,0 +1 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. diff --git a/l10n_us_hr_payroll/migrations/data.py b/l10n_us_hr_payroll/migrations/data.py new file mode 100644 index 00000000..25bb93d5 --- /dev/null +++ b/l10n_us_hr_payroll/migrations/data.py @@ -0,0 +1,47 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +FIELDS_CONTRACT_TO_US_PAYROLL_FORMS_2020 = { + # Federal + 'w4_allowances': 'fed_941_fit_w4_allowances', + 'w4_filing_status': 'fed_941_fit_w4_filing_status', + 'w4_is_nonresident_alien': 'fed_941_fit_w4_is_nonresident_alien', + 'w4_additional_withholding': 'fed_941_fit_w4_additional_withholding', + 'fica_exempt': 'fed_941_fica_exempt', + 'futa_type': 'fed_940_type', + +} + +XMLIDS_TO_REMOVE_2020 = [ + # Federal + # Categories -- These are now all up in the EE FICA or ER FICA + 'l10n_us_hr_payroll.hr_payroll_fica_emp_m', + 'l10n_us_hr_payroll.hr_payroll_fica_emp_m_add', + 'l10n_us_hr_payroll.hr_payroll_fica_emp_m_add_wages', + 'l10n_us_hr_payroll.hr_payroll_fica_comp_m', + 'l10n_us_hr_payroll.hr_payroll_futa_wages', + 'l10n_us_hr_payroll.hr_payroll_fica_emp_m_wages', + 'l10n_us_hr_payroll.hr_payroll_fica_emp_ss_wages', + # Rules -- These are mainly Wage rules or were simplified to a single rule + 'l10n_us_hr_payroll.hr_payroll_rules_fica_emp_ss_wages_2018', + 'l10n_us_hr_payroll.hr_payroll_rules_fica_emp_m_wages_2018', + 'l10n_us_hr_payroll.hr_payroll_rules_fica_emp_m_add_wages_2018', + 'l10n_us_hr_payroll.hr_payroll_rules_futa_wages_2018', + 'l10n_us_hr_payroll.hr_payroll_rules_fed_inc_withhold_2018_married', + +] + +XMLIDS_TO_RENAME_2020 = { + # Federal + 'l10n_us_hr_payroll.hr_payroll_futa': 'l10n_us_hr_payroll.hr_payroll_category_er_fed_940', + 'l10n_us_hr_payroll.hr_payroll_fica_emp_ss': 'l10n_us_hr_payroll.hr_payroll_category_ee_fed_941', + 'l10n_us_hr_payroll.hr_payroll_fed_income_withhold': 'l10n_us_hr_payroll.hr_payroll_category_ee_fed_941_fit', + 'l10n_us_hr_payroll.hr_payroll_fica_comp_ss': 'l10n_us_hr_payroll.hr_payroll_category_er_fed_941', + 'l10n_us_hr_payroll.hr_payroll_rules_fica_emp_ss_2018': 'l10n_us_hr_payroll.hr_payroll_rule_ee_fed_941_ss', + 'l10n_us_hr_payroll.hr_payroll_rules_fica_emp_m_2018': 'l10n_us_hr_payroll.hr_payroll_rule_ee_fed_941_m', + 'l10n_us_hr_payroll.hr_payroll_rules_fica_emp_m_add_2018': 'l10n_us_hr_payroll.hr_payroll_rule_ee_fed_941_m_add', + 'l10n_us_hr_payroll.hr_payroll_rules_futa_2018': 'l10n_us_hr_payroll.hr_payroll_rule_er_fed_940', + 'l10n_us_hr_payroll.hr_payroll_rules_fica_comp_ss': 'l10n_us_hr_payroll.hr_payroll_rule_er_fed_941_ss', + 'l10n_us_hr_payroll.hr_payroll_rules_fica_comp_m': 'l10n_us_hr_payroll.hr_payroll_rule_er_fed_941_m', + 'l10n_us_hr_payroll.hr_payroll_rules_fed_inc_withhold_2018_single': 'l10n_us_hr_payroll.hr_payroll_rule_ee_fed_941_fit', + +} diff --git a/l10n_us_hr_payroll/migrations/helper.py b/l10n_us_hr_payroll/migrations/helper.py new file mode 100644 index 00000000..b41cf304 --- /dev/null +++ b/l10n_us_hr_payroll/migrations/helper.py @@ -0,0 +1,58 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +TMP_PREFIX = 'tmp_' + +""" +Fields +""" + + +def field_exists(cr, table_name, field_name): + cr.execute('SELECT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name=%s and column_name=%s);', (table_name, field_name)) + return cr.fetchone()[0] + + +def temp_field_exists(cr, table_name, field_name): + tmp_field_name = TMP_PREFIX + field_name + cr.execute('SELECT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name=%s and column_name=%s);', (table_name, tmp_field_name)) + return cr.fetchone()[0] + + +def make_temp_field(cr, table_name, field_name): + tmp_field_name = TMP_PREFIX + field_name + cr.execute('SELECT data_type FROM information_schema.columns WHERE table_name=%s and column_name=%s;', (table_name, field_name)) + tmp_field_type = cr.fetchone()[0] + cr.execute('ALTER TABLE ' + table_name + ' ADD ' + tmp_field_name + ' ' + tmp_field_type) + cr.execute('UPDATE ' + table_name + ' SET ' + tmp_field_name + '=' + field_name) + + +def remove_temp_field(cr, table_name, field_name): + tmp_field_name = TMP_PREFIX + field_name + cr.execute('ALTER TABLE ' + table_name + ' DROP COLUMN ' + tmp_field_name) + + +def temp_field_values(cr, table_name, id, field_names): + tmp_field_names = [TMP_PREFIX + f for f in field_names] + if not tmp_field_names: + return {} + cr.execute('SELECT ' + ', '.join(tmp_field_names) + ' FROM ' + table_name + ' WHERE id=' + str(id)) + values = cr.dictfetchone() + if not values: + return {} + return {k.lstrip(TMP_PREFIX): v for k, v in values.items()} + + +""" +XMLIDs +""" + + +def remove_xmlid(cr, xmlid): + module, name = xmlid.split('.') + cr.execute('DELETE FROM ir_model_data WHERE module=%s and name=%s;', (module, name)) + + +def rename_xmlid(cr, from_xmlid, to_xmlid): + from_module, from_name = from_xmlid.split('.') + to_module, to_name = to_xmlid.split('.') + cr.execute('UPDATE ir_model_data SET module=%s, name=%s WHERE module=%s and name=%s;', (to_module, to_name, from_module, from_name)) diff --git a/l10n_us_mi_hr_payroll/__manifest__.py b/l10n_us_mi_hr_payroll/__manifest__.py index 8411421f..4d453e71 100755 --- a/l10n_us_mi_hr_payroll/__manifest__.py +++ b/l10n_us_mi_hr_payroll/__manifest__.py @@ -24,5 +24,5 @@ USA::Michigan Payroll Rules. 'data/rules.xml', 'data/final.xml', ], - 'installable': True + 'installable': False } diff --git a/l10n_us_mn_hr_payroll/__manifest__.py b/l10n_us_mn_hr_payroll/__manifest__.py index 62583b61..37b784d1 100755 --- a/l10n_us_mn_hr_payroll/__manifest__.py +++ b/l10n_us_mn_hr_payroll/__manifest__.py @@ -23,5 +23,5 @@ USA - Minnesota Payroll Rules 'data/rules.xml', 'data/final.xml', ], - 'installable': True + 'installable': False } diff --git a/l10n_us_mo_hr_payroll/__manifest__.py b/l10n_us_mo_hr_payroll/__manifest__.py index 636d550e..061a58af 100755 --- a/l10n_us_mo_hr_payroll/__manifest__.py +++ b/l10n_us_mo_hr_payroll/__manifest__.py @@ -24,5 +24,5 @@ USA::Missouri Payroll Rules. 'data/rules.xml', 'data/final.xml', ], - 'installable': True + 'installable': False } diff --git a/l10n_us_ms_hr_payroll/__manifest__.py b/l10n_us_ms_hr_payroll/__manifest__.py index 8a370516..f5ad13a6 100755 --- a/l10n_us_ms_hr_payroll/__manifest__.py +++ b/l10n_us_ms_hr_payroll/__manifest__.py @@ -24,5 +24,5 @@ USA::Mississippi Payroll Rules. 'data/rules.xml', 'data/final.xml', ], - 'installable': True + 'installable': False } diff --git a/l10n_us_mt_hr_payroll/__manifest__.py b/l10n_us_mt_hr_payroll/__manifest__.py index 64883a44..3d8c7396 100755 --- a/l10n_us_mt_hr_payroll/__manifest__.py +++ b/l10n_us_mt_hr_payroll/__manifest__.py @@ -24,5 +24,5 @@ USA::Montana Payroll Rules. 'data/rules.xml', 'data/final.xml', ], - 'installable': True + 'installable': False } diff --git a/l10n_us_nc_hr_payroll/__manifest__.py b/l10n_us_nc_hr_payroll/__manifest__.py index 4960939c..26637bde 100755 --- a/l10n_us_nc_hr_payroll/__manifest__.py +++ b/l10n_us_nc_hr_payroll/__manifest__.py @@ -24,5 +24,5 @@ USA::North Carolina Payroll Rules. 'data/rules.xml', 'data/final.xml', ], - 'installable': True + 'installable': False } diff --git a/l10n_us_nj_hr_payroll/__manifest__.py b/l10n_us_nj_hr_payroll/__manifest__.py index d93a3b11..89584029 100755 --- a/l10n_us_nj_hr_payroll/__manifest__.py +++ b/l10n_us_nj_hr_payroll/__manifest__.py @@ -28,5 +28,5 @@ USA::New Jersey Payroll Rules. 'data/rules.xml', 'data/final.xml', ], - 'installable': True + 'installable': False } diff --git a/l10n_us_oh_hr_payroll/__manifest__.py b/l10n_us_oh_hr_payroll/__manifest__.py index ea602ecd..49fc01d2 100755 --- a/l10n_us_oh_hr_payroll/__manifest__.py +++ b/l10n_us_oh_hr_payroll/__manifest__.py @@ -25,5 +25,5 @@ USA::Ohio Payroll Rules. 'data/rules.xml', 'data/final.xml', ], - 'installable': True + 'installable': False } diff --git a/l10n_us_pa_hr_payroll/__manifest__.py b/l10n_us_pa_hr_payroll/__manifest__.py index 3f124969..0cec3566 100755 --- a/l10n_us_pa_hr_payroll/__manifest__.py +++ b/l10n_us_pa_hr_payroll/__manifest__.py @@ -25,5 +25,5 @@ USA::Pennsylvania Payroll Rules. 'data/rules.xml', 'data/final.xml', ], - 'installable': True + 'installable': False } diff --git a/l10n_us_tx_hr_payroll/__manifest__.py b/l10n_us_tx_hr_payroll/__manifest__.py index fbc60187..650444a3 100755 --- a/l10n_us_tx_hr_payroll/__manifest__.py +++ b/l10n_us_tx_hr_payroll/__manifest__.py @@ -25,5 +25,5 @@ USA::Texas Payroll Rules. 'data/rules.xml', 'data/final.xml', ], - 'installable': True + 'installable': False } diff --git a/l10n_us_wa_hr_payroll/__manifest__.py b/l10n_us_wa_hr_payroll/__manifest__.py index 2fc72921..f20702be 100755 --- a/l10n_us_wa_hr_payroll/__manifest__.py +++ b/l10n_us_wa_hr_payroll/__manifest__.py @@ -25,5 +25,5 @@ USA::Washington Payroll Rules. 'data/rules.xml', 'data/final.xml', ], - 'installable': True + 'installable': False }