From acd75e75effc31886c6674787e2af9b62996033c Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 24 Aug 2016 22:37:22 +0200 Subject: [PATCH] Add module base_phone_business_document_import Add unitests in base_business_document_import Small code enhancements/simplifications --- account_invoice_import/__openerp__.py | 1 - account_invoice_import/account_invoice.py | 3 + .../wizard/account_invoice_import.py | 41 ++-- base_business_document_import/__openerp__.py | 2 +- .../models/business_document_import.py | 68 +++++-- .../tests/__init__.py | 3 + .../tests/test_business_document_import.py | 183 ++++++++++++++++++ .../README.rst | 57 ++++++ .../__init__.py | 3 + .../__openerp__.py | 20 ++ .../models/__init__.py | 3 + .../models/business_document_import.py | 53 +++++ .../tests/__init__.py | 3 + .../tests/test_phone_partner_match.py | 33 ++++ base_ubl/models/ubl.py | 16 +- 15 files changed, 458 insertions(+), 31 deletions(-) create mode 100644 base_business_document_import/tests/__init__.py create mode 100644 base_business_document_import/tests/test_business_document_import.py create mode 100644 base_phone_business_document_import/README.rst create mode 100644 base_phone_business_document_import/__init__.py create mode 100644 base_phone_business_document_import/__openerp__.py create mode 100644 base_phone_business_document_import/models/__init__.py create mode 100644 base_phone_business_document_import/models/business_document_import.py create mode 100644 base_phone_business_document_import/tests/__init__.py create mode 100644 base_phone_business_document_import/tests/test_phone_partner_match.py diff --git a/account_invoice_import/__openerp__.py b/account_invoice_import/__openerp__.py index b7755a8ccc..59e5e71c69 100644 --- a/account_invoice_import/__openerp__.py +++ b/account_invoice_import/__openerp__.py @@ -11,7 +11,6 @@ 'author': 'Akretion,Odoo Community Association (OCA)', 'website': 'http://www.akretion.com', 'depends': ['account', 'base_iban', 'base_business_document_import'], - 'external_dependencies': {'python': ['lxml']}, 'data': [ 'security/ir.model.access.csv', 'account_invoice_import_config_view.xml', diff --git a/account_invoice_import/account_invoice.py b/account_invoice_import/account_invoice.py index c5ac67886d..c84c77e9de 100644 --- a/account_invoice_import/account_invoice.py +++ b/account_invoice_import/account_invoice.py @@ -16,6 +16,9 @@ def name_get(self): new_res = [] for (inv_id, name) in res: inv = self.browse(inv_id) + # I didn't find a python method to easily display + # a float + currency symbol (before or after) + # depending on lang of context and currency name += _(' Amount w/o tax: %s %s') % ( inv.amount_untaxed, inv.currency_id.name) new_res.append((inv_id, name)) diff --git a/account_invoice_import/wizard/account_invoice_import.py b/account_invoice_import/wizard/account_invoice_import.py index 7c22a7f10b..3274f80667 100644 --- a/account_invoice_import/wizard/account_invoice_import.py +++ b/account_invoice_import/wizard/account_invoice_import.py @@ -217,7 +217,8 @@ def _prepare_create_invoice_vals(self, parsed_inv): il_vals = static_vals.copy() if config.invoice_line_method == 'nline_auto_product': product = self._match_product( - line['product'], parsed_inv['chatter_msg'], partner) + line['product'], parsed_inv['chatter_msg'], + seller=partner) fposition_id = partner.property_account_position.id il_vals.update( ailo.product_id_change( @@ -359,6 +360,7 @@ def import_invoice(self): parsed_inv.get('currency'), parsed_inv['chatter_msg']) parsed_inv['partner']['recordset'] = partner parsed_inv['currency']['recordset'] = currency + # TODO Move to IF below : make sure we don't access self.partner_id self.write({ 'partner_id': partner.id, 'invoice_type': parsed_inv['type'], @@ -482,28 +484,43 @@ def _prepare_update_invoice_vals(self, parsed_inv): def update_invoice(self): self.ensure_one() iaao = self.env['ir.actions.act_window'] - if not self.invoice_id: + invoice = self.invoice_id + if not invoice: raise UserError(_( 'You must select a supplier invoice or refund to update')) parsed_inv = self.parse_invoice() + currency = self._match_currency( + parsed_inv.get('currency'), parsed_inv['chatter_msg']) + if currency != invoice.currency_id: + raise UserError(_( + "The currency of the imported invoice (%s) is different from " + "the currency of the existing invoice (%s)") % ( + currency.name, invoice.currency_id.name)) # When invoice with embedded XML files will be more widely used, # we should also update invoice lines vals = self._prepare_update_invoice_vals(parsed_inv) logger.debug('Updating supplier invoice with vals=%s', vals) self.invoice_id.write(vals) - self.env['ir.attachment'].create({ - 'name': self.invoice_filename, - 'res_id': self.invoice_id.id, - 'res_model': 'account.invoice', - 'datas': self.invoice_file, - }) - logger.info('Supplier invoice ID %d updated', self.invoice_id.id) - self.invoice_id.message_post(_( - "This invoice has been updated automatically via file import")) + # Attach invoice and related documents + if parsed_inv.get('attachments'): + for filename, data_base64 in parsed_inv['attachments'].iteritems(): + self.env['ir.attachment'].create({ + 'name': filename, + 'res_id': invoice.id, + 'res_model': 'account.invoice', + 'datas': data_base64, + 'datas_fname': filename, + }) + logger.info( + 'Supplier invoice ID %d updated via import of file %s', + invoice.id, self.invoice_filename) + invoice.message_post(_( + "This invoice has been updated automatically via the import " + "of file %s") % self.invoice_filename) action = iaao.for_xml_id('account', 'action_invoice_tree2') action.update({ 'view_mode': 'form,tree,calendar,graph', 'views': False, - 'res_id': self.invoice_id.id, + 'res_id': invoice.id, }) return action diff --git a/base_business_document_import/__openerp__.py b/base_business_document_import/__openerp__.py index cf4bf7eed3..833b97709d 100644 --- a/base_business_document_import/__openerp__.py +++ b/base_business_document_import/__openerp__.py @@ -5,7 +5,7 @@ { 'name': 'Base Business Document Import', 'version': '8.0.1.0.0', - 'category': 'Hidden', + 'category': 'Tools', 'license': 'AGPL-3', 'summary': 'Provides technical tools to import sale orders or supplier ' 'invoices', diff --git a/base_business_document_import/models/business_document_import.py b/base_business_document_import/models/business_document_import.py index b22f0f5ead..1360ba0b89 100644 --- a/base_business_document_import/models/business_document_import.py +++ b/base_business_document_import/models/business_document_import.py @@ -18,6 +18,17 @@ class BusinessDocumentImport(models.AbstractModel): _name = 'business.document.import' _description = 'Common methods to import business documents' + @api.model + def _strip_cleanup_dict(self, match_dict): + if match_dict: + for key, value in match_dict.iteritems(): + if value and isinstance(value, (str, unicode)): + match_dict[key] = value.strip() + if match_dict.get('country_code'): + match_dict['country_code'] = match_dict['country_code'].upper() + if match_dict.get('state_code'): + match_dict['state_code'] = match_dict['state_code'].upper() + @api.model def _match_partner( self, partner_dict, chatter_msg, partner_type='supplier'): @@ -29,9 +40,14 @@ def _match_partner( 'email': 'roger.lemaire@akretion.com', 'name': 'Akretion France', 'ref': 'C1242', + 'phone': '01.41.98.12.42', + 'fax': '01.41.98.12.43', } + The keys 'phone' and 'fax' are used by the module + base_phone_business_document_import """ rpo = self.env['res.partner'] + self._strip_cleanup_dict(partner_dict) if partner_dict.get('recordset'): return partner_dict['recordset'] if partner_dict.get('id'): @@ -69,6 +85,11 @@ def _match_partner( '|', ('state_id', '=', False), ('state_id', '=', states[0].id)] + # Hook to plug alternative matching methods + partner = self._hook_match_partner( + partner_dict, chatter_msg, domain, partner_type_label) + if partner: + return partner if partner_dict.get('vat'): vat = partner_dict['vat'].replace(' ', '').upper() # use base_vat_sanitized @@ -79,7 +100,7 @@ def _match_partner( if partners: return partners[0] else: - raise UserError(_( + chatter_msg.append(_( "The analysis of the business document returned '%s' as " "%s VAT number. But there are no %s " "with this VAT number in Odoo.") @@ -139,14 +160,34 @@ def _match_partner( partner_dict.get('ref'), partner_dict.get('name'))) + @api.model + def _hook_match_partner( + self, partner_dict, chatter_msg, domain, partner_type_label): + return False + @api.model def _match_shipping_partner(self, shipping_dict, partner, chatter_msg): + """Example: + shipping_dict = { + 'partner': { + 'email': 'contact@akretion.com', + 'name': 'Akretion France', + }, + 'address': { + 'zip': '69100', + 'country_code': 'FR', + }, + } + The partner argument is a bit special: it is a fallback in case + shipping_dict['partner'] = {} + """ rpo = self.env['res.partner'] if shipping_dict.get('partner'): partner = self._match_partner( shipping_dict['partner'], chatter_msg, partner_type=False) domain = [('parent_id', '=', partner.id)] address_dict = shipping_dict['address'] + self._strip_cleanup_dict(address_dict) country = False if address_dict.get('country_code'): countries = self.env['res.country'].search([ @@ -173,7 +214,7 @@ def _match_shipping_partner(self, shipping_dict, partner, chatter_msg): ('state_id', '=', states[0].id)] if address_dict.get('zip'): domain.append(('zip', '=', address_dict['zip'])) - # TODO: sanitize ZIP ? + # sanitize ZIP ? partners = rpo.search(domain + [('type', '=', 'delivery')]) if partners: partner = partners[0] @@ -184,7 +225,7 @@ def _match_shipping_partner(self, shipping_dict, partner, chatter_msg): return partner @api.model - def _match_product(self, product_dict, chatter_msg, partner=False): + def _match_product(self, product_dict, chatter_msg, seller=False): """Example: product_dict = { 'ean13': '5449000054227', @@ -192,6 +233,7 @@ def _match_product(self, product_dict, chatter_msg, partner=False): } """ ppo = self.env['product.product'] + self._strip_cleanup_dict(product_dict) if product_dict.get('recordset'): return product_dict['recordset'] if product_dict.get('id'): @@ -210,9 +252,9 @@ def _match_product(self, product_dict, chatter_msg, partner=False): return products[0] # WARNING: Won't work for multi-variant products # because product.supplierinfo is attached to product template - if partner: + if seller: sinfo = self.env['product.supplierinfo'].search([ - ('name', '=', partner.id), + ('name', '=', seller.id), ('product_code', '=', product_dict['code']), ]) if ( @@ -230,7 +272,7 @@ def _match_product(self, product_dict, chatter_msg, partner=False): "Supplier: %s\n") % ( product_dict.get('ean13'), product_dict.get('code'), - partner and partner.name or 'None')) + seller and seller.name or 'None')) @api.model def _match_currency(self, currency_dict, chatter_msg): @@ -244,6 +286,7 @@ def _match_currency(self, currency_dict, chatter_msg): if not currency_dict: currency_dict = {} rco = self.env['res.currency'] + self._strip_cleanup_dict(currency_dict) if currency_dict.get('recordset'): return currency_dict['recordset'] if currency_dict.get('id'): @@ -262,13 +305,14 @@ def _match_currency(self, currency_dict, chatter_msg): if currency_dict.get('symbol'): currencies = rco.search( [('symbol', '=', currency_dict['symbol'])]) - if currencies: + if len(currencies) == 1: return currencies[0] else: - raise UserError(_( + chatter_msg.append(_( "The analysis of the business document returned '%s' as " - "the currency symbol. But there are no currency " - "with that symbol in Odoo.") % currency_dict['symbol']) + "the currency symbol. But there are none or several " + "currencies with that symbol in Odoo.") + % currency_dict['symbol']) if currency_dict.get('iso_or_symbol'): currencies = rco.search([ '|', @@ -283,7 +327,7 @@ def _match_currency(self, currency_dict, chatter_msg): "currency with the symbol nor ISO code in Odoo.") % currency_dict['iso_or_symbol']) if currency_dict.get('country_code'): - country_code = currency_dict['country_code'].upper() + country_code = currency_dict['country_code'] countries = self.env['res.country'].search([ ('code', '=', country_code)]) if countries: @@ -320,6 +364,7 @@ def _match_uom(self, uom_dict, chatter_msg, product=False): puo = self.env['product.uom'] if not uom_dict: uom_dict = {} + self._strip_cleanup_dict(uom_dict) if uom_dict.get('recordset'): return uom_dict['recordset'] if uom_dict.get('id'): @@ -382,6 +427,7 @@ def _match_tax( With l10n_fr, it will return 20% VAT tax. """ ato = self.env['account.tax'] + self._strip_cleanup_dict(tax_dict) if tax_dict.get('recordset'): return tax_dict['recordset'] if tax_dict.get('id'): diff --git a/base_business_document_import/tests/__init__.py b/base_business_document_import/tests/__init__.py new file mode 100644 index 0000000000..4f964c4100 --- /dev/null +++ b/base_business_document_import/tests/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import test_business_document_import diff --git a/base_business_document_import/tests/test_business_document_import.py b/base_business_document_import/tests/test_business_document_import.py new file mode 100644 index 0000000000..89df14b8f4 --- /dev/null +++ b/base_business_document_import/tests/test_business_document_import.py @@ -0,0 +1,183 @@ +# -*- coding: utf-8 -*- +# © 2016 Akretion (Alexis de Lattre ) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp.tests.common import TransactionCase + + +class TestFrIntrastatService(TransactionCase): + + def test_match_partner(self): + bdio = self.env['business.document.import'] + partner_dict = {'email': u' Agrolait@yourcompany.example.com'} + res = bdio._match_partner( + partner_dict, [], partner_type='customer') + + self.assertEquals(res, self.env.ref('base.res_partner_2')) + partner_dict = {'name': u'delta pc '} + res = bdio._match_partner( + partner_dict, [], partner_type='supplier') + self.assertEquals(res, self.env.ref('base.res_partner_4')) + + def test_match_shipping_partner(self): + rpo = self.env['res.partner'] + bdio = self.env['business.document.import'] + partner1 = rpo.create({ + 'name': 'Akretion France', + 'street': u'35B rue Montgolfier', + 'zip': '69100', + 'country_id': self.env.ref('base.fr').id, + 'email': 'contact@akretion.com', + }) + cpartner1 = rpo.create({ + 'parent_id': partner1.id, + 'name': u'Alexis de Lattre', + 'email': 'alexis.delattre@akretion.com', + 'use_parent_address': True, + 'type': 'delivery', + }) + rpo.create({ + 'parent_id': partner1.id, + 'name': u'Sébastien BEAU', + 'email': 'sebastien.beau@akretion.com', + 'use_parent_address': True, + 'type': 'default', + }) + cpartner3 = rpo.create({ + 'parent_id': partner1.id, + 'name': 'Flo', + 'email': 'flo@akretion.com', + 'street': "42 rue des lilas d'Espagne", + 'zip': '92400', + 'city': u'Courbevoie', + 'country_id': self.env.ref('base.fr').id, + 'type': 'invoice', + }) + agrolait = self.env.ref('base.res_partner_2') + shipping_dict = { + 'partner': {'email': 'contact@akretion.com'}, + 'address': {}, + } + res = bdio._match_shipping_partner(shipping_dict, agrolait, []) + self.assertEquals(res, cpartner1) + shipping_dict['address'] = { + 'zip': '92400', + 'country_code': 'fr', + } + res = bdio._match_shipping_partner(shipping_dict, agrolait, []) + self.assertEquals(res, cpartner3) + shipping_dict['address']['zip'] = '92500' + res = bdio._match_shipping_partner(shipping_dict, agrolait, []) + self.assertEquals(res, partner1) + shipping_dict = { + 'partner': {}, + 'address': {}, + } + res = bdio._match_shipping_partner(shipping_dict, partner1, []) + self.assertEquals(res, cpartner1) + + def test_match_currency(self): + bdio = self.env['business.document.import'] + currency_dict = {'iso': u'EUR'} + res = bdio._match_currency(currency_dict, []) + self.assertEquals(res, self.env.ref('base.EUR')) + currency_dict = {'symbol': u'€'} + res = bdio._match_currency(currency_dict, []) + self.assertEquals(res, self.env.ref('base.EUR')) + currency_dict = {'country_code': u'fr '} + res = bdio._match_currency(currency_dict, []) + self.assertEquals(res, self.env.ref('base.EUR')) + currency_dict = {'iso_or_symbol': u'€'} + res = bdio._match_currency(currency_dict, []) + self.assertEquals(res, self.env.ref('base.EUR')) + self.env.user.company_id.currency_id = self.env.ref('base.KRW') + currency_dict = {} + res = bdio._match_currency(currency_dict, []) + self.assertEquals(res, self.env.ref('base.KRW')) + + def test_match_product(self): + bdio = self.env['business.document.import'] + ppo = self.env['product.product'] + product1 = ppo.create({ + 'name': u'Test Product', + 'ean13': '9782203121102', + 'seller_ids': [ + (0, 0, { + 'name': self.env.ref('base.res_partner_2').id, + 'product_code': 'TEST1242', + }), + ] + }) + product_dict = {'code': u'A2324 '} + res = bdio._match_product(product_dict, []) + self.assertEquals(res, self.env.ref('product.product_product_4b')) + product_dict = {'ean13': u'9782203121102'} + res = bdio._match_product(product_dict, []) + self.assertEquals(res, product1) + product_dict = {'code': 'TEST1242'} + res = bdio._match_product( + product_dict, [], seller=self.env.ref('base.res_partner_2')) + self.assertEquals(res, product1) + raise_test = True + try: + bdio._match_product(product_dict, [], seller=False) + raise_test = False + except: + pass + self.assertTrue(raise_test) + + def test_match_uom(self): + bdio = self.env['business.document.import'] + uom_dict = {'unece_code': 'KGM'} + res = bdio._match_uom(uom_dict, []) + self.assertEquals(res, self.env.ref('product.product_uom_kgm')) + uom_dict = {'unece_code': 'NIU'} + res = bdio._match_uom(uom_dict, []) + self.assertEquals(res, self.env.ref('product.product_uom_unit')) + uom_dict = {'name': 'day'} + res = bdio._match_uom(uom_dict, []) + self.assertEquals(res, self.env.ref('product.product_uom_day')) + uom_dict = {'name': ' Liter '} + res = bdio._match_uom(uom_dict, []) + self.assertEquals(res, self.env.ref('product.product_uom_litre')) + + def test_match_tax(self): + # on purpose, I use a rate that doesn't exist + # so that this test works even if the l10n_de is installed + de_tax_21 = self.env['account.tax'].create({ + 'name': u'German VAT purchase 18.0%', + 'description': 'DE-VAT-buy-18.0', + 'type_tax_use': 'purchase', + 'price_include': False, + 'amount': 0.18, + 'type': 'percent', + 'unece_type_id': self.env.ref('account_tax_unece.tax_type_vat').id, + 'unece_categ_id': self.env.ref('account_tax_unece.tax_categ_s').id, + }) + de_tax_21_ttc = self.env['account.tax'].create({ + 'name': u'German VAT purchase 18.0% TTC', + 'description': 'DE-VAT-buy-18.0-TTC', + 'type_tax_use': 'purchase', + 'price_include': True, + 'amount': 0.18, + 'type': 'percent', + 'unece_type_id': self.env.ref('account_tax_unece.tax_type_vat').id, + 'unece_categ_id': self.env.ref('account_tax_unece.tax_categ_s').id, + }) + bdio = self.env['business.document.import'] + tax_dict = { + 'type': 'percent', + 'amount': 18, + 'unece_type_code': 'VAT', + 'unece_categ_code': 'S', + } + res = bdio._match_tax(tax_dict, [], type_tax_use='purchase') + self.assertEquals(res, de_tax_21) + tax_dict.pop('unece_categ_code') + res = bdio._match_tax(tax_dict, [], type_tax_use='purchase') + self.assertEquals(res, de_tax_21) + res = bdio._match_tax( + tax_dict, [], type_tax_use='purchase', price_include=True) + self.assertEquals(res, de_tax_21_ttc) + res = bdio._match_taxes([tax_dict], [], type_tax_use='purchase') + self.assertEquals(res, de_tax_21) diff --git a/base_phone_business_document_import/README.rst b/base_phone_business_document_import/README.rst new file mode 100644 index 0000000000..6d1f9e41d8 --- /dev/null +++ b/base_phone_business_document_import/README.rst @@ -0,0 +1,57 @@ +.. 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 + +=================================== +Base Phone Business Document Import +=================================== + +With this module, Odoo will be able to use phone or fax numbers to find the appropriate partner when importing business documents. When the *base_phone* module available on the `OCA connector-telephony project `_ is installed, the phone numbers are stored in E.164 format (for example: +33141983242) in Odoo. This allows reliable search on phone numbers when importing business documents. + +Installation +============ + +This module will be installed automatically if the modules *base_phone* and *base_business_document_import* are installed. + +Configuration +============= + +No configuration needed. + +Usage +===== + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/95/8.0 + +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 +======= + +Contributors +------------ + +* Alexis de Lattre + +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/base_phone_business_document_import/__init__.py b/base_phone_business_document_import/__init__.py new file mode 100644 index 0000000000..cde864bae2 --- /dev/null +++ b/base_phone_business_document_import/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models diff --git a/base_phone_business_document_import/__openerp__.py b/base_phone_business_document_import/__openerp__.py new file mode 100644 index 0000000000..7fb4294c62 --- /dev/null +++ b/base_phone_business_document_import/__openerp__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# © 2016 Akretion (Alexis de Lattre ) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + 'name': 'Base Phone Business Document Import', + 'version': '8.0.1.0.0', + 'category': 'Hidden', + 'license': 'AGPL-3', + 'summary': 'Use phone numbers to match partners upon import of ' + 'business documents', + 'author': 'Akretion,Odoo Community Association (OCA)', + 'website': 'http://www.akretion.com', + 'depends': [ + 'base_phone', + 'base_business_document_import', + ], + 'installable': True, + 'auto_install': True, +} diff --git a/base_phone_business_document_import/models/__init__.py b/base_phone_business_document_import/models/__init__.py new file mode 100644 index 0000000000..4a3c2e6a58 --- /dev/null +++ b/base_phone_business_document_import/models/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import business_document_import diff --git a/base_phone_business_document_import/models/business_document_import.py b/base_phone_business_document_import/models/business_document_import.py new file mode 100644 index 0000000000..612939627e --- /dev/null +++ b/base_phone_business_document_import/models/business_document_import.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# © 2015-2016 Akretion (Alexis de Lattre ) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import models, api +import phonenumbers +import logging + +logger = logging.getLogger(__name__) + + +class BusinessDocumentImport(models.AbstractModel): + _inherit = 'business.document.import' + + @api.model + def _hook_match_partner( + self, partner_dict, chatter_msg, domain, partner_type_label): + rpo = self.env['res.partner'] + if partner_dict.get('country_code') and partner_dict.get('fax'): + fax_num_e164 = False + try: + fax_num = phonenumbers.parse( + partner_dict['fax'], partner_dict['country_code'].upper()) + fax_num_e164 = phonenumbers.format_number( + fax_num, phonenumbers.PhoneNumberFormat.E164) + except: + pass + logger.debug('_hook_match_partner fax_num_e164: %s', fax_num_e164) + if fax_num_e164: + partners = rpo.search([('fax', '=', fax_num_e164)]) + if partners: + return partners[0] + if partner_dict.get('country_code') and partner_dict.get('phone'): + phone_num_e164 = False + try: + phone_num = phonenumbers.parse( + partner_dict['phone'], + partner_dict['country_code'].upper()) + phone_num_e164 = phonenumbers.format_number( + phone_num, phonenumbers.PhoneNumberFormat.E164) + except: + pass + logger.debug( + '_hook_match_partner phone_num_e164: %s', phone_num_e164) + if phone_num_e164: + partners = rpo.search([ + '|', + ('phone', '=', phone_num_e164), + ('mobile', '=', phone_num_e164)]) + if partners: + return partners[0] + return super(BusinessDocumentImport, self)._hook_match_partner( + partner_dict, chatter_msg, domain, partner_type_label) diff --git a/base_phone_business_document_import/tests/__init__.py b/base_phone_business_document_import/tests/__init__.py new file mode 100644 index 0000000000..ae81adb10a --- /dev/null +++ b/base_phone_business_document_import/tests/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import test_phone_partner_match diff --git a/base_phone_business_document_import/tests/test_phone_partner_match.py b/base_phone_business_document_import/tests/test_phone_partner_match.py new file mode 100644 index 0000000000..e5db9aaff2 --- /dev/null +++ b/base_phone_business_document_import/tests/test_phone_partner_match.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# © 2016 Akretion (Alexis de Lattre ) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp.tests.common import TransactionCase + + +class TestPhonePartnerMatch(TransactionCase): + + def test_phone_partner_match(self): + rpo = self.env['res.partner'] + bdoo = self.env['business.document.import'] + partner = rpo.create({ + 'name': u'Alexis de Lattre', + 'country_id': self.env.ref('base.fr').id, + 'supplier': True, + 'phone': '+33141981242', + 'fax': '+33141981243', + }) + partner_dict_phone = { + 'country_code': 'FR', + 'phone': '01.41.98.12.42', + } + res1 = bdoo._match_partner( + partner_dict_phone, [], partner_type='supplier') + self.assertEquals(res1, partner) + partner_dict_fax = { + 'country_code': 'FR', + 'fax': '(0)1-41-98-12-43', + } + res2 = bdoo._match_partner( + partner_dict_fax, [], partner_type='supplier') + self.assertEquals(res2, partner) diff --git a/base_ubl/models/ubl.py b/base_ubl/models/ubl.py index 47104d5a95..c8e255e153 100644 --- a/base_ubl/models/ubl.py +++ b/base_ubl/models/ubl.py @@ -375,10 +375,16 @@ def ubl_parse_party(self, party_node, ns): 'cac:PartyTaxScheme/cbc:CompanyID', namespaces=ns) email_xpath = party_node.xpath( 'cac:Contact/cbc:ElectronicMail', namespaces=ns) + phone_xpath = party_node.xpath( + 'cac:Contact/cbc:Telephone', namespaces=ns) + fax_xpath = party_node.xpath( + 'cac:Contact/cbc:Telefax', namespaces=ns) partner_dict = { 'vat': vat_xpath and vat_xpath[0].text or False, 'name': partner_name_xpath[0].text, 'email': email_xpath and email_xpath[0].text or False, + 'phone': phone_xpath and phone_xpath[0].text or False, + 'fax': fax_xpath and fax_xpath[0].text or False, } address_xpath = party_node.xpath('cac:PostalAddress', namespaces=ns) if address_xpath: @@ -391,14 +397,12 @@ def ubl_parse_address(self, address_node, ns): country_code_xpath = address_node.xpath( 'cac:Country/cbc:IdentificationCode', namespaces=ns) - country_code = country_code_xpath and country_code_xpath[0].text and\ - country_code_xpath[0].text.upper() or False + country_code = country_code_xpath and country_code_xpath[0].text\ + or False state_code_xpath = address_node.xpath( 'cbc:CountrySubentityCode', namespaces=ns) - state_code = state_code_xpath and state_code_xpath[0].text and \ - state_code_xpath[0].text.upper() or False - zip_xpath = address_node.xpath( - 'cbc:PostalZone', namespaces=ns) + state_code = state_code_xpath and state_code_xpath[0].text or False + zip_xpath = address_node.xpath('cbc:PostalZone', namespaces=ns) zip = zip_xpath and zip_xpath[0].text and\ zip_xpath[0].text.replace(' ', '') or False address_dict = {