Browse Source

[IMP] Migrate base_phone in 9.0

pull/83/head
Alexis de Lattre 9 years ago
committed by Sebastien LANGE
parent
commit
9d27f8ecee
  1. 19
      base_phone/__init__.py
  2. 10
      base_phone/__openerp__.py
  3. 149
      base_phone/base_phone.py
  4. 2
      base_phone/controller.py
  5. 26
      base_phone/res_partner_view.xml
  6. 4
      base_phone/res_users_view.xml
  7. 53
      base_phone/static/src/js/phone_widget.js
  8. 4
      base_phone/static/src/xml/phone.xml
  9. 71
      base_phone/wizard/reformat_all_phonenumbers.py

19
base_phone/__init__.py

@ -1,23 +1,4 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Base Phone module for OpenERP
# Copyright (C) 2014 Alexis de Lattre <alexis@via.ecp.fr>
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import base_phone
from . import wizard

10
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 <alexis@via.ecp.fr>
# Base Phone module for Odoo
# Copyright (C) 2014-2015 Alexis de Lattre <alexis@via.ecp.fr>
#
# 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,
}

149
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 <alexis@via.ecp.fr>
# Base Phone module for Odoo
# Copyright (C) 2010-2015 Alexis de Lattre <alexis@via.ecp.fr>
#
# 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,73 +32,81 @@ _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 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
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 any([vals.get(field) for field in self._phone_fields]):
countrycode = self._get_countrycode_from_vals(vals)
if not countrycode:
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)
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)
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
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 user.company_id.country_id:
countrycode = user.company_id.country_id.code
if self.env.user.company_id.country_id:
countrycode = self.env.user.company_id.country_id.code
else:
_logger.warning(
_logger.error(
"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
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)
vals.get(field), countrycode.upper())
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])
_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
@ -107,10 +115,10 @@ class PhoneCommon(models.AbstractModel):
# 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(
"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))
@ -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):

2
base_phone/controller.py

@ -1,4 +1,4 @@
# -*- encoding: utf-8 -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Base Phone module for Odoo

26
base_phone/res_partner_view.xml

@ -8,40 +8,14 @@
<openerp>
<data>
<record id="view_partner_simple_form" model="ir.ui.view">
<field name="name">base.phone.res.partner.simplified.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_simple_form"/>
<field name="arch" type="xml">
<field name="phone" position="attributes">
<attribute name="widget">phone</attribute>
</field>
<field name="mobile" position="attributes">
<attribute name="widget">phone</attribute>
</field>
</field>
</record>
<record id="view_partner_form" model="ir.ui.view">
<field name="name">base.phone.res.partner.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<xpath expr="//group/group/field[@name='phone']" position="attributes">
<attribute name="widget">phone</attribute>
</xpath>
<xpath expr="//group/group/field[@name='mobile']" position="attributes">
<attribute name="widget">phone</attribute>
</xpath>
<xpath expr="//group/group/field[@name='fax']" position="attributes">
<attribute name="widget">fax</attribute>
</xpath>
<xpath expr="//form[@string='Contact']/sheet/group/field[@name='phone']" position="attributes">
<attribute name="widget">phone</attribute>
</xpath>
<xpath expr="//form[@string='Contact']/sheet/group/field[@name='mobile']" position="attributes">
<attribute name="widget">phone</attribute>
</xpath>
</field>
</record>

4
base_phone/res_users_view.xml

@ -28,11 +28,11 @@
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form_simple_modif" />
<field name="arch" type="xml">
<group string="Email Preferences" position="after">
<xpath expr="//field[@name='email']/.." position="after">
<group name="phone" string="Telephony Preferences" invisible="1">
<!-- Empty group, that is used by other phone modules -->
</group>
</group>
</xpath>
</field>
</record>

53
base_phone/static/src/js/phone_widget.js

@ -1,12 +1,16 @@
/* Base phone module for OpenERP
Copyright (C) 2013-2014 Alexis de Lattre <alexis@via.ecp.fr>
/* Base phone module for Odoo
Copyright (C) 2013-2015 Alexis de Lattre <alexis@via.ecp.fr>
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);
*/
});

4
base_phone/static/src/xml/phone.xml

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Base phone module for OpenERP
Copyright (C) 2013-2014 Alexis de Lattre <alexis@via.ecp.fr>
Base phone module for Odoo
Copyright (C) 2013-2015 Alexis de Lattre <alexis@via.ecp.fr>
The licence is in the file __openerp__.py
-->

71
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
if any([
init_entry_vals.get(field) != entry_vals.get(field) for
field in fields]):
entry.pop('id')
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], {
self.write({
'phonenumbers_not_reformatted': phonenumbers_not_reformatted,
'state': 'done',
}, context=context)
})
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
Loading…
Cancel
Save