multicompany_product_sync/models/product_template.py
2026-05-25 08:42:22 +07:00

148 lines
6.3 KiB
Python

# -*- 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
current_company = self.env.company
branch_companies = self.env['res.company'].search([('id', 'child_of', current_company.id)]) - current_company
if not branch_companies:
return
for product in self:
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(current_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 == current_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