diff --git a/docsource/modules180-190.rst b/docsource/modules180-190.rst index 9fce2953cc1..f90c72de681 100644 --- a/docsource/modules180-190.rst +++ b/docsource/modules180-190.rst @@ -6,7 +6,7 @@ Module coverage 18.0 -> 19.0 +---------------------------------------------------+----------------------+-------------------------------------------------+ | Module | Status + Extra Information | +===================================================+======================+=================================================+ -| account | | | +| account |Done | | +---------------------------------------------------+----------------------+-------------------------------------------------+ | account_check_printing | | | +---------------------------------------------------+----------------------+-------------------------------------------------+ @@ -36,7 +36,7 @@ Module coverage 18.0 -> 19.0 +---------------------------------------------------+----------------------+-------------------------------------------------+ | account_update_tax_tags | |No DB layout changes. | +---------------------------------------------------+----------------------+-------------------------------------------------+ -| analytic | | | +| analytic |Nothing to do | | +---------------------------------------------------+----------------------+-------------------------------------------------+ | |new| api_doc | | | +---------------------------------------------------+----------------------+-------------------------------------------------+ @@ -768,7 +768,7 @@ Module coverage 18.0 -> 19.0 +---------------------------------------------------+----------------------+-------------------------------------------------+ | mrp_subcontracting_repair | | | +---------------------------------------------------+----------------------+-------------------------------------------------+ -| onboarding | | | +| onboarding |Nothing to do | | +---------------------------------------------------+----------------------+-------------------------------------------------+ | partner_autocomplete | | | +---------------------------------------------------+----------------------+-------------------------------------------------+ diff --git a/openupgrade_scripts/scripts/account/19.0.1.4/end-migration.py b/openupgrade_scripts/scripts/account/19.0.1.4/end-migration.py new file mode 100644 index 00000000000..2c1b2f518d2 --- /dev/null +++ b/openupgrade_scripts/scripts/account/19.0.1.4/end-migration.py @@ -0,0 +1,57 @@ +from openupgradelib import openupgrade + + +def account_move_line_is_storno(env): + """ + Compute is_storno on lines of companies with storno accounting + """ + lines_to_recompute = env["account.move.line"].search( + [("company_id.account_storno", "=", True)] + ) + lines_to_recompute._compute_is_storno() + + +def res_company(env): + """ + Set fields expense_account_id, income_account_id, price_difference_account_id + from localization if not set elsewhere and the localization sets it + """ + for company in env["res.company"].search([]): + AccountChartTemplate = env["account.chart.template"].with_context( + default_company_id=company.id, + allowed_company_ids=company.ids, + tracking_disable=True, + delay_account_group_sync=True, + lang="en_US", + chart_template_load=True, + ) + if company.chart_template not in AccountChartTemplate._template_register: + openupgrade.logger.error( + "chart template %s unknown (not yet migrated?)", + company.chart_template, + ) + continue + template_data = AccountChartTemplate._get_chart_template_data( + company.chart_template + ) + company_template_data = { + company_id: { + key: value + for key, value in company_data.items() + if key + in ( + "expense_account_id", + "income_account_id", + "price_difference_account_id", + ) + and not company[key] + } + for company_id, company_data in template_data["res.company"].items() + } + AccountChartTemplate._load_data({"res.company": company_template_data}) + + +@openupgrade.migrate() +def migrate(env, version): + account_move_line_is_storno(env) + res_company(env) diff --git a/openupgrade_scripts/scripts/account/19.0.1.4/post-migration.py b/openupgrade_scripts/scripts/account/19.0.1.4/post-migration.py new file mode 100644 index 00000000000..c730748b623 --- /dev/null +++ b/openupgrade_scripts/scripts/account/19.0.1.4/post-migration.py @@ -0,0 +1,202 @@ +# Copyright 2026 Hunki Enterprises BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import re + +from openupgradelib import openupgrade + +from odoo.orm.commands import Command + + +def account_reconcile_model(env): + """ + Apply changes to account.reconcile.model + """ + env.cr.execute( + """ + UPDATE account_reconcile_model + SET trigger='auto_reconcile' + WHERE auto_reconcile + """ + ) + + +def account_reconcile_model_partner_mapping(env): + """ + Model account.reconcile.model.partner.mapping is folded into + account.reconcile.model.line, so create a new model per partner + mapping, merge regexes from partner mapping and model if any + """ + link_column = openupgrade.get_legacy_name("partner_mapping_id") + env.cr.execute( + "ALTER TABLE account_reconcile_model " + f"ADD COLUMN IF NOT EXISTS {link_column} int " + ) + env.cr.execute( + """ + SELECT + model_id, + array_agg(id), + array_agg(partner_id), + array_agg(payment_ref_regex), + array_agg(narration_regex) + FROM account_reconcile_model_partner_mapping mapping + GROUP BY model_id + """ + ) + AccountReconcileModel = env["account.reconcile.model"] + ResPartner = env["res.partner"] + + for ( + reconcile_model_id, + mapping_ids, + partner_ids, + payment_ref_regexes, + narration_regexes, + ) in env.cr.fetchall(): + reconcile_model = AccountReconcileModel.browse(reconcile_model_id) + match_regex_lookahead = "" + if reconcile_model.match_label_param: + if reconcile_model.match_label == "contains": + match_regex_lookahead = ( + f"(?=.*{re.escape(reconcile_model.match_label_param)}.*)" + ) + elif reconcile_model.match_label == "not_contains": + match_regex_lookahead = ( + f"(?!{re.escape(reconcile_model.match_label_param)})" + ) + elif reconcile_model.match_label == "match_regex": + match_regex_lookahead = f"(?={reconcile_model.match_label_param})" + + for mapping_id, partner_id, payment_ref_regex, narration_regex in zip( + mapping_ids, + partner_ids, + payment_ref_regexes, + narration_regexes, + strict=True, + ): + partner = ResPartner.browse(partner_id) + match_regex = "|".join( + map( + lambda x: f"({x})", + filter(None, [payment_ref_regex, narration_regex]), + ) + ) + new_reconcile_model = reconcile_model.copy( + { + "name": reconcile_model.name + f" ({partner.name})", + "match_label": "match_regex", + "match_label_param": match_regex_lookahead + match_regex, + "line_ids": [ + Command.create( + { + "partner_id": partner_id, + } + ), + ], + } + ) + env.cr.execute( + f""" + UPDATE account_reconcile_model + SET {link_column} = {mapping_id} + WHERE id = {new_reconcile_model.id} + """ + ) + + +def account_account_active(env): + """ + Set active flag from deprecated + """ + env.cr.execute("UPDATE account_account SET active = FALSE where deprecated") + + +def fiscal_position_tax_ids(env): + """ + Fill account.fiscal.position#tax_ids from previous account.fiscal.position.tax + table + """ + env.cr.execute( + """ + INSERT INTO account_fiscal_position_account_tax_rel + (account_fiscal_position_id, account_tax_id) + SELECT DISTINCT position_id, tax_dest_id FROM account_fiscal_position_tax + WHERE tax_dest_id IS NOT NULL + """ + ) + + +def account_tax_original_tax_ids(env): + """ + Fill account.tax#original_tax_ids from previous account.fiscal.position.tax table + """ + env.cr.execute( + """ + INSERT INTO account_tax_alternatives + (dest_tax_id, src_tax_id) + SELECT DISTINCT tax_dest_id, tax_src_id FROM account_fiscal_position_tax + WHERE tax_dest_id IS NOT NULL AND tax_src_id IS NOT NULL + """ + ) + + +def account_full_reconcile_exchange_move_id(env): + """ + account.full.reconcile#exchange_move_id has been scrapped, clone a partial + reconciliation and link the exchange move to it + """ + env.cr.execute( + """ + SELECT id, exchange_move_id + FROM account_full_reconcile + WHERE exchange_move_id IS NOT NULL + """ + ) + AccountFullReconcile = env["account.full.reconcile"] + + for full_reconcile_id, exchange_move_id in env.cr.fetchall(): + AccountFullReconcile.browse(full_reconcile_id).partial_reconcile_ids[-1:].copy( + { + "exchange_move_id": exchange_move_id, + "full_reconcile_id": full_reconcile_id, + } + ) + + +def account_move_line_no_followup(env): + """ + Set no_followup = True on lines of journals of type 'general' + """ + env.cr.execute( + """ + UPDATE account_move_line + SET no_followup=True + FROM account_journal + WHERE + account_move_line.journal_id=account_journal.id AND + account_journal.type = 'general' + """ + ) + + +@openupgrade.migrate() +def migrate(env, version): + openupgrade.load_data(env, "account", "19.0.1.4/noupdate_changes.xml") + openupgrade.delete_record_translations( + env.cr, + "account", + [ + "email_template_edi_credit_note", + "email_template_edi_invoice", + "mail_template_data_payment_receipt", + ], + ["body_html"], + ) + account_reconcile_model(env) + account_reconcile_model_partner_mapping(env) + account_account_active(env) + fiscal_position_tax_ids(env) + account_tax_original_tax_ids(env) + account_full_reconcile_exchange_move_id(env) + account_move_line_no_followup(env) diff --git a/openupgrade_scripts/scripts/account/19.0.1.4/pre-migration.py b/openupgrade_scripts/scripts/account/19.0.1.4/pre-migration.py new file mode 100644 index 00000000000..e2b1dbb77ba --- /dev/null +++ b/openupgrade_scripts/scripts/account/19.0.1.4/pre-migration.py @@ -0,0 +1,143 @@ +# Copyright 2026 Hunki Enterprises BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from openupgradelib import openupgrade + +_added_fields = [ + ("taxable_supply_date", "account.move", "account_move", "date", None, "account"), + ( + "deductible_amount", + "account.move.line", + "account_move_line", + "float", + None, + "account", + 100, + ), + ( + "is_storno", + "account.move.line", + "account_move_line", + "boolean", + None, + "account", + False, + ), + ( + "no_followup", + "account.move.line", + "account_move_line", + "boolean", + None, + "account", + False, + ), + ( + "allow_foreign_vat", + "account.report", + "account_report", + "boolean", + None, + "account", + False, + ), +] + +_renamed_fields = [ + ( + "res.company", + "res_company", + "check_account_audit_trail", + "restrictive_audit_trail", + ), +] + + +_renamed_xmlids = [ + ( + "account_peppol_selfbilling.email_template_edi_self_billing_credit_note", + "account.email_template_edi_self_billing_credit_note", + ), + ( + "account_peppol_selfbilling.email_template_edi_self_billing_invoice", + "account.email_template_edi_self_billing_invoice", + ), +] + + +def account_journal_invoice_reference_type(env): + """ + Map account.journal#invoice_reference_type value 'none' to 'invoice' + """ + openupgrade.copy_columns( + env.cr, {"account_journal": [("invoice_reference_type", None, None)]} + ) + openupgrade.map_values( + env.cr, + openupgrade.get_legacy_name("invoice_reference_type"), + "invoice_reference_type", + [("none", "invoice")], + table="account_journal", + ) + + +def account_report(env): + """ + Map account.report#default_opening_date_filter values 'previous_tax_period', + 'this_tax_period' to 'previous_return_period', 'this_return_period' + Map account.report#filter_multi_company value 'disabled' to None + """ + openupgrade.copy_columns( + env.cr, {"account_report": [("default_opening_date_filter", None, None)]} + ) + openupgrade.map_values( + env.cr, + openupgrade.get_legacy_name("default_opening_date_filter"), + "default_opening_date_filter", + [ + ("this_tax_period", "this_return_period"), + ("previous_tax_period", "previous_return_period"), + ], + table="account_report", + ) + openupgrade.copy_columns( + env.cr, {"account_report": [("filter_multi_company", None, None)]} + ) + openupgrade.map_values( + env.cr, + openupgrade.get_legacy_name("filter_multi_company"), + "filter_multi_company", + [ + ("disabled", False), + ], + table="account_report", + ) + + +def account_report_expression(env): + """ + Map account.report.expression#date_scope value 'previous_tax_period' to + 'previous_return_period' + """ + openupgrade.copy_columns( + env.cr, {"account_report_expression": [("date_scope", None, None)]} + ) + openupgrade.map_values( + env.cr, + openupgrade.get_legacy_name("date_scope"), + "date_scope", + [ + ("previous_tax_period", "previous_return_period"), + ], + table="account_report_expression", + ) + + +@openupgrade.migrate() +def migrate(env, version): + openupgrade.add_fields(env, _added_fields) + openupgrade.rename_fields(env, _renamed_fields) + openupgrade.rename_xmlids(env.cr, _renamed_xmlids) + account_journal_invoice_reference_type(env) + account_report(env) + account_report_expression(env) diff --git a/openupgrade_scripts/scripts/account/19.0.1.4/upgrade_analysis_work.txt b/openupgrade_scripts/scripts/account/19.0.1.4/upgrade_analysis_work.txt new file mode 100644 index 00000000000..828d07e42f2 --- /dev/null +++ b/openupgrade_scripts/scripts/account/19.0.1.4/upgrade_analysis_work.txt @@ -0,0 +1,386 @@ +---Models in module 'account'--- +obsolete model account.fiscal.position.tax + +# NOTHING TO DO: handled by migration of account.fiscal.position#tax_ids, account.tax#original_tax_ids + +obsolete model account.reconcile.model.partner.mapping + +# DONE: merged into account.reconcile.model.line + +new model account.document.import.mixin [abstract] +---Fields in module 'account'--- +account / account.account / account_type (selection) : selection_keys added: [expense_other] (most likely nothing to do) + +# NOTHING TO DO + +account / account.account / active (boolean) : NEW hasdefault: default + +# DONE: set from deprecated + +account / account.account / activity_ids (one2many) : NEW relation: mail.activity +account / account.account / allowed_journal_ids (many2many): DEL relation: account.journal + +# NOTHING TO DO + +account / account.account / deprecated (boolean) : DEL + +# NOTHING TO DO + +account / account.account / description (text) : NEW translate + +# NOTHING TO DO: ORM will handle conversion + +account / account.account.tag / tax_negate (boolean) : DEL + +# NOTHING TO DO + +account / account.bank.statement / currency_id (many2one) : is now stored + +# NOTHING TO DO: ORM will compute value + +account / account.bank.statement / date (date) : not a function anymore + +# NOTHING TO DO + +account / account.bank.statement.line / taxable_supply_date (date) : previously in module l10n_cz + +# DONE: see account.move#taxable_supply_date + +account / account.fiscal.position / is_domestic (boolean) : NEW isfunction: function, stored + +# NOTHING TO DO + +account / account.fiscal.position / tax_ids (one2many) : relation is now 'account.tax' ('account.fiscal.position.tax') [nothing to do] +account / account.fiscal.position / tax_ids (one2many) : table is now 'account_fiscal_position_account_tax_rel' ('False') +account / account.fiscal.position / tax_ids (one2many) : type is now 'many2many' ('one2many') + +# DONE: filled from account_fiscal_position_tax in post-migration + +account / account.fiscal.position.tax / company_id (many2one) : DEL relation: res.company +account / account.fiscal.position.tax / position_id (many2one) : DEL relation: account.fiscal.position, required +account / account.fiscal.position.tax / tax_dest_id (many2one) : DEL relation: account.tax +account / account.fiscal.position.tax / tax_src_id (many2one) : DEL relation: account.tax, required + +# NOTHING TO DO: handled by migration of account.fiscal.position#tax_ids, account.tax#original_tax_ids + +account / account.full.reconcile / exchange_move_id (many2one) : DEL relation: account.move + +# DONE: create noop partial reconciliation and attach exchange move to it + +account / account.journal / account_control_ids (many2many): DEL relation: account.account + +# NOTHING TO DO: lost functionality + +account / account.journal / autocheck_on_post (boolean) : DEL + +# NOTHING TO DO: this now happens by default + +account / account.journal / display_invoice_template_pdf_report_id (boolean): NEW hasdefault: default, stored: False + +# NOTHING TO DO: computed from available_invoice_template_pdf_report_ids + +account / account.journal / incoming_einvoice_notification_email (char): NEW + +# NOTHING TO DO + +account / account.journal / invoice_reference_model (selection): selection_keys added: [number] (most likely nothing to do) + +# NOTHING TO DO + +account / account.journal / invoice_reference_type (selection): selection_keys removed: [none] + +# DONE: mapped to 'invoice' + +account / account.journal / invoice_template_pdf_report_id (many2one): NEW relation: ir.actions.report +account / account.journal / is_self_billing (boolean) : previously in module account_peppol_selfbilling +account / account.journal / non_deductible_account_id (many2one): NEW relation: account.account + +# NOTHING TO DO + +account / account.move / adjusting_entries_move_ids (many2many): NEW relation: account.move +account / account.move / adjusting_entry_origin_move_ids (many2many): NEW relation: account.move + +# NOTHING TO DO + +account / account.move / exchange_diff_partial_ids (one2many): NEW relation: account.partial.reconcile + +# NOTHING TO DO + +account / account.move / is_storno (boolean) : not stored anymore +account / account.move / is_storno (boolean) : now a function +account / account.move / journal_line_ids (one2many) : NEW relation: account.move.line + +# NOTHING TO DO + +account / account.move / status_in_payment (selection) : selection_keys added: [posted, sent] (most likely nothing to do) + +# NOTHING TO DO, field isn't stored + +account / account.move / taxable_supply_date (date) : previously in module l10n_cz + +# DONE: added in pre-migration + +account / account.move.line / collapse_composition (boolean): NEW +account / account.move.line / collapse_prices (boolean) : NEW + +# NOTHING TO DO + +account / account.move.line / deductible_amount (float) : NEW hasdefault: default + +# DONE: added in pre-migration + +account / account.move.line / display_type (selection) : selection_keys added: [line_subsection, non_deductible_product, non_deductible_product_total, non_deductible_tax] (most likely nothing to do) +account / account.move.line / extra_tax_data (json) : NEW + +# NOTHING TO DO + +account / account.move.line / is_storno (boolean) : is now stored +account / account.move.line / is_storno (boolean) : not related anymore + +# DONE: added in pre-migration, call compute function only if res.company#account_storno is activated in post-migration + +account / account.move.line / no_followup (boolean) : NEW isfunction: function, stored + +# DONE: added in pre-migration, adjusted in post-migration for general journals + +account / account.move.line / search_account_id (many2one) : NEW relation: account.account, stored: False + +# NOTHING TO DO: virtual search field + +account / account.move.line / tax_tag_invert (boolean) : DEL +account / account.partial.reconcile / draft_caba_move_vals (json) : NEW +account / account.reconcile.model / allow_payment_tolerance (boolean): DEL + +# NOTHING TO DO + +account / account.reconcile.model / auto_reconcile (boolean) : DEL + +# DONE: used to set trigger = 'auto_reconcile' + +account / account.reconcile.model / can_be_proposed (boolean) : NEW isfunction: function, stored +account / account.reconcile.model / counterpart_type (selection) : DEL selection_keys: ['general', 'purchase', 'sale'] +account / account.reconcile.model / decimal_separator (char) : DEL + +# NOTHING TO DO + +account / account.reconcile.model / mapped_partner_id (many2one) : NEW relation: res.partner, isfunction: function, stored + +# DONE: see account.reconcile.model.line + +account / account.reconcile.model / match_nature (selection) : DEL required, selection_keys: ['amount_paid', 'amount_received', 'both'] +account / account.reconcile.model / match_note (selection) : DEL selection_keys: ['contains', 'match_regex', 'not_contains'] +account / account.reconcile.model / match_note_param (char) : DEL +account / account.reconcile.model / match_partner (boolean) : DEL +account / account.reconcile.model / match_partner_category_ids (many2many): DEL relation: res.partner.category +account / account.reconcile.model / match_same_currency (boolean) : DEL +account / account.reconcile.model / match_text_location_label (boolean): DEL +account / account.reconcile.model / match_text_location_note (boolean): DEL +account / account.reconcile.model / match_text_location_reference (boolean): DEL +account / account.reconcile.model / match_transaction_type (selection): DEL selection_keys: ['contains', 'match_regex', 'not_contains'] +account / account.reconcile.model / match_transaction_type_param (char): DEL +account / account.reconcile.model / matching_order (selection) : DEL required, selection_keys: ['new_first', 'old_first'] + +# NOTHING TO DO: account_reconcile_model_oca will have to bring them back, so we just leave the columns untouched + +account / account.reconcile.model / next_activity_type_id (many2one): NEW relation: mail.activity.type + + +account / account.reconcile.model / partner_mapping_line_ids (one2many): DEL relation: account.reconcile.model.partner.mapping + +# DONE: create new model for every mapping with regexes merged into label regex + +account / account.reconcile.model / past_months_limit (integer) : DEL +account / account.reconcile.model / payment_tolerance_param (float): DEL +account / account.reconcile.model / payment_tolerance_type (selection): DEL required, selection_keys: ['fixed_amount', 'percentage'] +account / account.reconcile.model / rule_type (selection) : DEL required, selection_keys: ['invoice_matching', 'writeoff_button', 'writeoff_suggestion'] +account / account.reconcile.model / to_check (boolean) : DEL + +# NOTHING TO DO + +account / account.reconcile.model / trigger (selection) : NEW required, selection_keys: ['auto_reconcile', 'manual'], hasdefault: default + +# DONE: set to 'auto_reconcile' if auto_reconcile was set in v18 + +account / account.reconcile.model.line / force_tax_included (boolean) : DEL +account / account.reconcile.model.line / journal_id (many2one) : DEL relation: account.journal +account / account.reconcile.model.line / partner_id (many2one) : NEW relation: res.partner + +# NOTHING TO DO + +account / account.reconcile.model.partner.mapping / model_id (many2one) : DEL relation: account.reconcile.model, required +account / account.reconcile.model.partner.mapping / narration_regex (char) : DEL +account / account.reconcile.model.partner.mapping / partner_id (many2one) : DEL relation: res.partner, required +account / account.reconcile.model.partner.mapping / payment_ref_regex (char) : DEL + +# DONE: see above for account.reconcile.model#partner_mapping_line_ids + +account / account.report / allow_foreign_vat (boolean) : NEW hasdefault: compute + +# DONE: added in pre-migration + +account / account.report / default_opening_date_filter (selection): selection_keys added: [previous_return_period, this_return_period], removed: [previous_tax_period, this_tax_period] + +# DONE: mapped in pre-migration + +account / account.report / filter_fiscal_position (boolean): DEL + +# NOTHING TO DO + +account / account.report / filter_multi_company (selection): selection_keys removed: [disabled] + +# DONE: mapped to None in pre-migration + +account / account.report.expression / date_scope (selection) : selection_keys added: [previous_return_period], removed: [previous_tax_period] + +# DONE: mapped in pre-migration + +account / account.report.external.value / foreign_vat_fiscal_position_id (many2one): DEL relation: account.fiscal.position + +# NOTHING TO DO + +account / account.tax / fiscal_position_ids (many2many): NEW relation: account.fiscal.position + +# DONE: see account.fiscal.position#tax_ids + +account / account.tax / invoice_legal_notes (html) : now translatable + +# NOTHING TO DO + +account / account.tax / is_domestic (boolean) : NEW isfunction: function, stored + +# NOTHING TO DO: computed by ORM + +account / account.tax / name_searchable (char) : DEL stored: False + +# NOTHING TO DO + +account / account.tax / original_tax_ids (many2many) : NEW relation: account.tax +account / account.tax / replacing_tax_ids (many2many) : NEW relation: account.tax + +# DONE: set in post-migration from account.fiscal.position.tax + +account / res.company / account_purchase_receipt_fiscal_position_id (many2one): NEW relation: account.fiscal.position + +# NOTHING TO DO + +account / res.company / check_account_audit_trail (boolean): DEL + +# DONE: renamed to restrictive_audit_trail + +account / res.company / company_registry_placeholder (char): module is now 'base' ('account') + +# NOTHING TO DO + +account / res.company / domestic_fiscal_position_id (many2one): NEW relation: account.fiscal.position, isfunction: function, stored + +# NOTHING TO DO: will be computed by ORM, causes recomputation of account.tax#is_domestic + +account / res.company / expense_account_id (many2one) : NEW relation: account.account +account / res.company / income_account_id (many2one) : NEW relation: account.account + +# DONE: set from chart template in end-migration + +account / res.company / link_qr_code (boolean) : NEW + +# NOTHING TO DO + +account / res.company / price_difference_account_id (many2one): NEW relation: account.account + +# DONE: set from chart template in end-migration + +account / res.company / restrictive_audit_trail (boolean): NEW + +# DONE: renamed from check_account_audit_trail + +account / res.country.group / exclude_state_ids (many2many) : NEW relation: res.country.state +account / res.partner / debit_limit (float) : DEL +account / res.partner / invoice_warn (selection) : DEL selection_keys: ['block', 'no-message', 'warning'] +account / res.partner / invoice_warn_msg (text) : DEL +account / res.partner / is_coa_installed (boolean) : DEL stored: False + +# NOTHING TO DO + +---XML records in module 'account'--- +NEW ir.actions.act_window: account.action_account_moves_email_preview +NEW ir.actions.act_window: account.action_move_out_refund_type_non_legacy +DEL ir.actions.act_window: account.action_move_in_receipt_type +DEL ir.actions.act_window: account.action_move_out_receipt_type +DEL ir.actions.act_window: account.action_validate_account_move +NEW ir.actions.server: account.accountant_confirm_entries_action +NEW ir.actions.server: account.action_validate_account_moves +DEL ir.actions.server: account.action_new_bank_setting +DEL ir.model.access: account.access_account_fiscal_position_tax +DEL ir.model.access: account.access_account_fiscal_position_tax_product_manager +DEL ir.model.access: account.access_account_reconcile_model_partner_mapping +DEL ir.model.access: account.access_account_reconcile_model_partner_mapping_billing +DEL ir.model.access: account.access_account_reconcile_model_partner_mapping_readonly +DEL ir.model.access: account.access_product_product_account_manager +DEL ir.model.access: account.access_product_template_account_manager +NEW ir.model.constraint: account.constraint_account_bank_statement_first_line_index_idx +NEW ir.model.constraint: account.constraint_account_bank_statement_journal_id_date_desc_id_desc_idx +NEW ir.model.constraint: account.constraint_account_bank_statement_line_main_idx +NEW ir.model.constraint: account.constraint_account_bank_statement_line_orphan_idx +NEW ir.model.constraint: account.constraint_account_bank_statement_line_unreconciled_idx +NEW ir.model.constraint: account.constraint_account_lock_exception_company_id_end_datetime_idx +NEW ir.model.constraint: account.constraint_account_move_checked_idx +NEW ir.model.constraint: account.constraint_account_move_duplicate_bills_idx +NEW ir.model.constraint: account.constraint_account_move_journal_id_company_id_idx +NEW ir.model.constraint: account.constraint_account_move_line_account_id_date_idx +ir.model.constraint: account.constraint_account_move_line_check_accountable_required_fields (changed definition: is now 'CHECK(display_type IN ('line_section', 'line_subsection', 'line_note') OR account_id IS NOT NULL)' ('check(display_type in('line_section','line_note') or account_id is not null)')) +ir.model.constraint: account.constraint_account_move_line_check_amount_currency_balance_sign (changed definition: is now 'CHECK( display_type IN ('line_section', 'line_subsection', 'line_note') OR ( (balance <= 0 AND amount_currency <= 0) OR (balance >= 0 AND amount_currency >= 0) ) )' ('check( display_type in('line_section','line_note') or( (balance <= 0 and amount_currency <= 0) or (balance >= 0 and amount_currency >= 0) ) )')) +ir.model.constraint: account.constraint_account_move_line_check_credit_debit (changed definition: is now 'CHECK(display_type IN ('line_section', 'line_subsection', 'line_note') OR credit * debit=0)' ('check(display_type in('line_section','line_note') or credit * debit=0)')) +ir.model.constraint: account.constraint_account_move_line_check_non_accountable_fields_null (changed definition: is now 'CHECK(display_type NOT IN ('line_section', 'line_subsection', 'line_note') OR (amount_currency = 0 AND debit = 0 AND credit = 0 AND account_id IS NULL))' ('check(display_type not in('line_section','line_note') or(amount_currency = 0 and debit = 0 and credit = 0 and account_id is null))')) +NEW ir.model.constraint: account.constraint_account_move_line_date_name_id_idx +NEW ir.model.constraint: account.constraint_account_move_line_journal_id_neg_amnt_residual_idx +NEW ir.model.constraint: account.constraint_account_move_line_partner_id_ref_idx +NEW ir.model.constraint: account.constraint_account_move_line_unreconciled_index +NEW ir.model.constraint: account.constraint_account_move_made_gaps +NEW ir.model.constraint: account.constraint_account_move_payment_idx +NEW ir.model.constraint: account.constraint_account_payment_journal_id_company_id_idx +NEW ir.model.constraint: account.constraint_account_payment_unmatched_idx +DEL ir.model.constraint: account.constraint_account_fiscal_position_tax_tax_src_dest_uniq +DEL ir.model.constraint: account.constraint_account_reconcile_model_name_unique +DEL ir.module.category: account.module_category_accounting_bank +NEW ir.ui.menu: account.account_audit_control_menu +NEW ir.ui.menu: account.account_audit_menu +NEW ir.ui.menu: account.account_closing_menu +NEW ir.ui.menu: account.account_logs_menu +NEW ir.ui.menu: account.account_reports_taxes_and_fiscal_menu +NEW ir.ui.menu: account.account_transactions_menu +DEL ir.ui.menu: account.account_banks_menu +DEL ir.ui.menu: account.account_management_menu +DEL ir.ui.menu: account.action_account_reconcile_model_menu +DEL ir.ui.menu: account.menu_action_account_bank_journal_form +DEL ir.ui.menu: account.menu_action_move_in_receipt_type +DEL ir.ui.menu: account.menu_action_move_out_receipt_type +NEW ir.ui.view: account.account_tax_fiscal_position_view_tree +NEW ir.ui.view: account.country_group_form_inherit_account +NEW ir.ui.view: account.portal_my_details +NEW ir.ui.view: account.portal_my_journal_mail_notifications +NEW ir.ui.view: account.product_template_list_view_purchasable_inherit +NEW ir.ui.view: account.product_template_list_view_sellable_inherit +NEW ir.ui.view: account.setup_credit_card_account_wizard +DEL ir.ui.view: account.portal_my_details_fields +DEL ir.ui.view: account.product_template_view_tree +DEL ir.ui.view: account.view_account_reconcile_model_line_form +DEL ir.ui.view: account.view_in_invoice_receipt_tree + +# NOTHING TO DO + +NEW mail.template: account.email_template_edi_self_billing_credit_note [renamed from account_peppol_selfbilling module] (noupdate) +NEW mail.template: account.email_template_edi_self_billing_invoice [renamed from account_peppol_selfbilling module] (noupdate) + +# DONE: renamed in pre-migration + +NEW mail.template: account.mail_template_einvoice_notification (noupdate) +NEW mail.template: account.mail_template_invoice_subscriber (noupdate) +NEW res.country.group: account.europe_vat (noupdate) +NEW res.country.group: account.intrastat (noupdate) +NEW res.groups: account.group_partial_purchase_deductibility +DEL res.groups: account.group_purchase_receipts +DEL res.groups: account.group_sale_receipts +DEL res.groups: account.group_warning_account +NEW res.groups.privilege: account.res_group_privilege_accounting_bank +NEW res.groups.privilege: account.res_groups_privilege_accounting + +# NOTHING TO DO diff --git a/openupgrade_scripts/scripts/account/tests/data_account_migration.py b/openupgrade_scripts/scripts/account/tests/data_account_migration.py new file mode 100644 index 00000000000..9e2da55cee1 --- /dev/null +++ b/openupgrade_scripts/scripts/account/tests/data_account_migration.py @@ -0,0 +1,178 @@ +env = locals().get("env") + +# create fiscal positions with tax mappings to test their migration + +env["account.fiscal.position"].create( + { + "name": "Domestic fiscal position", + "country_id": env.company.country_id.id, + } +) + +domestic_tax = env.ref("account.1_purchase_tax_template") +foreign_tax1 = domestic_tax.copy( + { + "name": "Foreign tax1", + } +) + +foreign_tax2 = domestic_tax.copy( + { + "name": "Foreign tax2", + } +) + + +env["account.fiscal.position"].create( + { + "name": "Foreign fiscal position", + "tax_ids": [ + ( + 0, + 0, + { + "tax_src_id": domestic_tax.id, + "tax_dest_id": foreign_tax1.id, + }, + ), + ( + 0, + 0, + { + "tax_src_id": domestic_tax.id, + "tax_dest_id": foreign_tax2.id, + }, + ), + ], + } +) + +# create a reconciliation with exchange move to check if exchange_move_id is moved +# from full reconcile record to new partial reconciliation + +payable_account = env.ref("account.1_payable") +expense_account = env.ref("account.1_expense_rent") +eur = env.ref("base.EUR") + +original_move = env["account.move"].create( + { + "ref": "Exchange move test move", + "line_ids": [ + ( + 0, + 0, + { + "account_id": payable_account.id, + "credit": 42, + "currency_id": eur.id, + "amount_currency": 0, + }, + ), + ( + 0, + 0, + { + "account_id": expense_account.id, + "debit": 42, + }, + ), + ], + } +) +original_move.action_post() + +payment_move = env["account.move"].create( + { + "line_ids": [ + ( + 0, + 0, + { + "account_id": payable_account.id, + "debit": 40, + "currency_id": eur.id, + "amount_currency": 0, + }, + ), + ( + 0, + 0, + { + "account_id": expense_account.id, + "credit": 40, + }, + ), + ] + } +) + +payment_move.action_post() + +( + original_move.line_ids.filtered("account_id.reconcile") + + payment_move.line_ids.filtered("account_id.reconcile") +).reconcile() + +original_move.line_ids.full_reconcile_id.exchange_move_id.ref = ( + "Exchange move of test move's full reconciliation" +) + +# create reconciliation models with partner mappings to test if they are migrated +# correctly +env["account.reconcile.model"].create( + { + "name": "Model with partner mapping, contains label matching", + "match_label": "contains", + "match_label_param": "hello world", + "partner_mapping_line_ids": [ + ( + 0, + 0, + { + "partner_id": env.user.partner_id.id, + "payment_ref_regex": "hello", + "narration_regex": "world", + }, + ), + ], + } +) +env["account.reconcile.model"].create( + { + "name": "Model with partner mapping, not_contains label matching", + "match_label": "not_contains", + "match_label_param": "hello world", + "partner_mapping_line_ids": [ + ( + 0, + 0, + { + "partner_id": env.user.partner_id.id, + "payment_ref_regex": "hello", + "narration_regex": "world", + }, + ), + ], + } +) +env["account.reconcile.model"].create( + { + "name": "Model with partner mapping, regex label matching", + "match_label": "match_regex", + "match_label_param": "hello world", + "partner_mapping_line_ids": [ + ( + 0, + 0, + { + "partner_id": env.user.partner_id.id, + "payment_ref_regex": "hello", + "narration_regex": "world", + }, + ), + ], + } +) + + +env.cr.commit() diff --git a/openupgrade_scripts/scripts/account/tests/test_account_migration.py b/openupgrade_scripts/scripts/account/tests/test_account_migration.py new file mode 100644 index 00000000000..80a123da2ff --- /dev/null +++ b/openupgrade_scripts/scripts/account/tests/test_account_migration.py @@ -0,0 +1,82 @@ +from odoo.tests import TransactionCase, tagged + +from odoo.addons.openupgrade_framework import openupgrade_test + + +@openupgrade_test +class TestAccountMigration(TransactionCase): + def test_fiscal_position(self): + """ + Test that fiscal positions are migrated correctly + """ + domestic_tax = self.env.ref("account.1_purchase_tax_template") + foreign_tax1 = self.env["account.tax"].search([("name", "=", "Foreign tax1")]) + foreign_tax2 = self.env["account.tax"].search([("name", "=", "Foreign tax2")]) + foreign_fpos = self.env["account.fiscal.position"].search( + [("name", "=", "Foreign fiscal position")] + ) + + self.assertItemsEqual( + foreign_fpos.map_tax(domestic_tax), foreign_tax1 + foreign_tax2 + ) + + def test_exchange_move(self): + """ + Test that we create a partial reconciliation for the exchange move of a full + reconciliation if set + """ + reconciled_move = self.env["account.move"].search( + [("ref", "=", "Exchange move test move")] + ) + full_reconcile = reconciled_move.line_ids.full_reconcile_id + self.assertTrue(full_reconcile) + exchange_move = self.env["account.move"].search( + [("ref", "=", "Exchange move of test move's full reconciliation")] + ) + self.assertTrue(exchange_move) + self.assertIn( + exchange_move, full_reconcile.partial_reconcile_ids.exchange_move_id + ) + + def test_reconcile_model_partner_mapping(self): + """ + Test that for each partner mapping, a new reconcile model was created + """ + self._test_reconcile_model_partner_mapping( + "Model with partner mapping, contains label matching", + "(?=.*hello\\ world.*)(hello)|(world)", + ) + self._test_reconcile_model_partner_mapping( + "Model with partner mapping, not_contains label matching", + "(?!hello\\ world)(hello)|(world)", + ) + self._test_reconcile_model_partner_mapping( + "Model with partner mapping, regex label matching", + "(?=hello world)(hello)|(world)", + ) + + def _test_reconcile_model_partner_mapping(self, name, combined_regex): + models = self.env["account.reconcile.model"].search( + [ + ("name", "like", name), + ] + ) + self.assertEqual(len(models), 2) + model_with_mapping = models.filtered("mapped_partner_id") + self.assertTrue(model_with_mapping) + self.assertEqual( + model_with_mapping.match_label_param, + combined_regex, + ) + + +@openupgrade_test +@tagged("post_install") +class TestAccountPostMigration(TransactionCase): + def test_company_accounts(self): + """ + Test that end-migration has set expense_account_id, income_account_id + """ + company = self.env.ref("base.main_company") + self.assertTrue(company.expense_account_id) + self.assertTrue(company.income_account_id) diff --git a/openupgrade_scripts/scripts/analytic/19.0.1.2/upgrade_analysis_work.txt b/openupgrade_scripts/scripts/analytic/19.0.1.2/upgrade_analysis_work.txt new file mode 100644 index 00000000000..796eade377e --- /dev/null +++ b/openupgrade_scripts/scripts/analytic/19.0.1.2/upgrade_analysis_work.txt @@ -0,0 +1,7 @@ +---Models in module 'analytic'--- +---Fields in module 'analytic'--- +analytic / account.analytic.line / fiscal_year_search (boolean) : NEW stored: False + +# NOTHING TO DO: virtual search field + +---XML records in module 'analytic'--- diff --git a/openupgrade_scripts/scripts/onboarding/19.0.1.2/upgrade_analysis_work.txt b/openupgrade_scripts/scripts/onboarding/19.0.1.2/upgrade_analysis_work.txt new file mode 100644 index 00000000000..11630237e80 --- /dev/null +++ b/openupgrade_scripts/scripts/onboarding/19.0.1.2/upgrade_analysis_work.txt @@ -0,0 +1,7 @@ +---Models in module 'onboarding'--- +---Fields in module 'onboarding'--- +---XML records in module 'onboarding'--- +NEW ir.model.constraint: onboarding.constraint_onboarding_progress_onboarding_company_uniq +NEW ir.model.constraint: onboarding.constraint_onboarding_progress_step_company_uniq + +# NOTHING TO DO