Browse Source

[REF] partner_identification: Black python code

14.0
laurent.corron 5 years ago
committed by Tran Thanh Phuc
parent
commit
56c82dfebc
  1. 40
      partner_identification/__manifest__.py
  2. 60
      partner_identification/models/res_partner.py
  3. 64
      partner_identification/models/res_partner_id_category.py
  4. 55
      partner_identification/models/res_partner_id_number.py
  5. 21
      partner_identification/tests/fake_models.py
  6. 193
      partner_identification/tests/test_partner_identification.py
  7. 94
      partner_identification/tests/test_res_partner.py

40
partner_identification/__manifest__.py

@ -7,26 +7,24 @@
# Copyright 2016 ACSONE SA/NV (<http://acsone.eu>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
'name': 'Partner Identification Numbers',
'category': 'Customer Relationship Management',
'version': '12.0.1.0.0',
'license': 'AGPL-3',
'depends': [
'contacts',
"name": "Partner Identification Numbers",
"category": "Customer Relationship Management",
"version": "12.0.1.0.0",
"license": "AGPL-3",
"depends": ["contacts",],
"data": [
"security/ir.model.access.csv",
"views/res_partner_id_category_view.xml",
"views/res_partner_id_number_view.xml",
"views/res_partner_view.xml",
],
'data': [
'security/ir.model.access.csv',
'views/res_partner_id_category_view.xml',
'views/res_partner_id_number_view.xml',
'views/res_partner_view.xml',
],
'author': 'ChriCar Beteiligungs- und Beratungs- GmbH,'
'Tecnativa,'
'Camptocamp,'
'ACSONE SA/NV,'
'LasLabs,'
'Onestein,'
'Odoo Community Association (OCA)',
'website': 'https://github.com/OCA/partner-contact',
'development_status': 'Production/Stable',
"author": "ChriCar Beteiligungs- und Beratungs- GmbH,"
"Tecnativa,"
"Camptocamp,"
"ACSONE SA/NV,"
"LasLabs,"
"Onestein,"
"Odoo Community Association (OCA)",
"website": "https://github.com/OCA/partner-contact",
"development_status": "Production/Stable",
}

60
partner_identification/models/res_partner.py

@ -11,16 +11,16 @@ from odoo.exceptions import ValidationError
class ResPartner(models.Model):
_inherit = 'res.partner'
_inherit = "res.partner"
id_numbers = fields.One2many(
comodel_name='res.partner.id_number',
inverse_name='partner_id',
comodel_name="res.partner.id_number",
inverse_name="partner_id",
string="Identification Numbers",
)
@api.multi
@api.depends('id_numbers')
@api.depends("id_numbers")
def _compute_identification(self, field_name, category_code):
""" Compute a field that indicates a certain ID type.
@ -103,19 +103,20 @@ class ResPartner(models.Model):
if not name:
# No value to set
continue
category = self.env['res.partner.id_category'].search([
('code', '=', category_code),
])
category = self.env["res.partner.id_category"].search(
[("code", "=", category_code),]
)
if not category:
category = self.env['res.partner.id_category'].create({
'code': category_code,
'name': category_code,
})
self.env['res.partner.id_number'].create({
'partner_id': record.id,
'category_id': category.id,
'name': name,
})
category = self.env["res.partner.id_category"].create(
{"code": category_code, "name": category_code,}
)
self.env["res.partner.id_number"].create(
{
"partner_id": record.id,
"category_id": category.id,
"name": name,
}
)
# There was an identification record singleton found.
elif record_len == 1:
value = record[field_name]
@ -125,13 +126,14 @@ class ResPartner(models.Model):
id_number.active = False
# Guard against writing wrong records.
else:
raise ValidationError(_(
'This %s has multiple IDs of this type (%s), so a write '
'via the %s field is not possible. In order to fix this, '
'please use the IDs tab.',
) % (
record._name, category_code, field_name,
))
raise ValidationError(
_(
"This %s has multiple IDs of this type (%s), so a write "
"via the %s field is not possible. In order to fix this, "
"please use the IDs tab.",
)
% (record._name, category_code, field_name,)
)
@api.model
def _search_identification(self, category_code, operator, value):
@ -161,10 +163,12 @@ class ResPartner(models.Model):
Returns:
list: Domain to search with.
"""
id_numbers = self.env['res.partner.id_number'].search([
('name', operator, value),
('category_id.code', '=', category_code),
])
id_numbers = self.env["res.partner.id_number"].search(
[
("name", operator, value),
("category_id.code", "=", category_code),
]
)
return [
('id_numbers.id', 'in', id_numbers.ids),
("id_numbers.id", "in", id_numbers.ids),
]

