Browse Source
[ADD] Add base_phone module;it validates phone numbers using the *phonenumbers* Python library.
pull/38/head
[ADD] Add base_phone module;it validates phone numbers using the *phonenumbers* Python library.
pull/38/head
20 changed files with 1692 additions and 0 deletions
-
25base_phone/__init__.py
-
86base_phone/__openerp__.py
-
269base_phone/base_phone.py
-
18base_phone/base_phone_demo.xml
-
35base_phone/controller.py
-
273base_phone/i18n/base_phone.pot
-
273base_phone/i18n/fr.po
-
63base_phone/report_sxw_format.py
-
33base_phone/res_company_view.xml
-
50base_phone/res_partner_view.xml
-
40base_phone/res_users_view.xml
-
2base_phone/security/ir.model.access.csv
-
17base_phone/security/phone_security.xml
-
105base_phone/static/src/js/phone_widget.js
-
51base_phone/static/src/xml/phone.xml
-
23base_phone/wizard/__init__.py
-
129base_phone/wizard/number_not_found.py
-
55base_phone/wizard/number_not_found_view.xml
-
101base_phone/wizard/reformat_all_phonenumbers.py
-
44base_phone/wizard/reformat_all_phonenumbers_view.xml
@ -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 |
@ -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, |
|||
} |
@ -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."), |
|||
] |
@ -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> |
@ -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 |
@ -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 "" |
|||
|
@ -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" |
|||
|
@ -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 |
@ -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> |
@ -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> |
@ -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> |
@ -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 |
@ -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> |
@ -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'); |
|||
|
|||
} |
@ -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> |
@ -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 |
@ -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 |
@ -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> |
@ -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 |
@ -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> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue