[IMP] im_livechat: allow visitors to receive calls
task-2900771 closes odoo/odoo#135109 Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
@@ -98,6 +98,7 @@ Help your customers with this chat, and analyse their feedback.
|
||||
'web/static/lib/odoo_ui_icons/style.css',
|
||||
'mail/static/src/core/common/**/*',
|
||||
'mail/static/src/discuss/core/common/*',
|
||||
'mail/static/src/discuss/call/common/**',
|
||||
'mail/static/src/discuss/typing/**/*',
|
||||
'mail/static/src/utils/common/**/*',
|
||||
('remove', 'mail/static/src/**/*.dark.scss'),
|
||||
|
||||
@@ -6,5 +6,6 @@ from . import chatbot
|
||||
from . import link_preview
|
||||
from . import main
|
||||
from . import message_reaction
|
||||
from . import rtc
|
||||
from . import thread
|
||||
from . import webclient
|
||||
|
||||
@@ -275,14 +275,18 @@ class LivechatController(http.Controller):
|
||||
channel._email_livechat_transcript(email)
|
||||
|
||||
@http.route('/im_livechat/visitor_leave_session', type='json', auth="public", cors="*")
|
||||
@add_guest_to_context
|
||||
def visitor_leave_session(self, uuid):
|
||||
""" Called when the livechat visitor leaves the conversation.
|
||||
This will clean the chat request and warn the operator that the conversation is over.
|
||||
This allows also to re-send a new chat request to the visitor, as while the visitor is
|
||||
in conversation with an operator, it's not possible to send the visitor a chat request."""
|
||||
discuss_channel = request.env['discuss.channel'].sudo().search([('uuid', '=', uuid)])
|
||||
if discuss_channel:
|
||||
discuss_channel._close_livechat_session()
|
||||
if not discuss_channel:
|
||||
return
|
||||
channel_member_sudo = request.env["discuss.channel.member"]._get_as_sudo_from_context_or_raise(channel_id=discuss_channel.id)
|
||||
channel_member_sudo._rtc_leave_call()
|
||||
discuss_channel._close_livechat_session()
|
||||
|
||||
@http.route(['/im_livechat/chat_history'], type="json", auth="public", cors="*")
|
||||
def im_livechat_chat_history(self, uuid, last_id=False, limit=20):
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.http import route
|
||||
from odoo.addons.mail.models.discuss.mail_guest import add_guest_to_context
|
||||
from odoo.addons.mail.controllers.discuss.rtc import RtcController
|
||||
|
||||
|
||||
class LivechatRtcController(RtcController):
|
||||
@route("/mail/rtc/session/notify_call_members", cors="*")
|
||||
@add_guest_to_context
|
||||
def session_call_notify(self, peer_notifications):
|
||||
return super().session_call_notify(peer_notifications)
|
||||
|
||||
@route("/mail/rtc/session/update_and_broadcast", cors="*")
|
||||
@add_guest_to_context
|
||||
def session_update_and_broadcast(self, session_id, values):
|
||||
return super().session_update_and_broadcast(session_id, values)
|
||||
|
||||
@route("/mail/rtc/channel/join_call", cors="*")
|
||||
@add_guest_to_context
|
||||
def channel_call_join(self, channel_id, check_rtc_session_ids=None):
|
||||
return super().channel_call_join(channel_id, check_rtc_session_ids=check_rtc_session_ids)
|
||||
|
||||
@route("/mail/rtc/channel/leave_call", cors="*")
|
||||
@add_guest_to_context
|
||||
def channel_call_leave(self, channel_id):
|
||||
return super().channel_call_leave(channel_id)
|
||||
|
||||
@route("/discuss/channel/ping", cors="*")
|
||||
@add_guest_to_context
|
||||
def channel_ping(self, channel_id, rtc_session_id=None, check_rtc_session_ids=None):
|
||||
return super().channel_ping(channel_id, rtc_session_id=rtc_session_id, check_rtc_session_ids=check_rtc_session_ids)
|
||||
@@ -31,6 +31,10 @@ patch(Thread, {
|
||||
});
|
||||
|
||||
patch(Thread.prototype, {
|
||||
get typesAllowingCalls() {
|
||||
return super.typesAllowingCalls.concat(["livechat"]);
|
||||
},
|
||||
|
||||
get isChannel() {
|
||||
return this.type === "livechat" || super.isChannel;
|
||||
},
|
||||
|
||||
@@ -39,7 +39,7 @@ patch(Store.prototype, {
|
||||
},
|
||||
});
|
||||
|
||||
const allowedThreadActions = new Set(["fold-chat-window", "close", "restart"]);
|
||||
const allowedThreadActions = new Set(["fold-chat-window", "close", "restart", "settings"]);
|
||||
for (const [actionName] of threadActionsRegistry.getEntries()) {
|
||||
if (!allowedThreadActions.has(actionName)) {
|
||||
threadActionsRegistry.remove(actionName);
|
||||
|
||||
@@ -127,14 +127,13 @@ export class LivechatService {
|
||||
*/
|
||||
async leaveSession({ notifyServer = true } = {}) {
|
||||
const session = JSON.parse(this.cookie.current[this.SESSION_COOKIE] ?? "{}");
|
||||
if (this.state === SESSION_STATE.PERSISTED && notifyServer) {
|
||||
this.busService.deleteChannel(session.uuid);
|
||||
await this.rpc("/im_livechat/visitor_leave_session", { uuid: session.uuid });
|
||||
}
|
||||
this.cookie.deleteCookie(this.SESSION_COOKIE);
|
||||
this.state = SESSION_STATE.NONE;
|
||||
this.sessionInitialized = false;
|
||||
if (!session?.uuid || !notifyServer) {
|
||||
return;
|
||||
}
|
||||
this.busService.deleteChannel(session.uuid);
|
||||
await this.rpc("/im_livechat/visitor_leave_session", { uuid: session.uuid });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,11 +4,10 @@ import { Messaging } from "@mail/core/common/messaging_service";
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { session } from "@web/session";
|
||||
import { SESSION_STATE } from "@im_livechat/embed/core/livechat_service";
|
||||
|
||||
patch(Messaging.prototype, {
|
||||
initialize() {
|
||||
if (this.env.services["im_livechat.livechat"].state === SESSION_STATE.PERSISTED) {
|
||||
if (this.env.services["im_livechat.livechat"].guestToken) {
|
||||
return super.initialize();
|
||||
}
|
||||
if (session.livechatData?.options.current_partner_id) {
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { SESSION_STATE } from "@im_livechat/embed/core/livechat_service";
|
||||
|
||||
registry.category("mail.thread/actions").add("restart", {
|
||||
import { threadActionsRegistry } from "@mail/core/common/thread_actions";
|
||||
import "@mail/discuss/call/common/thread_actions";
|
||||
import { useComponent } from "@odoo/owl";
|
||||
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
threadActionsRegistry.add("restart", {
|
||||
condition(component) {
|
||||
return component.chatbotService.canRestart;
|
||||
},
|
||||
@@ -15,3 +22,22 @@ registry.category("mail.thread/actions").add("restart", {
|
||||
},
|
||||
sequence: 99,
|
||||
});
|
||||
|
||||
const callSettingsAction = threadActionsRegistry.get("settings");
|
||||
patch(callSettingsAction, {
|
||||
condition(component) {
|
||||
if (component.thread?.type !== "livechat") {
|
||||
return super.condition(...arguments);
|
||||
}
|
||||
return (
|
||||
component.livechatService.state === SESSION_STATE.PERSISTED &&
|
||||
component.rtcService.state.channel?.eq(component.thread)
|
||||
);
|
||||
},
|
||||
setup() {
|
||||
super.setup(...arguments);
|
||||
const component = useComponent();
|
||||
component.livechatService = useService("im_livechat.livechat");
|
||||
component.rtcService = useService("discuss.rtc");
|
||||
},
|
||||
});
|
||||
|
||||
@@ -56,6 +56,10 @@ patch(Thread.prototype, {
|
||||
return this.type === "livechat" || super.isChatChannel;
|
||||
},
|
||||
|
||||
get typesAllowingCalls() {
|
||||
return super.typesAllowingCalls.concat(["livechat"]);
|
||||
},
|
||||
|
||||
get isLastMessageFromCustomer() {
|
||||
if (this.type !== "livechat") {
|
||||
return super.isLastMessageFromCustomer;
|
||||
|
||||
@@ -1,30 +1,9 @@
|
||||
/* @odoo-module */
|
||||
|
||||
import { Command } from "@mail/../tests/helpers/command";
|
||||
import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils";
|
||||
import { click, start, startServer } from "@mail/../tests/helpers/test_utils";
|
||||
|
||||
QUnit.module("chat window (patch)");
|
||||
|
||||
QUnit.test("No call buttons", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const guestId = pyEnv["mail.guest"].create({ name: "Visitor 11" });
|
||||
pyEnv["discuss.channel"].create({
|
||||
anonymous_name: "Visitor 11",
|
||||
channel_member_ids: [
|
||||
[0, 0, { partner_id: pyEnv.currentPartnerId }],
|
||||
Command.create({ guest_id: guestId }),
|
||||
],
|
||||
channel_type: "livechat",
|
||||
livechat_operator_id: pyEnv.currentPartnerId,
|
||||
});
|
||||
await start();
|
||||
await click(".o_menu_systray i[aria-label='Messages']");
|
||||
await click(".o-mail-NotificationItem");
|
||||
await contains(".o-mail-ChatWindow");
|
||||
await contains(".o-mail-ChatWindow-command i.fa-phone", { count: 0 });
|
||||
await contains(".o-mail-ChatWindow-command i.fa-gear", { count: 0 });
|
||||
});
|
||||
|
||||
QUnit.test("closing a chat window with no message from admin side unpins it", async (assert) => {
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({ name: "Demo" });
|
||||
|
||||
@@ -7,25 +7,6 @@ import { start, startServer } from "@mail/../tests/helpers/test_utils";
|
||||
|
||||
QUnit.module("discuss (patch)");
|
||||
|
||||
QUnit.test("No call buttons", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const guestId = pyEnv["mail.guest"].create({ name: "Visitor 11" });
|
||||
pyEnv["discuss.channel"].create({
|
||||
anonymous_name: "Visitor 11",
|
||||
channel_member_ids: [
|
||||
[0, 0, { partner_id: pyEnv.currentPartnerId }],
|
||||
Command.create({ guest_id: guestId }),
|
||||
],
|
||||
channel_type: "livechat",
|
||||
livechat_operator_id: pyEnv.currentPartnerId,
|
||||
});
|
||||
const { openDiscuss } = await start();
|
||||
await openDiscuss();
|
||||
await contains(".o-mail-Discuss-header");
|
||||
await contains(".o-mail-Discuss-header button[title='Start a Call']", { count: 0 });
|
||||
await contains(".o-mail-Discuss-header button[title='Show Call Settings']", { count: 0 });
|
||||
});
|
||||
|
||||
QUnit.test("add livechat in the sidebar on visitor sending first message", async () => {
|
||||
const pyEnv = await startServer();
|
||||
pyEnv["res.users"].write([pyEnv.currentUserId], { im_status: "online" });
|
||||
|
||||
@@ -248,9 +248,13 @@ export class Thread extends Record {
|
||||
return ["chat", "channel", "group"].includes(this.type);
|
||||
}
|
||||
|
||||
get typesAllowingCalls() {
|
||||
return ["chat", "channel", "group"];
|
||||
}
|
||||
|
||||
get allowCalls() {
|
||||
return (
|
||||
["chat", "channel", "group"].includes(this.type) &&
|
||||
this.typesAllowingCalls.includes(this.type) &&
|
||||
!this.correspondent?.eq(this._store.odoobot)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user