Skip to content

Commit

Permalink
[ADD] voip_oca
Browse files Browse the repository at this point in the history
Co-authored-by: Luis Rodríguez <luis.rodrigues@dixmit.com>
  • Loading branch information
etobella and Luis Rodríguez committed Mar 9, 2025
1 parent c756a62 commit 37a0cd1
Show file tree
Hide file tree
Showing 62 changed files with 24,783 additions and 0 deletions.
171 changes: 171 additions & 0 deletions voip_oca/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
========
Voip OCA
========

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:47d50ef1020cecf9f9e86092d8f1ccbf956584c838aafd013e8526008182795f
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fconnector--telephony-lightgray.png?logo=github
:target: https://github.com/OCA/connector-telephony/tree/17.0/voip_oca
:alt: OCA/connector-telephony
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/connector-telephony-17-0/connector-telephony-17-0-voip_oca
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/connector-telephony&target_branch=17.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module allows the use of VOIP directly from Odoo.

It relies on SIP.js to connect to the PBX using a websocket directly
from the browser.

Odoo server will not connect directly to the PBX server, but will have
users and passwords stored.

**Table of contents**

.. contents::
:local:

Configuration
=============

Create the PBX Connection
-------------------------

- Access in Debug mode.
- Go to ``Settings > Technical > Discuss > PBX Servers``.
- Create a PBX server and define the domain name and websocket link.

You can set it as ``Development`` or ``Production``. Development
environment will never contact the PBX server.

Configure users
---------------

For each user, we need to define their PBX server, user and password. To
do this, we have two options:

1. Configure users as an admin and define the information directly
2. As a user, go to your Preferences and modify the information.

Usage
=====

Automatically the system will login into the PBX server once we enter
odoo with our user. If we are on a test environment, no login is made
and the libraries of SIP are not loaded.

Once we are logged, we can use the VOIP widget in order to call
directly. In order to open all the selectors, we can press on the top
bar and the bottom widget will be opened.

.. figure:: https://raw.githubusercontent.com/OCA/connector-telephony/17.0/voip_oca/static/description/widget.png

We can make call by:

1. Select the partner and press the number
2. Select an activity and press the number of the associated partner
3. Select an old call and press the number
4. Press the keyboard and write the number directly

.. figure:: https://raw.githubusercontent.com/OCA/connector-telephony/17.0/voip_oca/static/description/partner.png

Inside a call, we can transfer the call, end the call, mute the call and
put the call on Hold.

Also, the system allows to receive call. In that case, the system will
try to find the related partner and will open the widget automatically.

.. figure:: https://raw.githubusercontent.com/OCA/connector-telephony/17.0/voip_oca/static/description/received_call.png

Known issues / Roadmap
======================

The following options are interesting but are not implemented right now:

- Allow to enable or disable the VOIP as a user (Login / Logout)
- Create a call system where the calls are done automatically according
to tasks

The following options will be done before release:

- Show the status of the VOIP connection on the header

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/connector-telephony/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/connector-telephony/issues/new?body=module:%20voip_oca%0Aversion:%2017.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* Dixmit

Contributors
------------

- `Dixmit <https://www.dixmit.com>`__:

- Enric Alomar
- Luis Rodríguez

Other credits
-------------

The development of this module has been financially supported by:

- Associacion Española de Odoo (`AEODOO <https://www.aeodoo.org/>`__)

The tones provided by default comes from Pixabay:

- Ringback tone: Sound Effect by freesound_community from Pixabay
- Call tone: Sound Effect by Jeremay Jimenez from Pixabay
- Dial tone: Sound Effect by freesound_community from Pixabay

Maintainers
-----------

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

.. |maintainer-etobella| image:: https://github.com/etobella.png?size=40px
:target: https://github.com/etobella
:alt: etobella

Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-etobella|

