# -*- coding: utf-8 -*- from odoo import api, fields, models class ProductTemplate(models.Model): _inherit = 'product.template' def _get_counterpart_record(self, record, target_company): """Helper to find counterpart record in target company, fallback to parent if not found.""" if not record: return record.browse() has_company_ids = 'company_ids' in record._fields has_company_id = 'company_id' in record._fields if has_company_ids and target_company in record.company_ids: return record if has_company_id and record.company_id and record.company_id.id == target_company.id: return record if not has_company_ids and not has_company_id: return record if has_company_id and not record.company_id: return record model_name = record._name domain = [] if has_company_ids: domain.append(('company_ids', 'in', [target_company.id])) else: domain.append(('company_id', '=', target_company.id)) if model_name == 'account.account': domain.append(('code', '=', record.code)) elif model_name == 'account.journal': domain.append(('code', '=', record.code)) elif model_name == 'stock.location': match = self.env['stock.location'].search([ ('company_id', '=', target_company.id), ('complete_name', '=', record.complete_name) ], limit=1) if match: return match domain.append(('name', '=', record.name)) elif model_name == 'account.tax': domain.extend([ ('name', '=', record.name), ('type_tax_use', '=', record.type_tax_use), ('amount', '=', record.amount), ('amount_type', '=', record.amount_type) ]) elif model_name == 'stock.route': domain.append(('name', '=', record.name)) else: if 'name' in record._fields: domain.append(('name', '=', record.name)) else: return record match = self.env[model_name].search(domain, limit=1) if not match: return record return match def _sync_to_branch_companies(self, sync_taxes=True, sync_m2o=True): """Replicate product template settings to all active branch companies recursively.""" if self.env.context.get('skip_company_dependent_sync'): return for product in self: parent_company = product.company_id or self.env.company branch_companies = self.env['res.company'].search([('id', 'child_of', parent_company.id)]) - parent_company if not branch_companies: continue for branch in branch_companies: # 1. Sync company-dependent many2one fields (accounts, locations) if sync_m2o: vals_to_write = {} m2o_fields = [ 'property_account_income_id', 'property_account_expense_id', 'property_price_difference_account_id', 'property_stock_inventory', 'property_stock_production' ] for field in m2o_fields: val = product.with_company(parent_company)[field] if val: counterpart = product._get_counterpart_record(val, branch) vals_to_write[field] = counterpart.id if counterpart else False else: vals_to_write[field] = False if vals_to_write: product.with_company(branch).with_context(skip_company_dependent_sync=True).write(vals_to_write) # 2. Sync many2many fields (taxes, routes) safely preserving other companies' values if sync_taxes: m2m_fields = ['taxes_id', 'supplier_taxes_id', 'route_ids'] for field in m2m_fields: all_records = product[field] # Filter active/parent company records current_records = all_records.filtered( lambda r: 'company_id' in r._fields and r.company_id == parent_company ) # Filter target branch company records branch_records = all_records.filtered( lambda r: 'company_id' in r._fields and r.company_id == branch ) # Filter records belonging to other companies other_records = all_records - current_records - branch_records counterparts = self.env[all_records._name] for r in current_records: match = product._get_counterpart_record(r, branch) if match: counterparts |= match final_records = other_records | current_records | counterparts product.with_context(skip_company_dependent_sync=True).write({ field: [(6, 0, final_records.ids)] }) @api.model_create_multi def create(self, vals_list): products = super().create(vals_list) products._sync_to_branch_companies() return products def write(self, vals): res = super().write(vals) m2o_fields = [ 'property_account_income_id', 'property_account_expense_id', 'property_price_difference_account_id', 'property_stock_inventory', 'property_stock_production' ] m2m_fields = ['taxes_id', 'supplier_taxes_id', 'route_ids'] sync_taxes = any(f in vals for f in m2m_fields) sync_m2o = any(f in vals for f in m2o_fields) if sync_taxes or sync_m2o: self._sync_to_branch_companies(sync_taxes=sync_taxes, sync_m2o=sync_m2o) return res