Browse Source
Merge pull request #88 from akretion/9-full-port
Merge pull request #88 from akretion/9-full-port
[revolution] Port from 8 to 9 + new fields.Phone archipull/103/head
Alexis de Lattre
8 years ago
committed by
GitHub
80 changed files with 1616 additions and 3386 deletions
-
6.travis.yml
-
19asterisk_click2dial/__init__.py
-
47asterisk_click2dial/__openerp__.py
-
539asterisk_click2dial/asterisk_click2dial.py
-
69asterisk_click2dial/asterisk_click2dial_demo.xml
-
21asterisk_click2dial/asterisk_server_view.xml
-
37asterisk_click2dial/controller.py
-
1asterisk_click2dial/requirements.txt
-
21asterisk_click2dial/res_users_view.xml
-
6asterisk_click2dial/scripts/set_name_agi.py
-
5asterisk_click2dial/static/src/css/asterisk_click2dial.css
-
139asterisk_click2dial/static/src/js/asterisk_click2dial.js
-
5asterisk_click2dial/static/src/xml/asterisk_click2dial.xml
-
11asterisk_click2dial/web_asterisk_click2dial.xml
-
21asterisk_click2dial_crm/__init__.py
-
48asterisk_click2dial_crm/__openerp__.py
-
1base_phone/README.rst
-
5base_phone/__init__.py
-
7base_phone/__openerp__.py
-
307base_phone/base_phone.py
-
137base_phone/fields.py
-
6base_phone/models/__init__.py
-
0base_phone/models/controller.py
-
139base_phone/models/phone_common.py
-
28base_phone/models/res_company.py
-
31base_phone/models/res_partner.py
-
63base_phone/report_sxw_format.py
-
1397base_phone/static/lib/phonenumbers/PhoneFormat.js
-
77base_phone/static/src/js/phone_widget.js
-
48base_phone/static/src/xml/phone.xml
-
50base_phone/test/phonenum.yml
-
3base_phone/tests/__init__.py
-
55base_phone/tests/test_phone.py
-
9base_phone/views/res_company_view.xml
-
11base_phone/views/res_partner_view.xml
-
9base_phone/views/res_users_view.xml
-
11base_phone/web_phone.xml
-
68base_phone/wizard/number_not_found.py
-
12base_phone/wizard/number_not_found_view.xml
-
62base_phone/wizard/reformat_all_phonenumbers.py
-
19base_phone_popup/__init__.py
-
33base_phone_popup/__openerp__.py
-
68base_phone_popup/popup.py
-
8base_phone_popup/res_users_view.xml
-
19crm_claim_phone/__init__.py
-
47crm_claim_phone/crm_claim_phone.py
-
9crm_claim_phone/crm_claim_view.xml
-
19crm_phone/__init__.py
-
40crm_phone/__openerp__.py
-
199crm_phone/crm_phone.py
-
59crm_phone/demo/crm_phonecall.xml
-
3crm_phone/security/ir.model.access.csv
-
28crm_phone/security/phonecall_security.xml
-
41crm_phone/test/phonenum.yml
-
3crm_phone/tests/__init__.py
-
46crm_phone/tests/test_crm_phone.py
-
55crm_phone/view/crm_lead.xml
-
160crm_phone/view/crm_phonecall.xml
-
30crm_phone/view/res_partner.xml
-
9crm_phone/view/res_users.xml
-
19crm_phone/wizard/__init__.py
-
47crm_phone/wizard/create_crm_phonecall.py
-
96crm_phone/wizard/number_not_found.py
-
20crm_phone/wizard/number_not_found_view.xml
-
19event_phone/__init__.py
-
29event_phone/__openerp__.py
-
47event_phone/event_phone.py
-
23event_phone/event_view.xml
-
19hr_phone/__init__.py
-
30hr_phone/__openerp__.py
-
48hr_phone/hr_phone.py
-
10hr_phone/hr_view.xml
-
1hr_phone/security/ir.model.access.csv
-
19hr_recruitment_phone/__init__.py
-
30hr_recruitment_phone/__openerp__.py
-
62hr_recruitment_phone/hr_recruitment_phone.py
-
10hr_recruitment_phone/hr_recruitment_view.xml
-
19ovh_telephony_connector/__init__.py
-
4ovh_telephony_connector/__openerp__.py
-
24ovh_telephony_connector/ovh_connector.py
@ -1,23 +1,4 @@ |
|||
# -*- coding: 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 . import asterisk_click2dial |
|||
from . import controller |
@ -1,38 +1,41 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<!-- |
|||
Asterisk Click2dial module for OpenERP |
|||
Copyright (C) 2010-2012 Alexis de Lattre <alexis@via.ecp.fr> |
|||
The licence is in the file __openerp__.py |
|||
|
|||
Demo data for the click2dial module |
|||
© 2010-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
--> |
|||
|
|||
<openerp> |
|||
<data noupdate="1"> |
|||
<record id="demo_ast_server" model="asterisk.server"> |
|||
<field name="name">Akretion Asterisk IPBX</field> |
|||
<field name="ip_address">asterisk.akretion.com</field> |
|||
<field name="login">click2dial</field> |
|||
<field name="password">mypassword</field> |
|||
<field name="context">from-internal</field> |
|||
<field name="alert_info">info=<Bellcore-dr5></field> |
|||
<field name="company_id" ref="base.main_company" /> |
|||
</record> |
|||
<record id="base.user_root" model="res.users"> |
|||
<field name="internal_number">11</field> |
|||
<field name="resource">11</field> |
|||
<field name="callerid">Administrator <0141981242></field> |
|||
<field name="asterisk_server_id" ref="demo_ast_server"/> |
|||
</record> |
|||
<record id="base.user_demo" model="res.users"> |
|||
<field name="internal_number">12</field> |
|||
<field name="resource">12</field> |
|||
<field name="callerid">Demo user <0141984212></field> |
|||
<field name="asterisk_server_id" ref="demo_ast_server"/> |
|||
</record> |
|||
<record id="base.main_partner" model="res.partner"> |
|||
<field name="country_id" ref="base.fr"/> |
|||
</record> |
|||
</data> |
|||
</openerp> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
|
|||
|
|||
<record id="demo_ast_server" model="asterisk.server"> |
|||
<field name="name">Akretion Asterisk IPBX</field> |
|||
<field name="ip_address">asterisk.akretion.com</field> |
|||
<field name="login">odoo</field> |
|||
<field name="password">mypassword</field> |
|||
<field name="context">from-internal</field> |
|||
<field name="alert_info">info=<Bellcore-dr5></field> |
|||
<field name="company_id" ref="base.main_company" /> |
|||
</record> |
|||
|
|||
<record id="base.user_root" model="res.users"> |
|||
<field name="internal_number">11</field> |
|||
<field name="resource">11</field> |
|||
<field name="callerid">Administrator <0141981242></field> |
|||
<field name="asterisk_server_id" ref="demo_ast_server"/> |
|||
</record> |
|||
|
|||
<record id="base.user_demo" model="res.users"> |
|||
<field name="internal_number">12</field> |
|||
<field name="resource">12</field> |
|||
<field name="callerid">Demo user <0141984212></field> |
|||
<field name="asterisk_server_id" ref="demo_ast_server"/> |
|||
</record> |
|||
|
|||
<record id="base.main_partner" model="res.partner"> |
|||
<field name="country_id" ref="base.fr"/> |
|||
</record> |
|||
|
|||
|
|||
</data> |
|||
</odoo> |
@ -1,31 +1,16 @@ |
|||
# -*- 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/>. |
|||
# |
|||
############################################################################## |
|||
# -*- coding: utf-8 -*- |
|||
# © 2014-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
|||
# © 2015-2016 Juris Malinens (port to v9) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
import openerp |
|||
from openerp import http |
|||
|
|||
|
|||
class AsteriskClick2dialController(openerp.addons.web.http.Controller): |
|||
_cp_path = '/asterisk_click2dial' |
|||
class AsteriskClick2dialController(http.Controller): |
|||
|
|||
@openerp.addons.web.http.jsonrequest |
|||
def get_record_from_my_channel(self, req): |
|||
res = req.session.model('asterisk.server').get_record_from_my_channel() |
|||
@http.route( |
|||
'/asterisk_click2dial/get_record_from_my_channel/', |
|||
type='json', auth='public') |
|||
def get_record_from_my_channel(self, **kw): |
|||
res = http.request.env['asterisk.server'].get_record_from_my_channel() |
|||
return res |
@ -1,2 +1 @@ |
|||
phonenumbers |
|||
py-Asterisk |
@ -1,73 +1,96 @@ |
|||
/* Asterisk_click2dial module for OpenERP |
|||
Copyright (C) 2014 Alexis de Lattre <alexis@via.ecp.fr> |
|||
The licence is in the file __openerp__.py */ |
|||
/* © 2014-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
|||
© 2015-2016 Juris Malinens (port to v9) |
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
|
|||
|
|||
openerp.asterisk_click2dial = function (instance) { |
|||
odoo.define('asterisk_click2dial.click2dial', function (require) { |
|||
"use strict"; |
|||
|
|||
var _t = instance.web._t; |
|||
var UserMenu = require('web.UserMenu'); |
|||
var WebClient = require('web.WebClient'); |
|||
var web_client = require('web.web_client'); |
|||
var Widget = require('web.Widget'); |
|||
var core = require('web.core'); |
|||
var _t = core._t; |
|||
|
|||
instance.web.OpenCaller = instance.web.Widget.extend({ |
|||
template:'asterisk_click2dial.OpenCaller', |
|||
var click2dial = {}; |
|||
|
|||
start: function () { |
|||
this.$('#asterisk-open-caller').on( |
|||
'click', this.on_open_caller); |
|||
this._super(); |
|||
}, |
|||
click2dial.OpenCaller = Widget.extend({ |
|||
template: 'asterisk_click2dial.OpenCaller', |
|||
|
|||
start: function () { |
|||
this.$('#asterisk-open-caller').on( |
|||
'click', this.on_open_caller); |
|||
this._super(); |
|||
}, |
|||
|
|||
on_open_caller: function (event) { |
|||
event.stopPropagation(); |
|||
var self = this; |
|||
self.rpc('/asterisk_click2dial/get_record_from_my_channel', {}).done(function(r) { |
|||
// console.log('RESULT RPC r='+r);
|
|||
// console.log('RESULT RPC type r='+typeof r);
|
|||
// console.log('RESULT RPC isNaN r='+isNaN(r));
|
|||
if (r === false) { |
|||
self.do_warn( |
|||
_t('Failure'), |
|||
_t('Problem in the connection to Asterisk'), |
|||
false); |
|||
} |
|||
else if (typeof r == 'string' && isNaN(r)) { |
|||
self.do_warn( |
|||
r, |
|||
_t('The calling number is not a phone number!'), |
|||
false); |
|||
} |
|||
else if (typeof r == 'string') { |
|||
var action = { |
|||
name: _t('Number Not Found'), |
|||
type: 'ir.actions.act_window', |
|||
res_model: 'number.not.found', |
|||
view_mode: 'form', |
|||
views: [[false, 'form']], |
|||
target: 'new', |
|||
context: {'default_calling_number': r}, |
|||
}; |
|||
web_client.action_manager.do_action(action); |
|||
|
|||
on_open_caller: function (event) { |
|||
event.stopPropagation(); |
|||
var self = this; |
|||
self.rpc('/asterisk_click2dial/get_record_from_my_channel', {}).done(function(r) { |
|||
// console.log('RESULT RPC r='+r);
|
|||
// console.log('RESULT RPC type r='+typeof r);
|
|||
if (r === false) { |
|||
self.do_notify( |
|||
_t('Failure'), |
|||
_t('Problem in the connection to Asterisk')); |
|||
} |
|||
else if (typeof r == 'string') { |
|||
var action = { |
|||
name: _t('Number Not Found'), |
|||
type: 'ir.actions.act_window', |
|||
res_model: 'number.not.found', |
|||
view_mode: 'form', |
|||
views: [[false, 'form']], |
|||
target: 'new', |
|||
context: {'default_calling_number': r}, |
|||
}; |
|||
instance.client.action_manager.do_action(action); |
|||
|
|||
} |
|||
else if (typeof r == 'object' && r.length == 3) { |
|||
self.do_notify( // Not working
|
|||
_t('Success'), |
|||
_t('Moving to %s ID %d', r[0], r[1])); |
|||
var action = { |
|||
type: 'ir.actions.act_window', |
|||
res_model: r[0], |
|||
res_id: r[1], |
|||
view_mode: 'form,tree', |
|||
views: [[false, 'form']], |
|||
target: 'current', |
|||
context: {}, |
|||
}; |
|||
instance.client.action_manager.do_action(action); |
|||
} |
|||
}); |
|||
}, |
|||
else if (typeof r == 'object' && r.length == 3) { |
|||
self.do_notify( // Not working
|
|||
_t('Success'), |
|||
_t('Moving to %s ID %d', r[0], r[1]), |
|||
false); |
|||
var action = { |
|||
type: 'ir.actions.act_window', |
|||
res_model: r[0], |
|||
res_id: r[1], |
|||
view_mode: 'form,tree', |
|||
views: [[false, 'form']], |
|||
/* If you want to make it work with the 'web' module |
|||
of Odoo Enterprise edition, you have to change the line |
|||
target: 'current', |
|||
to: |
|||
target: 'new', |
|||
If you want to use target: 'current', with web/enterprise, |
|||
you have to reload the Web page just after */ |
|||
target: 'current', |
|||
context: {}, |
|||
}; |
|||
web_client.action_manager.do_action(action); |
|||
} |
|||
}); |
|||
}, |
|||
}); |
|||
|
|||
instance.web.UserMenu.include({ |
|||
UserMenu.include({ |
|||
do_update: function(){ |
|||
this._super.apply(this, arguments); |
|||
this.update_promise.then(function() { |
|||
var asterisk_button = new instance.web.OpenCaller(); |
|||
asterisk_button.appendTo(instance.webclient.$el.find('.oe_systray')); |
|||
var asterisk_button = new click2dial.OpenCaller(); |
|||
// attach the phone logo/button to the systray
|
|||
asterisk_button.appendTo($('.oe_systray')); |
|||
}); |
|||
}, |
|||
}); |
|||
|
|||
}; |
|||
|
|||
|
|||
}); |
@ -1,21 +0,0 @@ |
|||
# -*- encoding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# Asterisk click2dial CRM module for OpenERP |
|||
# Copyright (c) 2012-2014 Akretion (http://www.akretion.com) |
|||
# @author: Alexis de Lattre <alexis.delattre@akretion.com> |
|||
# |
|||
# 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/>. |
|||
# |
|||
############################################################################## |
@ -1,48 +0,0 @@ |
|||
# -*- encoding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# Asterisk click2dial CRM module for OpenERP |
|||
# Copyright (c) 2012-2014 Akretion (http://www.akretion.com) |
|||
# @author: Alexis de Lattre <alexis.delattre@akretion.com> |
|||
# |
|||
# 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": "Asterisk Click2dial CRM", |
|||
"version": "8.0.0.1.0", |
|||
"author": "Akretion,Odoo Community Association (OCA)", |
|||
"website": "http://www.akretion.com", |
|||
"license": "AGPL-3", |
|||
"category": "Phone", |
|||
"description": """ |
|||
Asterisk Click2dial CRM |
|||
======================= |
|||
|
|||
This module is *EMPTY* ; so you should uninstall it now. |
|||
The code that used to be in this module has been moved to the module |
|||
*crm_phone* that is available in the same GitHub repository |
|||
https://github.com/OCA/connector-telephony |
|||
|
|||
This module will be removed from the repository in the near future. |
|||
""", |
|||
"depends": [ |
|||
'asterisk_click2dial', |
|||
'crm_phone', |
|||
], |
|||
"data": [], |
|||
'installable': False, |
|||
"application": False, |
|||
} |
@ -1,6 +1,5 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import base_phone |
|||
from . import fields |
|||
from . import models |
|||
from . import wizard |
|||
from . import report_sxw_format |
|||
from . import controller |
@ -1,307 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# Base Phone module for Odoo |
|||
# Copyright (C) 2010-2015 Alexis de Lattre <alexis@via.ecp.fr> |
|||
# |
|||
# This program is free software: you can redistribute it and/or modify |
|||
# it under the terms of the GNU Affero General Public License as |
|||
# 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 import models, fields, api, _ |
|||
from openerp.tools.safe_eval import safe_eval |
|||
from openerp.exceptions import UserError |
|||
import logging |
|||
# Lib for phone number reformating -> pip install phonenumbers |
|||
import phonenumbers |
|||
|
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
|
|||
class PhoneCommon(models.AbstractModel): |
|||
_name = 'phone.common' |
|||
|
|||
@api.model |
|||
def _reformat_phonenumbers_create(self, vals): |
|||
assert isinstance(self._phone_fields, list),\ |
|||
'self._phone_fields must be a list' |
|||
if any([vals.get(field) for field in self._phone_fields]): |
|||
countrycode = self._get_countrycode_from_vals(vals) |
|||
countrycode = self._countrycode_fallback(countrycode) |
|||
vals = self._reformat_phonenumbers(vals, countrycode) |
|||
return vals |
|||
|
|||
@api.multi |
|||
def _reformat_phonenumbers_write(self, vals): |
|||
assert isinstance(self._phone_fields, list),\ |
|||
'self._phone_fields must be a list' |
|||
if any([vals.get(field) for field in self._phone_fields]): |
|||
countrycode = self._get_countrycode_from_vals(vals) |
|||
if not countrycode: |
|||
if self._country_field: |
|||
country = safe_eval( |
|||
'self.' + self._country_field, {'self': self}) |
|||
countrycode = country and country.code or None |
|||
elif self._partner_field: |
|||
partner = safe_eval( |
|||
'self.' + self._partner_field, {'self': self}) |
|||
if partner: |
|||
countrycode = partner.country_id and\ |
|||
partner.country_id.code or None |
|||
|
|||
countrycode = self._countrycode_fallback(countrycode) |
|||
vals = self._reformat_phonenumbers(vals, countrycode) |
|||
return vals |
|||
|
|||
@api.model |
|||
def _get_countrycode_from_vals(self, vals): |
|||
assert isinstance(self._country_field, (str, unicode, type(None))),\ |
|||
'Wrong self._country_field' |
|||
assert isinstance(self._partner_field, (str, unicode, type(None))),\ |
|||
'Wrong self._partner_field' |
|||
countrycode = None |
|||
if self._country_field and vals.get(self._country_field): |
|||
country = self.env['res.country'].browse( |
|||
int(vals[self._country_field])) |
|||
countrycode = country.code |
|||
elif self._partner_field and vals.get(self._partner_field): |
|||
partner = self.env['res.partner'].browse( |
|||
int(vals[self._partner_field])) |
|||
countrycode = partner.country_id.code or False |
|||
return countrycode |
|||
|
|||
@api.model |
|||
def _countrycode_fallback(self, countrycode): |
|||
if not countrycode: |
|||
if self.env.user.company_id.country_id: |
|||
countrycode = self.env.user.company_id.country_id.code |
|||
else: |
|||
_logger.error( |
|||
"You should set a country on the company '%s' " |
|||
"to allow the reformat of phone numbers", |
|||
self.env.user.company_id.name) |
|||
return countrycode |
|||
|
|||
@api.model |
|||
def _reformat_phonenumbers(self, vals, countrycode): |
|||
for field in self._phone_fields: |
|||
if vals.get(field): |
|||
init_value = vals.get(field) |
|||
try: |
|||
res_parse = phonenumbers.parse( |
|||
vals.get(field), countrycode.upper()) |
|||
vals[field] = phonenumbers.format_number( |
|||
res_parse, phonenumbers.PhoneNumberFormat.E164) |
|||
if init_value != vals[field]: |
|||
_logger.info( |
|||
"%s initial value: '%s' updated value: '%s'" |
|||
% (field, init_value, vals[field])) |
|||
except Exception, e: |
|||
# I do BOTH logger and raise, because: |
|||
# raise is usefull when the record is created/written |
|||
# by a user via the Web interface |
|||
# logger is usefull when the record is created/written |
|||
# via the webservices |
|||
_logger.error( |
|||
"Cannot reformat the phone number '%s' to " |
|||
"international format with region=%s", |
|||
vals.get(field), countrycode) |
|||
if self.env.context.get('raise_if_phone_parse_fails'): |
|||
raise UserError( |
|||
_("Cannot reformat the phone number '%s' to " |
|||
"international format. Error message: %s") |
|||
% (vals.get(field), e)) |
|||
return vals |
|||
|
|||
@api.model |
|||
def get_name_from_phone_number(self, presented_number): |
|||
'''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(presented_number) |
|||
if res: |
|||
return res[2] |
|||
else: |
|||
return False |
|||
|
|||
@api.model |
|||
def get_record_from_phone_number(self, presented_number): |
|||
'''If it finds something, it returns (object name, ID, record name) |
|||
For example : ('res.partner', 42, u'Alexis de Lattre (Akretion)') |
|||
''' |
|||
_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) |
|||
|
|||
nr_digits_to_match_from_end = \ |
|||
self.env.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 |
|||
|
|||
phoneobjects = self._get_phone_fields() |
|||
phonefieldslist = [] # [('res.parter', 10), ('crm.lead', 20)] |
|||
for objname in phoneobjects: |
|||
if ( |
|||
'_phone_name_sequence' in dir(self.env[objname]) and |
|||
self.env[objname]._phone_name_sequence): |
|||
phonefieldslist.append( |
|||
(objname, self.env[objname]._phone_name_sequence)) |
|||
phonefieldslist_sorted = sorted( |
|||
phonefieldslist, |
|||
key=lambda element: element[1]) |
|||
_logger.debug('phonefieldslist_sorted=%s' % phonefieldslist_sorted) |
|||
for (objname, prio) in phonefieldslist_sorted: |
|||
obj = self.with_context(callerid=True).env[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 obj._phone_fields: |
|||
domain.append((phonefield, '=like', pg_search_number)) |
|||
if len(obj._phone_fields) > 1: |
|||
domain = ['|'] * (len(obj._phone_fields) - 1) + domain |
|||
res_obj = obj.search(domain) |
|||
if len(res_obj) > 1: |
|||
_logger.warning( |
|||
u"There are several %s (IDS = %s) with a phone number " |
|||
"ending with '%s'. Taking the first one." |
|||
% (objname, res_obj.ids, end_number_to_match)) |
|||
res_obj = res_obj[0] |
|||
if res_obj: |
|||
name = res_obj.name_get()[0][1] |
|||
res = (objname, res_obj.id, 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 |
|||
|
|||
@api.model |
|||
def _get_phone_fields(self): |
|||
'''Returns a dict with key = object name |
|||
and value = list of phone fields''' |
|||
models = self.env['ir.model'].search([('transient', '=', False)]) |
|||
res = [] |
|||
for model in models: |
|||
senv = False |
|||
try: |
|||
senv = self.env[model.model] |
|||
except: |
|||
continue |
|||
if ( |
|||
'_phone_fields' in dir(senv) and |
|||
isinstance(senv._phone_fields, list)): |
|||
res.append(model.model) |
|||
return res |
|||
|
|||
@api.model |
|||
def click2dial(self, erp_number): |
|||
'''This function is designed to be overridden in IPBX-specific |
|||
modules, such as asterisk_click2dial or ovh_telephony_connector''' |
|||
return {'dialed_number': erp_number} |
|||
|
|||
@api.model |
|||
def convert_to_dial_number(self, erp_number): |
|||
''' |
|||
This function is dedicated to the transformation of the number |
|||
available in Odoo to the number that can be dialed. |
|||
You may have to inherit this function in another module specific |
|||
for your company if you are not happy with the way I reformat |
|||
the numbers. |
|||
''' |
|||
assert(erp_number), 'Missing phone number' |
|||
_logger.debug('Number before reformat = %s' % erp_number) |
|||
# erp_number are supposed to be in E.164 format, so no need to |
|||
# give a country code here |
|||
parsed_num = phonenumbers.parse(erp_number, None) |
|||
country_code = self.env.user.company_id.country_id.code |
|||
assert(country_code), 'Missing country on company' |
|||
_logger.debug('Country code = %s' % country_code) |
|||
to_dial_number = phonenumbers.format_out_of_country_calling_number( |
|||
parsed_num, country_code.upper()) |
|||
to_dial_number = str(to_dial_number).translate(None, ' -.()/') |
|||
_logger.debug('Number to be sent to phone system: %s' % to_dial_number) |
|||
return to_dial_number |
|||
|
|||
|
|||
class ResPartner(models.Model): |
|||
_name = 'res.partner' |
|||
_inherit = ['res.partner', 'phone.common'] |
|||
_phone_fields = ['phone', 'mobile', 'fax'] |
|||
_phone_name_sequence = 10 |
|||
_country_field = 'country_id' |
|||
_partner_field = None |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
vals_reformated = self._reformat_phonenumbers_create(vals) |
|||
return super(ResPartner, self).create(vals_reformated) |
|||
|
|||
@api.multi |
|||
def write(self, vals): |
|||
vals_reformated = self._reformat_phonenumbers_write(vals) |
|||
return super(ResPartner, self).write(vals_reformated) |
|||
|
|||
@api.multi |
|||
def name_get(self): |
|||
if self._context.get('callerid'): |
|||
res = [] |
|||
for partner in self: |
|||
if partner.parent_id and partner.parent_id.is_company: |
|||
name = u'%s (%s)' % (partner.name, partner.parent_id.name) |
|||
else: |
|||
name = partner.name |
|||
res.append((partner.id, name)) |
|||
return res |
|||
else: |
|||
return super(ResPartner, self).name_get() |
|||
|
|||
|
|||
class ResCompany(models.Model): |
|||
_inherit = 'res.company' |
|||
|
|||
number_of_digits_to_match_from_end = fields.Integer( |
|||
string='Number of Digits To Match From End', |
|||
default=8, |
|||
help="In several situations, OpenERP will have to find a " |
|||
"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.") |
|||
|
|||
_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,137 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Akretion (http://www.akretion.com) |
|||
# Sébastien BEAU <sebastien.beau@akretion.com> |
|||
# Alexis de Lattre <alexis.delattre@akretion.com> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
|
|||
from openerp import api, fields, models |
|||
from operator import attrgetter |
|||
import phonenumbers |
|||
import logging |
|||
|
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
|
|||
class Phone(fields.Char): |
|||
|
|||
_slots = { |
|||
'country_field': None, |
|||
'partner_field': None, |
|||
} |
|||
|
|||
def __init__( |
|||
self, string=None, country_field=None, partner_field=None, |
|||
**kwargs): |
|||
super(Phone, self).__init__( |
|||
string=string, country_field=country_field, |
|||
partner_field=partner_field, **kwargs) |
|||
|
|||
_related_country_field = property(attrgetter('country_field')) |
|||
_related_partner_field = property(attrgetter('partner_field')) |
|||
|
|||
def _setup_regular_full(self, model): |
|||
super(Phone, self)._setup_regular_full(model) |
|||
assert self.country_field in model._fields or \ |
|||
self.partner_field in model._fields, \ |
|||
"field %s with unknown country_field and partner_field" % self |
|||
|
|||
def convert_to_cache(self, value, record, validate=True): |
|||
res = super(Phone, self).convert_to_cache( |
|||
value, record, validate=validate) |
|||
# print 'db value', res |
|||
if res: |
|||
try: |
|||
res_parse = phonenumbers.parse(res) |
|||
res = phonenumbers.format_number( |
|||
res_parse, phonenumbers.PhoneNumberFormat.INTERNATIONAL) |
|||
no_break_space = u'\u00A0' |
|||
res = res.replace(' ', no_break_space) |
|||
except: |
|||
pass |
|||
# print 'cache value', res |
|||
return res |
|||
|
|||
|
|||
def convert_phone_field(value, country_code): |
|||
_logger.debug( |
|||
'convert_phone_field value=%s country=%s', value, country_code) |
|||
try: |
|||
res_parse = phonenumbers.parse( |
|||
value, country_code) |
|||
_logger.debug('res_parse=%s', res_parse) |
|||
new_value = phonenumbers.format_number( |
|||
res_parse, phonenumbers.PhoneNumberFormat.E164) |
|||
_logger.debug('new_value=%s', new_value) |
|||
except: |
|||
_logger.error( |
|||
"Cannot reformat the phone number '%s' to " |
|||
"international format with region=%s", |
|||
value, country_code) |
|||
new_value = value |
|||
return new_value |
|||
|
|||
|
|||
def convert_all_phone_fields(self, vals, fields_to_convert): |
|||
loc_vals = vals.copy() |
|||
for field in fields_to_convert: |
|||
country_key = self._fields[field].country_field |
|||
partner_key = self._fields[field].partner_field |
|||
country = False |
|||
if country_key: |
|||
if country_key in loc_vals: |
|||
country = self.env['res.country'].browse(vals[country_key]) |
|||
else: |
|||
country = self[country_key] |
|||
if partner_key and not country: |
|||
if partner_key in loc_vals: |
|||
partner = self.env['res.partner'].browse(vals[partner_key]) |
|||
else: |
|||
partner = self[partner_key] |
|||
if partner: |
|||
country = partner.country_id |
|||
if not country: |
|||
country = self.env.user.company_id.country_id |
|||
country_code = False |
|||
if country: |
|||
country_code = country.code.upper() |
|||
if loc_vals[field]: |
|||
loc_vals[field] = convert_phone_field( |
|||
loc_vals[field], country_code) |
|||
return loc_vals |
|||
|
|||
|
|||
def get_phone_fields(self, vals): |
|||
fields_to_convert = [] |
|||
for key in vals: |
|||
if isinstance(self._fields.get(key), Phone): |
|||
fields_to_convert.append(key) |
|||
return fields_to_convert |
|||
|
|||
original_write = models.Model.write |
|||
original_create = models.Model.create |
|||
|
|||
|
|||
@api.multi |
|||
def write(self, vals): |
|||
fields_to_convert = get_phone_fields(self, vals) |
|||
if fields_to_convert: |
|||
for record in self: |
|||
loc_vals = convert_all_phone_fields( |
|||
record, vals, fields_to_convert) |
|||
original_write(record, loc_vals) |
|||
return True |
|||
else: |
|||
return original_write(self, vals) |
|||
|
|||
|
|||
@api.model |
|||
@api.returns('self', lambda value: value.id) |
|||
def create(self, vals): |
|||
fields_to_convert = get_phone_fields(self, vals) |
|||
if fields_to_convert: |
|||
vals = convert_all_phone_fields(self, vals, fields_to_convert) |
|||
return original_create(self, vals) |
|||
|
|||
models.Model.write = write |
|||
models.Model.create = create |
@ -0,0 +1,6 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import controller |
|||
from . import res_company |
|||
from . import res_partner |
|||
from . import phone_common |
@ -0,0 +1,139 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2010-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
from openerp import models, api |
|||
from openerp.addons.base_phone.fields import Phone |
|||
import logging |
|||
# Lib for phone number reformating -> pip install phonenumbers |
|||
import phonenumbers |
|||
|
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
|
|||
class PhoneCommon(models.AbstractModel): |
|||
_name = 'phone.common' |
|||
|
|||
@api.model |
|||
def get_name_from_phone_number(self, presented_number): |
|||
'''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(presented_number) |
|||
if res: |
|||
return res[2] |
|||
else: |
|||
return False |
|||
|
|||
@api.model |
|||
def get_record_from_phone_number(self, presented_number): |
|||
'''If it finds something, it returns (object name, ID, record name) |
|||
For example : ('res.partner', 42, u'Alexis de Lattre (Akretion)') |
|||
''' |
|||
_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) |
|||
|
|||
nr_digits_to_match_from_end = \ |
|||
self.env.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 |
|||
|
|||
sorted_phonemodels = self._get_phone_models() |
|||
for obj_dict in sorted_phonemodels: |
|||
obj = obj_dict['object'] |
|||
pg_search_number = str('%' + end_number_to_match) |
|||
_logger.debug( |
|||
"Will search phone and mobile numbers in %s ending with '%s'", |
|||
obj._name, end_number_to_match) |
|||
domain = [] |
|||
for field in obj_dict['fields']: |
|||
domain.append((field, '=like', pg_search_number)) |
|||
if len(domain) > 1: |
|||
domain = ['|'] * (len(domain) - 1) + domain |
|||
_logger.debug('searching on %s with domain=%s', obj._name, domain) |
|||
res_obj = obj.search(domain) |
|||
if len(res_obj) > 1: |
|||
_logger.warning( |
|||
u"There are several %s (IDS = %s) with a phone number " |
|||
"ending with '%s'. Taking the first one.", |
|||
obj._name, res_obj.ids, end_number_to_match) |
|||
res_obj = res_obj[0] |
|||
if res_obj: |
|||
name = res_obj.name_get()[0][1] |
|||
res = (obj._name, res_obj.id, 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'", |
|||
obj._name, end_number_to_match) |
|||
return False |
|||
|
|||
@api.model |
|||
def _get_phone_models(self): |
|||
phoneobj = [] |
|||
for model_name in self.env.registry.keys(): |
|||
senv = False |
|||
try: |
|||
senv = self.with_context(callerid=True).env[model_name] |
|||
except: |
|||
continue |
|||
if ( |
|||
hasattr(senv, '_phone_name_sequence') and |
|||
isinstance(senv._phone_name_sequence, int)): |
|||
phoneobj.append((senv, senv._phone_name_sequence)) |
|||
|
|||
phoneobj_sorted = sorted(phoneobj, key=lambda element: element[1]) |
|||
|
|||
res = [] |
|||
for (obj, prio) in phoneobj_sorted: |
|||
entry = {'object': obj, 'fields': []} |
|||
for field in obj._fields: |
|||
if isinstance(obj._fields[field], Phone): |
|||
entry['fields'].append(field) |
|||
res.append(entry) |
|||
# [{'fields': ['fax', 'phone', 'mobile'], 'object': res.partner()}, |
|||
# {'fields': ['fax', 'phone', 'mobile'], 'object': crm.lead()}] |
|||
return res |
|||
|
|||
@api.model |
|||
def click2dial(self, erp_number): |
|||
'''This function is designed to be overridden in IPBX-specific |
|||
modules, such as asterisk_click2dial or ovh_telephony_connector''' |
|||
return {'dialed_number': erp_number} |
|||
|
|||
@api.model |
|||
def convert_to_dial_number(self, erp_number): |
|||
''' |
|||
This function is dedicated to the transformation of the number |
|||
available in Odoo to the number that can be dialed. |
|||
You may have to inherit this function in another module specific |
|||
for your company if you are not happy with the way I reformat |
|||
the numbers. |
|||
''' |
|||
assert(erp_number), 'Missing phone number' |
|||
_logger.debug('Number before reformat = %s' % erp_number) |
|||
# erp_number are supposed to be in International format, so no need to |
|||
# give a country code here |
|||
parsed_num = phonenumbers.parse(erp_number, None) |
|||
country_code = self.env.user.company_id.country_id.code |
|||
assert(country_code), 'Missing country on company' |
|||
_logger.debug('Country code = %s' % country_code) |
|||
to_dial_number = phonenumbers.format_out_of_country_calling_number( |
|||
parsed_num, country_code.upper()) |
|||
to_dial_number = str(to_dial_number).translate(None, ' -.()/') |
|||
_logger.debug('Number to be sent to phone system: %s' % to_dial_number) |
|||
return to_dial_number |
@ -0,0 +1,28 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
from openerp import models, fields |
|||
|
|||
|
|||
class ResCompany(models.Model): |
|||
_inherit = 'res.company' |
|||
|
|||
number_of_digits_to_match_from_end = fields.Integer( |
|||
string='Number of Digits To Match From End', |
|||
default=8, |
|||
help="In several situations, OpenERP will have to find a " |
|||
"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.") |
|||
|
|||
_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,31 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
|
|||
from openerp import models, api |
|||
from openerp.addons.base_phone import fields |
|||
|
|||
|
|||
class ResPartner(models.Model): |
|||
_inherit = 'res.partner' |
|||
_phone_name_sequence = 10 |
|||
|
|||
phone = fields.Phone(country_field='country_id', partner_field='parent_id') |
|||
mobile = fields.Phone( |
|||
country_field='country_id', partner_field='parent_id') |
|||
fax = fields.Phone(country_field='country_id', partner_field='parent_id') |
|||
|
|||
@api.multi |
|||
def name_get(self): |
|||
if self._context.get('callerid'): |
|||
res = [] |
|||
for partner in self: |
|||
if partner.parent_id and partner.parent_id.is_company: |
|||
name = u'%s (%s)' % (partner.name, partner.parent_id.name) |
|||
else: |
|||
name = partner.name |
|||
res.append((partner.id, name)) |
|||
return res |
|||
else: |
|||
return super(ResPartner, self).name_get() |
@ -1,63 +0,0 @@ |
|||
# -*- 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 openerp import models |
|||
from openerp.report import report_sxw |
|||
import phonenumbers |
|||
|
|||
|
|||
class BasePhoneInstalled(models.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 |
1397
base_phone/static/lib/phonenumbers/PhoneFormat.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,50 +0,0 @@ |
|||
- |
|||
Write country = FR for the main company |
|||
- |
|||
!record {model: res.company, id: base.main_company}: |
|||
country_id: base.fr |
|||
- |
|||
Write french phone numbers in national format |
|||
- |
|||
!record {model: res.partner, id: partner1}: |
|||
name: Pierre Paillet |
|||
mobile: 06 42 77 42 66 |
|||
fax: (0) 1 45 42 12 42 |
|||
- |
|||
Write swiss phone numbers in international format |
|||
- |
|||
!record {model: res.partner, id: partner2}: |
|||
name: Joël Grand-Guillaume |
|||
parent_id: base.res_partner_12 |
|||
phone: +41 21 619 10 10 |
|||
mobile: +41 79 606 42 42 |
|||
- |
|||
Write invalid phone number |
|||
- |
|||
!record {model: res.partner, id: partner3}: |
|||
name: Jean Badphone |
|||
phone: 42 |
|||
- |
|||
Check that valid phone numbers have been converted to E.164 |
|||
- |
|||
!python {model: res.partner}: | |
|||
partner1 = self.browse(cr, uid, ref('partner1'), context=context) |
|||
assert partner1.mobile == '+33642774266', 'Mobile number not written in E.164 format (partner1)' |
|||
assert partner1.fax == '+33145421242', 'Fax number not written in E.164 format (partner1)' |
|||
partner2 = self.browse(cr, uid, ref('partner2'), context=context) |
|||
assert partner2.phone == '+41216191010', 'Phone number not written in E.164 format (partner2)' |
|||
assert partner2.mobile == '+41796064242', 'Mobile number not written in E.164 format (partner2)' |
|||
- |
|||
Check that invalid phone numbers are kept unchanged |
|||
- |
|||
!python {model: res.partner}: | |
|||
partner3 = self.browse(cr, uid, ref('partner3'), context=context) |
|||
assert partner3.phone == '42', 'Invalid phone numbers should not be changed' |
|||
- |
|||
Get name from phone number |
|||
- |
|||
!python {model: phone.common}: | |
|||
name = self.get_name_from_phone_number(cr, uid, '0642774266') |
|||
assert name == 'Pierre Paillet', 'Wrong result for get_name_from_phone_number' |
|||
name2 = self.get_name_from_phone_number(cr, uid, '0041216191010') |
|||
assert name2 == u'Joël Grand-Guillaume (Camptocamp)', 'Wrong result for get_name_from_phone_number (partner2)' |
@ -0,0 +1,3 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import test_phone |
@ -0,0 +1,55 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Akretion France (Alexis de Lattre <alexis.delattre@akretion.com>) |
|||
|
|||
from openerp.tests.common import TransactionCase |
|||
|
|||
|
|||
class TestPhone(TransactionCase): |
|||
|
|||
def test_phone(self): |
|||
company = self.env.ref('base.main_company') |
|||
company.country_id = self.env.ref('base.fr').id |
|||
rpo = self.env['res.partner'] |
|||
# Create an existing partner without country |
|||
partner1 = rpo.create({ |
|||
'name': u'Pierre Paillet', |
|||
'phone': '04-72-08-87-32', |
|||
'mobile': '06.42.77.42.66', |
|||
'fax': '(0) 1 45 42 12 42', |
|||
}) |
|||
self.assertEquals(partner1.phone, u'+33 4 72 08 87 32') |
|||
self.assertEquals(partner1.mobile, u'+33 6 42 77 42 66') |
|||
self.assertEquals(partner1.fax, u'+33 1 45 42 12 42') |
|||
# Create a partner with country |
|||
self.env.ref('base.res_partner_12').country_id =\ |
|||
self.env.ref('base.ch').id |
|||
partner2 = rpo.create({ |
|||
'name': u'Joël Grand-Guillaume', |
|||
'parent_id': self.env.ref('base.res_partner_12').id, |
|||
'use_parent_address': True, |
|||
'phone': '(0) 21 619 10 10', |
|||
'mobile': '(0) 79 606 42 42', |
|||
}) |
|||
self.assertEquals(partner2.country_id, self.env.ref('base.ch')) |
|||
self.assertEquals(partner2.phone, u'+41 21 619 10 10') |
|||
self.assertEquals(partner2.mobile, u'+41 79 606 42 42') |
|||
# Write on an existing partner |
|||
agrolait = self.env.ref('base.res_partner_2') |
|||
self.assertEquals(agrolait.country_id, self.env.ref('base.be')) |
|||
agrolait.write({'phone': '(0) 2 391 43 74'}) |
|||
self.assertEquals(agrolait.phone, u'+32 2 391 43 74') |
|||
# Write on an existing partner with country at the same time |
|||
agrolait.write({ |
|||
'fax': '04 72 89 32 43', |
|||
'country_id': self.env.ref('base.fr').id, |
|||
}) |
|||
self.assertEquals(agrolait.fax, u'+33 4 72 89 32 43') |
|||
# Write an invalid phone number |
|||
partner2.fax = '42' |
|||
self.assertEquals(partner2.fax, u'42') |
|||
# Test get_name_from_phone_number |
|||
pco = self.env['phone.common'] |
|||
name = pco.get_name_from_phone_number('0642774266') |
|||
self.assertEquals(name, 'Pierre Paillet') |
|||
name2 = pco.get_name_from_phone_number('0041216191010') |
|||
self.assertEquals(name2, u'Joël Grand-Guillaume (Camptocamp)') |
@ -1,22 +1,3 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# Base Phone Pop-up module for Odoo/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 popup |
@ -1,22 +1,3 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# CRM Claim Phone module for Odoo/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 crm_claim_phone |
@ -1,43 +1,12 @@ |
|||
# -*- encoding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# CRM Claim Phone module for Odoo/OpenERP |
|||
# Copyright (c) 2012-2014 Akretion (http://www.akretion.com) |
|||
# @author: Alexis de Lattre <alexis.delattre@akretion.com> |
|||
# |
|||
# 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/>. |
|||
# |
|||
############################################################################## |
|||
# -*- coding: utf-8 -*- |
|||
# © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
from openerp.osv import orm |
|||
from openerp import models |
|||
from openerp.addons.base_phone.fields import Phone |
|||
|
|||
|
|||
class crm_claim(orm.Model): |
|||
_name = 'crm.claim' |
|||
_inherit = ['crm.claim', 'phone.common'] |
|||
_phone_fields = ['partner_phone'] |
|||
_country_field = None |
|||
_partner_field = 'partner_id' |
|||
class CrmClaim(models.Model): |
|||
_inherit = 'crm.claim' |
|||
|
|||
def create(self, cr, uid, vals, context=None): |
|||
vals_reformated = self._generic_reformat_phonenumbers( |
|||
cr, uid, None, vals, context=context) |
|||
return super(crm_claim, 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, ids, vals, context=context) |
|||
return super(crm_claim, self).write( |
|||
cr, uid, ids, vals_reformated, context=context) |
|||
partner_phone = Phone(partner_field='partner_id') |
@ -1,23 +1,4 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# CRM Phone module for Odoo/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 crm_phone |
|||
from . import wizard |
@ -0,0 +1,59 @@ |
|||
<?xml version="1.0"?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
|
|||
|
|||
<record id="crm_phonecall1" model="crm.phonecall"> |
|||
<field name="date" eval="time.strftime('%Y-%m-01 11:42:12')"/> |
|||
<field name="partner_id" ref="base.res_partner_1"/> |
|||
<field name="user_id" ref="base.user_root"/> |
|||
<field name="name">Presentation of new product line</field> |
|||
<field name="state">done</field> |
|||
<field name="partner_phone">+33442127812</field> |
|||
<field name="direction">outbound</field> |
|||
</record> |
|||
|
|||
<record id="crm_phonecall2" model="crm.phonecall"> |
|||
<field name="date" eval="time.strftime('%Y-%m-28 09:12:42')"/> |
|||
<field name="partner_id" ref="base.res_partner_2"/> |
|||
<field name="user_id" ref="base.user_demo"/> |
|||
<field name="name">Close the deal</field> |
|||
<field name="state">open</field> |
|||
<field name="partner_phone">+33543137913</field> |
|||
<field name="direction">outbound</field> |
|||
</record> |
|||
|
|||
<record id="crm_phonecall3" model="crm.phonecall"> |
|||
<field name="date" eval="time.strftime('%Y-%m-27 09:45:42')"/> |
|||
<field name="partner_id" ref="base.res_partner_address_3"/> |
|||
<field name="user_id" ref="base.user_demo"/> |
|||
<field name="name">Lobby about our offer</field> |
|||
<field name="state">open</field> |
|||
<field name="partner_phone">+33543137914</field> |
|||
<field name="direction">outbound</field> |
|||
</record> |
|||
|
|||
<record id="crm_phonecall4" model="crm.phonecall"> |
|||
<field name="date" eval="time.strftime('%Y-%m-26 09:45:42')"/> |
|||
<field name="opportunity_id" ref="crm.crm_case_2"/> |
|||
<field name="user_id" ref="base.user_root"/> |
|||
<field name="name">Remote Demo of the software</field> |
|||
<field name="state">open</field> |
|||
<field name="partner_phone">+33789320421</field> |
|||
<field name="direction">outbound</field> |
|||
</record> |
|||
|
|||
<record id="crm_phonecall5" model="crm.phonecall"> |
|||
<field name="date" eval="time.strftime('%Y-%m-02 09:45:42')"/> |
|||
<field name="opportunity_id" ref="crm.crm_case_1"/> |
|||
<field name="user_id" ref="base.user_demo"/> |
|||
<field name="name">Asked training program</field> |
|||
<field name="state">done</field> |
|||
<field name="partner_phone">+33389320442</field> |
|||
<field name="direction">inbound</field> |
|||
</record> |
|||
|
|||
|
|||
|
|||
</data> |
|||
</odoo> |
@ -1,2 +1,5 @@ |
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
|||
callerid_crm_lead_read,Read access on crm.lead,crm.model_crm_lead,base_phone.group_callerid,1,0,0,0 |
|||
access_crm_phonecall_partner_manager,Full access on crm.phonecall to Contact mgr,model_crm_phonecall,base.group_partner_manager,1,1,1,1 |
|||
access_crm_phonecall_sale_manager,Full access on crm.phonecall to Sale mgr,model_crm_phonecall,base.group_sale_manager,1,1,1,1 |
|||
access_crm_phonecall_sale_user,Read/Write/Create access on crm.phonecall to Sale users,model_crm_phonecall,base.group_sale_salesman,1,1,1,0 |
@ -0,0 +1,28 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
|
|||
|
|||
<record id="my_crm_phonecall_rule" model="ir.rule"> |
|||
<field name="name">Personal Phone Calls</field> |
|||
<field name="model_id" ref="model_crm_phonecall"/> |
|||
<field name="groups" eval="[(4, ref('base.group_sale_salesman'))]"/> |
|||
<field name="domain_force">['|', ('user_id', '=', False), ('user_id', '=', user.id)]</field> |
|||
</record> |
|||
|
|||
<record id="all_crm_phonecall_rule" model="ir.rule"> |
|||
<field name="name">All Phone Calls</field> |
|||
<field name="model_id" ref="model_crm_phonecall"/> |
|||
<field name="groups" eval="[(4, ref('base.group_sale_salesman_all_leads'))]"/> |
|||
<field name="domain_force">[(1, '=', 1)]</field> |
|||
</record> |
|||
|
|||
<record id="multi_company_crm_phonecall_rule" model="ir.rule"> |
|||
<field name="name">Multi-company Phone Calls</field> |
|||
<field name="model_id" ref="model_crm_phonecall"/> |
|||
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field> |
|||
</record> |
|||
|
|||
|
|||
</data> |
|||
</odoo> |
@ -1,41 +0,0 @@ |
|||
- |
|||
Write french phone numbers in national format |
|||
- |
|||
!record {model: crm.lead, id: lead1}: |
|||
name: Jacques Toufaux |
|||
mobile: 06 42 77 42 77 |
|||
fax: (0) 1 45 44 42 43 |
|||
country_id: base.fr |
|||
- |
|||
Write swiss phone numbers in national format |
|||
- |
|||
!record {model: crm.lead, id: lead2}: |
|||
name: Michel Content |
|||
country_id: base.ch |
|||
phone: 04 31 23 45 67 |
|||
- |
|||
Create a german lead |
|||
- |
|||
!record {model: crm.lead, id: lead3}: |
|||
name: Angela Strasse |
|||
country_id: base.de |
|||
- |
|||
Check that valid phone numbers have been converted to E.164 |
|||
- |
|||
!python {model: crm.lead}: | |
|||
lead1 = self.browse(cr, uid, ref('lead1'), context=context) |
|||
assert lead1.mobile == '+33642774277', 'Mobile number not written in E.164 format (lead1)' |
|||
assert lead1.fax == '+33145444243', 'Fax number not written in E.164 format (lead1)' |
|||
lead2 = self.browse(cr, uid, ref('lead2'), context=context) |
|||
assert lead2.phone == '+41431234567', 'Phone number not written in E.164 format (lead2)' |
|||
self.write(cr, uid, ref('lead3'), {'phone': '0891234567'}) |
|||
lead3 = self.browse(cr, uid, ref('lead3'), context=context) |
|||
assert lead3.phone == '+49891234567', 'Phone number not written in E.164 format (lead3)' |
|||
- |
|||
Get name from phone number |
|||
- |
|||
!python {model: phone.common}: | |
|||
name = self.get_name_from_phone_number(cr, uid, '0642774277') |
|||
assert name == 'Jacques Toufaux', 'Wrong result for get_name_from_phone_number (lead1)' |
|||
name2 = self.get_name_from_phone_number(cr, uid, '0041431234567') |
|||
assert name2 == 'Michel Content', 'Wrong result for get_name_from_phone_number (lead2)' |
@ -0,0 +1,3 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import test_crm_phone |
@ -0,0 +1,46 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Akretion France (Alexis de Lattre <alexis.delattre@akretion.com>) |
|||
|
|||
|
|||
from openerp.tests.common import TransactionCase |
|||
|
|||
|
|||
class TestCRMPhone(TransactionCase): |
|||
|
|||
def test_crm_phone(self): |
|||
clo = self.env['crm.lead'] |
|||
lead1 = clo.create({ |
|||
'name': 'The super deal of the year !', |
|||
'partner_name': 'Ford', |
|||
'contact_name': 'Jacques Toufaux', |
|||
'mobile': '06.42.77.42.77', |
|||
'fax': '(0) 1 45 44 42 43', |
|||
'country_id': self.env.ref('base.fr').id, |
|||
}) |
|||
self.assertEquals(lead1.mobile, u'+33 6 42 77 42 77') |
|||
self.assertEquals(lead1.fax, u'+33 1 45 44 42 43') |
|||
lead2 = clo.create({ |
|||
'name': u'Automobile Odoo deployment', |
|||
'partner_name': u'Kia', |
|||
'contact_name': u'Mikaël Content', |
|||
'country_id': self.env.ref('base.ch').id, |
|||
'phone': '04 31 23 45 67', |
|||
}) |
|||
self.assertEquals(lead2.phone, u'+41 43 123 45 67') |
|||
lead3 = clo.create({ |
|||
'name': 'Angela Strasse', |
|||
'country_id': self.env.ref('base.de').id, |
|||
}) |
|||
lead3.write({'phone': '08912345678'}) |
|||
self.assertEquals(lead3.phone, u'+49 89 12345678') |
|||
lead4 = clo.create({ |
|||
'name': 'Large Odoo deployment', |
|||
'partner_id': self.env.ref('base.res_partner_2').id, |
|||
}) |
|||
lead4.write({'mobile': '(0) 2-391-43-75'}) |
|||
self.assertEquals(lead4.mobile, u'+32 2 391 43 75') |
|||
pco = self.env['phone.common'] |
|||
name = pco.get_name_from_phone_number('0642774277') |
|||
self.assertEquals(name, 'Jacques Toufaux (Ford)') |
|||
name2 = pco.get_name_from_phone_number('0041431234567') |
|||
self.assertEquals(name2, u'Mikaël Content (Kia)') |
@ -0,0 +1,160 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<!-- |
|||
© 2014-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
--> |
|||
|
|||
<odoo> |
|||
<data> |
|||
|
|||
|
|||
<record id="crm_phonecall_form" model="ir.ui.view"> |
|||
<field name="name">crm.phonecall.form</field> |
|||
<field name="model">crm.phonecall</field> |
|||
<field name="arch" type="xml"> |
|||
<form string="Phone Call"> |
|||
<header> |
|||
<field name="state" widget="statusbar" clickable="True"/> |
|||
</header> |
|||
<sheet> |
|||
<div class="oe_button_box" name="button_box"> |
|||
<button class="oe_stat_button" type="object" |
|||
name="schedule_another_call" icon="fa-phone" |
|||
string="Schedule Another Call"/> |
|||
</div> |
|||
<div class="oe_title"> |
|||
<div class="oe_edit_only"> |
|||
<label for="name"/> |
|||
</div> |
|||
<h1><field name="name"/></h1> |
|||
</div> |
|||
<group name="main"> |
|||
<group name="left"> |
|||
<field name="date"/> |
|||
<field name="user_id"/> |
|||
<field name="partner_id"/> |
|||
<field name="partner_phone" widget="phone"/> |
|||
<field name="partner_mobile" widget="phone"/> |
|||
<field name="opportunity_id"/> |
|||
</group> |
|||
<group name="right"> |
|||
<field name="direction"/> |
|||
<field name="team_id" groups="base.group_multi_salesteams"/> |
|||
<field name="company_id" groups="base.group_multi_company"/> |
|||
<field name="priority" widget="priority"/> |
|||
</group> |
|||
</group> |
|||
<group name="description" string="Description"> |
|||
<field name="description" nolabel="1" |
|||
placeholder="Summary of the phone call..."/> |
|||
</group> |
|||
</sheet> |
|||
<div class="oe_chatter"> |
|||
<field name="message_follower_ids" widget="mail_followers"/> |
|||
<field name="message_ids" widget="mail_thread"/> |
|||
</div> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
|
|||
<record id="crm_phonecall_tree" model="ir.ui.view"> |
|||
<field name="name">crm.phonecall.tree</field> |
|||
<field name="model">crm.phonecall</field> |
|||
<field name="arch" type="xml"> |
|||
<tree string="Phone Calls" editable="top"> |
|||
<field name="date"/> |
|||
<field name="name"/> |
|||
<field name="partner_id"/> |
|||
<field name="opportunity_id"/> |
|||
<field name="user_id"/> |
|||
<field name="team_id" groups="base.group_multi_salesteams"/> |
|||
<field name="direction"/> |
|||
<field name="state"/> |
|||
<button name="schedule_another_call" type="object" |
|||
string="Schedule Another Call" icon="terp-call-start"/> |
|||
</tree> |
|||
</field> |
|||
</record> |
|||
|
|||
<record id="crm_phonecall_calendar" model="ir.ui.view"> |
|||
<field name="name">crm.phonecall.calendar</field> |
|||
<field name="model">crm.phonecall</field> |
|||
<field name="arch" type="xml"> |
|||
<calendar string="Phone Calls" date_start="date" color="user_id"> |
|||
<field name="name"/> |
|||
<field name="partner_id"/> |
|||
</calendar> |
|||
</field> |
|||
</record> |
|||
|
|||
<record id="crm_phonecall_search" model="ir.ui.view"> |
|||
<field name="name">crm.phonecall.search</field> |
|||
<field name="model">crm.phonecall</field> |
|||
<field name="arch" type="xml"> |
|||
<search string="Search Phone Calls"> |
|||
<field name="name" string="Phonecalls"/> |
|||
<field name="date"/> |
|||
<field name="user_id"/> |
|||
<field name="partner_id" operator="child_of"/> |
|||
<field name="opportunity_id"/> |
|||
<field name="team_id" groups="base.group_multi_salesteams"/> |
|||
<filter string="My Phonecalls" domain="[('user_id', '=', uid)]"/> |
|||
<filter string="My Team" domain="[('section_id.user_id', '=', uid)]"/> |
|||
<filter string="Unassigned" domain="[('user_id', '=', False)]"/> |
|||
<separator/> |
|||
<filter string="To Do" name="open" domain="[('state', '=', 'open')]"/> |
|||
<filter string="Held" name="done" domain="[('state', '=', 'done')]"/> |
|||
<separator/> |
|||
<filter string="Inbound" domain="[('direction', '=', 'inbound')]"/> |
|||
<filter string="Outbound" domain="[('direction', '=', 'outbound')]"/> |
|||
<group string="Group By" name="groupby"> |
|||
<filter name="partner_groupby" string="Partner" |
|||
context="{'group_by': 'partner_id'}"/> |
|||
<filter name="user_groupby" string="Responsible" |
|||
context="{'group_by': 'user_id'}"/> |
|||
<filter name="team_groupby" string="Team" |
|||
context="{'group_by': 'team_id'}" |
|||
groups="base.group_multi_salesteams"/> |
|||
<filter name="date_groupby" string="Month" |
|||
context="{'group_by': 'date'}"/> |
|||
<filter name="state_groupby" string="State" |
|||
context="{'group_by': 'state'}"/> |
|||
<filter name="direction" string="Direction" |
|||
context="{'group_by': 'direction'}"/> |
|||
</group> |
|||
</search> |
|||
</field> |
|||
</record> |
|||
|
|||
<menuitem id="crm_phonecall_menu" name="Phone Calls" |
|||
parent="base.menu_base_partner" sequence="7" groups="base.group_sale_salesman"/> |
|||
|
|||
<record id="crm_phonecall_action" model="ir.actions.act_window"> |
|||
<field name="name">Phone Calls</field> |
|||
<field name="res_model">crm.phonecall</field> |
|||
<field name="view_mode">tree,calendar,form</field> |
|||
</record> |
|||
|
|||
<record id="crm_phonecall_action_done" model="ir.actions.act_window"> |
|||
<field name="name">Logged Calls</field> |
|||
<field name="res_model">crm.phonecall</field> |
|||
<field name="view_mode">tree,calendar,form</field> |
|||
<field name="context">{'search_default_done': 1, 'default_state': 'done'}</field> |
|||
</record> |
|||
|
|||
<menuitem id="crm_phonecall_menu_done" action="crm_phonecall_action_done" |
|||
parent="crm_phonecall_menu" sequence="10"/> |
|||
|
|||
<record id="crm_phonecall_action_open" model="ir.actions.act_window"> |
|||
<field name="name">Scheduled Calls</field> |
|||
<field name="res_model">crm.phonecall</field> |
|||
<field name="view_mode">tree,calendar,form</field> |
|||
<field name="context">{'search_default_open': 1, 'default_state': 'open'}</field> |
|||
</record> |
|||
|
|||
<menuitem id="crm_phonecall_menu_open" action="crm_phonecall_action_open" |
|||
parent="crm_phonecall_menu" sequence="20"/> |
|||
|
|||
|
|||
</data> |
|||
</odoo> |
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<!-- |
|||
© 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
--> |
|||
|
|||
<odoo> |
|||
<data> |
|||
|
|||
|
|||
<record id="view_partner_form" model="ir.ui.view"> |
|||
<field name="name">phonecall.res.partner.form</field> |
|||
<field name="model">res.partner</field> |
|||
<field name="inherit_id" ref="base.view_partner_form"/> |
|||
<field name="groups_id" eval="[(4, ref('base.group_sale_salesman')), (4, ref('base.group_partner_manager'))]"/> |
|||
<field name="arch" type="xml"> |
|||
<div name="button_box" position="inside"> |
|||
<button class="oe_inline oe_stat_button" type="action" |
|||
name="%(crm_phone.crm_phonecall_action)d" |
|||
icon="fa-phone" |
|||
context="{'search_default_partner_id': active_id}"> |
|||
<field string="Calls" name="phonecall_count" widget="statinfo"/> |
|||
</button> |
|||
</div> |
|||
</field> |
|||
</record> |
|||
|
|||
|
|||
</data> |
|||
</odoo> |
@ -1,23 +1,4 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# CRM 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 number_not_found |
|||
from . import create_crm_phonecall |
@ -1,22 +1,3 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# Event Phone module for Odoo/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 event_phone |
@ -1,44 +1,13 @@ |
|||
# -*- encoding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# Event phone module for Odoo/OpenERP |
|||
# Copyright (c) 2012-2014 Akretion (http://www.akretion.com) |
|||
# @author: Alexis de Lattre <alexis.delattre@akretion.com> |
|||
# |
|||
# 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/>. |
|||
# |
|||
############################################################################## |
|||
# -*- coding: utf-8 -*- |
|||
# © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
from openerp.osv import orm |
|||
from openerp import models |
|||
from openerp.addons.base_phone.fields import Phone |
|||
|
|||
|
|||
class event_registration(orm.Model): |
|||
_name = 'event.registration' |
|||
_inherit = ['event.registration', 'phone.common'] |
|||
_phone_fields = ['phone'] |
|||
class EventRegistration(models.Model): |
|||
_inherit = 'event.registration' |
|||
_phone_name_sequence = 100 |
|||
_country_field = None |
|||
_partner_field = 'partner_id' |
|||
|
|||
def create(self, cr, uid, vals, context=None): |
|||
vals_reformated = self._generic_reformat_phonenumbers( |
|||
cr, uid, None, vals, context=context) |
|||
return super(event_registration, 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, ids, vals, context=context) |
|||
return super(event_registration, self).write( |
|||
cr, uid, ids, vals_reformated, context=context) |
|||
phone = Phone(partner_field='partner_id') |
@ -1,22 +1,3 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# HR Phone module for Odoo/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 hr_phone |
@ -1,44 +1,14 @@ |
|||
# -*- encoding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# HR phone module for Odoo/OpenERP |
|||
# Copyright (c) 2012-2014 Akretion (http://www.akretion.com) |
|||
# @author: Alexis de Lattre <alexis.delattre@akretion.com> |
|||
# |
|||
# 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/>. |
|||
# |
|||
############################################################################## |
|||
# -*- coding: utf-8 -*- |
|||
# © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
from openerp.osv import orm |
|||
from openerp import models |
|||
from openerp.addons.base_phone.fields import Phone |
|||
|
|||
|
|||
class hr_employee(orm.Model): |
|||
_name = 'hr.employee' |
|||
_inherit = ['hr.employee', 'phone.common'] |
|||
_phone_fields = ['work_phone', 'mobile_phone'] |
|||
class HrEmployee(models.Model): |
|||
_inherit = 'hr.employee' |
|||
_phone_name_sequence = 30 |
|||
_country_field = 'country_id' |
|||
_partner_field = None |
|||
|
|||
def create(self, cr, uid, vals, context=None): |
|||
vals_reformated = self._generic_reformat_phonenumbers( |
|||
cr, uid, None, vals, context=context) |
|||
return super(hr_employee, 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, ids, vals, context=context) |
|||
return super(hr_employee, self).write( |
|||
cr, uid, ids, vals_reformated, context=context) |
|||
work_phone = Phone(country_field='country_id') |
|||
mobile_phone = Phone(country_field='country_id') |
@ -1,2 +1,3 @@ |
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
|||
callerid_hr_employee_read,Read access on hr.employee,hr.model_hr_employee,base_phone.group_callerid,1,0,0,0 |
|||
callerid_resource_resource_read,Read access on resource.resource,resource.model_resource_resource,base_phone.group_callerid,1,0,0,0 |
@ -1,22 +1,3 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# HR Recruitment Phone module for Odoo/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 hr_recruitment_phone |
@ -1,44 +1,30 @@ |
|||
# -*- encoding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# HR Recruitment phone module for Odoo/OpenERP |
|||
# Copyright (c) 2012-2014 Akretion (http://www.akretion.com) |
|||
# @author: Alexis de Lattre <alexis.delattre@akretion.com> |
|||
# |
|||
# 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/>. |
|||
# |
|||
############################################################################## |
|||
# -*- coding: utf-8 -*- |
|||
# © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
from openerp.osv import orm |
|||
from openerp import models, api |
|||
from openerp.addons.base_phone.fields import Phone |
|||
|
|||
|
|||
class hr_applicant(orm.Model): |
|||
_name = 'hr.applicant' |
|||
_inherit = ['hr.applicant', 'phone.common'] |
|||
_phone_fields = ['partner_phone', 'partner_mobile'] |
|||
class HrApplicant(models.Model): |
|||
_inherit = 'hr.applicant' |
|||
_phone_name_sequence = 50 |
|||
_country_field = None |
|||
_partner_field = 'partner_id' |
|||
|
|||
def create(self, cr, uid, vals, context=None): |
|||
vals_reformated = self._generic_reformat_phonenumbers( |
|||
cr, uid, None, vals, context=context) |
|||
return super(hr_applicant, self).create( |
|||
cr, uid, vals_reformated, context=context) |
|||
partner_phone = Phone(partner_field='partner_id') |
|||
partner_mobile = Phone(partner_field='partner_id') |
|||
|
|||
def write(self, cr, uid, ids, vals, context=None): |
|||
vals_reformated = self._generic_reformat_phonenumbers( |
|||
cr, uid, ids, vals, context=context) |
|||
return super(hr_applicant, self).write( |
|||
cr, uid, ids, vals_reformated, context=context) |
|||
@api.multi |
|||
def name_get(self): |
|||
if self._context.get('callerid'): |
|||
res = [] |
|||
for appl in self: |
|||
if appl.partner_id: |
|||
name = u'%s (%s)' % (appl.partner_id.name, appl.name) |
|||
elif appl.partner_name: |
|||
name = u'%s (%s)' % (appl.partner_name, appl.name) |
|||
else: |
|||
name = appl.name |
|||
res.append((appl.id, name)) |
|||
return res |
|||
else: |
|||
return super(HrApplicant, self).name_get() |
@ -1,22 +1,3 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################## |
|||
# |
|||
# OVH Connector module for Odoo |
|||
# Copyright (C) 2015 Alexis de Lattre <alexis@via.ecp.fr> |
|||
# |
|||
# This program is free software: you can redistribute it and/or modify |
|||
# it under the terms of the GNU Affero General Public License as |
|||
# 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 ovh_connector |
Write
Preview
Loading…
Cancel
Save
Reference in new issue