@@ -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,57 +23,149 @@ 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+ if self .company_id or len (self .env ["res.company" ].search ([]).ids ) <= 1 :
28+ self .divergent_company_taxes = False
29+ return
30+ self .divergent_company_taxes = False
31+ for one in self :
32+ # A unique constraint in account.tax makes it impossible to have
33+ # duplicated tax names by company
34+
35+ one .divergent_company_taxes = one ._is_divergent_company_taxes (
36+ "taxes"
37+ ) or self ._is_divergent_company_taxes ("purchase" )
38+ if one .divergent_company_taxes :
39+ continue
40+
41+ def _is_divergent_company_taxes (self , tax_type ):
42+ """Returns true or false if there are differences in product taxes.
43+
44+ :param one: product to be checked
45+ :param tax_type: can be 'taxes' or 'purchase'
46+ """
47+ self .ensure_one ()
2748 all_companies = self .env ["res.company" ].search (
2849 [
2950 # Useful for tests, to avoid pollution
30- ("id" , "not in" , self .env .context .get ("ignored_company_ids" , []))
51+ ("id" , "not in" , self .env .context .get ("ignored_company_ids" , [])),
3152 ]
3253 )
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
54+ current_company = self .env .company
55+
56+ dict_product_taxes_bd = dict (self ._origin ._get_product_taxes (tax_type ))
57+ for company_id in list (dict_product_taxes_bd .keys ()):
58+ if company_id not in all_companies .ids or company_id == current_company .id :
59+ dict_product_taxes_bd .pop (company_id )
60+ if tax_type == "taxes" :
61+ current_tax = self .taxes_id
62+ field_name_data = "account_sale_tax_id"
63+ elif tax_type == "purchase" :
64+ current_tax = self .supplier_taxes_id
65+ field_name_data = "account_purchase_tax_id"
66+ propagate_taxes = False
67+
68+ # Tax-free
69+ if not current_tax :
70+ # Since all companies can have an empty tax field,if there is data
71+ # in the database, it means that we can propagate leaving it empty.
72+ if len (dict_product_taxes_bd ) > 0 :
73+ propagate_taxes = True
74+ # No tax in other products
75+ elif not dict_product_taxes_bd :
76+ # If we do not have any taxes in the database and we add a tax, it means
77+ # that we can update the product taxes.
78+ current_product_tax_ids = current_tax .filtered (
79+ lambda t : t .company_id == current_company
80+ ).ids
81+ current_product_taxes_other_companies = set ()
82+ other_companies = all_companies .filtered (
83+ lambda c : c .id != current_company .id
84+ )
85+ for company in other_companies :
86+ current_product_taxes_other_companies .update (
87+ self ._taxes_by_company (
88+ field_name_data , company , current_product_tax_ids
89+ )
5290 )
53- for company in all_companies
54- }
55- if len (supplier_taxes ) > 1 :
56- one .divergent_company_taxes = True
57- continue
91+ if len (current_product_taxes_other_companies ) > 0 :
92+ propagate_taxes = True
93+ else :
94+ current_names = current_tax .filtered (
95+ lambda t : t .company_id == current_company
96+ ).mapped ("name" )
97+ current_product_tax_ids = current_tax .filtered (
98+ lambda t : t .company_id == current_company
99+ ).ids
100+ for company_id , value in dict_product_taxes_bd .items ():
101+ if current_names == list (value .values ()):
102+ continue
103+ # We are looking to see if there are any taxes that can be applied to
104+ # other companies from the taxes that the current product has.
105+ current_product_taxes_other_companies = self ._taxes_by_company (
106+ field_name_data ,
107+ self .env ["res.company" ].browse (company_id ),
108+ current_product_tax_ids ,
109+ )
110+ if len (current_product_taxes_other_companies ) == len (current_tax ):
111+ propagate_taxes = True
112+ break
113+
114+ return propagate_taxes
115+
116+ def _get_product_taxes (self , field ):
117+ """Returns taxes on purchase or sales taxes
58118
59- def taxes_by_company (self , field , company , match_tax_ids = None ):
119+ We need the product taxes for other companies, and we cannot take
120+ them from the object itself, so we have to consult the database
121+ where the product taxes passed by parameter are located for all
122+ companies.
123+
124+ :param field: can be 'taxes' or 'purchase'
125+ """
126+ if not self .id :
127+ return []
128+
129+ self .ensure_one ()
130+
131+ table_by_field = {
132+ "taxes" : "product_taxes_rel" ,
133+ "purchase" : "product_supplier_taxes_rel" ,
134+ }
135+ field_name = table_by_field .get (field )
136+
137+ if not field_name :
138+ raise ValueError ("field should be 'taxes' or 'purchase'" )
139+
140+ sql = f"""
141+ SELECT DISTINCT a_tax.company_id, a_tax.name
142+ FROM { field_name } ptr
143+ LEFT JOIN account_tax a_tax ON tax_id = a_tax.id
144+ WHERE ptr.prod_id = %s
145+ """
146+ self .env .cr .execute (sql , [self .id ])
147+ return self .env .cr .fetchall ()
148+
149+ def _taxes_by_company (self , field , company , match_tax_ids = None ):
60150 taxes_ids = []
61151 if match_tax_ids is None :
62152 taxes_ids = company [field ].ids
63153 # If None: return default taxes
64154 if not match_tax_ids :
65155 return taxes_ids
66156 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- )
157+ account_tax = self .env ["account.tax" ].sudo ().browse (match_tax_ids )
158+ taxes_ids = account_tax .filtered_domain ([("type_tax_use" , "=" , type_tax_use )])
159+ if not taxes_ids :
160+ return taxes_ids
161+ taxes_name = list ({n for n in taxes_ids .mapped ("name" ) if n })
162+ taxes_ids = account_tax .search (
163+ [
164+ ("type_tax_use" , "=" , type_tax_use ),
165+ ("company_id" , "=" , company .id ),
166+ ("name" , "in" , taxes_name ),
167+ ]
168+ ).ids
78169 return taxes_ids
79170
80171 def _delete_product_taxes (
@@ -94,14 +185,14 @@ def _delete_product_taxes(
94185 if excl_customer_tax_ids :
95186 customer_sql += tax_where
96187 customer_sql_params .append (tuple (excl_customer_tax_ids ))
97- self .env .cr .execute (customer_sql + ";" , customer_sql_params )
188+ self .env .cr .execute (customer_sql , customer_sql_params )
98189 # Delete supplier taxes
99190 supplier_sql = "DELETE FROM product_supplier_taxes_rel WHERE prod_id IN %s"
100191 supplier_sql_params = [tuple (self .ids )]
101192 if excl_supplier_tax_ids :
102193 supplier_sql += tax_where
103194 supplier_sql_params .append (tuple (excl_supplier_tax_ids ))
104- self .env .cr .execute (supplier_sql + ";" , supplier_sql_params )
195+ self .env .cr .execute (supplier_sql , supplier_sql_params )
105196
106197 def set_multicompany_taxes (self ):
107198 self .ensure_one ()
@@ -114,11 +205,10 @@ def set_multicompany_taxes(self):
114205 supplier_tax_ids = supplier_tax .ids
115206 if not supplier_tax .filtered (lambda r : r .company_id == user_company ):
116207 supplier_tax_ids = []
117- obj = self .sudo ()
118- default_customer_tax_ids = obj .taxes_by_company (
208+ default_customer_tax_ids = self ._taxes_by_company (
119209 "account_sale_tax_id" , user_company
120210 )
121- default_supplier_tax_ids = obj . taxes_by_company (
211+ default_supplier_tax_ids = self . _taxes_by_company (
122212 "account_purchase_tax_id" , user_company
123213 )
124214 # Clean taxes from other companies (cannot replace it with sudo)
@@ -137,14 +227,14 @@ def set_multicompany_taxes(self):
137227 if default_supplier_tax_ids != supplier_tax_ids
138228 else None
139229 )
140- for company in obj .env ["res.company" ].search ([("id" , "!=" , user_company .id )]):
230+ for company in self .env ["res.company" ].search ([("id" , "!=" , user_company .id )]):
141231 customer_tax_ids .extend (
142- obj . taxes_by_company (
232+ self . _taxes_by_company (
143233 "account_sale_tax_id" , company , match_customer_tax_ids
144234 )
145235 )
146236 supplier_tax_ids .extend (
147- obj . taxes_by_company (
237+ self . _taxes_by_company (
148238 "account_purchase_tax_id" , company , match_suplier_tax_ids
149239 )
150240 )
@@ -160,6 +250,7 @@ def create(self, vals_list):
160250 new_products = super ().create (vals_list )
161251 for product in new_products :
162252 product .set_multicompany_taxes ()
253+ new_products .invalidate_recordset (fnames = ["taxes_id" , "supplier_taxes_id" ])
163254 return new_products
164255
165256
0 commit comments