From 02c74cd7bbbd60670372be430e0644c7f068237c Mon Sep 17 00:00:00 2001 From: Denis Roussel Date: Mon, 8 Aug 2016 09:58:31 +0200 Subject: [PATCH] Add module to manage GLN partner identification number --- partner_identification_gln/README.rst | 61 ++++++++++++++ partner_identification_gln/__init__.py | 2 + partner_identification_gln/__openerp__.py | 23 ++++++ .../data/partner_identification_gln.xml | 15 ++++ partner_identification_gln/models/__init__.py | 5 ++ partner_identification_gln/models/partner.py | 65 +++++++++++++++ .../static/description/icon.svg | 79 +++++++++++++++++++ partner_identification_gln/tests/__init__.py | 5 ++ partner_identification_gln/tests/test_gln.py | 70 ++++++++++++++++ 9 files changed, 325 insertions(+) create mode 100644 partner_identification_gln/README.rst create mode 100644 partner_identification_gln/__init__.py create mode 100644 partner_identification_gln/__openerp__.py create mode 100644 partner_identification_gln/data/partner_identification_gln.xml create mode 100644 partner_identification_gln/models/__init__.py create mode 100644 partner_identification_gln/models/partner.py create mode 100644 partner_identification_gln/static/description/icon.svg create mode 100644 partner_identification_gln/tests/__init__.py create mode 100644 partner_identification_gln/tests/test_gln.py diff --git a/partner_identification_gln/README.rst b/partner_identification_gln/README.rst new file mode 100644 index 000000000..e59a31c8e --- /dev/null +++ b/partner_identification_gln/README.rst @@ -0,0 +1,61 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +========================== +Partner Identification Gln +========================== + +This addon extends "Partner Identification Numbers" to provide a number category for GLN registration + +see: http://www.gs1.org/1/glnrules/en/ + +Installation +============ + +This module depends on 'stdnum' python module + + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/repo/github-com-oca-partner-contact-134 + +.. repo_id is available in https://github.com/OCA/maintainer-tools/blob/master/tools/repos_with_ids.txt +.. branch is "8.0" for example + + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smashing it by providing a detailed and welcomed feedback. + +Credits +======= + +Images +------ + +* Odoo Community Association: `Icon `_. + +Contributors +------------ + +* Denis Roussel + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/partner_identification_gln/__init__.py b/partner_identification_gln/__init__.py new file mode 100644 index 000000000..a9e337226 --- /dev/null +++ b/partner_identification_gln/__init__.py @@ -0,0 +1,2 @@ + +from . import models diff --git a/partner_identification_gln/__openerp__.py b/partner_identification_gln/__openerp__.py new file mode 100644 index 000000000..305ef2bb8 --- /dev/null +++ b/partner_identification_gln/__openerp__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 Acsone S.A. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + 'name': 'Partner Identification Gln', + 'summary': """ + This addon extends "Partner Identification Numbers" + to provide a number category for GLN registration""", + 'version': '8.0.1.0.0', + 'license': 'AGPL-3', + 'author': 'Acsone S.A.,Odoo Community Association (OCA)', + 'website': 'https://www.acsone.eu', + 'external_dependencies': { + 'python': ['stdnum' + ], + }, + 'depends': ['partner_identification' + ], + 'data': ['data/partner_identification_gln.xml' + ], + 'installable': True, +} diff --git a/partner_identification_gln/data/partner_identification_gln.xml b/partner_identification_gln/data/partner_identification_gln.xml new file mode 100644 index 000000000..a0649dd1b --- /dev/null +++ b/partner_identification_gln/data/partner_identification_gln.xml @@ -0,0 +1,15 @@ + + + + + GLN Identification Number + gln_id_number + + + + GCP Identification Number + gcp_id_number + + + + \ No newline at end of file diff --git a/partner_identification_gln/models/__init__.py b/partner_identification_gln/models/__init__.py new file mode 100644 index 000000000..4f649425e --- /dev/null +++ b/partner_identification_gln/models/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 Acsone S.A. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import partner diff --git a/partner_identification_gln/models/partner.py b/partner_identification_gln/models/partner.py new file mode 100644 index 000000000..f04a835d9 --- /dev/null +++ b/partner_identification_gln/models/partner.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +# © 2016 ACSONE SA/NV () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +import logging +from openerp import api, models +_logger = logging.getLogger(__name__) + +try: + from stdnum import ean + from stdnum.exceptions import InvalidChecksum +except ImportError: + _logger.debug('Cannot `import external dependency python stdnum package`.') + + +class ResPartnerIdCategory(models.Model): + _inherit = 'res.partner.id_category' + + def _search_duplicate(self, category_id, id_number, force_active=False): + domain = [('category_id', '=', category_id), + ('name', '=', id_number.name), + ('name', '!=', False), + ('id', '!=', id_number.id)] + + if force_active: + domain.append(('partner_id.active', '=', True)) + num_obj = self.env['res.partner.id_number'] + return num_obj.search(domain) + + @api.multi + def validate_res_partner_gln(self, id_number): + self.ensure_one() + if not id_number: + return False + + try: + ean.validate(id_number.name) + except InvalidChecksum: + return True + + cat = self.env.ref('partner_identification_gln.' + 'partner_identification_gln_number_category').id + duplicate_gln = self._search_duplicate(cat, id_number, True) + + if duplicate_gln: + return True + + return False + + @api.multi + def validate_res_partner_gcp(self, id_number): + self.ensure_one() + if not id_number: + return False + + if len(id_number.name) < 1 or len(id_number.name) > 12: + return True + + cat = self.env.ref('partner_identification_gln.' + 'partner_identification_gcp_number_category').id + duplicate_gln = self._search_duplicate(cat, id_number) + + if duplicate_gln: + return True + + return False diff --git a/partner_identification_gln/static/description/icon.svg b/partner_identification_gln/static/description/icon.svg new file mode 100644 index 000000000..a7a26d093 --- /dev/null +++ b/partner_identification_gln/static/description/icon.svg @@ -0,0 +1,79 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/partner_identification_gln/tests/__init__.py b/partner_identification_gln/tests/__init__.py new file mode 100644 index 000000000..a064df9b0 --- /dev/null +++ b/partner_identification_gln/tests/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 Acsone S.A. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import test_gln diff --git a/partner_identification_gln/tests/test_gln.py b/partner_identification_gln/tests/test_gln.py new file mode 100644 index 000000000..50f7459e3 --- /dev/null +++ b/partner_identification_gln/tests/test_gln.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 Acsone S.A. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp.exceptions import ValidationError +from openerp.tests.common import TransactionCase + + +class TestGLN(TransactionCase): + def setUp(self): + super(TestGLN, self).setUp() + self.partner = self.env['res.partner'].create({'name': 'TestGLN'}) + self.partner2 = self.env['res.partner'].create({'name': 'TestGLN2'}) + pc = self.env.ref('partner_identification_gln.' + 'partner_identification_gln_number_category') + self.partner_id_category = pc + + pc_gcp = self.env.ref('partner_identification_gln.' + 'partner_identification_gcp_number_category') + self.partner_id_gcp_category = pc_gcp + + def test_gln(self): + # Good GLN + vals = {'name': '5450534001717', + 'category_id': self.partner_id_category.id + } + self.partner.write({'id_numbers': [(0, 0, vals)]}) + id_number = self.partner.id_numbers[0] + + self.assertEqual(id_number.name, '5450534001717') + + # Duplicate GLN + vals = {'name': '5450534001717', + 'category_id': self.partner_id_category.id + } + + with self.assertRaises(ValidationError): + self.partner2.write({'id_numbers': [(0, 0, vals)]}) + + # Bad GLN + vals = {'name': '5450534001716', + 'category_id': self.partner_id_category.id + } + with self.assertRaises(ValidationError): + self.partner.write({'id_numbers': [(0, 0, vals)]}) + + def test_gcp(self): + # Good GLN + vals = {'name': '545053', + 'category_id': self.partner_id_gcp_category.id + } + self.partner.write({'id_numbers': [(0, 0, vals)]}) + id_number = self.partner.id_numbers[0] + + self.assertEqual(id_number.name, '545053') + + # Duplicate GLN + vals = {'name': '545053', + 'category_id': self.partner_id_gcp_category.id + } + + with self.assertRaises(ValidationError): + self.partner2.write({'id_numbers': [(0, 0, vals)]}) + + # Bad GLN + vals = {'name': '5450534001716', + 'category_id': self.partner_id_gcp_category.id + } + with self.assertRaises(ValidationError): + self.partner.write({'id_numbers': [(0, 0, vals)]})