64
partner_identification/models/res_partner_id_category.py

@ -19,32 +19,42 @@ class ResPartnerIdCategory(models.Model):
_order = "name"
code = fields.Char(
string="Code", size=16, required=True,
string="Code",
size=16,
required=True,
help="Abbreviation or acronym of this ID type. For example, "
"'driver_license'")
"'driver_license'",
)
name = fields.Char(
string="ID name", required=True, translate=True,
help="Name of this ID type. For example, 'Driver License'")
string="ID name",
required=True,
translate=True,
help="Name of this ID type. For example, 'Driver License'",
)
active = fields.Boolean(string="Active", default=True)
validation_code = fields.Text(
'Python validation code',
"Python validation code",
help="Python code called to validate an id number.",
default=lambda self: self._default_validation_code())
default=lambda self: self._default_validation_code(),
)
def _default_validation_code(self):
return _("\n# Python code. Use failed = True to specify that the id "
"number is not valid.\n"
"# You can use the following variables :\n"
"# - self: browse_record of the current ID Category "
"browse_record\n"
"# - id_number: browse_record of ID number to validate")
return _(
"\n# Python code. Use failed = True to specify that the id "
"number is not valid.\n"
"# You can use the following variables :\n"
"# - self: browse_record of the current ID Category "
"browse_record\n"
"# - id_number: browse_record of ID number to validate"
)
@api.multi
def _validation_eval_context(self, id_number):
self.ensure_one()
return {'self': self,
'id_number': id_number,
}
return {
"self": self,
"id_number": id_number,
}
@api.multi
def validate_id_number(self, id_number):
@ -53,19 +63,23 @@ class ResPartnerIdCategory(models.Model):
python validation code fails
"""
self.ensure_one()
if self.env.context.get('id_no_validate'):
if self.env.context.get("id_no_validate"):
return
eval_context = self._validation_eval_context(id_number)
try:
safe_eval(self.validation_code,
eval_context,
mode='exec',
nocopy=True)
safe_eval(
self.validation_code, eval_context, mode="exec", nocopy=True
)
except Exception as e:
raise UserError(
_('Error when evaluating the id_category validation code:'
':\n %s \n(%s)') % (self.name, e))
if eval_context.get('failed', False):
_(
"Error when evaluating the id_category validation code:"
":\n %s \n(%s)"
)
% (self.name, e)
)
if eval_context.get("failed", False):
raise ValidationError(
_("%s is not a valid %s identifier") % (
id_number.name, self.name))
_("%s is not a valid %s identifier")
% (id_number.name, self.name)
)

55
partner_identification/models/res_partner_id_number.py

@ -15,44 +15,59 @@ class ResPartnerIdNumber(models.Model):
_description = "Partner ID Number"
_order = "name"
@api.constrains('name', 'category_id')
@api.constrains("name", "category_id")
def validate_id_number(self):
self.category_id.validate_id_number(self)
name = fields.Char(
string="ID Number", required=True,
string="ID Number",
required=True,
help="The ID itself. For example, Driver License number of this "
"person")
"person",
)
category_id = fields.Many2one(
string="Category", required=True,
comodel_name='res.partner.id_category',
help="ID type defined in configuration. For example, Driver License")
partner_id = fields.Many2one(string="Partner", required=True,
comodel_name='res.partner',
ondelete='cascade')
string="Category",
required=True,
comodel_name="res.partner.id_category",
help="ID type defined in configuration. For example, Driver License",
)
partner_id = fields.Many2one(
string="Partner",
required=True,
comodel_name="res.partner",
ondelete="cascade",
)
partner_issued_id = fields.Many2one(
string="Issued by", comodel_name='res.partner',
string="Issued by",
comodel_name="res.partner",
help="Another partner, who issued this ID. For example, Traffic "
"National Institution")
"National Institution",
)
place_issuance = fields.Char(
string="Place of Issuance",
help="The place where the ID has been issued. For example the country "
"for passports and visa")
"for passports and visa",
)
date_issued = fields.Date(
string="Issued on",
help="Issued date. For example, date when person approved his driving "
"exam, 21/10/2009")
"exam, 21/10/2009",
)
valid_from = fields.Date(
string="Valid from",
help="Validation period stating date.")
string="Valid from", help="Validation period stating date."
)
valid_until = fields.Date(
string="Valid until",
help="Expiration date. For example, date when person needs to renew "
"his driver license, 21/10/2019")
"his driver license, 21/10/2019",
)
comment = fields.Text(string="Notes")
status = fields.Selection(
[('draft', 'New'),
('open', 'Running'),
('pending', 'To Renew'),
('close', 'Expired')])
[
("draft", "New"),
("open", "Running"),
("pending", "To Renew"),
("close", "Expired"),
]
)
active = fields.Boolean(string="Active", default=True)

21
partner_identification/tests/fake_models.py

@ -14,8 +14,7 @@ def setup_test_model(env, model_cls):
model_cls._build_model(env.registry, env.cr)
env.registry.setup_models(env.cr)
env.registry.init_models(
env.cr, [model_cls._name],
dict(env.context, update_custom_fields=True)
env.cr, [model_cls._name], dict(env.context, update_custom_fields=True)
)
@ -24,24 +23,18 @@ def teardown_test_model(env, model_cls):
Courtesy of SBidoul from https://github.com/OCA/mis-builder :)
"""
if not getattr(model_cls, '_teardown_no_delete', False):
if not getattr(model_cls, "_teardown_no_delete", False):
del env.registry.models[model_cls._name]
env.registry.setup_models(env.cr)
class ResPartner(models.Model):
_name = 'res.partner'
_inherit = 'res.partner'
_name = "res.partner"
_inherit = "res.partner"
_teardown_no_delete = True
social_security = fields.Char(
compute=lambda s: s._compute_identification(
'social_security', 'SSN',
),
inverse=lambda s: s._inverse_identification(
'social_security', 'SSN',
),
search=lambda s, *a: s._search_identification(
'SSN', *a
),
compute=lambda s: s._compute_identification("social_security", "SSN",),
inverse=lambda s: s._inverse_identification("social_security", "SSN",),
search=lambda s, *a: s._search_identification("SSN", *a),
)

