[FIX] analytic: plan's applicability don't work without companies

If you create an applicability and remove the company field,
they are never used.
An applicability like this should be valid for all companies.
We put a 0.5 value for the company field so an applicability
so it has a lesser priority than other fields.
Same idea as the distribution models.

opw-3847415

closes odoo/odoo#162152

Signed-off-by: Olivier Colson (oco) <oco@odoo.com>
This commit is contained in:
Gauthier Wala (gawa)
2024-04-26 15:42:57 +00:00
parent 16de0f70a0
commit ffcf2ee1a3
3 changed files with 53 additions and 11 deletions
@@ -264,3 +264,31 @@ class TestAccountAnalyticAccount(AccountTestInvoicingCommon):
self.assertEqual(self.analytic_account_a.invoice_count, 1) self.assertEqual(self.analytic_account_a.invoice_count, 1)
self.analytic_account_a._compute_vendor_bill_count() self.analytic_account_a._compute_vendor_bill_count()
self.assertEqual(self.analytic_account_a.vendor_bill_count, 1) self.assertEqual(self.analytic_account_a.vendor_bill_count, 1)
def test_applicability_score(self):
""" Tests which applicability is chosen if several ones are valid """
applicability_without_company, applicability_with_company = self.env['account.analytic.applicability'].create([
{
'business_domain': 'invoice',
'product_categ_id': self.product_a.categ_id.id,
'applicability': 'mandatory',
'analytic_plan_id': self.default_plan.id,
'company_id': False,
},
{
'business_domain': 'invoice',
'applicability': 'unavailable',
'analytic_plan_id': self.default_plan.id,
'company_id': self.env.company.id,
},
])
applicability = self.default_plan._get_applicability(business_domain='invoice', company_id=self.env.company.id, product=self.product_a.id)
self.assertEqual(applicability, 'mandatory', "product takes precedence over company")
# If the model that asks for a validation does not have a company_id,
# the score shouldn't take into account the company of the applicability
score = applicability_without_company._get_score(business_domain='invoice', product=self.product_a.id)
self.assertEqual(score, 2)
score = applicability_with_company._get_score(business_domain='invoice', product=self.product_a.id)
self.assertEqual(score, 1)
+11 -3
View File
@@ -233,7 +233,12 @@ class AccountAnalyticPlan(models.Model):
else: else:
score = 0 score = 0
applicability = self.default_applicability applicability = self.default_applicability
for applicability_rule in self.applicability_ids.filtered(lambda rule: rule.company_id == self.env.company): for applicability_rule in self.applicability_ids.filtered(
lambda rule:
not rule.company_id
or not kwargs.get('company_id')
or rule.company_id.id == kwargs.get('company_id')
):
score_rule = applicability_rule._get_score(**kwargs) score_rule = applicability_rule._get_score(**kwargs)
if score_rule > score: if score_rule > score:
applicability = applicability_rule.applicability applicability = applicability_rule.applicability
@@ -304,7 +309,10 @@ class AccountAnalyticApplicability(models.Model):
def _get_score(self, **kwargs): def _get_score(self, **kwargs):
""" Gives the score of an applicability with the parameters of kwargs """ """ Gives the score of an applicability with the parameters of kwargs """
self.ensure_one() self.ensure_one()
# 0.5 is because company is less important than other fields for an equal number of valid fields
# No company on the applicability and the kwargs together are not considered a more fitting rule
score = 0.5 if self.company_id and kwargs.get('company_id') else 0
if not kwargs.get('business_domain'): if not kwargs.get('business_domain'):
return 0 return score
else: else:
return 1 if kwargs.get('business_domain') == self.business_domain else -1 return score + 1 if kwargs.get('business_domain') == self.business_domain else -1
+14 -8
View File
@@ -72,23 +72,29 @@ class TestAnalyticPlanOperations(TransactionCase):
company_2 = self.env['res.company'].create({ company_2 = self.env['res.company'].create({
'name': 'company_2', 'name': 'company_2',
}) })
mandatory_plan = self.env['account.analytic.plan'].create([{ plan = self.env['account.analytic.plan'].create([{
'name': 'Mandatory Plan', 'name': 'Plan',
'default_applicability': 'optional', 'default_applicability': 'optional',
}]) }])
mandatory_plan.with_company(company_2).write({'default_applicability': 'mandatory'}) applicability = self.env['account.analytic.applicability'].create({
self.env['account.analytic.applicability'].create({
'business_domain': 'general', 'business_domain': 'general',
'analytic_plan_id': mandatory_plan.id, 'analytic_plan_id': plan.id,
'applicability': 'mandatory', 'applicability': 'mandatory',
'company_id': company_2.id, 'company_id': company_2.id,
}) })
self.env['account.analytic.account'].create([{ self.env['account.analytic.account'].create([{
'name': 'Mandatory Account', 'name': 'Mandatory Account',
'code': 'manda', 'code': 'manda',
'plan_id': mandatory_plan.id, 'plan_id': plan.id,
}]) }])
distribution_model = self.env['account.analytic.distribution.model'].create({}).with_context(validate_analytic=True) distribution_model = self.env['account.analytic.distribution.model'].create({}).with_context(validate_analytic=True)
# only mandatory applicability is in company_2, should not raise # mandatory applicability is only in company_2, should not raise for company_1
distribution_model._validate_distribution(business_domain='general') distribution_model._validate_distribution(business_domain='general', company_id=self.env.company.id)
applicability.company_id = False
# It should apply for all companies now
with self.assertRaisesRegex(UserError, r'require a 100% analytic distribution'):
distribution_model._validate_distribution(business_domain='general', company_id=self.env.company.id)
with self.assertRaisesRegex(UserError, r'require a 100% analytic distribution'):
distribution_model._validate_distribution(business_domain='general')