Skip to content

Commit

Permalink
Merge pull request #612 from pankk/8.0-partner-identification-backport
Browse files Browse the repository at this point in the history
[8.0][MIG] partner_identification backport
  • Loading branch information
pedrobaeza committed Sep 1, 2018
2 parents 1b3c2f4 + 3e7004b commit 79cfc58
Show file tree
Hide file tree
Showing 7 changed files with 329 additions and 13 deletions.
17 changes: 13 additions & 4 deletions partner_identification/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ and vary from country to country.
* Fiscal ID's
* Membership numbers
* Driver license
* ...
* etc


Installation
Expand All @@ -35,8 +35,15 @@ Name:
Code:
Code, abbreviation or acronym of this ID type. For example, 'driver_license'
Python validation code:
Optional python code called to validate ID numbers of this ID type.
Optional python code called to validate ID numbers of this ID type. This functionality can be
overridden by setting ``id_no_validate`` to ``True`` in the context, such as:

.. code-block:: python
partner.with_context(id_no_validate=True).write({
'name': 'Bad Value',
'category_id': self.env.ref('id_category_only_numerics').id,
})
Usage
=====
Expand All @@ -63,7 +70,7 @@ Notes:

.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/
:target: https://runbot.odoo-community.org/runbot/134/8.0


Known issues / Roadmap
Expand Down Expand Up @@ -97,7 +104,9 @@ Contributors
* Ferdinand Gassauer <office@chrcar.at>
* Gerhard Könighofer <gerhard.koenighofer@swing-system.com>
* Laurent Mignon <laurent.mignon@acsone.eu>
* Yajo <Yajo@users.noreply.github.com>
* Jairo Llopis <jairo.llopis@tecnativa.com>
* Dave Lasley <dave@laslabs.com>
* Kevin Graveman <k.graveman@onestein.nl>

Maintainer
----------
Expand Down
7 changes: 4 additions & 3 deletions partner_identification/__openerp__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,19 @@
{
'name': 'Partner Identification Numbers',
'category': 'Customer Relationship Management',
'version': '8.0.1.0.0',
'version': '8.0.1.1.1',
'data': [
'views/res_partner_id_category_view.xml',
'views/res_partner_id_number_view.xml',
'views/res_partner_view.xml',
'security/ir.model.access.csv',
],
'author': 'ChriCar Beteiligungs- und Beratungs- GmbH, '
'Antiun Ingeniería S.L.',
'Tecnativa,'
'Camptocamp,'
'ACSONE SA/NV,'
'Odoo Community Association (OCA)'
'LasLabs,'
'Odoo Community Association (OCA)',
'website': 'https://odoo-community.org/',
'license': 'AGPL-3',
'installable': True,
Expand Down
161 changes: 157 additions & 4 deletions partner_identification/models/res_partner.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,165 @@
# Antonio Espinosa <antonioea@antiun.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from openerp import models, fields
from openerp import api, models, fields, _
from openerp.exceptions import ValidationError


class ResPartner(models.Model):
_inherit = 'res.partner'
_inherit = 'res.partner' # pylint: disable=R7980

id_numbers = fields.One2many(
comodel_name='res.partner.id_number', inverse_name='partner_id',
string="Identification Numbers")
comodel_name='res.partner.id_number',
inverse_name='partner_id',
string="Identification Numbers",
)

@api.multi
@api.depends('id_numbers')
def _compute_identification(self, field_name, category_code):
""" Compute a field that indicates a certain ID type.
Use this on a field that represents a certain ID type. It will compute
the desired field as that ID(s).
This ID can be worked with as if it were a Char field, but it will
be relating back to a ``res.partner.id_number`` instead.
Example:
.. code-block:: python
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
),
)
Args:
field_name (str): Name of field to set.
category_code (str): Category code of the Identification type.
"""
for record in self:
id_numbers = record.id_numbers.filtered(
lambda r: r.category_id.code == category_code
)
if not id_numbers:
continue
value = id_numbers[0].name
record[field_name] = value

@api.multi
def _inverse_identification(self, field_name, category_code):
""" Inverse for an identification field.
This method will create a new record, or modify the existing one
in order to allow for the associated field to work like a Char.
If a category does not exist of the correct code, it will be created
using `category_code` as both the `name` and `code` values.
If the value of the target field is unset, the associated ID will
be deactivated in order to preserve history.
Example:
.. code-block:: python
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
),
)
Args:
field_name (str): Name of field to set.
category_code (str): Category code of the Identification type.
"""
for record in self:
id_number = record.id_numbers.filtered(
lambda r: r.category_id.code == category_code
)
record_len = len(id_number)
# Record for category is not existent.
if record_len == 0:
name = record[field_name]
if not name:
# No value to set
continue
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,
})
# There was an identification record singleton found.
elif record_len == 1:
value = record[field_name]
if value:
id_number.name = value
else:
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,
))

@api.model
def _search_identification(self, category_code, operator, value):
""" Search method for an identification field.
Example:
.. code-block:: python
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
),
)
Args:
category_code (str): Category code of the Identification type.
operator (str): Operator of domain.
value (str): Value to search for.
Returns:
list: Domain to search with.
"""
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),
]
2 changes: 2 additions & 0 deletions partner_identification/models/res_partner_id_category.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ def validate_id_number(self, id_number):
python validation code fails
"""
self.ensure_one()
if self.env.context.get('id_no_validate'):
return
eval_context = self._validation_eval_context(id_number)
try:
safe_eval(self.validation_code,
Expand Down
2 changes: 2 additions & 0 deletions partner_identification/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from . import test_partner_identification
from . import test_res_partner
22 changes: 20 additions & 2 deletions partner_identification/tests/test_partner_identification.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# © 2016 ACSONE SA/NV (<http://acsone.eu>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from psycopg2._psycopg import IntegrityError
import openerp.tests.common as common
from openerp.tests import common
from openerp.exceptions import ValidationError


Expand Down Expand Up @@ -75,7 +75,7 @@ def test_partner_id_number_validation(self):
'category_id': partner_id_category2.id
})

def test_bad_calidation_code(self):
def test_bad_validation_code(self):
partner_id_category = self.env['res.partner.id_category'].create({
'code': 'id_code',
'name': 'id_name',
Expand All @@ -90,3 +90,21 @@ def test_bad_calidation_code(self):
'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': """
if id_number.name != '1234' # missing :
failed = True
"""
})
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
})]})
Loading

0 comments on commit 79cfc58

Please sign in to comment.