Skip to content

Commit

Permalink
FIX pylint
Browse files Browse the repository at this point in the history
(cherry picked from commit eadcae2)

Conflicts:
	partner_identification/__openerp__.py
	Set version to 8.0.1.0.0.
	Remove dependency on sales_team, as the relevant change is not
in 8.0.

Change emails to the new ones
(cherry picked from commit 3455ae6)

Update new name
(cherry picked from commit 5b592d7)

[FIX] try me on runbot link

(cherry picked from commit bd587b6)

Conflicts:
	partner_identification/README.rst
	Changed runbot to 8.0

[IMP] partner_identification: Add context override (OCA#373)

Allow for context override of validations using ``id_no_validate``
(cherry picked from commit 76c2e7b)

[10.0][IMP] partner_identification: Add field computation and inverses (OCA#419)

* [IMP] partner_identification: Add field computation and inverses
* Add methods to allow for computation and inverse of an ID field of a specific category type

* [IMP] partner_identification: Add search option

(cherry picked from commit 19c5fb6)

[FIX] partner_identification: Infinite loop in search (OCA#436)

(cherry picked from commit fa9b390)

[FIX] partner-contact CI interactions

(cherry picked from commit bc93e7b)

[ADD][8.0] Backport of the 9.0 module.

(cherry picked from commit a425403)

[8.0][MIG] partner_identification backport
  • Loading branch information
jjscarafia authored and Kevin Graveman committed Aug 10, 2018
1 parent 580a585 commit 082f4f9
Show file tree
Hide file tree
Showing 7 changed files with 329 additions and 13 deletions.
17 changes: 13 additions & 4 deletions 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 <[email protected]>
* Gerhard Könighofer <[email protected]>
* Laurent Mignon <[email protected]>
* Yajo <[email protected]>
* Jairo Llopis <[email protected]>
* Dave Lasley <[email protected]>
* Kevin Graveman <[email protected]>

Maintainer
----------
Expand Down
7 changes: 4 additions & 3 deletions __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 models/res_partner.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,165 @@
# Antonio Espinosa <[email protected]>
# 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 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 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 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 082f4f9

Please sign in to comment.