@@ -14,7 +14,6 @@ class ProductTemplate(models.Model):
1414 string = "Has divergent cross-company taxes" ,
1515 compute = "_compute_divergent_company_taxes" ,
1616 compute_sudo = True ,
17- store = True ,
1817 help = (
1918 "Does this product have divergent cross-company taxes? "
2019 "(Only for multi-company products)"
@@ -24,58 +23,153 @@ class ProductTemplate(models.Model):
2423 @api .depends ("company_id" , "taxes_id" , "supplier_taxes_id" )
2524 def _compute_divergent_company_taxes (self ):
2625 """Know if this product has divergent taxes across companies."""
26+ # Skip single-company products
27+ self .divergent_company_taxes = False
28+ if len (self .env ["res.company" ].search ([]).ids ) == 1 :
29+ return
30+ for one in self :
31+ # A unique constraint in account.tax makes it impossible to have
32+ # duplicated tax names by company
33+ if self .company_id :
34+ continue
35+ one .divergent_company_taxes = one ._is_divergent_company_taxes (
36+ "taxes"
37+ ) or self ._is_divergent_company_taxes ("purchase" )
38+
39+ def _is_divergent_company_taxes (self , tax_type ):
40+ """Returns true or false if there are differences in product taxes.
41+
42+ :param tax_type: can be 'taxes' or 'purchase'
43+ """
44+ self .ensure_one ()
2745 all_companies = self .env ["res.company" ].search (
2846 [
2947 # Useful for tests, to avoid pollution
30- ("id" , "not in" , self .env .context .get ("ignored_company_ids" , []))
48+ ("id" , "not in" , self .env .context .get ("ignored_company_ids" , [])),
3149 ]
3250 )
33- for one in self :
34- one .divergent_company_taxes = False
35- # Skip single-company products
36- if one .company_id :
37- continue
38- # A unique constraint in account.tax makes it impossible to have
39- # duplicated tax names by company
40- customer_taxes = {
41- frozenset (tax .name for tax in one .taxes_id if tax .company_id == company )
42- for company in all_companies
43- }
44- if len (customer_taxes ) > 1 :
45- one .divergent_company_taxes = True
46- continue
47- supplier_taxes = {
48- frozenset (
49- tax .name
50- for tax in one .supplier_taxes_id
51- if tax .company_id == company
51+ current_company = self .env .company
52+
53+ company_tax_bd_map = dict (self ._origin ._get_product_taxes (tax_type ))
54+ for company_id in list (company_tax_bd_map .keys ()):
55+ if company_id not in all_companies .ids or company_id == current_company .id :
56+ company_tax_bd_map .pop (company_id )
57+ if tax_type == "taxes" :
58+ current_tax = self .taxes_id
59+ field_name_data = "account_sale_tax_id"
60+ elif tax_type == "purchase" :
61+ current_tax = self .supplier_taxes_id
62+ field_name_data = "account_purchase_tax_id"
63+ propagate_taxes = False
64+
65+ # Tax-free
66+ if not current_tax :
67+ # Since all companies can have an empty tax field,if there is data
68+ # in the database, it means that we can propagate leaving it empty.
69+ if len (company_tax_bd_map ) > 0 :
70+ propagate_taxes = True
71+ # No tax in other products
72+ elif not company_tax_bd_map :
73+ # If we do not have any taxes in the database and we add a tax, it means
74+ # that we can update the product taxes.
75+ current_product_tax_ids = current_tax .filtered (
76+ lambda tax : tax .company_id == current_company
77+ ).ids
78+ current_product_taxes_other_companies = set ()
79+ other_companies = all_companies .filtered (
80+ lambda company : company .id != current_company .id
81+ )
82+ for company in other_companies :
83+ current_product_taxes_other_companies .update (
84+ self ._taxes_by_company (
85+ field_name_data , company , current_product_tax_ids
86+ )
5287 )
53- for company in all_companies
54- }
55- if len (supplier_taxes ) > 1 :
56- one .divergent_company_taxes = True
57- continue
88+ if len (current_product_taxes_other_companies ) > 0 :
89+ propagate_taxes = True
90+ else :
91+ current_names = current_tax .filtered (
92+ lambda tax : tax .company_id == current_company
93+ ).mapped ("name" )
94+ current_product_tax_ids = current_tax .filtered (
95+ lambda tax : tax .company_id == current_company
96+ ).ids
97+ for company in all_companies - current_company :
98+ if company_tax_bd_map .get (company .id ) and current_names == list (
99+ company_tax_bd_map .get (company .id ).values ()
100+ ):
101+ continue
102+ # We are looking to see if there are any taxes that can be applied to
103+ # other companies from the taxes that the current product has.
104+ current_product_taxes_other_companies = self ._taxes_by_company (
105+ field_name_data ,
106+ self .env ["res.company" ].browse (company .id ),
107+ current_product_tax_ids ,
108+ )
109+ if len (current_product_taxes_other_companies ) == len (current_tax ):
110+ propagate_taxes = True
111+ break
112+
113+ return propagate_taxes
114+
115+ def _get_product_taxes (self , field ):
116+ """Returns taxes on purchase or sales taxes
117+
118+ We need the product taxes for other companies, and we cannot take
119+ them from the object itself, so we have to consult the database
120+ where the product taxes passed by parameter are located for all
121+ companies.
122+
123+ :param field: can be 'taxes' or 'purchase'
124+ """
125+ if not self .ids :
126+ return []
127+ # Need stay her because sometimes can be empty
128+ self .ensure_one ()
58129
59- def taxes_by_company (self , field , company , match_tax_ids = None ):
130+ table_by_field = {
131+ "taxes" : "product_taxes_rel" ,
132+ "purchase" : "product_supplier_taxes_rel" ,
133+ }
134+ field_name = table_by_field .get (field )
135+
136+ if not field_name :
137+ raise ValueError ("field should be 'taxes' or 'purchase'" )
138+
139+ sql = f"""
140+ SELECT DISTINCT a_tax.company_id, a_tax.name
141+ FROM { field_name } ptr
142+ LEFT JOIN account_tax a_tax ON tax_id = a_tax.id
143+ WHERE ptr.prod_id = %s
144+ """
145+ self .env .cr .execute (sql , [self .id ])
146+ return self .env .cr .fetchall ()
147+
148+ def _taxes_by_company (self , field , company , match_tax_ids = None ):
149+ """Returns the IDs of all accounts that match the parameters passed.
150+
151+ :param field: fields to search (account_sale_tax_id or account_purchase_tax_id)
152+ :param company: company to search for
153+ :param match_tax_ids: tax IDs to search for
154+ """
60155 taxes_ids = []
61156 if match_tax_ids is None :
62157 taxes_ids = company [field ].ids
63158 # If None: return default taxes
64159 if not match_tax_ids :
65160 return taxes_ids
66161 type_tax_use = "sale" if field == "account_sale_tax_id" else "purchase"
67- AccountTax = self .env ["account.tax" ]
68- for tax in AccountTax .browse (match_tax_ids ):
69- taxes_ids .extend (
70- AccountTax .search (
71- [
72- ("type_tax_use" , "=" , type_tax_use ),
73- ("name" , "=" , tax .name ),
74- ("company_id" , "=" , company .id ),
75- ]
76- ).ids
77- )
78- return taxes_ids
162+ account_tax = self .env ["account.tax" ].sudo ().browse (match_tax_ids )
163+ taxes = account_tax .filtered_domain ([("type_tax_use" , "=" , type_tax_use )])
164+ if not taxes :
165+ return []
166+ return account_tax .search (
167+ [
168+ ("type_tax_use" , "=" , type_tax_use ),
169+ ("company_id" , "=" , company .id ),
170+ ("name" , "in" , taxes .mapped ("name" )),
171+ ]
172+ ).ids
79173
80174 def _delete_product_taxes (
81175 self ,
@@ -94,31 +188,30 @@ def _delete_product_taxes(
94188 if excl_customer_tax_ids :
95189 customer_sql += tax_where
96190 customer_sql_params .append (tuple (excl_customer_tax_ids ))
97- self .env .cr .execute (customer_sql + ";" , customer_sql_params )
191+ self .env .cr .execute (customer_sql , customer_sql_params )
98192 # Delete supplier taxes
99193 supplier_sql = "DELETE FROM product_supplier_taxes_rel WHERE prod_id IN %s"
100194 supplier_sql_params = [tuple (self .ids )]
101195 if excl_supplier_tax_ids :
102196 supplier_sql += tax_where
103197 supplier_sql_params .append (tuple (excl_supplier_tax_ids ))
104- self .env .cr .execute (supplier_sql + ";" , supplier_sql_params )
198+ self .env .cr .execute (supplier_sql , supplier_sql_params )
105199
106200 def set_multicompany_taxes (self ):
107201 self .ensure_one ()
108202 user_company = self .env .company
109203 customer_tax = self .taxes_id
110204 customer_tax_ids = customer_tax .ids
111- if not customer_tax .filtered (lambda r : r .company_id == user_company ):
205+ if not customer_tax .filtered (lambda tax : tax .company_id == user_company ):
112206 customer_tax_ids = []
113207 supplier_tax = self .supplier_taxes_id
114208 supplier_tax_ids = supplier_tax .ids
115- if not supplier_tax .filtered (lambda r : r .company_id == user_company ):
209+ if not supplier_tax .filtered (lambda tax : tax .company_id == user_company ):
116210 supplier_tax_ids = []
117- obj = self .sudo ()
118- default_customer_tax_ids = obj .taxes_by_company (
211+ default_customer_tax_ids = self ._taxes_by_company (
119212 "account_sale_tax_id" , user_company
120213 )
121- default_supplier_tax_ids = obj . taxes_by_company (
214+ default_supplier_tax_ids = self . _taxes_by_company (
122215 "account_purchase_tax_id" , user_company
123216 )
124217 # Clean taxes from other companies (cannot replace it with sudo)
@@ -137,14 +230,14 @@ def set_multicompany_taxes(self):
137230 if default_supplier_tax_ids != supplier_tax_ids
138231 else None
139232 )
140- for company in obj .env ["res.company" ].search ([("id" , "!=" , user_company .id )]):
233+ for company in self .env ["res.company" ].search ([("id" , "!=" , user_company .id )]):
141234 customer_tax_ids .extend (
142- obj . taxes_by_company (
235+ self . _taxes_by_company (
143236 "account_sale_tax_id" , company , match_customer_tax_ids
144237 )
145238 )
146239 supplier_tax_ids .extend (
147- obj . taxes_by_company (
240+ self . _taxes_by_company (
148241 "account_purchase_tax_id" , company , match_suplier_tax_ids
149242 )
150243 )
@@ -160,6 +253,7 @@ def create(self, vals_list):
160253 new_products = super ().create (vals_list )
161254 for product in new_products :
162255 product .set_multicompany_taxes ()
256+ new_products .invalidate_recordset (fnames = ["taxes_id" , "supplier_taxes_id" ])
163257 return new_products
164258
165259
0 commit comments