diff --git a/base_phone/__init__.py b/base_phone/__init__.py index 36edafc..425df7e 100644 --- a/base_phone/__init__.py +++ b/base_phone/__init__.py @@ -1,23 +1,4 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Base Phone module for OpenERP -# Copyright (C) 2014 Alexis de Lattre -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## from . import base_phone from . import wizard diff --git a/base_phone/__openerp__.py b/base_phone/__openerp__.py index b9b4bd5..ae90138 100644 --- a/base_phone/__openerp__.py +++ b/base_phone/__openerp__.py @@ -1,8 +1,8 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- ############################################################################## # -# Base Phone module for OpenERP -# Copyright (C) 2014 Alexis de Lattre +# Base Phone module for Odoo +# Copyright (C) 2014-2015 Alexis de Lattre # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -22,7 +22,7 @@ { 'name': 'Base Phone', - 'version': '8.0.0.1.0', + 'version': '9.0.0.1.0', 'category': 'Phone', 'license': 'AGPL-3', 'summary': 'Validate phone numbers', @@ -78,5 +78,5 @@ for any help or question about this module. 'qweb': ['static/src/xml/*.xml'], 'test': ['test/phonenum.yml'], 'images': [], - 'installable': False, + 'installable': True, } diff --git a/base_phone/base_phone.py b/base_phone/base_phone.py index 2580168..13db43a 100644 --- a/base_phone/base_phone.py +++ b/base_phone/base_phone.py @@ -1,8 +1,8 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- ############################################################################## # -# Base Phone module for Odoo/OpenERP -# Copyright (C) 2010-2014 Alexis de Lattre +# Base Phone module for Odoo +# Copyright (C) 2010-2015 Alexis de Lattre # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -21,7 +21,7 @@ from openerp import models, fields, api, _ from openerp.tools.safe_eval import safe_eval -from openerp.exceptions import Warning +from openerp.exceptions import UserError import logging # Lib for phone number reformating -> pip install phonenumbers import phonenumbers @@ -32,88 +32,96 @@ _logger = logging.getLogger(__name__) class PhoneCommon(models.AbstractModel): _name = 'phone.common' - def _generic_reformat_phonenumbers( - self, cr, uid, ids, vals, context=None): - """Reformat phone numbers in E.164 format i.e. +33141981242""" - assert isinstance(self._country_field, (str, unicode, type(None))),\ - 'Wrong self._country_field' - assert isinstance(self._partner_field, (str, unicode, type(None))),\ - 'Wrong self._partner_field' + @api.model + def _reformat_phonenumbers_create(self, vals): + assert isinstance(self._phone_fields, list),\ + 'self._phone_fields must be a list' + if any([vals.get(field) for field in self._phone_fields]): + countrycode = self._get_countrycode_from_vals(vals) + countrycode = self._countrycode_fallback(countrycode) + vals = self._reformat_phonenumbers(vals, countrycode) + return vals + + @api.multi + def _reformat_phonenumbers_write(self, vals): assert isinstance(self._phone_fields, list),\ 'self._phone_fields must be a list' - if context is None: - context = {} - if ids and isinstance(ids, (int, long)): - ids = [ids] if any([vals.get(field) for field in self._phone_fields]): - user = self.pool['res.users'].browse(cr, uid, uid, context=context) - # country_id on res.company is a fields.function that looks at - # company_id.partner_id.addres(default).country_id - countrycode = None - if self._country_field: - if vals.get(self._country_field): - country = self.pool['res.country'].browse( - cr, uid, vals[self._country_field], context=context) - countrycode = country.code - elif ids: - rec = self.browse(cr, uid, ids[0], context=context) + countrycode = self._get_countrycode_from_vals(vals) + if not countrycode: + if self._country_field: country = safe_eval( - 'rec.' + self._country_field, {'rec': rec}) + 'self.' + self._country_field, {'self': self}) countrycode = country and country.code or None - elif self._partner_field: - if vals.get(self._partner_field): - partner = self.pool['res.partner'].browse( - cr, uid, vals[self._partner_field], context=context) - countrycode = partner.country_id and\ - partner.country_id.code or None - elif ids: - rec = self.browse(cr, uid, ids[0], context=context) + elif self._partner_field: partner = safe_eval( - 'rec.' + self._partner_field, {'rec': rec}) + 'self.' + self._partner_field, {'self': self}) if partner: countrycode = partner.country_id and\ partner.country_id.code or None - if not countrycode: - if user.company_id.country_id: - countrycode = user.company_id.country_id.code - else: - _logger.warning( - "You should set a country on the company '%s' " - "to allow the reformat of phone numbers", - user.company_id.name) - countrycode = None - if countrycode: - countrycode = countrycode.upper() - # with country code = None, phonenumbers.parse() will work - # with phonenumbers formatted in E164, but will fail with - # phone numbers in national format - for field in self._phone_fields: - if vals.get(field): - init_value = vals.get(field) - try: - res_parse = phonenumbers.parse( - vals.get(field), countrycode) - vals[field] = phonenumbers.format_number( - res_parse, phonenumbers.PhoneNumberFormat.E164) - if init_value != vals[field]: - _logger.debug( - "%s initial value: '%s' updated value: '%s'", - field, init_value, vals[field]) - except Exception, e: - # I do BOTH logger and raise, because: - # raise is usefull when the record is created/written - # by a user via the Web interface - # logger is usefull when the record is created/written - # via the webservices - _logger.error( - "Cannot reformat the phone number '%s' to " - "international format with region=%s" - % (vals.get(field), countrycode)) - if context.get('raise_if_phone_parse_fails'): - raise Warning( - _("Cannot reformat the phone number '%s' to " - "international format. Error message: %s") - % (vals.get(field), e)) + + countrycode = self._countrycode_fallback(countrycode) + vals = self._reformat_phonenumbers(vals, countrycode) + return vals + + @api.model + def _get_countrycode_from_vals(self, vals): + assert isinstance(self._country_field, (str, unicode, type(None))),\ + 'Wrong self._country_field' + assert isinstance(self._partner_field, (str, unicode, type(None))),\ + 'Wrong self._partner_field' + countrycode = None + if self._country_field and vals.get(self._country_field): + country = self.env['res.country'].browse( + vals[self._country_field]) + countrycode = country.code + elif self._partner_field and vals.get(self._partner_field): + partner = self.env['res.partner'].browse( + vals[self._partner_field]) + countrycode = partner.country_id.code or False + return countrycode + + @api.model + def _countrycode_fallback(self, countrycode): + if not countrycode: + if self.env.user.company_id.country_id: + countrycode = self.env.user.company_id.country_id.code + else: + _logger.error( + "You should set a country on the company '%s' " + "to allow the reformat of phone numbers", + self.env.user.company_id.name) + return countrycode + + @api.model + def _reformat_phonenumbers(self, vals, countrycode): + for field in self._phone_fields: + if vals.get(field): + init_value = vals.get(field) + try: + res_parse = phonenumbers.parse( + vals.get(field), countrycode.upper()) + vals[field] = phonenumbers.format_number( + res_parse, phonenumbers.PhoneNumberFormat.E164) + if init_value != vals[field]: + _logger.info( + "%s initial value: '%s' updated value: '%s'" + % (field, init_value, vals[field])) + except Exception, e: + # I do BOTH logger and raise, because: + # raise is usefull when the record is created/written + # by a user via the Web interface + # logger is usefull when the record is created/written + # via the webservices + _logger.error( + "Cannot reformat the phone number '%s' to " + "international format with region=%s", + vals.get(field), countrycode) + if self.env.context.get('raise_if_phone_parse_fails'): + raise UserError( + _("Cannot reformat the phone number '%s' to " + "international format. Error message: %s") + % (vals.get(field), e)) return vals @api.model @@ -198,7 +206,7 @@ class PhoneCommon(models.AbstractModel): def _get_phone_fields(self): '''Returns a dict with key = object name and value = list of phone fields''' - models = self.env['ir.model'].search([('osv_memory', '=', False)]) + models = self.env['ir.model'].search([('transient', '=', False)]) res = [] for model in models: senv = False @@ -212,7 +220,8 @@ class PhoneCommon(models.AbstractModel): res.append(model.model) return res - def click2dial(self, cr, uid, erp_number, context=None): + @api.model + def click2dial(self, erp_number): '''This function is designed to be overridden in IPBX-specific modules, such as asterisk_click2dial or ovh_telephony_connector''' return {'dialed_number': erp_number} @@ -249,26 +258,21 @@ class ResPartner(models.Model): _country_field = 'country_id' _partner_field = None - def create(self, cr, uid, vals, context=None): - vals_reformated = self._generic_reformat_phonenumbers( - cr, uid, None, vals, context=context) - return super(ResPartner, self).create( - cr, uid, vals_reformated, context=context) + @api.model + def create(self, vals): + vals_reformated = self._reformat_phonenumbers_create(vals) + return super(ResPartner, self).create(vals_reformated) - def write(self, cr, uid, ids, vals, context=None): - vals_reformated = self._generic_reformat_phonenumbers( - cr, uid, ids, vals, context=context) - return super(ResPartner, self).write( - cr, uid, ids, vals_reformated, context=context) + @api.multi + def write(self, vals): + vals_reformated = self._reformat_phonenumbers_write(vals) + return super(ResPartner, self).write(vals_reformated) - def name_get(self, cr, uid, ids, context=None): - if context is None: - context = {} - if context.get('callerid'): + @api.multi + def name_get(self): + if self._context.get('callerid'): res = [] - if isinstance(ids, (int, long)): - ids = [ids] - for partner in self.browse(cr, uid, ids, context=context): + for partner in self: if partner.parent_id and partner.parent_id.is_company: name = u'%s (%s)' % (partner.name, partner.parent_id.name) else: @@ -276,8 +280,7 @@ class ResPartner(models.Model): res.append((partner.id, name)) return res else: - return super(ResPartner, self).name_get( - cr, uid, ids, context=context) + return super(ResPartner, self).name_get() class ResCompany(models.Model): diff --git a/base_phone/controller.py b/base_phone/controller.py index 1a90e95..1fb2edb 100644 --- a/base_phone/controller.py +++ b/base_phone/controller.py @@ -1,4 +1,4 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- ############################################################################## # # Base Phone module for Odoo diff --git a/base_phone/res_partner_view.xml b/base_phone/res_partner_view.xml index 28bf5e5..b3b0d22 100644 --- a/base_phone/res_partner_view.xml +++ b/base_phone/res_partner_view.xml @@ -8,40 +8,14 @@ - - base.phone.res.partner.simplified.form - res.partner - - - - phone - - - phone - - - - base.phone.res.partner.form res.partner - - phone - - - phone - fax - - phone - - - phone - diff --git a/base_phone/res_users_view.xml b/base_phone/res_users_view.xml index c9962f7..37043bb 100644 --- a/base_phone/res_users_view.xml +++ b/base_phone/res_users_view.xml @@ -28,11 +28,11 @@ res.users - + - + diff --git a/base_phone/static/src/js/phone_widget.js b/base_phone/static/src/js/phone_widget.js index 2307b4b..0e9a9d2 100644 --- a/base_phone/static/src/js/phone_widget.js +++ b/base_phone/static/src/js/phone_widget.js @@ -1,12 +1,16 @@ -/* Base phone module for OpenERP - Copyright (C) 2013-2014 Alexis de Lattre +/* Base phone module for Odoo + Copyright (C) 2013-2015 Alexis de Lattre The licence is in the file __openerp__.py */ -openerp.base_phone = function (instance) { +odoo.define('base_phone.phone_widget', function (require) { +"use strict"; - var _t = instance.web._t; +var core = require('web.core'); +var formwidgets = require('web.form_widgets'); +var _t = core._t; - instance.base_phone.FieldPhone = instance.web.form.FieldChar.extend({ + +var FieldPhone = formwidgets.FieldChar.extend({ template: 'FieldPhone', initialize_content: function() { this._super(); @@ -20,7 +24,7 @@ openerp.base_phone = function (instance) { } else { var self = this; var phone_num = this.get('value'); - //console.log('BASE_PHONE phone_num = %s', phone_num); + // console.log('BASE_PHONE phone_num = %s', phone_num); var href = '#'; var href_text = ''; if (phone_num) { @@ -50,7 +54,7 @@ openerp.base_phone = function (instance) { 'click2dial_model': self.view.dataset.model, 'click2dial_id': self.view.datarecord.id}; self.rpc('/base_phone/click2dial', arg).done(function(r) { - //console.log('Click2dial r=%s', JSON.stringify(r)); + // console.log('Click2dial r=%s', JSON.stringify(r)); if (r === false) { self.do_warn("Click2dial failed"); } else if (typeof r === 'object') { @@ -72,7 +76,7 @@ openerp.base_phone = function (instance) { target: 'new', context: context, }; - instance.client.action_manager.do_action(action); + formwidgets.client.action_manager.do_action(action); } } }); @@ -84,9 +88,8 @@ openerp.base_phone = function (instance) { } }); - instance.web.form.widgets.add('phone', 'instance.base_phone.FieldPhone'); - instance.base_phone.FieldFax = instance.web.form.FieldChar.extend({ +var FieldFax = formwidgets.FieldChar.extend({ template: 'FieldFax', initialize_content: function() { this._super(); @@ -99,7 +102,7 @@ openerp.base_phone = function (instance) { this._super(); } else { var fax_num = this.get('value'); - //console.log('BASE_PHONE fax_num = %s', fax_num); + // console.log('BASE_PHONE fax_num = %s', fax_num); var href = '#'; var href_text = ''; if (fax_num) { @@ -120,19 +123,31 @@ openerp.base_phone = function (instance) { } }); - instance.web.form.widgets.add('fax', 'instance.base_phone.FieldFax'); +core.form_widget_registry + .add('phone', FieldPhone) + .add('fax', FieldFax); + +/* +var Column = require('web.list_view.js'); - /* ability to add widget="phone" in TREE view */ - var _super_list_char_format_ = instance.web.list.Char.prototype._format; - instance.web.list.Char.prototype._format = function(row_data, options) { - res = _super_list_char_format_.call(this, row_data, options); +var ColumnPhone = Column.extend({ + // ability to add widget="phone" in TREE view + _format: function(row_data, options) { + console.log('row_data=' + row_data); + console.log('options='); + console.log(options); var value = row_data[this.id].value; if (value && this.widget === 'phone') { readable_space = formatInternational('', value); readable_no_break_space = readable_space.replace(/\s/g, ' '); return readable_no_break_space; } - return res; - }; + console.log('return normal'); + return this._super(row_data, options); + } +}); + -}; +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 7c5aae4..71711b5 100644 --- a/base_phone/static/src/xml/phone.xml +++ b/base_phone/static/src/xml/phone.xml @@ -1,7 +1,7 @@ diff --git a/base_phone/wizard/reformat_all_phonenumbers.py b/base_phone/wizard/reformat_all_phonenumbers.py index 7cc28c0..65b229b 100644 --- a/base_phone/wizard/reformat_all_phonenumbers.py +++ b/base_phone/wizard/reformat_all_phonenumbers.py @@ -19,13 +19,13 @@ # ############################################################################## -from openerp import models, fields +from openerp import models, fields, api import logging logger = logging.getLogger(__name__) -class reformat_all_phonenumbers(models.TransientModel): +class ReformatAllPhonenumbers(models.TransientModel): _name = "reformat.all.phonenumbers" _inherit = "res.config.installer" _description = "Reformat all phone numbers" @@ -37,18 +37,18 @@ class reformat_all_phonenumbers(models.TransientModel): ('done', 'Done'), ], string='State', default='draft') - def run_reformat_all_phonenumbers(self, cr, uid, ids, context=None): + @api.multi + def run_reformat_all_phonenumbers(self): + self.ensure_one() logger.info('Starting to reformat all the phone numbers') - phonenumbers_not_reformatted = '' - phoneobjects = self.pool['phone.common']._get_phone_fields( - cr, uid, context=context) - ctx_raise = dict(context, raise_if_phone_parse_fails=True) + phonenumbers_not_reformatted = u'' + phoneobjects = self.env['phone.common']._get_phone_fields() for objname in phoneobjects: - fields = self.pool[objname]._phone_fields - obj = self.pool[objname] + fields = self.env[objname]._phone_fields + obj = self.env[objname] logger.info( 'Starting to reformat phone numbers on object %s ' - '(fields = %s)' % (objname, fields)) + '(fields = %s)', objname, fields) # search if this object has an 'active' field if obj._columns.get('active') or objname == 'hr.employee': # hr.employee inherits from 'resource.resource' and @@ -58,46 +58,47 @@ class reformat_all_phonenumbers(models.TransientModel): domain = ['|', ('active', '=', True), ('active', '=', False)] else: domain = [] - all_ids = obj.search(cr, uid, domain, context=context) - for entry in obj.read( - cr, uid, all_ids, fields, context=context): - init_entry = entry.copy() + all_entries = obj.search(domain) + + for entry in all_entries: + print "entry=", entry + init_entry_vals = {} + for field in fields: + init_entry_vals[field] = entry[field] + print "init_entry=", init_entry_vals + entry_vals = init_entry_vals.copy() # entry is _updated_ by the fonction # _generic_reformat_phonenumbers() try: - obj._generic_reformat_phonenumbers( - cr, uid, [entry['id']], entry, context=ctx_raise) + entry.with_context(raise_if_phone_parse_fails=True).\ + _reformat_phonenumbers_write(entry_vals) except Exception, e: - name = obj.name_get( - cr, uid, [init_entry['id']], context=context)[0][1] + name = entry.name_get()[0][1] phonenumbers_not_reformatted += \ "Problem on %s '%s'. Error message: %s\n" % ( obj._description, name, unicode(e)) logger.warning( - "Problem on %s '%s'. Error message: %s" % ( - obj._description, name, unicode(e))) + "Problem on %s '%s'. Error message: %s", + obj._description, name, unicode(e)) continue - if any( - [init_entry.get(field) != entry.get(field) for - field in fields]): - entry.pop('id') + if any([ + init_entry_vals.get(field) != entry_vals.get(field) for + field in fields]): + print "entry_vals=", entry_vals logger.info( - '[%s] Reformating phone number: FROM %s TO %s' % ( - obj._description, unicode(init_entry), - unicode(entry))) - obj.write( - cr, uid, init_entry['id'], entry, context=context) + '[%s] Reformating phone number: FROM %s TO %s', + obj._description, unicode(init_entry_vals), + unicode(entry_vals)) + entry.write(entry_vals) if not phonenumbers_not_reformatted: phonenumbers_not_reformatted = \ 'All phone numbers have been reformatted successfully.' - self.write( - cr, uid, ids[0], { - 'phonenumbers_not_reformatted': phonenumbers_not_reformatted, - 'state': 'done', - }, context=context) + self.write({ + 'phonenumbers_not_reformatted': phonenumbers_not_reformatted, + 'state': 'done', + }) logger.info('End of the phone number reformatting wizard') - action = self.pool['ir.actions.act_window'].for_xml_id( - cr, uid, 'base_phone', 'reformat_all_phonenumbers_action', - context=context) - action['res_id'] = ids[0] + action = self.env['ir.actions.act_window'].for_xml_id( + 'base_phone', 'reformat_all_phonenumbers_action') + action['res_id'] = self.id return action