Browse Source

[ADD] Add base_phone module;it validates phone numbers using the *phonenumbers* Python library.

pull/38/head
EL HADJI DEM 11 years ago
parent
commit
c95456c68c
  1. 25
      base_phone/__init__.py
  2. 86
      base_phone/__openerp__.py
  3. 269
      base_phone/base_phone.py
  4. 18
      base_phone/base_phone_demo.xml
  5. 35
      base_phone/controller.py
  6. 273
      base_phone/i18n/base_phone.pot
  7. 273
      base_phone/i18n/fr.po
  8. 63
      base_phone/report_sxw_format.py
  9. 33
      base_phone/res_company_view.xml
  10. 50
      base_phone/res_partner_view.xml
  11. 40
      base_phone/res_users_view.xml
  12. 2
      base_phone/security/ir.model.access.csv
  13. 17
      base_phone/security/phone_security.xml
  14. 105
      base_phone/static/src/js/phone_widget.js
  15. 51
      base_phone/static/src/xml/phone.xml
  16. 23
      base_phone/wizard/__init__.py
  17. 129
      base_phone/wizard/number_not_found.py
  18. 55
      base_phone/wizard/number_not_found_view.xml
  19. 101
      base_phone/wizard/reformat_all_phonenumbers.py
  20. 44
      base_phone/wizard/reformat_all_phonenumbers_view.xml

25
base_phone/__init__.py

@ -0,0 +1,25 @@
# -*- 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
from . import report_sxw_format
from . import controller

86
base_phone/__openerp__.py