193
partner_identification/tests/test_partner_identification.py

@ -7,111 +7,164 @@ from odoo.tools import mute_logger
class TestPartnerIdentificationBase(common.TransactionCase):
def test_create_id_category(self):
partner_id_category = self.env['res.partner.id_category'].create({
'code': 'id_code',
'name': 'id_name',
})
self.assertEqual(partner_id_category.name, 'id_name')
self.assertEqual(partner_id_category.code, 'id_code')
partner_id_category = self.env["res.partner.id_category"].create(
{"code": "id_code", "name": "id_name",}
)
self.assertEqual(partner_id_category.name, "id_name")
self.assertEqual(partner_id_category.code, "id_code")
@mute_logger('odoo.sql_db')
@mute_logger("odoo.sql_db")
def test_update_partner_with_no_category(self):
partner_1 = self.env.ref('base.res_partner_1')
partner_1 = self.env.ref("base.res_partner_1")
self.assertEqual(len(partner_1.id_numbers), 0)
# create without required category
with self.assertRaises(IntegrityError):
partner_1.write({'id_numbers': [(0, 0, {
'name': '1234',
})]})
partner_1.write({"id_numbers": [(0, 0, {"name": "1234",})]})
def test_update_partner_with_category(self):
partner_1 = self.env.ref('base.res_partner_1')
partner_id_category = self.env['res.partner.id_category'].create({
'code': 'new_code',
'name': 'new_name',
})
partner_1 = self.env.ref("base.res_partner_1")
partner_id_category = self.env["res.partner.id_category"].create(
{"code": "new_code", "name": "new_name",}
)
# successful creation
partner_1.write({'id_numbers': [(0, 0, {
'name': '1234',
'category_id': partner_id_category.id
})]})
partner_1.write(
{
"id_numbers": [
(
0,
0,
{
"name": "1234",
"category_id": partner_id_category.id,
},
)
]
}
)
self.assertEqual(len(partner_1.id_numbers), 1)
self.assertEqual(partner_1.id_numbers.name, '1234')
self.assertEqual(partner_1.id_numbers.name, "1234")
# delete
partner_1.write({'id_numbers': [(5, 0, 0)]})
partner_1.write({"id_numbers": [(5, 0, 0)]})
self.assertEqual(len(partner_1.id_numbers), 0)
class TestPartnerCategoryValidation(common.TransactionCase):
def test_partner_id_number_validation(self):
partner_id_category = self.env['res.partner.id_category'].create({
'code': 'id_code',
'name': 'id_name',
'validation_code': """
partner_id_category = self.env["res.partner.id_category"].create(
{
"code": "id_code",
"name": "id_name",
"validation_code": """
if id_number.name != '1234':
failed = True
"""
})
partner_1 = self.env.ref('base.res_partner_1')
""",
}
)
partner_1 = self.env.ref("base.res_partner_1")
with self.assertRaises(ValidationError), self.cr.savepoint():
partner_1.write({'id_numbers': [(0, 0, {
'name': '01234',
'category_id': partner_id_category.id
})]})
partner_1.write({'id_numbers': [(0, 0, {
'name': '1234',
'category_id': partner_id_category.id
})]})
partner_1.write(
{
"id_numbers": [
(
0,
0,
{
"name": "01234",
"category_id": partner_id_category.id,
},
)
]
}
)
partner_1.write(
{
"id_numbers": [
(
0,
0,
{
"name": "1234",
"category_id": partner_id_category.id,
},
)
]
}
)
self.assertEqual(len(partner_1.id_numbers), 1)
self.assertEqual(partner_1.id_numbers.name, '1234')
self.assertEqual(partner_1.id_numbers.name, "1234")
partner_id_category2 = self.env['res.partner.id_category'].create({
'code': 'id_code2',
'name': 'id_name2',
'validation_code': """
partner_id_category2 = self.env["res.partner.id_category"].create(
{
"code": "id_code2",
"name": "id_name2",
"validation_code": """
if id_number.name != '1235':
failed = True
"""})
""",
}
)
# check that the constrains is also checked when we change the
# associated category
with self.assertRaises(ValidationError), self.cr.savepoint():
partner_1.id_numbers.write({
'category_id': partner_id_category2.id
})
partner_1.id_numbers.write(
{"category_id": partner_id_category2.id}
)
def test_bad_validation_code(self):
partner_id_category = self.env['res.partner.id_category'].create({
'code': 'id_code',
'name': 'id_name',
'validation_code': """
partner_id_category = self.env["res.partner.id_category"].create(
{
"code": "id_code",
"name": "id_name",
"validation_code": """
if id_number.name != '1234' # missing :
failed = True
"""
})
partner_1 = self.env.ref('base.res_partner_1')
""",
}
)
partner_1 = self.env.ref("base.res_partner_1")
with self.assertRaises(ValidationError):
partner_1.write({'id_numbers': [(0, 0, {
'name': '1234',
'category_id': partner_id_category.id
})]})
partner_1.write(
{
"id_numbers": [
(
0,
0,
{
"name": "1234",
"category_id": partner_id_category.id,
},
)
]
}
)
def test_bad_validation_code_override(self):
""" It should allow a bad validation code if context overrides. """
partner_id_category = self.env['res.partner.id_category'].create({
'code': 'id_code',
'name': 'id_name',
'validation_code': """
partner_id_category = self.env["res.partner.id_category"].create(
{
"code": "id_code",
"name": "id_name",
"validation_code": """
if id_number.name != '1234' # missing :
failed = True
"""
})
partner_1 = self.env.ref('base.res_partner_1').with_context(
""",
}
)
partner_1 = self.env.ref("base.res_partner_1").with_context(
id_no_validate=True,
)
partner_1.write({'id_numbers': [(0, 0, {
'name': '1234',
'category_id': partner_id_category.id
})]})
partner_1.write(
{
"id_numbers": [
(
0,
0,
{
"name": "1234",
"category_id": partner_id_category.id,
},
)
]
}
)

