[FIX] analytic: field None should not validate model

If an aml has no product, it should not trigger a model that has a product.
So, we now define the fields that have to be checked on the model, instead of just being the ones given as parameters.

The way the field `company_id` impacts the model has also been changed.
The idea is that a model with a company specified should be better than a model without one.
But we also want that a model with 1 valid rule and no company is better than one with only a good selected company.

closes odoo/odoo#107165

X-original-commit: feff1a8a056f1fbbc852f7cf164e73abf83c4cc9
Signed-off-by: William André (wan) <wan@odoo.com>
This commit is contained in:
gawa-odoo
2022-12-04 17:57:58 +01:00
parent f33e1ca222
commit 4d7a9eea13
3 changed files with 76 additions and 26 deletions
@@ -26,12 +26,3 @@ class AccountAnalyticDistributionModel(models.Model):
def _create_domain(self, fname, value):
if not fname == 'account_prefix':
return super()._create_domain(fname, value)
def _check_score(self, key, value):
if key == 'account_prefix':
if value.startswith(self.account_prefix):
return 1
else:
return -1
else:
return super()._check_score(key, value)
@@ -5,6 +5,10 @@ from odoo import api, fields, models, _
from odoo.exceptions import UserError
class NonMatchingDistribution(Exception):
pass
class AccountAnalyticDistributionModel(models.Model):
_name = 'account.analytic.distribution.model'
_inherit = 'analytic.mixin'
@@ -57,29 +61,38 @@ class AccountAnalyticDistributionModel(models.Model):
domain += self._create_domain(fname, value) or []
best_score = 0
res = {}
fnames = set(self._get_fields_to_check())
for rec in self.search(domain):
score = 0
for key, value in vals.items():
if value and rec[key]:
if rec._check_score(key, value) == 1:
score += 1
else:
score = -1
break
if score > best_score:
res = rec.analytic_distribution
best_score = score
try:
score = sum(rec._check_score(key, vals.get(key)) for key in fnames)
if score > best_score:
res = rec.analytic_distribution
best_score = score
except NonMatchingDistribution:
continue
return res
def _get_fields_to_check(self):
return (
set(self.env['account.analytic.distribution.model']._fields)
- set(self.env['analytic.mixin']._fields)
- set(models.MAGIC_COLUMNS) - {'display_name', '__last_update'}
)
def _check_score(self, key, value):
self.ensure_one()
if key == 'partner_category_id':
if self[key].id in value:
return 1
if value == self[key].id:
if key == 'company_id':
if not self.company_id or value == self.company_id.id:
return 1 if self.company_id else 0.5
raise NonMatchingDistribution
if not self[key]:
return 0
if value and ((self[key].id in value) if isinstance(value, (list, tuple))
else (value.startswith(self[key])) if key.endswith('_prefix')
else (value == self[key].id)
):
return 1
else:
return -1
raise NonMatchingDistribution
def _create_domain(self, fname, value):
if not value:
@@ -2,6 +2,7 @@
from odoo.tests import tagged
from odoo.tests.common import TransactionCase
from odoo import Command
@tagged('post_install', '-at_install')
@@ -113,9 +114,54 @@ class TestAnalyticAccount(TransactionCase):
self.assertEqual(distribution_json, {}, "No distribution should be given")
distribution_json = self.env['account.analytic.distribution.model']._get_distribution({
"partner_id": self.partner_a.id,
"company_id": self.company_data.id,
})
self.assertEqual(distribution_json, {str(self.analytic_account_3.id): 100}, "Distribution 1 should be given")
distribution_json = self.env['account.analytic.distribution.model']._get_distribution({
"partner_id": self.partner_b.id,
"company_id": self.company_data.id,
})
self.assertEqual(distribution_json, {str(self.analytic_account_2.id): 100}, "Distribution 2 should be given")
def test_order_analytic_distribution_model(self):
""" Test the distribution returned with company field"""
distribution_3 = self.env['account.analytic.distribution.model'].create({
'partner_id': self.partner_a.id,
'analytic_distribution': {self.analytic_account_1.id: 100},
'company_id': self.company_data.id,
})
distribution_json = self.env['account.analytic.distribution.model']._get_distribution({})
self.assertEqual(distribution_json, {}, "No distribution should be given")
distribution_json = self.env['account.analytic.distribution.model']._get_distribution({
"partner_id": self.partner_a.id,
"company_id": self.company_data.id,
})
self.assertEqual(distribution_json, distribution_3.analytic_distribution,
"Distribution 3 should be given, as the company is specified in the model")
distribution_json = self.env['account.analytic.distribution.model']._get_distribution({
"partner_id": self.partner_b.id,
"company_id": self.company_data.id,
})
self.assertEqual(distribution_json, {str(self.analytic_account_2.id): 100},
"Distribution 2 should be given, for the partner")
partner_category = self.env['res.partner.category'].create({'name': 'partner_categ'})
self.partner_a.write({
'category_id': [Command.set([partner_category.id])]
})
distribution_4 = self.env['account.analytic.distribution.model'].create({
'partner_id': self.partner_a.id,
'analytic_distribution': {self.analytic_account_1.id: 100, self.analytic_account_2.id: 100},
'partner_category_id': partner_category.id,
})
distribution_json = self.env['account.analytic.distribution.model']._get_distribution({
"partner_id": self.partner_a.id,
"company_id": self.company_data.id,
"partner_category_id": partner_category.ids,
})
self.assertEqual(distribution_json, distribution_4.analytic_distribution,
"Distribution 4 should be given, as the partner_category_id is better than the company_id")