This module is part of the `OCA/connector-telephony <https://github.com/OCA/connector-telephony/tree/17.0/voip_oca>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions voip_oca/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
33 changes: 33 additions & 0 deletions voip_oca/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright 2025 Dixmit
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

{
"name": "Voip OCA",
"summary": "Provides the use of Voip",
"version": "17.0.1.0.0",
"author": "Dixmit, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/connector-telephony",
"license": "AGPL-3",
"category": "Productivity/VOIP",
"depends": ["mail"],
"maintainers": ["etobella"],
"data": [
"security/ir.model.access.csv",
"views/res_users.xml",
"views/voip_oca_call.xml",
"views/voip_oca_pbx.xml",
"views/menus.xml",
],
"demo": ["demo/demo_data.xml"],
"assets": {
"web.assets_backend": [
"voip_oca/static/src/**/*.scss",
"voip_oca/static/src/**/*.xml",
"voip_oca/static/src/**/*.esm.js",
"voip_oca/static/src/**/*.d.ts",
],
"voip_oca.agent_assets": [
"voip_oca/static/lib/*.js",
],
},
}
4 changes: 4 additions & 0 deletions voip_oca/data/neutralize.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- disable VOIP module by default

UPDATE voip_oca_pbx SET mode = 'test';
UPDATE res_users SET voip_username = NULL, voip_password = NULL WHERE voip_username IS NOT NULL;
24 changes: 24 additions & 0 deletions voip_oca/demo/demo_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<odoo>
<record id="voip_call_1" model="voip.oca.call">
<field name="partner_id" ref="base.res_partner_1" />
<field name="user_id" ref="base.user_admin" />
<field name="phone_number">+1234567890</field>
<field name="type_call">outgoing</field>
<field name="state">terminated</field>
<field name="activity_name">Call to +1234567890</field>
<field name="end_date">2020-01-01 10:15:00</field>
<field name="start_date">2020-01-01 10:00:00</field>
</record>

<record id="voip_call_2" model="voip.oca.call">
<field name="partner_id" ref="base.res_partner_2" />
<field name="user_id" ref="base.user_admin" />
<field name="phone_number">+1234567842</field>
<field name="type_call">incoming</field>
<field name="state">missed</field>
<field name="activity_name">Call to +1234567890</field>
<field name="end_date">2020-01-01 15:37:00</field>
<field name="start_date">2020-01-01 14:00:00</field>
</record>

</odoo>
7 changes: 7 additions & 0 deletions voip_oca/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from . import res_partner
from . import voip_oca_call
from . import mail_activity
from . import mail_activity_mixin
from . import res_users
from . import voip_oca_pbx
from . import ir_http
19 changes: 19 additions & 0 deletions voip_oca/models/ir_http.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2025 Dixmit
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import models
from odoo.http import request


class Http(models.AbstractModel):
_inherit = "ir.http"

def session_info(self):
res = super().session_info()
user = request.env.user
res.update(
{
"voip": user._get_voip_info(),
}
)
return res
44 changes: 44 additions & 0 deletions voip_oca/models/mail_activity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright 2025 Dixmit
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import api, fields, models
from odoo.osv import expression


class VoipOcaActivity(models.Model):
_inherit = "mail.activity"

main_partner_id = fields.Many2one(
"res.partner", string="Main Contact", compute="_compute_main_partner_id"
)
main_partner = fields.Char(compute="_compute_main_partner_id")

@api.depends("res_id")
def _compute_main_partner_id(self):
for activity in self:
partner = (
self.env[activity.res_model]
.browse(activity.res_id)
.activity_main_partner_id
)
activity.main_partner_id = partner
activity.main_partner = partner.name

@api.model
def get_call_activities(self, _search, offset, limit):
activity_type_id = self.env["mail.activity.type"].search(
[("name", "=", "Call")], limit=1
)
domain = [
("user_id", "=", self.env.uid),
("activity_type_id", "=", activity_type_id.id),
("date_deadline", "<=", fields.Datetime.now()),
]
if _search:
search_fields = ["res_name", "summary", "date_deadline"]
search_domain = expression.OR(
[[(field, "ilike", _search)] for field in search_fields]
)
domain = expression.AND([domain, search_domain])
activities = self.search(domain, offset=offset, limit=limit)
return activities.activity_format()
25 changes: 25 additions & 0 deletions voip_oca/models/mail_activity_mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright 2025 Dixmit
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import fields, models


class ResConfigSettings(models.AbstractModel):
_inherit = "mail.activity.mixin"

activity_main_partner_id = fields.Many2one(
"res.partner",
string="Main Contact",
compute="_compute_activity_main_partner_id",
)

def _compute_activity_main_partner_id(self):
for record in self:
record.activity_main_partner_id = record.get_activity_main_partner_id()

def get_activity_main_partner_id(self):
if self._name == "res.partner":
return self
if "partner_id" in self._fields:
return self.partner_id
return self.env["res.partner"]
32 changes: 32 additions & 0 deletions voip_oca/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright 2025 Dixmit
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import api, models
from odoo.osv import expression


class VoipOcaCall(models.Model):
_inherit = "res.partner"

def format_partner(self):
return {
"id": self.id,
"type": "partner",
"displayName": self.display_name,
"email": self.email,
"landlineNumber": self.phone,
"mobileNumber": self.mobile,
"name": self.name,
}

@api.model
def get_voip_contacts(self, _search, offset, limit):
domain = ["|", ("phone", "!=", False), ("mobile", "!=", False)]
if _search:
search_fields = ["name", "phone", "mobile", "email"]
search_domain = expression.OR(
[[(field, "ilike", _search)] for field in search_fields]
)
domain = expression.AND([domain, search_domain])
contacts = self.search(domain, offset=offset, limit=limit)
return [contact.format_partner() for contact in contacts]
Loading

0 comments on commit 37a0cd1

Please sign in to comment.