From e81c7b46d5f635c49a9514a4fec4d43f716d1493 Mon Sep 17 00:00:00 2001 From: Sylvain Garancher Date: Mon, 17 Oct 2016 09:30:30 +0200 Subject: [PATCH] [MIG] Migrated base_phone to v10.0 (#107) [MIG] Migrated base_phone to v10.0 * Define Phone and Fax as real field types, to avoid the need of defining the widget on each view * [IMP] Add missing ImportError checks for the phonenumbers module --- .travis.yml | 4 - base_phone/README.rst | 2 +- base_phone/__init__.py | 1 + base_phone/__manifest__.py | 4 +- base_phone/controllers/__init__.py | 3 + .../controller.py => controllers/main.py} | 8 +- base_phone/fields.py | 28 ++-- base_phone/models/__init__.py | 1 - base_phone/models/phone_common.py | 14 +- base_phone/models/res_company.py | 13 +- base_phone/models/res_partner.py | 6 +- base_phone/security/phone_security.xml | 14 +- base_phone/static/src/js/phone_widget.js | 155 ++++++++---------- base_phone/static/src/xml/phone.xml | 12 +- base_phone/tests/test_phone.py | 1 - base_phone/views/res_company_view.xml | 33 ++-- base_phone/views/res_partner_view.xml | 30 +--- base_phone/views/res_users_view.xml | 54 +++--- base_phone/web_phone.xml | 18 +- base_phone/wizard/number_not_found.py | 46 +++--- base_phone/wizard/number_not_found_view.xml | 80 +++++---- .../wizard/reformat_all_phonenumbers.py | 2 +- .../wizard/reformat_all_phonenumbers_view.xml | 80 +++++---- 23 files changed, 276 insertions(+), 333 deletions(-) create mode 100644 base_phone/controllers/__init__.py rename base_phone/{models/controller.py => controllers/main.py} (89%) diff --git a/.travis.yml b/.travis.yml index 676fdac..33d405f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,10 +32,6 @@ install: - export PATH=${HOME}/maintainer-quality-tools/travis:${PATH} - travis_install_nightly - pip install phonenumbers py-Asterisk SOAPpy - - hg clone http://bitbucket.org/anybox/web_action_request -b ${VERSION} ${HOME}/web_action_request - - if [ -d /home/travis/${ODOO_REPO##*/}-${VERSION}/addons ]; then ln -s ${HOME}/web_action_request/web_action_request /home/travis/${ODOO_REPO##*/}-${VERSION}/addons; fi - - hg clone http://bitbucket.org/anybox/bus_enhanced -b ${VERSION} ${HOME}/bus_enhanced - - if [ -d /home/travis/${ODOO_REPO##*/}-${VERSION}/addons ]; then ln -s ${HOME}/bus_enhanced/bus_enhanced /home/travis/${ODOO_REPO##*/}-${VERSION}/addons; fi script: - travis_run_tests diff --git a/base_phone/README.rst b/base_phone/README.rst index 646db9d..3283848 100644 --- a/base_phone/README.rst +++ b/base_phone/README.rst @@ -54,7 +54,7 @@ There is no specific usage procedure for this 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_id}/9.0 + :target: https://runbot.odoo-community.org/runbot/228/10.0 Known issues / Roadmap ====================== diff --git a/base_phone/__init__.py b/base_phone/__init__.py index c27d191..cb9f2c6 100644 --- a/base_phone/__init__.py +++ b/base_phone/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from . import fields +from . import controllers from . import models from . import wizard diff --git a/base_phone/__manifest__.py b/base_phone/__manifest__.py index 84da8d5..a2aba3f 100644 --- a/base_phone/__manifest__.py +++ b/base_phone/__manifest__.py @@ -22,7 +22,7 @@ { 'name': 'Base Phone', - 'version': '9.0.0.1.0', + 'version': '10.0.0.1.0', 'category': 'Phone', 'license': 'AGPL-3', 'summary': 'Validate phone numbers', @@ -42,5 +42,5 @@ ], 'qweb': ['static/src/xml/*.xml'], 'images': [], - 'installable': False, + 'installable': True, } diff --git a/base_phone/controllers/__init__.py b/base_phone/controllers/__init__.py new file mode 100644 index 0000000..65a8c12 --- /dev/null +++ b/base_phone/controllers/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import main diff --git a/base_phone/models/controller.py b/base_phone/controllers/main.py similarity index 89% rename from base_phone/models/controller.py rename to base_phone/controllers/main.py index 1fb2edb..deb4238 100644 --- a/base_phone/models/controller.py +++ b/base_phone/controllers/main.py @@ -19,13 +19,11 @@ # ############################################################################## -import openerp +import odoo -class BasePhoneController(openerp.addons.web.http.Controller): - _cp_path = '/base_phone' - - @openerp.addons.web.http.jsonrequest +class BasePhoneController(odoo.http.Controller): + @odoo.http.route('/base_phone', type='json', auth='none') def click2dial(self, req, phone_number, click2dial_model, click2dial_id): res = req.session.model('phone.common').click2dial( phone_number, { diff --git a/base_phone/fields.py b/base_phone/fields.py index 859d50f..6855624 100644 --- a/base_phone/fields.py +++ b/base_phone/fields.py @@ -5,15 +5,19 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from openerp import api, fields, models +from odoo import api, fields, models from operator import attrgetter -import phonenumbers import logging - _logger = logging.getLogger(__name__) +try: + import phonenumbers +except ImportError: + _logger.debug('Cannot `import phonenumbers`.') + -class Phone(fields.Char): +class Fax(fields.Char): + type = 'fax' _slots = { 'country_field': None, @@ -21,9 +25,9 @@ class Phone(fields.Char): } def __init__( - self, string=None, country_field=None, partner_field=None, - **kwargs): - super(Phone, self).__init__( + self, string=fields.Default, country_field=fields.Default, + partner_field=fields.Default, **kwargs): + super(Fax, self).__init__( string=string, country_field=country_field, partner_field=partner_field, **kwargs) @@ -31,13 +35,13 @@ class Phone(fields.Char): _related_partner_field = property(attrgetter('partner_field')) def _setup_regular_full(self, model): - super(Phone, self)._setup_regular_full(model) + super(Fax, self)._setup_regular_full(model) assert self.country_field in model._fields or \ self.partner_field in model._fields, \ "field %s with unknown country_field and partner_field" % self def convert_to_cache(self, value, record, validate=True): - res = super(Phone, self).convert_to_cache( + res = super(Fax, self).convert_to_cache( value, record, validate=validate) # print 'db value', res if res: @@ -53,6 +57,10 @@ class Phone(fields.Char): return res +class Phone(Fax): + type = 'phone' + + def convert_phone_field(value, country_code): _logger.debug( 'convert_phone_field value=%s country=%s', value, country_code) @@ -104,7 +112,7 @@ def convert_all_phone_fields(self, vals, fields_to_convert): def get_phone_fields(self, vals): fields_to_convert = [] for key in vals: - if isinstance(self._fields.get(key), Phone): + if isinstance(self._fields.get(key), Fax): fields_to_convert.append(key) return fields_to_convert diff --git a/base_phone/models/__init__.py b/base_phone/models/__init__.py index 70636f6..0b99d39 100644 --- a/base_phone/models/__init__.py +++ b/base_phone/models/__init__.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- -from . import controller from . import res_company from . import res_partner from . import phone_common diff --git a/base_phone/models/phone_common.py b/base_phone/models/phone_common.py index 8a2a3eb..853484a 100644 --- a/base_phone/models/phone_common.py +++ b/base_phone/models/phone_common.py @@ -2,14 +2,16 @@ # © 2010-2016 Akretion (Alexis de Lattre ) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from openerp import models, api -from openerp.addons.base_phone.fields import Phone +from odoo import models, api +from .. import fields as phone_fields import logging -# Lib for phone number reformating -> pip install phonenumbers -import phonenumbers - _logger = logging.getLogger(__name__) +try: + import phonenumbers +except ImportError: + _logger.debug('Cannot `import phonenumbers`.') + class PhoneCommon(models.AbstractModel): _name = 'phone.common' @@ -102,7 +104,7 @@ class PhoneCommon(models.AbstractModel): for (obj, prio) in phoneobj_sorted: entry = {'object': obj, 'fields': []} for field in obj._fields: - if isinstance(obj._fields[field], Phone): + if isinstance(obj._fields[field], phone_fields.Phone): entry['fields'].append(field) res.append(entry) # [{'fields': ['fax', 'phone', 'mobile'], 'object': res.partner()}, diff --git a/base_phone/models/res_company.py b/base_phone/models/res_company.py index ba4f9f0..f8b76e1 100644 --- a/base_phone/models/res_company.py +++ b/base_phone/models/res_company.py @@ -2,7 +2,8 @@ # © 2016 Akretion (Alexis de Lattre ) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from openerp import models, fields +from odoo import models, fields +from .. import fields as phone_fields class ResCompany(models.Model): @@ -11,15 +12,19 @@ class ResCompany(models.Model): number_of_digits_to_match_from_end = fields.Integer( string='Number of Digits To Match From End', default=8, - help="In several situations, OpenERP will have to find a " + help="In several situations, Odoo will have to find a " "Partner/Lead/Employee/... from a phone number presented by the " "calling party. As the phone numbers presented by your phone " "operator may not always be displayed in a standard format, " "the best method to find the related Partner/Lead/Employee/... " - "in OpenERP is to try to match the end of the phone number in " - "OpenERP with the N last digits of the phone number presented " + "in Odoo is to try to match the end of the phone number in " + "Odoo with the N last digits of the phone number presented " "by the calling party. N is the value you should enter in this " "field.") + phone = phone_fields.Phone( + country_field='country_id', partner_field='partner_id') + fax = phone_fields.Fax( + country_field='country_id', partner_field='partner_id') _sql_constraints = [( 'number_of_digits_to_match_from_end_positive', diff --git a/base_phone/models/res_partner.py b/base_phone/models/res_partner.py index aa56956..feb05e2 100644 --- a/base_phone/models/res_partner.py +++ b/base_phone/models/res_partner.py @@ -3,8 +3,8 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from openerp import models, api -from openerp.addons.base_phone import fields +from odoo import models, api +from .. import fields class ResPartner(models.Model): @@ -14,7 +14,7 @@ class ResPartner(models.Model): phone = fields.Phone(country_field='country_id', partner_field='parent_id') mobile = fields.Phone( country_field='country_id', partner_field='parent_id') - fax = fields.Phone(country_field='country_id', partner_field='parent_id') + fax = fields.Fax(country_field='country_id', partner_field='parent_id') @api.multi def name_get(self): diff --git a/base_phone/security/phone_security.xml b/base_phone/security/phone_security.xml index 627bdad..ead10ca 100644 --- a/base_phone/security/phone_security.xml +++ b/base_phone/security/phone_security.xml @@ -5,13 +5,11 @@ The licence is in the file __openerp__.py --> - - + - - - Phone CallerID - + + + Phone CallerID + - - + diff --git a/base_phone/static/src/js/phone_widget.js b/base_phone/static/src/js/phone_widget.js index b51b2aa..b364417 100644 --- a/base_phone/static/src/js/phone_widget.js +++ b/base_phone/static/src/js/phone_widget.js @@ -3,15 +3,16 @@ The licence is in the file __openerp__.py */ odoo.define('base_phone.phone_widget', function (require) { -"use strict"; + "use strict"; -var core = require('web.core'); -var formwidgets = require('web.form_widgets'); -var web_client = require('web.web_client'); -var _t = core._t; + var core = require('web.core'); + var formwidgets = require('web.form_widgets'); + var web_client = require('web.web_client'); + var _t = core._t; -var FieldPhone = formwidgets.FieldChar.extend({ - template: 'FieldPhone', + var FieldFax = formwidgets.FieldEmail.extend({ + template: 'FieldFax', + prefix: 'fax', initialize_content: function() { this._super(); var $button = this.$el.find('button'); @@ -19,36 +20,45 @@ var FieldPhone = formwidgets.FieldChar.extend({ this.setupFocus($button); }, render_value: function() { - if (!this.get('effective_readonly')) { - this._super(); - } else { - var self = this; + this._super(); + if (this.get("effective_readonly") && this.clickable) { var phone_num = this.get('value'); - // console.log('BASE_PHONE phone_num = %s', phone_num); - var raw_phone_num = ''; - if (phone_num) { - // remove non-breaking-space - raw_phone_num = phone_num.replace(/ /g, ''); - raw_phone_num = raw_phone_num.replace(/-/g, ''); - this.$el.find('a.oe_form_uri').attr('href', 'tel:' + raw_phone_num).text(phone_num); + if(phone_num) { + phone_num = phone_num.replace(/ /g, '').replace(/-/g, ''); + this.$el.attr('href', this.prefix + ':' + phone_num); } - else { - this.$el.find('a.oe_form_uri').attr('href', '').text(''); + } + }, + on_button_clicked: function() { + location.href = this.prefix + ':' + this.get('value'); + } + }); + + var FieldPhone = FieldFax.extend({ + template: 'FieldPhone', + prefix: 'tel', + render_value: function() { + this._super(); + if (this.get("effective_readonly") && this.clickable) { + var self = this; + var phone_num = this.get('value'); + if(phone_num) { + phone_num = phone_num.replace(/ /g, '').replace(/-/g, ''); } var click2dial_text = ''; if (phone_num && !this.options.dial_button_invisible) { - click2dial_text = _t('Dial'); + click2dial_text = _t('Dial'); } this.$el.find('#click2dial').off('click'); this.$el.find('#click2dial') .text(click2dial_text) .on('click', function(ev) { self.do_notify( - _t('Click2dial started'), - _t('Unhook your ringing phone'), - false); + _t('Click2dial started'), + _t('Unhook your ringing phone'), + false); var arg = { - 'phone_number': raw_phone_num, + 'phone_number': phone_num, 'click2dial_model': self.view.dataset.model, 'click2dial_id': self.view.datarecord.id}; self.rpc('/base_phone/click2dial', arg).done(function(r) { @@ -57,15 +67,15 @@ var FieldPhone = formwidgets.FieldChar.extend({ self.do_warn("Click2dial failed"); } else if (typeof r === 'object') { self.do_notify( - _t('Click2dial successfull'), - _t('Number dialed:') + ' ' + r.dialed_number, - false); + _t('Click2dial successfull'), + _t('Number dialed:') + ' ' + r.dialed_number, + false); if (r.action_model) { var context = { 'click2dial_model': self.view.dataset.model, 'click2dial_id': self.view.datarecord.id, - 'phone_number': raw_phone_num, - }; + 'phone_number': phone_num, + }; var action = { name: r.action_name, type: 'ir.actions.act_window', @@ -74,80 +84,47 @@ var FieldPhone = formwidgets.FieldChar.extend({ views: [[false, 'form']], target: 'new', context: context, - }; + }; web_client.action_manager.do_action(action); } } }); }); } - }, - on_button_clicked: function() { - location.href = 'tel:' + this.get('value'); } }); + // To avoid conflicts, we check that widgets do not exist before using + if(!core.form_widget_registry.get('fax')){ + core.form_widget_registry.add('fax', FieldFax); + } -var FieldFax = formwidgets.FieldChar.extend({ - template: 'FieldFax', - initialize_content: function() { - this._super(); - var $button = this.$el.find('button'); - $button.click(this.on_button_clicked); - this.setupFocus($button); - }, - render_value: function() { - if (!this.get('effective_readonly')) { - this._super(); - } else { - var fax_num = this.get('value'); - // console.log('BASE_PHONE fax_num = %s', fax_num); - if (fax_num) { - var raw_fax_num = fax_num.replace(/ /g, ''); - raw_fax_num = raw_fax_num.replace(/-/g, ''); - this.$el.find('a').attr('href', 'fax:' + raw_fax_num).text(fax_num); - } - else { - this.$el.find('a').attr('href', '').text(''); - } - } - }, - on_button_clicked: function() { - location.href = 'fax:' + this.get('value'); - } - }); - -// To avoid conflicts, we check that widgets do not exist before using -if(!core.form_widget_registry.get('fax')){ - core.form_widget_registry.add('fax', FieldFax); -} - -if(!core.form_widget_registry.get('phone')){ - core.form_widget_registry.add('phone', FieldPhone); -} + if(!core.form_widget_registry.get('phone')){ + core.form_widget_registry.add('phone', FieldPhone); + } -var treewidgets = require('web.ListView'); + var treewidgets = require('web.ListView'); -var ColumnPhone = treewidgets.Column.extend({ - // ability to add widget="phone" in TREE view - _format: function(row_data, options) { - var phone_num = row_data[this.id].value; - if (phone_num) { - var raw_phone_num = phone_num.replace(/ /g, ''); - raw_phone_num = raw_phone_num.replace(/-/g, ''); - return _.template("<%-text%>")({ - href: raw_phone_num, - text: phone_num - }); + var ColumnPhone = treewidgets.Column.extend({ + // ability to add widget="phone" in TREE view + _format: function(row_data, options) { + var phone_num = row_data[this.id].value; + if (phone_num) { + var raw_phone_num = phone_num.replace(/ /g, ''); + raw_phone_num = raw_phone_num.replace(/-/g, ''); + return _.template("<%-text%>")({ + href: raw_phone_num, + text: phone_num + }); + } + return this._super(row_data, options); } - return this._super(row_data, options); - } -}); + }); -if (!core.list_widget_registry.get('phone')) { - core.list_widget_registry.add('field.phone', ColumnPhone); -} + if (!core.list_widget_registry.get('phone')) { + core.list_widget_registry.add('field.phone', ColumnPhone); + } }); diff --git a/base_phone/static/src/xml/phone.xml b/base_phone/static/src/xml/phone.xml index af790ff..c975f08 100644 --- a/base_phone/static/src/xml/phone.xml +++ b/base_phone/static/src/xml/phone.xml @@ -7,16 +7,12 @@ - - - this.removeClass('oe_form_field_email').addClass('oe_form_field_phone'); + + - - - - this.removeClass('oe_form_field_email').addClass('oe_form_field_fax'); + + - diff --git a/base_phone/tests/test_phone.py b/base_phone/tests/test_phone.py index 2559c18..18d457a 100644 --- a/base_phone/tests/test_phone.py +++ b/base_phone/tests/test_phone.py @@ -26,7 +26,6 @@ class TestPhone(TransactionCase): partner2 = rpo.create({ 'name': u'Joël Grand-Guillaume', 'parent_id': self.env.ref('base.res_partner_12').id, - 'use_parent_address': True, 'phone': '(0) 21 619 10 10', 'mobile': '(0) 79 606 42 42', }) diff --git a/base_phone/views/res_company_view.xml b/base_phone/views/res_company_view.xml index 9a1e962..896703b 100644 --- a/base_phone/views/res_company_view.xml +++ b/base_phone/views/res_company_view.xml @@ -6,27 +6,20 @@ --> - - - base_phone.company.form - res.company - - - - - - - - - phone + + base_phone.company.form + res.company + + + + + + + + + - - fax - - - - + - diff --git a/base_phone/views/res_partner_view.xml b/base_phone/views/res_partner_view.xml index b58ad6b..c32b340 100644 --- a/base_phone/views/res_partner_view.xml +++ b/base_phone/views/res_partner_view.xml @@ -5,33 +5,9 @@ --> - - - base.phone.res.partner.form - res.partner - - - - fax - - - + + {'search_default_customer': 1, 'raise_if_phone_parse_fails': True} + - - base_phone.phone.widget.partner.tree - res.partner - - - - phone - - - - - - {'search_default_customer': 1, 'raise_if_phone_parse_fails': True} - - - diff --git a/base_phone/views/res_users_view.xml b/base_phone/views/res_users_view.xml index f266e02..a840704 100644 --- a/base_phone/views/res_users_view.xml +++ b/base_phone/views/res_users_view.xml @@ -5,35 +5,33 @@ --> - - - base_phone.res.users.telephony_tab - res.users - - - - - - - - - - - + + base_phone.res.users.telephony_tab + res.users + + + + + + + + + + + - - base_phone.user_preferences.view - res.users - - - - - - - - - + + base_phone.user_preferences.view + res.users + + + + + + + + + - diff --git a/base_phone/web_phone.xml b/base_phone/web_phone.xml index fd37180..029e25b 100644 --- a/base_phone/web_phone.xml +++ b/base_phone/web_phone.xml @@ -5,17 +5,13 @@ --> - + - - - - diff --git a/base_phone/wizard/number_not_found.py b/base_phone/wizard/number_not_found.py index 57b1498..fa63c34 100644 --- a/base_phone/wizard/number_not_found.py +++ b/base_phone/wizard/number_not_found.py @@ -2,39 +2,43 @@ # © 2010-2016 Akretion (Alexis de Lattre ) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from openerp import models, fields, api, _ -from openerp.exceptions import UserError +from odoo import models, fields, api, _ +from .. import fields as phone_fields +from odoo.exceptions import UserError import logging -import phonenumbers - _logger = logging.getLogger(__name__) +try: + import phonenumbers +except ImportError: + _logger.debug('Cannot `import phonenumbers`.') + class NumberNotFound(models.TransientModel): _name = "number.not.found" _description = "Number not found" - calling_number = fields.Char(string='Calling Number', size=64, - readonly=True, - help="Phone number of calling party that has " - "been obtained from the telephony server, in " - "the format used by the telephony server " - "(not E.164).") - e164_number = fields.Char(string='E.164 Number', size=64, - help="E.164 equivalent of the calling number.") + calling_number = fields.Char( + string='Calling Number', size=64, readonly=True, + help="Phone number of calling party that has been obtained from the " + "telephony server, in the format used by the telephony server (not " + "E.164).") + e164_number = fields.Char( + string='E.164 Number', size=64, + help="E.164 equivalent of the calling number.") number_type = fields.Selection(selection=[ ('phone', 'Fixed'), ('mobile', 'Mobile') ], string='Fixed/Mobile', required=True) - to_update_partner_id = fields.Many2one(comodel_name='res.partner', - string='Partner to Update', - help="Partner on which the phone " - "number will be written") - current_partner_phone = fields.Char(related='to_update_partner_id.phone', - string='Current Phone', readonly=True) - current_partner_mobile = fields.Char(related='to_update_partner_id.mobile', - string='Current Mobile', - readonly=True) + to_update_partner_id = fields.Many2one( + comodel_name='res.partner', string='Partner to Update', + help="Partner on which the phone number will be written") + current_partner_phone = phone_fields.Phone( + related='to_update_partner_id.phone', string='Current Phone', + readonly=True) + current_partner_mobile = phone_fields.Phone( + related='to_update_partner_id.mobile', string='Current Mobile', + readonly=True) @api.model def default_get(self, fields_list): diff --git a/base_phone/wizard/number_not_found_view.xml b/base_phone/wizard/number_not_found_view.xml index fc51914..81c9f42 100644 --- a/base_phone/wizard/number_not_found_view.xml +++ b/base_phone/wizard/number_not_found_view.xml @@ -5,49 +5,45 @@ --> - - - - number.not.found.form - number.not.found - -
-
-

- -

-
- - -