@ -0,0 +1,86 @@
# -*- encoding: 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/>.
#
##############################################################################
{
'name': 'Base Phone',
'version': '0.1',
'category': 'Phone',
'license': 'AGPL-3',
'summary': 'Validate phone numbers',
'description': """
Base Phone
==========
This module validates phone numbers using the *phonenumbers* Python library,
which is a port of the library used in Android smartphones. For example,
if your user is linked to a French company and you update the form
view of a partner with a badly written French phone number
such as '01-55-42-12-42', Odoo will automatically update the phone number
to E.164 format '+33155421242' and display in the form view of the partner
the readable equivalent '+33 1 55 42 12 42'.
This module also adds *tel:* links on phone numbers and *fax:* links on fax
numbers. If you have a softphone or a client software on your PC
that is associated with *tel:* links, the softphone should propose
you to dial the phone number when you click on such a link.
This module also updates the format() function for reports
and adds 2 arguments :
* *phone* : should be True for a phone number, False (default) otherwize.
* *phone_format* : it can have 3 possible values :
* *international* (default) : the report will display '+33 1 55 42 12 42'
* *national* : the report will display '01 55 42 12 42'
* *e164* : the report will display '+33155421242'
For example, in the Sale Order report, to display the phone
number of the Salesman, you can write : o.user_id and o.user_id.phone
and format(o.user_id.phone, phone=True, phone_format='national') or ''
This module is independant from the Asterisk connector.
Please contact Alexis de Lattre from Akretion <alexis.delattre@akretion.com>
for any help or question about this module.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com/',
'depends': ['base', 'web'],
'external_dependencies': {'python': ['phonenumbers']},
'data': [
'security/phone_security.xml',
'security/ir.model.access.csv',
'res_partner_view.xml',
'res_company_view.xml',
'res_users_view.xml',
'wizard/reformat_all_phonenumbers_view.xml',
'wizard/number_not_found_view.xml',
],
'js': [
'static/src/js/*.js',
'static/lib/js/*.js',
],
'qweb': ['static/src/xml/*.xml'],
'demo': ['base_phone_demo.xml'],
'images': [],
'installable': True,
'active': False,
}

269
base_phone/base_phone.py

@ -0,0 +1,269 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Base Phone module for Odoo/OpenERP
# Copyright (C) 2010-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 openerp.osv import orm, fields
from openerp.tools.translate import _
import logging
# Lib for phone number reformating -> pip install phonenumbers
import phonenumbers
_logger = logging.getLogger(__name__)
class phone_common(orm.AbstractModel):
_name = 'phone.common'
def generic_phonenumber_to_e164(
self, cr, uid, ids, field_from_to_seq, context=None):
result = {}
from_field_seq = [item[0] for item in field_from_to_seq]
for record in self.read(cr, uid, ids, from_field_seq, context=context):
result[record['id']] = {}
for fromfield, tofield in field_from_to_seq:
if not record.get(fromfield):
res = False
else:
try:
res = phonenumbers.format_number(
phonenumbers.parse(record.get(fromfield), None),
phonenumbers.PhoneNumberFormat.E164)
except Exception, e:
_logger.error(
"Cannot reformat the phone number '%s' to E.164 "
"format. Error message: %s"
% (record.get(fromfield), e))
_logger.error(
"You should fix this number and run the wizard "
"'Reformat all phone numbers' from the menu "
"Settings > Configuration > Phones")
# If I raise an exception here, it won't be possible to
# install the module on a DB with bad phone numbers
res = False
result[record['id']][tofield] = res
return result
def _generic_reformat_phonenumbers(
self, cr, uid, vals,
phonefields=[
'phone', 'partner_phone', 'work_phone', 'fax',
'mobile', 'partner_mobile', 'mobile_phone',
],
context=None):
"""Reformat phone numbers in E.164 format i.e. +33141981242"""
if any([vals.get(field) for field in phonefields]):
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
if user.company_id.country_id:
user_countrycode = user.company_id.country_id.code
else:
# We need to raise an exception here because, if we pass None
# as second arg of phonenumbers.parse(), it will raise an
# exception when you try to enter a phone number in
# national format... so it's better to raise the exception here
raise orm.except_orm(
_('Error:'),
_("You should set a country on the company '%s'")
% user.company_id.name)
for field in phonefields:
if vals.get(field):
init_value = vals.get(field)
try:
res_parse = phonenumbers.parse(
vals.get(field), user_countrycode)
except Exception, e:
raise orm.except_orm(
_('Error:'),
_("Cannot reformat the phone number '%s' to "
"international format. Error message: %s")
% (vals.get(field), e))
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]))
return vals
def get_name_from_phone_number(
self, cr, uid, presented_number, context=None):
'''Function to get name from phone number. Usefull for use from IPBX
to add CallerID name to incoming calls.'''
res = self.get_record_from_phone_number(
cr, uid, presented_number, context=context)
if res:
return res[2]
else:
return False
def get_record_from_phone_number(
self, cr, uid, presented_number, context=None):
'''If it finds something, it returns (object name, ID, record name)
For example : ('res.partner', 42, u'Alexis de Lattre (Akretion)')
'''
if context is None:
context = {}
ctx_phone = context.copy()
ctx_phone['callerid'] = True
_logger.debug(
u"Call get_name_from_phone_number with number = %s"
% presented_number)
if not isinstance(presented_number, (str, unicode)):
_logger.warning(
u"Number '%s' should be a 'str' or 'unicode' but it is a '%s'"
% (presented_number, type(presented_number)))
return False
if not presented_number.isdigit():
_logger.warning(
u"Number '%s' should only contain digits." % presented_number)
user = self.pool['res.users'].browse(cr, uid, uid, context=context)
nr_digits_to_match_from_end = \
user.company_id.number_of_digits_to_match_from_end
if len(presented_number) >= nr_digits_to_match_from_end:
end_number_to_match = presented_number[
-nr_digits_to_match_from_end:len(presented_number)]
else:
end_number_to_match = presented_number
phonefieldsdict = self._get_phone_fields(cr, uid, context=context)
phonefieldslist = []
for objname, prop in phonefieldsdict.iteritems():
if prop.get('get_name_sequence'):
phonefieldslist.append({objname: prop})
phonefieldslist_sorted = sorted(
phonefieldslist,
key=lambda element: element.values()[0]['get_name_sequence'])
for phonedict in phonefieldslist_sorted:
objname = phonedict.keys()[0]
prop = phonedict.values()[0]
phonefields = prop['phonefields']
obj = self.pool[objname]
pg_search_number = str('%' + end_number_to_match)
_logger.debug(
"Will search phone and mobile numbers in %s ending with '%s'"
% (objname, end_number_to_match))
domain = []
for phonefield in phonefields:
domain.append((phonefield, 'like', pg_search_number))
if len(phonefields) > 1:
domain = ['|'] * (len(phonefields) - 1) + domain
res_ids = obj.search(cr, uid, domain, context=context)
if len(res_ids) > 1:
_logger.warning(
u"There are several %s (IDS = %s) with a phone number "
"ending with '%s'. Taking the first one."
% (objname, res_ids, end_number_to_match))
if res_ids:
name = obj.name_get(
cr, uid, res_ids[0], context=ctx_phone)[0][1]
res = (objname, res_ids[0], name)
_logger.debug(
u"Answer get_record_from_phone_number: (%s, %d, %s)"
% (res[0], res[1], res[2]))
return res
else:
_logger.debug(
u"No match on %s for end of phone number '%s'"
% (objname, end_number_to_match))
return False
def _get_phone_fields(self, cr, uid, context=None):
'''Returns a dict with key = object name
and value = list of phone fields'''
res = {
'res.partner': {
'phonefields': ['phone', 'mobile'],
'faxfields': ['fax'],
'get_name_sequence': 10,
},
}
return res
def click2dial(self, cr, uid, erp_number, context=None):
'''This function is designed to be overridden in IPBX-specific
modules, such as asterisk_click2dial'''
return {'dialed_number': erp_number}
class res_partner(orm.Model):
_name = 'res.partner'
_inherit = ['res.partner', 'phone.common']
def create(self, cr, uid, vals, context=None):
vals_reformated = self._generic_reformat_phonenumbers(
cr, uid, vals, context=context)
return super(res_partner, self).create(
cr, uid, vals_reformated, context=context)
def write(self, cr, uid, ids, vals, context=None):
vals_reformated = self._generic_reformat_phonenumbers(
cr, uid, vals, context=context)
return super(res_partner, self).write(
cr, uid, ids, vals_reformated, context=context)
def name_get(self, cr, uid, ids, context=None):
if context is None:
context = {}
if context.get('callerid'):
res = []
if isinstance(ids, (int, long)):
ids = [ids]
for partner in self.browse(cr, uid, ids, context=context):
if partner.parent_id and partner.parent_id.is_company:
name = u'%s (%s)' % (partner.name, partner.parent_id.name)
else:
name = partner.name
res.append((partner.id, name))
return res
else:
return super(res_partner, self).name_get(
cr, uid, ids, context=context)
class res_company(orm.Model):
_inherit = 'res.company'
_columns = {
'number_of_digits_to_match_from_end': fields.integer(
'Number of Digits To Match From End',
help="In several situations, OpenERP 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 "
"by the calling party. N is the value you should enter in this "
"field."),
}
_defaults = {
'number_of_digits_to_match_from_end': 8,
}
_sql_constraints = [(
'number_of_digits_to_match_from_end_positive',
'CHECK (number_of_digits_to_match_from_end > 0)',
"The value of the field 'Number of Digits To Match From End' must "
"be positive."),
]

18
base_phone/base_phone_demo.xml

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2014 Alexis de Lattre
@author Alexis de Lattre <alexis@via.ecp.fr>
The licence is in the file __openerp__.py
-->
<openerp>
<data noupdate="1">
<!-- I need a country on the company, because otherwize it raises an error -->
<record id="base.main_company" model="res.company">
<field name="country_id" ref="base.fr"/>
</record>
</data>
</openerp>

35
base_phone/controller.py

@ -0,0 +1,35 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Asterisk click2dial 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/>.
#
##############################################################################
import openerp
class BasePhoneController(openerp.addons.web.http.Controller):
_cp_path = '/base_phone'
@openerp.addons.web.http.jsonrequest
def click2dial(self, req, phone_number, click2dial_model, click2dial_id):
res = req.session.model('phone.common').click2dial(
phone_number, {
'click2dial_model': click2dial_model,
'click2dial_id': click2dial_id,
})
return res

273
base_phone/i18n/base_phone.pot

@ -0,0 +1,273 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * base_phone
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-08-25 21:28+0000\n"
"PO-Revision-Date: 2014-08-25 21:28+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: base_phone
#: view:reformat.all.phonenumbers:0
msgid "Cancel"
msgstr ""
#. module: base_phone
#: code:addons/base_phone/base_phone.py:95
#, python-format
msgid "Cannot reformat the phone number '%s' to international format. Error message: %s"
msgstr ""
#. module: base_phone
#. openerp-web
#: code:addons/base_phone/static/src/js/phone_widget.js:34
#, python-format
msgid "Click2dial started"
msgstr ""
#. module: base_phone
#. openerp-web
#: code:addons/base_phone/static/src/js/phone_widget.js:46
#, python-format
msgid "Click2dial successfull"
msgstr ""
#. module: base_phone
#: view:number.not.found:0
msgid "Close"
msgstr ""
#. module: base_phone
#: model:ir.model,name:base_phone.model_res_company
msgid "Companies"
msgstr ""
#. module: base_phone
#: code:addons/base_phone/wizard/number_not_found.py:85
#, python-format
msgid "Create New Partner"
msgstr ""
#. module: base_phone
#: view:number.not.found:0
msgid "Create Partner with this Number"
msgstr ""
#. module: base_phone
#: view:number.not.found:0
msgid "Create or Update a Partner"
msgstr ""
#. module: base_phone
#: field:number.not.found,current_partner_mobile:0
msgid "Current Mobile"
msgstr ""
#. module: base_phone
#: field:number.not.found,current_partner_phone:0
msgid "Current Phone"
msgstr ""
#. module: base_phone
#. openerp-web
#: code:addons/base_phone/static/src/js/phone_widget.js:31
#, python-format
msgid "Dial"
msgstr ""
#. module: base_phone
#: field:number.not.found,e164_number:0
msgid "E.164 Number"
msgstr ""
#. module: base_phone
#: help:number.not.found,e164_number:0
msgid "E.164 equivalent of the calling number."
msgstr ""
#. module: base_phone
#: view:res.users:0
msgid "Email Preferences"
msgstr ""
#. module: base_phone
#: code:addons/base_phone/base_phone.py:83
#: code:addons/base_phone/base_phone.py:94
#: code:addons/base_phone/wizard/number_not_found.py:99
#, python-format
msgid "Error:"
msgstr ""
#. module: base_phone
#: selection:number.not.found,number_type:0
msgid "Fixed"
msgstr ""
#. module: base_phone
#: field:number.not.found,number_type:0
msgid "Fixed/Mobile"
msgstr ""
#. module: base_phone
#: help:res.company,number_of_digits_to_match_from_end:0
msgid "In several situations, OpenERP 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 by the calling party. N is the value you should enter in this field."
msgstr ""
#. module: base_phone
#: selection:number.not.found,number_type:0
msgid "Mobile"
msgstr ""
#. module: base_phone
#: view:number.not.found:0
msgid "Number Not Found"
msgstr ""
#. module: base_phone
#: view:number.not.found:0
msgid "Number converted to international format:"
msgstr ""
#. module: base_phone
#. openerp-web
#: code:addons/base_phone/static/src/js/phone_widget.js:47
#, python-format
msgid "Number dialed:"
msgstr ""
#. module: base_phone
#: model:ir.model,name:base_phone.model_number_not_found
msgid "Number not found"
msgstr ""
#. module: base_phone
#: view:number.not.found:0
msgid "Number not found:"
msgstr ""
#. module: base_phone
#: field:res.company,number_of_digits_to_match_from_end:0
msgid "Number of Digits To Match From End"
msgstr ""
#. module: base_phone
#: model:ir.model,name:base_phone.model_res_partner
msgid "Partner"
msgstr ""
#. module: base_phone
#: code:addons/base_phone/wizard/number_not_found.py:105
#, python-format
msgid "Partner: %s"
msgstr ""
#. module: base_phone
#: view:res.company:0
msgid "Phone"
msgstr ""
#. module: base_phone
#: model:res.groups,name:base_phone.group_callerid
msgid "Phone CallerID"
msgstr ""
#. module: base_phone
#: field:reformat.all.phonenumbers,phonenumbers_not_reformatted:0
msgid "Phone numbers that couldn't be reformatted"
msgstr ""
#. module: base_phone
#: view:reformat.all.phonenumbers:0
msgid "Phone numbers that couldn't be reformatted:"
msgstr ""
#. module: base_phone
#: model:ir.actions.act_window,name:base_phone.reformat_all_phonenumbers_action
#: model:ir.ui.menu,name:base_phone.reformat_all_phonenumbers_menu
msgid "Reformat Phone Numbers"
msgstr ""
#. module: base_phone
#: model:ir.model,name:base_phone.model_reformat_all_phonenumbers
#: view:reformat.all.phonenumbers:0
msgid "Reformat all phone numbers"
msgstr ""
#. module: base_phone
#: code:addons/base_phone/wizard/number_not_found.py:100
#, python-format
msgid "Select the Partner to Update."
msgstr ""
#. module: base_phone
#: model:ir.ui.menu,name:base_phone.menu_config_phone
#: view:res.users:0
msgid "Telephony"
msgstr ""
#. module: base_phone
#: view:res.users:0
msgid "Telephony Preferences"
msgstr ""
#. module: base_phone
#: sql_constraint:res.company:0
msgid "The value of the field 'Number of Digits To Match From End' must be positive."
msgstr ""
#. module: base_phone
#: view:reformat.all.phonenumbers:0
msgid "This wizard reformats the phone, mobile and fax numbers of all partners in standard international format e.g. +33141981242"
msgstr ""
#. module: base_phone
#. openerp-web
#: code:addons/base_phone/static/src/js/phone_widget.js:35
#, python-format
msgid "Unhook your ringing phone"
msgstr ""
#. module: base_phone
#: view:number.not.found:0
msgid "Update Partner with this Number"
msgstr ""
#. module: base_phone
#: constraint:res.partner:0
msgid "You cannot create recursive Partner hierarchies."
msgstr ""
#. module: base_phone
#: code:addons/base_phone/base_phone.py:84
#, python-format
msgid "You should set a country on the company '%s'"
msgstr ""
#. module: base_phone
#: model:ir.model,name:base_phone.model_base_phone_installed
msgid "base.phone.installed"
msgstr ""
#. module: base_phone
#: view:res.partner:0
msgid "fax"
msgstr ""
#. module: base_phone
#: view:res.partner:0
msgid "phone"
msgstr ""
#. module: base_phone
#: model:ir.model,name:base_phone.model_phone_common
msgid "phone.common"
msgstr ""

273
base_phone/i18n/fr.po

@ -0,0 +1,273 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * base_phone
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-08-25 21:29+0000\n"
"PO-Revision-Date: 2014-08-25 21:29+0000\n"
"Last-Translator: Alexis de Lattre <alexis.delattre@akretion.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: base_phone
#: view:reformat.all.phonenumbers:0
msgid "Cancel"
msgstr "Annuler"
#. module: base_phone
#: code:addons/base_phone/base_phone.py:95
#, python-format
msgid "Cannot reformat the phone number '%s' to international format. Error message: %s"
msgstr "Impossible de reformatter le numéro de téléphone '%s' au format international. Message d'erreur : %s"
#. module: base_phone
#. openerp-web
#: code:addons/base_phone/static/src/js/phone_widget.js:34
#, python-format
msgid "Click2dial started"
msgstr "Début du Click2dial"
#. module: base_phone
#. openerp-web
#: code:addons/base_phone/static/src/js/phone_widget.js:46
#, python-format
msgid "Click2dial successfull"
msgstr "Click2dial réussi"
#. module: base_phone
#: view:number.not.found:0
msgid "Close"
msgstr "Fermer"
#. module: base_phone
#: model:ir.model,name:base_phone.model_res_company
msgid "Companies"
msgstr "Sociétés"
#. module: base_phone
#: code:addons/base_phone/wizard/number_not_found.py:85
#, python-format
msgid "Create New Partner"
msgstr "Créer un nouveau partenaire"
#. module: base_phone
#: view:number.not.found:0
msgid "Create Partner with this Number"
msgstr "Créer un partenaire avec ce numéro"
#. module: base_phone
#: view:number.not.found:0
msgid "Create or Update a Partner"
msgstr "Créer ou mettre à jour un partenaire"
#. module: base_phone
#: field:number.not.found,current_partner_mobile:0
msgid "Current Mobile"
msgstr "Portable actuel"
#. module: base_phone
#: field:number.not.found,current_partner_phone:0
msgid "Current Phone"
msgstr "Téléphone actuel"
#. module: base_phone
#. openerp-web
#: code:addons/base_phone/static/src/js/phone_widget.js:31
#, python-format
msgid "Dial"
msgstr "Composer"
#. module: base_phone
#: field:number.not.found,e164_number:0
msgid "E.164 Number"
msgstr "Numéro E.164"
#. module: base_phone
#: help:number.not.found,e164_number:0
msgid "E.164 equivalent of the calling number."
msgstr "Equivalent au format E.164 du numéro appelant."
#. module: base_phone
#: view:res.users:0
msgid "Email Preferences"
msgstr "Préférences de messagerie électronique"
#. module: base_phone
#: code:addons/base_phone/base_phone.py:83
#: code:addons/base_phone/base_phone.py:94
#: code:addons/base_phone/wizard/number_not_found.py:99
#, python-format
msgid "Error:"
msgstr "Erreur :"
#. module: base_phone
#: selection:number.not.found,number_type:0
msgid "Fixed"
msgstr "Fixe"
#. module: base_phone
#: field:number.not.found,number_type:0
msgid "Fixed/Mobile"
msgstr "Fixe/Portable"
#. module: base_phone
#: help:res.company,number_of_digits_to_match_from_end:0
msgid "In several situations, OpenERP 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 by the calling party. N is the value you should enter in this field."
msgstr "In several situations, OpenERP 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 by the calling party. N is the value you should enter in this field."
#. module: base_phone
#: selection:number.not.found,number_type:0
msgid "Mobile"
msgstr "Portable"
#. module: base_phone
#: view:number.not.found:0
msgid "Number Not Found"
msgstr "Numéro introuvable"
#. module: base_phone
#: view:number.not.found:0
msgid "Number converted to international format:"
msgstr "Numéro converti au format international :"
#. module: base_phone
#. openerp-web
#: code:addons/base_phone/static/src/js/phone_widget.js:47
#, python-format
msgid "Number dialed:"
msgstr "Numéro composé :"
#. module: base_phone
#: model:ir.model,name:base_phone.model_number_not_found
msgid "Number not found"
msgstr "Numéro introuvable"
#. module: base_phone
#: view:number.not.found:0
msgid "Number not found:"
msgstr "Numéro introuvable :"
#. module: base_phone
#: field:res.company,number_of_digits_to_match_from_end:0
msgid "Number of Digits To Match From End"
msgstr "Nombre de chiffres à faire correspondre en partant de la fin"
#. module: base_phone
#: model:ir.model,name:base_phone.model_res_partner
msgid "Partner"
msgstr "Partenaire"
#. module: base_phone
#: code:addons/base_phone/wizard/number_not_found.py:105
#, python-format
msgid "Partner: %s"
msgstr "Partenaire : %s"
#. module: base_phone
#: view:res.company:0
msgid "Phone"
msgstr "Téléphone"
#. module: base_phone
#: model:res.groups,name:base_phone.group_callerid
msgid "Phone CallerID"
msgstr "CallerID du téléphone"
#. module: base_phone
#: field:reformat.all.phonenumbers,phonenumbers_not_reformatted:0
msgid "Phone numbers that couldn't be reformatted"
msgstr "Numéros de téléphone qui n'ont pas pu être reformatés"
#. module: base_phone
#: view:reformat.all.phonenumbers:0
msgid "Phone numbers that couldn't be reformatted:"
msgstr "Numéros de téléphone qui n'ont pas pu être reformatés :"
#. module: base_phone
#: model:ir.actions.act_window,name:base_phone.reformat_all_phonenumbers_action
#: model:ir.ui.menu,name:base_phone.reformat_all_phonenumbers_menu
msgid "Reformat Phone Numbers"
msgstr "Reformate les numéros de téléphone"
#. module: base_phone
#: model:ir.model,name:base_phone.model_reformat_all_phonenumbers
#: view:reformat.all.phonenumbers:0
msgid "Reformat all phone numbers"
msgstr "Reformate tous les numéros de téléphone"
#. module: base_phone
#: code:addons/base_phone/wizard/number_not_found.py:100
#, python-format
msgid "Select the Partner to Update."
msgstr "Selectionnez le partenaire à mettre à jour."
#. module: base_phone
#: model:ir.ui.menu,name:base_phone.menu_config_phone
#: view:res.users:0
msgid "Telephony"
msgstr "Téléphonie"
#. module: base_phone
#: view:res.users:0
msgid "Telephony Preferences"
msgstr "Préférences téléphoniques"
#. module: base_phone
#: sql_constraint:res.company:0
msgid "The value of the field 'Number of Digits To Match From End' must be positive."
msgstr "The value of the field 'Number of Digits To Match From End' must be positive."
#. module: base_phone
#: view:reformat.all.phonenumbers:0
msgid "This wizard reformats the phone, mobile and fax numbers of all partners in standard international format e.g. +33141981242"
msgstr "Cet assistant reformate le numéro de téléphone fixe, portable et le fax de tous les partenaires au format standard international i.e. +33141981242"
#. module: base_phone
#. openerp-web
#: code:addons/base_phone/static/src/js/phone_widget.js:35
#, python-format
msgid "Unhook your ringing phone"
msgstr "Décrochez votre téléphone"
#. module: base_phone
#: view:number.not.found:0
msgid "Update Partner with this Number"
msgstr "Mettre à jour le partenaire avec ce numéro"
#. module: base_phone
#: constraint:res.partner:0
msgid "You cannot create recursive Partner hierarchies."
msgstr "You cannot create recursive Partner hierarchies."
#. module: base_phone
#: code:addons/base_phone/base_phone.py:84
#, python-format
msgid "You should set a country on the company '%s'"
msgstr "Vous devez renseigner un pays pour la société '%s'"
#. module: base_phone
#: model:ir.model,name:base_phone.model_base_phone_installed
msgid "base.phone.installed"
msgstr "base.phone.installed"
#. module: base_phone
#: view:res.partner:0
msgid "fax"
msgstr "fax"
#. module: base_phone
#: view:res.partner:0
msgid "phone"
msgstr "phone"
#. module: base_phone
#: model:ir.model,name:base_phone.model_phone_common
msgid "phone.common"
msgstr "phone.common"

63
base_phone/report_sxw_format.py

@ -0,0 +1,63 @@
# -*- encoding: 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 openerp.osv import orm
from openerp.report import report_sxw
import phonenumbers
class base_phone_installed(orm.AbstractModel):
'''When you use monkey patching, the code is executed when the module
is in the addons_path of the OpenERP server, even is the module is not
installed ! In order to avoid the side-effects it can create,
we create an AbstractModel inside the module and we test the
availability of this Model in the code of the monkey patching below.
At Akretion, we call this the "Guewen trick", in reference
to a trick used by Guewen Baconnier in the "connector" module.
'''
_name = "base.phone.installed"
format_original = report_sxw.rml_parse.format
def format(
self, text, oldtag=None, phone=False, phone_format='international'):
if self.pool.get('base.phone.installed') and phone and text:
# text should already be in E164 format, so we don't have
# to give a country code to phonenumbers.parse()
phone_number = phonenumbers.parse(text)
if phone_format == 'international':
res = phonenumbers.format_number(
phone_number, phonenumbers.PhoneNumberFormat.INTERNATIONAL)
elif phone_format == 'national':
res = phonenumbers.format_number(
phone_number, phonenumbers.PhoneNumberFormat.NATIONAL)
elif phone_format == 'e164':
res = phonenumbers.format_number(
phone_number, phonenumbers.PhoneNumberFormat.E164)
else:
res = text
else:
res = format_original(self, text, oldtag=oldtag)
return res
report_sxw.rml_parse.format = format

33
base_phone/res_company_view.xml

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2014 Akretion (http://www.akretion.com/)
@author Alexis de Lattre <alexis.delattre@akretion.com>
The licence is in the file __openerp__.py
-->
<openerp>
<data>
<record id="view_company_form" model="ir.ui.view">
<field name="name">base_phone.company.form</field>
<field name="model">res.company</field>
<field name="inherit_id" ref="base.view_company_form" />
<field name="arch" type="xml">
<group name="account_grp" position="after">
<group name="phone" string="Phone">
<field name="number_of_digits_to_match_from_end" />
</group>
</group>
<field name="phone" position="attributes">
<attribute name="widget">phone</attribute>
</field>
<field name="fax" position="attributes">
<attribute name="widget">fax</attribute>
</field>
</field>
</record>
</data>
</openerp>

50
base_phone/res_partner_view.xml

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Base Phone module for OpenERP
Copyright (C) 2010-2014 Alexis de Lattre <alexis@via.ecp.fr>
The licence is in the file __openerp__.py
-->
<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>
</data>
</openerp>

40
base_phone/res_users_view.xml

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Base Phone module for OpenERP
Copyright (C) 2010-2014 Alexis de Lattre <alexis@via.ecp.fr>
The licence is in the file __openerp__.py
-->
<openerp>
<data>
<record id="view_users_form" model="ir.ui.view">
<field name="name">base_phone.res.users.telephony_tab</field>
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form"/>
<field name="arch" type="xml">
<notebook>
<page string="Telephony" name="phone" invisible="1" position="inside">
<!-- Empty page, which will be used by other phone modules -->
<group name="phone-preferences" string="Telephony Preferences">
</group>
</page>
</notebook>
</field>
</record>
<record id="view_users_form_simple_modif" model="ir.ui.view">
<field name="name">base_phone.user_preferences.view</field>
<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">
<group name="phone" string="Telephony Preferences" invisible="1">
<!-- Empty group, that is used by other phone modules -->
</group>
</group>
</field>
</record>
</data>
</openerp>

2
base_phone/security/ir.model.access.csv

@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
callerid_res_partner_read,Read access on res.partner,base.model_res_partner,group_callerid,1,0,0,0

17
base_phone/security/phone_security.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Base Phone module for Odoo/OpenERP
Copyright (C) 2010-2014 Alexis de Lattre <alexis@via.ecp.fr>
The licence is in the file __openerp__.py
-->
<openerp>
<data noupdate="1">
<!-- New group dedicated to the "Get CallerID name from OpenERP" feature -->
<record id="group_callerid" model="res.groups">
<field name="name">Phone CallerID</field>
</record>
</data>
</openerp>

105
base_phone/static/src/js/phone_widget.js

@ -0,0 +1,105 @@
/* Base phone module for OpenERP
Copyright (C) 2013-2014 Alexis de Lattre <alexis@via.ecp.fr>
The licence is in the file __openerp__.py */
openerp.base_phone = function (instance) {
var _t = instance.web._t;
instance.base_phone.FieldPhone = instance.web.form.FieldChar.extend({
template: 'FieldPhone',
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 self = this;
var phone_num = this.get('value');
//console.log('BASE_PHONE phone_num = %s', phone_num);
if (phone_num) {
this.$el.find('a.oe_form_uri')
.attr('href', 'tel:' + phone_num)
.text(formatInternational('', phone_num) || '');
}
if (phone_num && !this.options.dial_button_invisible) {
this.$el.find('#click2dial')
.text(phone_num && _t('Dial') || '')
.on('click', function(ev) {
self.do_notify(
_t('Click2dial started'),
_t('Unhook your ringing phone'));
var arg = {
'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) {
//console.log('Click2dial r=%s', JSON.stringify(r));
if (r === false) {
self.do_warn("Click2dial failed");
} else if (typeof r === 'object') {
self.do_notify(
_t('Click2dial successfull'),
_t('Number dialed:') + ' ' + r.dialed_number);
if (r.action_model) {
var context = {};
if (self.view.dataset.model == 'res.partner') {
context = {
'partner_id': self.view.datarecord.id};
}
var action = {
name: r.action_name,
type: 'ir.actions.act_window',
res_model: r.action_model,
view_mode: 'form',
views: [[false, 'form']],
target: 'new',
context: context,
};
instance.client.action_manager.do_action(action);
}
}
});
});
}
}
},
on_button_clicked: function() {
location.href = 'tel:' + this.get('value');
}
});
instance.web.form.widgets.add('phone', 'instance.base_phone.FieldPhone');
instance.base_phone.FieldFax = instance.web.form.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');
if (fax_num) {
this.$el.find('a.oe_form_uri')
.attr('href', 'fax:' + fax_num)
.text(formatInternational('', fax_num) || '');
}
}
},
on_button_clicked: function() {
location.href = 'fax:' + this.get('value');
}
});
instance.web.form.widgets.add('fax', 'instance.base_phone.FieldFax');
}

51
base_phone/static/src/xml/phone.xml

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Base phone module for OpenERP
Copyright (C) 2013-2014 Alexis de Lattre <alexis@via.ecp.fr>
The licence is in the file __openerp__.py
-->
<templates id="template" xml:space="preserve">
<t t-name="FieldPhone">
<span class="oe_form_field oe_form_field_email" t-att-style="widget.node.attrs.style">
<t t-if="widget.get('effective_readonly')">
<a href="#" class="oe_form_uri"/>
<!--
You should add the following "<a .. />" in your IPBX-specific
module (such as asterisk_click2dial) via <t t-extend="FieldPhone">
<a id="click2dial" href="#" class="oe_bold"/>
-->
</t>
<t t-if="!widget.get('effective_readonly')">
<div>
<input type="text"
t-att-id="widget.id_for_label"
t-att-tabindex="widget.node.attrs.tabindex"
t-att-autofocus="widget.node.attrs.autofocus"
t-att-placeholder="widget.node.attrs.placeholder"
t-att-maxlength="widget.field.size"
/>
</div>
</t>
</span>
</t>
<t t-name="FieldFax">
<span class="oe_form_field oe_form_field_email" t-att-style="widget.node.attrs.style">
<a t-if="widget.get('effective_readonly')" href="#" class="oe_form_uri"/>
<t t-if="!widget.get('effective_readonly')">
<div>
<input type="text"
t-att-id="widget.id_for_label"
t-att-tabindex="widget.node.attrs.tabindex"
t-att-autofocus="widget.node.attrs.autofocus"
t-att-placeholder="widget.node.attrs.placeholder"
t-att-maxlength="widget.field.size"
/>
</div>
</t>
</span>
</t>
</templates>

23
base_phone/wizard/__init__.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Base Phone module for OpenERP
# Copyright (C) 2012-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 reformat_all_phonenumbers
from . import number_not_found

129
base_phone/wizard/number_not_found.py

@ -0,0 +1,129 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Asterisk Click2dial module for OpenERP
# Copyright (C) 2010-2013 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 openerp.osv import orm, fields
from openerp.tools.translate import _
import logging
import phonenumbers
_logger = logging.getLogger(__name__)
class number_not_found(orm.TransientModel):
_name = "number.not.found"
_description = "Number not found"
_columns = {
'calling_number': fields.char(
'Calling Number', size=64, readonly=True,
help="Phone number of calling party that has been obtained "
"from Asterisk, in the format used by Asterisk (not E.164)."),
'e164_number': fields.char(
'E.164 Number', size=64,
help="E.164 equivalent of the calling number."),
'number_type': fields.selection(
[('phone', 'Fixed'), ('mobile', 'Mobile')],
'Fixed/Mobile', required=True),
'to_update_partner_id': fields.many2one(
'res.partner', 'Partner to Update',
help="Partner on which the phone number will be written"),
'current_partner_phone': fields.related(
'to_update_partner_id', 'phone', type='char',
relation='res.partner', string='Current Phone', readonly=True),
'current_partner_mobile': fields.related(
'to_update_partner_id', 'mobile', type='char',
relation='res.partner', string='Current Mobile', readonly=True),
}
def default_get(self, cr, uid, fields_list, context=None):
res = super(number_not_found, self).default_get(
cr, uid, fields_list, context=context)
if not res:
res = {}
if res.get('calling_number'):
convert = self.pool['phone.common']._generic_reformat_phonenumbers(
cr, uid, {'phone': res.get('calling_number')}, context=context)
parsed_num = phonenumbers.parse(convert.get('phone'))
res['e164_number'] = phonenumbers.format_number(
parsed_num, phonenumbers.PhoneNumberFormat.INTERNATIONAL)
number_type = phonenumbers.number_type(parsed_num)
if number_type == 1:
res['number_type'] = 'mobile'
else:
res['number_type'] = 'phone'
return res
def create_partner(self, cr, uid, ids, context=None):
'''Function called by the related button of the wizard'''
if context is None:
context = {}
wiz = self.browse(cr, uid, ids[0], context=context)
parsed_num = phonenumbers.parse(wiz.e164_number, None)
context['default_%s' % wiz.number_type] = wiz.e164_number
action = {
'name': _('Create New Partner'),
'view_mode': 'form,tree,kanban',
'res_model': 'res.partner',
'type': 'ir.actions.act_window',
'nodestroy': False,
'target': 'current',
'context': context,
}
return action
def update_partner(self, cr, uid, ids, context=None):
wiz = self.browse(cr, uid, ids[0], context=context)
if not wiz.to_update_partner_id:
raise orm.except_orm(
_('Error:'),
_("Select the Partner to Update."))
self.pool['res.partner'].write(
cr, uid, wiz.to_update_partner_id.id,
{wiz.number_type: wiz.e164_number}, context=context)
action = {
'name': _('Partner: %s' % wiz.to_update_partner_id.name),
'type': 'ir.actions.act_window',
'res_model': 'res.partner',
'view_mode': 'form,tree,kanban',
'nodestroy': False,
'target': 'current',
'res_id': wiz.to_update_partner_id.id,
'context': context,
}
return action
def onchange_to_update_partner(
self, cr, uid, ids, to_update_partner_id, context=None):
res = {'value': {}}
if to_update_partner_id:
to_update_partner = self.pool['res.partner'].browse(
cr, uid, to_update_partner_id, context=context)
res['value'].update({
'current_partner_phone': to_update_partner.phone,
'current_partner_mobile': to_update_partner.mobile,
})
else:
res['value'].update({
'current_partner_phone': False,
'current_partner_mobile': False,
})
return res

55
base_phone/wizard/number_not_found_view.xml

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Asterisk Click2dial module for OpenERP
Copyright (C) 2012-2013 Alexis de Lattre <alexis@via.ecp.fr>
The licence is in the file __openerp__.py
-->
<openerp>
<data>
<record id="number_not_found_form" model="ir.ui.view">
<field name="name">number.not.found.form</field>
<field name="model">number.not.found</field>
<field name="arch" type="xml">
<form string="Number Not Found" version="7.0">
<div class="oe_title">
<label string="Number not found:" for="calling_number"/>
<h1>
<field name="calling_number" />
</h1>
<label string="Number converted to international format:"
for="e164_number"/>
<h2>
<field name="e164_number" />
</h2>
<label for="number_type"/>
<h3>
<field name="number_type"/>
</h3>
</div>
<group colspan="4" col="2" name="create-update">
<group name="partner" string="Create or Update a Partner"
colspan="1" col="2">
<button name="create_partner" icon="gtk-new" colspan="2"
string="Create Partner with this Number" type="object"/>
<field name="to_update_partner_id"
on_change="onchange_to_update_partner(to_update_partner_id)"/>
<field name="current_partner_phone" widget="phone"
options="{'dial_button_invisible': True}"/>
<field name="current_partner_mobile" widget="phone"
options="{'dial_button_invisible': True}"/>
<button name="update_partner" icon="gtk-convert" colspan="2"
string="Update Partner with this Number" type="object"/>
</group>
</group>
<footer>
<button special="cancel" string="Close" class="oe_link"/>
</footer>
</form>
</field>
</record>
</data>
</openerp>

101
base_phone/wizard/reformat_all_phonenumbers.py

@ -0,0 +1,101 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Base Phone module for OpenERP
# Copyright (C) 2012-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 openerp.osv import orm, fields
import logging
logger = logging.getLogger(__name__)
class reformat_all_phonenumbers(orm.TransientModel):
_name = "reformat.all.phonenumbers"
_description = "Reformat all phone numbers"
_columns = {
'phonenumbers_not_reformatted': fields.text(
"Phone numbers that couldn't be reformatted"),
}
def run_reformat_all_phonenumbers(self, cr, uid, ids, context=None):
logger.info('Starting to reformat all the phone numbers')
phonenumbers_not_reformatted = ''
toreformat_dict = self.pool['phone.common']._get_phone_fields(
cr, uid, context=context)
for objname, prop in toreformat_dict.iteritems():
fields = []
obj = self.pool[objname]
if prop.get('phonefields'):
fields += prop['phonefields']
if prop.get('faxfields'):
fields += prop['faxfields']
logger.info(
'Starting to reformat phone numbers on object %s '
'(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
# 'resource.resource' has an active field
# As I don't know how to detect such cases, I hardcode it here
# If you know a better solution, please tell me
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()
# entry is _updated_ by the fonction
# _generic_reformat_phonenumbers()
try:
obj._generic_reformat_phonenumbers(
cr, uid, entry, context=context)
except Exception, e:
name = obj.name_get(
cr, uid, [init_entry['id']], context=context)[0][1]
phonenumbers_not_reformatted += \
"Problem on %s '%s'. Error message: %s\n" % (
obj._description,
name, e[1])
logger.warning(
"Problem on %s '%s'. Error message: %s" % (
obj._description,
name, e[1]))
continue
if any(
[init_entry.get(field)
!= entry.get(field) for field
in fields]):
entry.pop('id')
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)
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},
context=context)
logger.info('End of the phone number reformatting wizard')
return True

44
base_phone/wizard/reformat_all_phonenumbers_view.xml

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Base Phone module for OpenERP
Copyright (C) 2012-2013 Alexis de Lattre <alexis@via.ecp.fr>
The licence is in the file __openerp__.py
-->
<openerp>
<data>
<record id="reformat_all_phonenumbers_form" model="ir.ui.view">
<field name="name">reformat_all_phonenumbers.form</field>
<field name="model">reformat.all.phonenumbers</field>
<field name="arch" type="xml">
<form string="Reformat all phone numbers" version="7.0">
<!-- TODO : add a "state" and display fields accordingly -->
<group name="main">
<label string="This wizard reformats the phone, mobile and fax numbers of all partners in standard international format e.g. +33141981242" colspan="4"/>
<label colspan="4" string="Phone numbers that couldn't be reformatted:"/>
<field name="phonenumbers_not_reformatted" colspan="4" nolabel="1"/>
</group>
<footer>
<button name="run_reformat_all_phonenumbers" string="Reformat all phone numbers" type="object" class="oe_highlight"/>
<button special="cancel" string="Cancel" class="oe_link" />
</footer>
</form>
</field>
</record>
<record id="reformat_all_phonenumbers_action" model="ir.actions.act_window">
<field name="name">Reformat Phone Numbers</field>
<field name="res_model">reformat.all.phonenumbers</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<!-- Menu entry under Settings > Technical -->
<menuitem id="menu_config_phone" name="Telephony" parent="base.menu_custom"/>
<menuitem id="reformat_all_phonenumbers_menu" action="reformat_all_phonenumbers_action" parent="menu_config_phone" sequence="100"/>
</data>
</openerp>
Loading…
Cancel
Save