odoo/odoo · error · UserError

You can't change the company of an analytic account that alr

Error message

You can't change the company of an analytic account that already has analytic items! It's a recipe for an analytical disaster!

What it means

A constraint on account.analytic.account.company_id (_check_company_consistency). It blocks changing the company of analytic accounts that already have analytic lines whose company is not a child of the new company, because analytic lines would be left pointing at accounts of a different company.

Source

Thrown at addons/analytic/models/analytic_account.py:102

    )
    credit = fields.Monetary(
        compute='_compute_debit_credit_balance',
        string='Credit',
    )

    currency_id = fields.Many2one(
        related="company_id.currency_id",
        string="Currency",
    )

    @api.constrains('company_id')
    def _check_company_consistency(self):
        for company, accounts in groupby(self, lambda account: account.company_id):
            if company and self.env['account.analytic.line'].sudo().search_count([
                ('auto_account_id', 'in', [account.id for account in accounts]),
                '!', ('company_id', 'child_of', company.id),
            ], limit=1):
                raise UserError(_("You can't change the company of an analytic account that already has analytic items! It's a recipe for an analytical disaster!"))

    @api.depends('code', 'partner_id')
    def _compute_display_name(self):
        for analytic in self:
            name = analytic.name
            if analytic.code:
                name = f'[{analytic.code}] {name}'
            if analytic.partner_id.commercial_partner_id.name:
                name = f'{name} - {analytic.partner_id.commercial_partner_id.name}'
            analytic.display_name = name

    def copy_data(self, default=None):
        default = dict(default or {})
        vals_list = super().copy_data(default=default)
        if 'name' not in default:
            for account, vals in zip(self, vals_list):
                vals['name'] = _("%s (copy)", account.name)
        return vals_list

View on GitHub (pinned to 1e661df964)

Solutions

  1. First move or delete the analytic lines referencing the account (or reassign them to a company under the target)
  2. Create a new analytic account in the target company and move postings there instead of changing company_id
  3. If lines are stale/test data, archive or delete them, then retry the company change

Example fix

// before
analytic_account.write({'company_id': new_company_id})
// after
lines = env['account.analytic.line'].sudo().search([('auto_account_id', '=', account.id)])
lines.write({'company_id': new_company_id})  # or reassign
account.write({'company_id': new_company_id})
Defensive patterns

Strategy: validation

Validate before calling

def can_change_company(env, accounts, new_company):
    return not env['account.analytic.line'].sudo().search_count([
        ('auto_account_id', 'in', accounts.ids),
        '!', ('company_id', 'child_of', new_company.id),
    ], limit=1)

Try / catch

try:
    account.write({'company_id': new_co.id})
except UserError:
    # move lines first, then retry
    move_analytic_lines(account, new_co)
    account.write({'company_id': new_co.id})

Prevention

When it happens

Trigger: Calling write({'company_id': new_company_id}) on one or more analytic accounts that have account.analytic.line records via auto_account_id where those lines' company_id is outside the new company subtree. The search_count is done sudo(), so record rules do not shield it.

Common situations: Reorganizing a multi-company database (moving analytic accounts to a new company); merging companies; CSV imports or XML data that update company_id on existing analytic accounts.

Related errors


AI-assisted analysis of odoo/odoo@1e661df964 (2026-08-15). Data as JSON: /api/errors/48717e64ae629ef0. Report an issue: GitHub.