94
partner_identification/tests/test_res_partner.py

@ -7,30 +7,31 @@ from .fake_models import ResPartner, setup_test_model, teardown_test_model
class TestResPartner(common.SavepointCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
setup_test_model(cls.env, ResPartner)
bad_cat = cls.env['res.partner.id_category'].create({
'code': 'another_code',
'name': 'another_name',
})
cls.env['res.partner.id_number'].create({
'name': 'Bad ID',
'category_id': bad_cat.id,
'partner_id': cls.env.user.partner_id.id,
})
cls.partner_id_category = cls.env['res.partner.id_category'].create({
'code': 'id_code',
'name': 'id_name',
})
cls.partner = cls.env.ref('base.main_partner')
cls.partner_id = cls.env['res.partner.id_number'].create({
'name': 'Good ID',
'category_id': cls.partner_id_category.id,
'partner_id': cls.partner.id,
})
bad_cat = cls.env["res.partner.id_category"].create(
{"code": "another_code", "name": "another_name",}
)
cls.env["res.partner.id_number"].create(
{
"name": "Bad ID",
"category_id": bad_cat.id,
"partner_id": cls.env.user.partner_id.id,
}
)
cls.partner_id_category = cls.env["res.partner.id_category"].create(
{"code": "id_code", "name": "id_name",}
)
cls.partner = cls.env.ref("base.main_partner")
cls.partner_id = cls.env["res.partner.id_number"].create(
{
"name": "Good ID",
"category_id": cls.partner_id_category.id,
"partner_id": cls.partner.id,
}
)
@classmethod
def tearDownClass(cls):
@ -39,49 +40,52 @@ class TestResPartner(common.SavepointCase):
def test_compute_identification(self):
""" It should set the proper field to the proper ID name. """
self.partner._compute_identification('name', 'id_code')
self.partner._compute_identification("name", "id_code")
self.assertEqual(self.partner.name, self.partner_id.name)
def test_inverse_identification_saves(self):
""" It should set the ID name to the proper field value. """
self.partner._inverse_identification('name', 'id_code')
self.partner._inverse_identification("name", "id_code")
self.assertEqual(self.partner_id.name, self.partner.name)
def test_inverse_identification_creates_new_category(self):
""" It should create a new category of the type if non-existent. """
self.partner._inverse_identification('name', 'new_code_type')
category = self.env['res.partner.id_category'].search([
('code', '=', 'new_code_type'),
])
self.partner._inverse_identification("name", "new_code_type")
category = self.env["res.partner.id_category"].search(
[("code", "=", "new_code_type"),]
)
self.assertTrue(category)
def test_inverse_identification_creates_new_id(self):
""" It should create a new ID of the type if non-existent. """
category = self.env['res.partner.id_category'].create({
'code': 'new_code_type',
'name': 'new_code_type',
})
self.partner._inverse_identification('name', 'new_code_type')
identification = self.env['res.partner.id_number'].search([
('category_id', '=', category.id),
('partner_id', '=', self.partner.id),
])
category = self.env["res.partner.id_category"].create(
{"code": "new_code_type", "name": "new_code_type",}
)
self.partner._inverse_identification("name", "new_code_type")
identification = self.env["res.partner.id_number"].search(
[
("category_id", "=", category.id),
("partner_id", "=", self.partner.id),
]
)
self.assertEqual(identification.name, self.partner.name)
def test_inverse_identification_multi_exception(self):
""" It should not allow a write when multiple IDs of same type. """
self.env['res.partner.id_number'].create({
'name': 'Another ID',
'category_id': self.partner_id_category.id,
'partner_id': self.partner.id,
})
self.env["res.partner.id_number"].create(
{
"name": "Another ID",
"category_id": self.partner_id_category.id,
"partner_id": self.partner.id,
}
)
with self.assertRaises(ValidationError):
self.partner._inverse_identification('name', 'id_code')
self.partner._inverse_identification("name", "id_code")
def test_search_identification(self):
""" It should return the right record when searched by ID. """
self.partner.social_security = 'Test'
partner = self.env['res.partner'].search([
('social_security', '=', 'Test'),
])
self.partner.social_security = "Test"
partner = self.env["res.partner"].search(
[("social_security", "=", "Test"),]
)
self.assertEqual(partner, self.partner)
Loading…
Cancel
Save