mirror of
https://github.com/bringout/oca-ocb-mail.git
synced 2026-04-22 23:02:00 +02:00
19.0 vanilla
This commit is contained in:
parent
5df8c07b59
commit
daa394e8b0
2114 changed files with 564841 additions and 299642 deletions
|
|
@ -0,0 +1,265 @@
|
|||
import {
|
||||
mailDataHelpers,
|
||||
parseRequestParams,
|
||||
registerRoute,
|
||||
} from "@mail/../tests/mock_server/mail_mock_server";
|
||||
import { Command, makeKwArgs, serverState } from "@web/../tests/web_test_helpers";
|
||||
import { loadBundle } from "@web/core/assets";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
/**
|
||||
* @template [T={}]
|
||||
* @typedef {import("@web/../tests/web_test_helpers").RouteCallback<T>} RouteCallback
|
||||
*/
|
||||
|
||||
registerRoute("/im_livechat/get_session", get_session);
|
||||
/** @type {RouteCallback} */
|
||||
async function get_session(request) {
|
||||
/** @type {import("mock_models").DiscussChannel} */
|
||||
const DiscussChannel = this.env["discuss.channel"];
|
||||
/** @type {import("mock_models").LivechatChannel} */
|
||||
const LivechatChannel = this.env["im_livechat.channel"];
|
||||
/** @type {import("mock_models").ResCountry} */
|
||||
const ResCountry = this.env["res.country"];
|
||||
/** @type {import("mock_models").ResPartner} */
|
||||
const ResPartner = this.env["res.partner"];
|
||||
/** @type {import("mock_models").ResUsers} */
|
||||
const ResUsers = this.env["res.users"];
|
||||
|
||||
let {
|
||||
channel_id,
|
||||
previous_operator_id,
|
||||
persisted,
|
||||
context = {},
|
||||
} = await parseRequestParams(request);
|
||||
previous_operator_id = parseInt(previous_operator_id);
|
||||
const agent = LivechatChannel._get_operator(channel_id, previous_operator_id);
|
||||
if (!agent) {
|
||||
return false;
|
||||
}
|
||||
let country_id;
|
||||
if (this.env.user && !ResUsers._is_public(this.env.uid)) {
|
||||
country_id = this.env.user.country_id;
|
||||
} else if (context.mockedCountryCode) {
|
||||
// simulate geoip
|
||||
const country = ResCountry._filter([["code", "=", context.mockedCountryCode]])[0];
|
||||
if (country) {
|
||||
country_id = country.id;
|
||||
}
|
||||
}
|
||||
if (!persisted) {
|
||||
const store = new mailDataHelpers.Store();
|
||||
ResUsers._init_store_data(store);
|
||||
store.add("discuss.channel", {
|
||||
channel_type: "livechat",
|
||||
fetchChannelInfoState: "fetched",
|
||||
id: -1,
|
||||
isLoaded: true,
|
||||
livechat_operator_id: mailDataHelpers.Store.one(
|
||||
ResPartner.browse(agent.partner_id),
|
||||
makeKwArgs({ fields: ["avatar_128", "user_livechat_username"] })
|
||||
),
|
||||
scrollUnread: false,
|
||||
});
|
||||
return { store_data: store.get_result(), channel_id: -1 };
|
||||
}
|
||||
const channelVals = LivechatChannel._get_livechat_discuss_channel_vals(channel_id, {
|
||||
agent: agent,
|
||||
});
|
||||
channelVals.country_id = country_id;
|
||||
const channelId = DiscussChannel.create(channelVals);
|
||||
const store = new mailDataHelpers.Store();
|
||||
ResUsers._init_store_data(store);
|
||||
store.add(DiscussChannel.browse(channelId));
|
||||
store.add(DiscussChannel.browse(channelId), {
|
||||
isLoaded: true,
|
||||
scrollUnread: false,
|
||||
});
|
||||
return { store_data: store.get_result(), channel_id: channelId };
|
||||
}
|
||||
|
||||
registerRoute("/im_livechat/visitor_leave_session", visitor_leave_session);
|
||||
/** @type {RouteCallback} */
|
||||
async function visitor_leave_session(request) {
|
||||
/** @type {import("mock_models").DiscussChannel} */
|
||||
const DiscussChannel = this.env["discuss.channel"];
|
||||
|
||||
const { channel_id } = await parseRequestParams(request);
|
||||
const [channel] = DiscussChannel.search_read([["id", "=", channel_id]]);
|
||||
if (!channel) {
|
||||
return;
|
||||
}
|
||||
DiscussChannel._close_livechat_session(channel_id);
|
||||
}
|
||||
registerRoute("/im_livechat/feedback", feedback);
|
||||
/** @type {RouteCallback} */
|
||||
async function feedback(request) {
|
||||
/** @type {import("mock_models").DiscussChannel} */
|
||||
const DiscussChannel = this.env["discuss.channel"];
|
||||
/** @type {import("mock_models").RatingRating} */
|
||||
const RatingRating = this.env["rating.rating"];
|
||||
|
||||
const { channel_id, rate, reason } = await parseRequestParams(request);
|
||||
let [channel] = DiscussChannel.search_read([["id", "=", channel_id]]);
|
||||
if (!channel) {
|
||||
return false;
|
||||
}
|
||||
const values = {
|
||||
rating: rate,
|
||||
consumed: true,
|
||||
feedback: reason,
|
||||
is_internal: false,
|
||||
res_id: channel.id,
|
||||
res_model: "discuss.channel",
|
||||
rated_partner_id: channel.channel_partner_ids[0],
|
||||
};
|
||||
if (channel.rating_ids.length === 0) {
|
||||
RatingRating.create(values);
|
||||
} else {
|
||||
RatingRating.write([channel.rating_ids[0]], values);
|
||||
}
|
||||
[channel] = DiscussChannel.search_read([["id", "=", channel_id]]);
|
||||
return channel.rating_ids[0];
|
||||
}
|
||||
|
||||
registerRoute("/im_livechat/init", livechat_init);
|
||||
/** @type {RouteCallback} */
|
||||
async function livechat_init(request) {
|
||||
return {
|
||||
available_for_me: true,
|
||||
rule: {},
|
||||
};
|
||||
}
|
||||
|
||||
registerRoute("/im_livechat/email_livechat_transcript", email_livechat_transcript);
|
||||
/** @type {RouteCallback} */
|
||||
async function email_livechat_transcript(request) {
|
||||
const DiscussChannel = this.env["discuss.channel"];
|
||||
const { channel_id, email } = await parseRequestParams(request);
|
||||
const [channel] = DiscussChannel.search_read([["id", "=", channel_id]]);
|
||||
if (!channel) {
|
||||
return;
|
||||
}
|
||||
DiscussChannel._email_livechat_transcript(channel_id, email);
|
||||
}
|
||||
|
||||
registerRoute("/im_livechat/emoji_bundle", get_emoji_bundle);
|
||||
/** @type {RouteCallback} */
|
||||
async function get_emoji_bundle(request) {
|
||||
await loadBundle("web.assets_emoji");
|
||||
return new Response();
|
||||
}
|
||||
|
||||
registerRoute("/im_livechat/session/update_status", session_update_status);
|
||||
/** @type {RouteCallback} */
|
||||
async function session_update_status(request) {
|
||||
/** @type {import("mock_models").DiscussChannel} */
|
||||
const DiscussChannel = this.env["discuss.channel"];
|
||||
const { channel_id, livechat_status } = await parseRequestParams(request);
|
||||
if (this.env.user.share) {
|
||||
return false;
|
||||
}
|
||||
const [channel] = DiscussChannel.search_read([["id", "=", channel_id]]);
|
||||
if (!channel) {
|
||||
return false;
|
||||
}
|
||||
DiscussChannel.write([channel_id], {
|
||||
livechat_status: livechat_status,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
registerRoute("/im_livechat/session/update_note", session_update_note);
|
||||
/** @type {RouteCallback} */
|
||||
async function session_update_note(request) {
|
||||
/** @type {import("mock_models").DiscussChannel} */
|
||||
const DiscussChannel = this.env["discuss.channel"];
|
||||
const { channel_id, note } = await parseRequestParams(request);
|
||||
if (this.env.user.share) {
|
||||
return false;
|
||||
}
|
||||
const [channel] = DiscussChannel.search_read([["id", "=", channel_id]]);
|
||||
if (!channel) {
|
||||
return false;
|
||||
}
|
||||
DiscussChannel.write([channel_id], {
|
||||
livechat_note: note,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
registerRoute("/im_livechat/conversation/write_expertises", livechat_conversation_write_expertises);
|
||||
/** @type {RouteCallback} */
|
||||
async function livechat_conversation_write_expertises(request) {
|
||||
/** @type {import("mock_models").DiscussChannel} */
|
||||
const DiscussChannel = this.env["discuss.channel"];
|
||||
const { channel_id, orm_commands } = await parseRequestParams(request);
|
||||
const [channel] = DiscussChannel.search_read([["id", "=", channel_id]]);
|
||||
if (!channel) {
|
||||
return false;
|
||||
}
|
||||
DiscussChannel.write(channel_id, { livechat_expertise_ids: orm_commands });
|
||||
}
|
||||
|
||||
registerRoute(
|
||||
"/im_livechat/conversation/create_and_link_expertise",
|
||||
livechat_conversation_create_and_link_expertise
|
||||
);
|
||||
/** @type {RouteCallback} */
|
||||
async function livechat_conversation_create_and_link_expertise(request) {
|
||||
/** @type {import("mock_models").DiscussChannel} */
|
||||
const DiscussChannel = this.env["discuss.channel"];
|
||||
/** @type {import("mock_models").ImLivechatExpertise} */
|
||||
const ImLivechatExpertise = this.env["im_livechat.expertise"];
|
||||
const { channel_id, expertise_name } = await parseRequestParams(request);
|
||||
const [channel] = DiscussChannel.search([["id", "=", channel_id]]);
|
||||
if (!channel) {
|
||||
return false;
|
||||
}
|
||||
const [expertise] = ImLivechatExpertise.search([["name", "=", expertise_name]]);
|
||||
let expertiseId = expertise?.id;
|
||||
if (!expertise) {
|
||||
expertiseId = ImLivechatExpertise.create({ name: expertise_name });
|
||||
}
|
||||
DiscussChannel.write(channel_id, { livechat_expertise_ids: [Command.link(expertiseId)] });
|
||||
}
|
||||
|
||||
patch(mailDataHelpers, {
|
||||
_process_request_for_all(store, name, params) {
|
||||
const ResPartner = this.env["res.partner"];
|
||||
const ResUsers = this.env["res.users"];
|
||||
super._process_request_for_all(...arguments);
|
||||
store.add({ livechat_available: true });
|
||||
if (name === "init_livechat") {
|
||||
if (this.env.user && !ResUsers._is_public(this.env.uid)) {
|
||||
store.add(
|
||||
ResPartner.browse(this.env.user.partner_id),
|
||||
makeKwArgs({ fields: ["email"] })
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
_process_request_for_internal_user(store, name, params) {
|
||||
super._process_request_for_internal_user(...arguments);
|
||||
if (name === "im_livechat.channel") {
|
||||
const LivechatChannel = this.env["im_livechat.channel"];
|
||||
store.add(
|
||||
LivechatChannel.browse(LivechatChannel.search([])),
|
||||
makeKwArgs({ fields: ["are_you_inside", "name"] })
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (name === "/im_livechat/looking_for_help") {
|
||||
const DiscussChannel = this.env["discuss.channel"];
|
||||
store.add(
|
||||
DiscussChannel.browse(
|
||||
DiscussChannel.search([["livechat_status", "=", "need_help"]])
|
||||
)
|
||||
);
|
||||
}
|
||||
if (name === "/im_livechat/fetch_self_expertise") {
|
||||
const ResUsers = this.env["res.users"];
|
||||
store.add(ResUsers.browse(serverState.userId), ["livechat_expertise_ids"]);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
declare module "mock_models" {
|
||||
import { LivechatChannel as LivechatChannel2 } from "../im_livechat_channel";
|
||||
import { RatingRating as RatingRating2 } from "../rating_rating";
|
||||
|
||||
export interface LivechatChannel extends LivechatChannel2 {}
|
||||
export interface RatingRating extends RatingRating2 {}
|
||||
|
||||
export interface Models {
|
||||
"im_livechat.channel": LivechatChannel,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
import { mailModels } from "@mail/../tests/mail_test_helpers";
|
||||
import { mailDataHelpers } from "@mail/../tests/mock_server/mail_mock_server";
|
||||
|
||||
import { fields, getKwArgs, makeKwArgs, serverState } from "@web/../tests/web_test_helpers";
|
||||
import { serializeDate } from "@web/core/l10n/dates";
|
||||
import { ensureArray } from "@web/core/utils/arrays";
|
||||
|
||||
export class DiscussChannel extends mailModels.DiscussChannel {
|
||||
livechat_channel_id = fields.Many2one({ relation: "im_livechat.channel", string: "Channel" }); // FIXME: somehow not fetched properly
|
||||
livechat_lang_id = fields.Many2one({ relation: "res.lang", string: "Language" });
|
||||
livechat_note = fields.Html({ sanitize: true });
|
||||
livechat_status = fields.Selection({
|
||||
selection: [
|
||||
("in_progress", "In progress"),
|
||||
("waiting", "Waiting for customer"),
|
||||
("need_help", "Looking for help"),
|
||||
],
|
||||
});
|
||||
livechat_expertise_ids = fields.Many2many({
|
||||
relation: "im_livechat.expertise",
|
||||
});
|
||||
|
||||
action_unfollow(idOrIds) {
|
||||
/** @type {import("mock_models").BusBus} */
|
||||
const BusBus = this.env["bus.bus"];
|
||||
|
||||
const ids = ensureArray(idOrIds);
|
||||
for (const channel_id of ids) {
|
||||
const [channel] = this.browse(channel_id);
|
||||
if (channel.channel_type == "livechat" && channel.channel_member_ids.length <= 2) {
|
||||
this.write([channel.id], { livechat_end_dt: serializeDate(luxon.DateTime.now()) });
|
||||
BusBus._sendone(
|
||||
channel,
|
||||
"mail.record/insert",
|
||||
new mailDataHelpers.Store()
|
||||
.add(this.browse(channel_id), makeKwArgs({ fields: ["livechat_end_dt"] }))
|
||||
.get_result()
|
||||
);
|
||||
}
|
||||
}
|
||||
return super.action_unfollow(...arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @param {number[]} ids
|
||||
* @param {number[]} partner_ids
|
||||
* @param {boolean} [invite_to_rtc_call=undefined]
|
||||
*/
|
||||
add_members(ids, partner_ids, invite_to_rtc_call) {
|
||||
const kwargs = getKwArgs(arguments, "ids", "partner_ids", "invite_to_rtc_call");
|
||||
ids = kwargs.ids;
|
||||
delete kwargs.ids;
|
||||
partner_ids = kwargs.partner_ids || [];
|
||||
const channels = this.browse(
|
||||
Array.from(super.add_members(ids, partner_ids, invite_to_rtc_call)).map(
|
||||
({ channel_id }) => channel_id
|
||||
)
|
||||
);
|
||||
for (const channel of channels) {
|
||||
if (channel.livechat_status == "need_help") {
|
||||
this.write([channel.id], { livechat_status: "in_progress" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_channel_basic_info_fields() {
|
||||
return [
|
||||
...super._channel_basic_info_fields(),
|
||||
"livechat_lang_id",
|
||||
"livechat_note",
|
||||
"livechat_status",
|
||||
"livechat_expertise_ids",
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @type {typeof mailModels.DiscussChannel["prototype"]["_to_store"]}
|
||||
*/
|
||||
_to_store(store) {
|
||||
/** @type {import("mock_models").ResCountry} */
|
||||
const ResCountry = this.env["res.country"];
|
||||
/** @type {import("mock_models").ResLang} */
|
||||
const ResLang = this.env["res.lang"];
|
||||
/** @type {import("mock_models").ResPartner} */
|
||||
const ResPartner = this.env["res.partner"];
|
||||
|
||||
super._to_store(...arguments);
|
||||
for (const channel of this) {
|
||||
const channelInfo = {};
|
||||
const [country] = ResCountry.browse(channel.country_id);
|
||||
channelInfo["country_id"] = country
|
||||
? {
|
||||
code: country.code,
|
||||
id: country.id,
|
||||
name: country.name,
|
||||
}
|
||||
: false;
|
||||
// add the last message date
|
||||
if (channel.channel_type === "livechat") {
|
||||
// add the operator id
|
||||
if (channel.livechat_operator_id) {
|
||||
// livechat_username ignored for simplicity
|
||||
channelInfo.livechat_operator_id = mailDataHelpers.Store.one(
|
||||
ResPartner.browse(channel.livechat_operator_id),
|
||||
makeKwArgs({ fields: ["avatar_128", "user_livechat_username"] })
|
||||
);
|
||||
} else {
|
||||
channelInfo.livechat_operator_id = false;
|
||||
}
|
||||
channelInfo.livechat_lang_id = channel.livechat_lang_id
|
||||
? mailDataHelpers.Store.one(
|
||||
ResLang.browse(channel.livechat_lang_id),
|
||||
makeKwArgs({ fields: ["name"] })
|
||||
)
|
||||
: false;
|
||||
channelInfo["livechat_end_dt"] = channel.livechat_end_dt;
|
||||
channelInfo["livechat_note"] = ["markup", channel.livechat_note];
|
||||
channelInfo["livechat_status"] = channel.livechat_status;
|
||||
channelInfo["livechat_expertise_ids"] = mailDataHelpers.Store.many(
|
||||
this.env["im_livechat.expertise"].browse(channel.livechat_expertise_ids),
|
||||
makeKwArgs({ fields: ["name"] })
|
||||
);
|
||||
channelInfo.livechat_channel_id = mailDataHelpers.Store.one(
|
||||
this.env["im_livechat.channel"].browse(channel.livechat_channel_id),
|
||||
makeKwArgs({ fields: ["name"] })
|
||||
);
|
||||
}
|
||||
store._add_record_fields(this.browse(channel.id), channelInfo);
|
||||
}
|
||||
}
|
||||
_close_livechat_session(channel_id) {
|
||||
/** @type {import("mock_models").BusBus} */
|
||||
const BusBus = this.env["bus.bus"];
|
||||
|
||||
if (this.browse(channel_id)[0].livechat_end_dt) {
|
||||
return;
|
||||
}
|
||||
this.write([channel_id], { livechat_end_dt: serializeDate(luxon.DateTime.now()) });
|
||||
const [channel] = this.browse(channel_id);
|
||||
BusBus._sendone(
|
||||
channel,
|
||||
"mail.record/insert",
|
||||
new mailDataHelpers.Store()
|
||||
.add(this.browse(channel_id), makeKwArgs({ fields: ["livechat_end_dt"] }))
|
||||
.get_result()
|
||||
);
|
||||
if (channel.message_ids.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.message_post(
|
||||
channel.id,
|
||||
makeKwArgs({
|
||||
body: this._get_visitor_leave_message(),
|
||||
message_type: "comment",
|
||||
subtype_xmlid: "mail.mt_comment",
|
||||
})
|
||||
);
|
||||
}
|
||||
_get_visitor_leave_message() {
|
||||
return "Visitor left the conversation.";
|
||||
}
|
||||
|
||||
_email_livechat_transcript(channel_id, email) {
|
||||
const [channel] = this.browse(channel_id);
|
||||
this.message_post(
|
||||
channel.id,
|
||||
makeKwArgs({
|
||||
body: `<div class="o_mail_notification o_hide_author">${this.env.user.name} sent the conversation to ${email}</div>`,
|
||||
message_type: "notification",
|
||||
subtype_xmlid: "mail.mt_comment",
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @type {typeof mailModels.DiscussChannel["prototype"]["_types_allowing_seen_infos"]}
|
||||
*/
|
||||
_types_allowing_seen_infos() {
|
||||
return super._types_allowing_seen_infos(...arguments).concat(["livechat"]);
|
||||
}
|
||||
|
||||
livechat_join_channel_needing_help(idOrIds) {
|
||||
const channel = this.browse(idOrIds)[0];
|
||||
if (channel.livechat_status !== "need_help") {
|
||||
return false;
|
||||
}
|
||||
this.add_members([channel.id], [this.env.user.partner_id]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @type {typeof models.Model["prototype"]["write"]} */
|
||||
write(idOrIds, values) {
|
||||
const kwargs = getKwArgs(arguments, "ids", "vals");
|
||||
({ ids: idOrIds, vals: values } = kwargs);
|
||||
const needHelpBefore = [];
|
||||
for (const channel of this._filter([["livechat_status", "=", "need_help"]])) {
|
||||
needHelpBefore.push(channel.id);
|
||||
}
|
||||
const result = super.write(...arguments);
|
||||
const needHelpAfter = [];
|
||||
for (const channel of this._filter([["livechat_status", "=", "need_help"]])) {
|
||||
needHelpAfter.push(channel.id);
|
||||
}
|
||||
const updatedChannelIds = [
|
||||
...needHelpBefore.filter((id) => !needHelpAfter.includes(id)),
|
||||
...needHelpAfter.filter((id) => !needHelpBefore.includes(id)),
|
||||
];
|
||||
if (updatedChannelIds.length) {
|
||||
this.env["bus.bus"]._sendone(
|
||||
[this.env["res.groups"].browse(serverState.groupLivechatId), "LOOKING_FOR_HELP"],
|
||||
"mail.record/insert",
|
||||
new mailDataHelpers.Store().add(this.browse(updatedChannelIds)).get_result()
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
import { mailModels } from "@mail/../tests/mail_test_helpers";
|
||||
import { fields } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class DiscussChannelMember extends mailModels.DiscussChannelMember {
|
||||
livechat_member_type = fields.Selection({
|
||||
selection: [
|
||||
["agent", "Agent"],
|
||||
["visitor", "Visitor"],
|
||||
["bot", "Chatbot"],
|
||||
],
|
||||
compute: false,
|
||||
});
|
||||
/**
|
||||
* @override
|
||||
* @type {typeof mailModels.DiscussChannelMember["prototype"]["_get_store_partner_fields"]}
|
||||
*/
|
||||
_get_store_partner_fields(fields) {
|
||||
/** @type {import("mock_models").DiscussChannel} */
|
||||
const DiscussChannel = this.env["discuss.channel"];
|
||||
|
||||
const member = this[0];
|
||||
const [channel] = DiscussChannel.browse(member.channel_id);
|
||||
if (channel.channel_type === "livechat") {
|
||||
if (!fields) {
|
||||
fields = [
|
||||
"active",
|
||||
"avatar_128",
|
||||
"country_id",
|
||||
"im_status",
|
||||
"is_public",
|
||||
"user_livechat_username",
|
||||
];
|
||||
if (member.livechat_member_type == "visitor") {
|
||||
fields.push("offline_since", "email");
|
||||
}
|
||||
}
|
||||
}
|
||||
return super._get_store_partner_fields(fields);
|
||||
}
|
||||
/**
|
||||
* @override
|
||||
* @type {typeof mailModels.DiscussChannelMember["prototype"]["_to_store"]}
|
||||
*/
|
||||
_to_store(store, fields, extra_fields) {
|
||||
super._to_store(...arguments);
|
||||
for (const member of this) {
|
||||
store._add_record_fields(this.browse(member.id), {
|
||||
livechat_member_type: member.livechat_member_type,
|
||||
});
|
||||
}
|
||||
}
|
||||
get _to_store_defaults() {
|
||||
return super._to_store_defaults.concat(["livechat_member_type"]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
import { mailDataHelpers } from "@mail/../tests/mock_server/mail_mock_server";
|
||||
|
||||
import { Command, fields, getKwArgs, makeKwArgs, models } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class LivechatChannel extends models.ServerModel {
|
||||
_name = "im_livechat.channel";
|
||||
|
||||
available_operator_ids = fields.Many2many({ relation: "res.users" }); // FIXME: somehow not fetched properly
|
||||
user_ids = fields.Many2many({ relation: "res.users" }); // FIXME: somehow not fetched properly
|
||||
|
||||
/** @param {integer} id */
|
||||
action_join(id) {
|
||||
this.write([id], { user_ids: [Command.link(this.env.user.id)] });
|
||||
const [partner] = this.env["res.partner"].read(this.env.user.partner_id);
|
||||
this.env["bus.bus"]._sendone(
|
||||
partner,
|
||||
"mail.record/insert",
|
||||
new mailDataHelpers.Store(
|
||||
this.browse(id),
|
||||
makeKwArgs({ fields: ["are_you_inside", "name"] })
|
||||
).get_result()
|
||||
);
|
||||
}
|
||||
|
||||
/** @param {integer} id */
|
||||
action_quit(id) {
|
||||
this.write(id, { user_ids: [Command.unlink(this.env.user.id)] });
|
||||
const [partner] = this.env["res.partner"].read(this.env.user.partner_id);
|
||||
this.env["bus.bus"]._sendone(
|
||||
partner,
|
||||
"mail.record/insert",
|
||||
new mailDataHelpers.Store(
|
||||
this.browse(id),
|
||||
makeKwArgs({ fields: ["are_you_inside", "name"] })
|
||||
).get_result()
|
||||
);
|
||||
}
|
||||
|
||||
/** @param {integer} id */
|
||||
_compute_available_operator_ids(id) {
|
||||
/** @type {import("mock_models").ResUsers} */
|
||||
const ResUsers = this.env["res.users"];
|
||||
|
||||
const [livechatChannel] = this.browse(id);
|
||||
const users = ResUsers.browse(livechatChannel.user_ids);
|
||||
return users.filter((user) => user.im_status === "online");
|
||||
}
|
||||
/** @param {integer} id */
|
||||
_get_livechat_discuss_channel_vals(id, operator_info) {
|
||||
/** @type {import("mock_models").MailGuest} */
|
||||
const MailGuest = this.env["mail.guest"];
|
||||
/** @type {import("mock_models").ResUsers} */
|
||||
const ResUsers = this.env["res.users"];
|
||||
const agent = operator_info["agent"];
|
||||
|
||||
const membersToAdd = [
|
||||
Command.create({
|
||||
last_interest_dt: "2021-01-01 10:00:00",
|
||||
livechat_member_type: "agent",
|
||||
partner_id: agent.partner_id,
|
||||
unpin_dt: "2021-01-01 12:00:00",
|
||||
}),
|
||||
];
|
||||
const guest = ResUsers._is_public(this.env.uid) && MailGuest._get_guest_from_context();
|
||||
if (guest) {
|
||||
membersToAdd.push(
|
||||
Command.create({ guest_id: guest.id, livechat_member_type: "visitor" })
|
||||
);
|
||||
}
|
||||
let visitorUser;
|
||||
if (this.env.user && !ResUsers._is_public(this.env.uid) && this.env.user !== agent) {
|
||||
visitorUser = this.env.user;
|
||||
membersToAdd.push(
|
||||
Command.create({
|
||||
livechat_member_type: "visitor",
|
||||
partner_id: visitorUser.partner_id,
|
||||
})
|
||||
);
|
||||
}
|
||||
const membersName = [
|
||||
visitorUser ? visitorUser.display_name : guest.name,
|
||||
agent.livechat_username ? agent.livechat_username : agent.name,
|
||||
];
|
||||
return {
|
||||
channel_partner_ids: [agent.partner_id],
|
||||
channel_member_ids: membersToAdd,
|
||||
livechat_operator_id: agent.partner_id,
|
||||
livechat_channel_id: id,
|
||||
livechat_status: "in_progress",
|
||||
channel_type: "livechat",
|
||||
name: membersName.join(" "),
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Simplified mock implementation: returns
|
||||
* the previous operator if he is still available
|
||||
* or the first available operator.
|
||||
*
|
||||
* @param {integer} id
|
||||
*/
|
||||
_get_operator(id, previous_operator_id) {
|
||||
const availableUsers = this._compute_available_operator_ids(id);
|
||||
return (
|
||||
availableUsers.find((operator) => operator.partner_id === previous_operator_id) ??
|
||||
availableUsers[0]
|
||||
);
|
||||
}
|
||||
|
||||
_to_store(store, fields) {
|
||||
const kwargs = getKwArgs(arguments, "store", "fields");
|
||||
fields = kwargs.fields;
|
||||
store._add_record_fields(
|
||||
this,
|
||||
fields.filter((field) => field !== "are_you_inside")
|
||||
);
|
||||
for (const livechatChannel of this) {
|
||||
if (fields.includes("are_you_inside")) {
|
||||
store._add_record_fields(this.browse(livechatChannel.id), {
|
||||
are_you_inside: livechatChannel.user_ids.includes(this.env.user.id),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import { models } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class Im_LivechatExpertise extends models.ServerModel {
|
||||
_name = "im_livechat.expertise";
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import { mailModels } from "@mail/../tests/mail_test_helpers";
|
||||
|
||||
import { serverState } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class IrWebSocket extends mailModels.IrWebSocket {
|
||||
/**
|
||||
* @override
|
||||
* @type {typeof busModels.IrWebSocket["prototype"]["_build_bus_channel_list"]}
|
||||
*/
|
||||
_build_bus_channel_list(channels) {
|
||||
channels = [...super._build_bus_channel_list(channels)];
|
||||
const result = channels;
|
||||
for (const channel of channels) {
|
||||
if (channel === "im_livechat.looking_for_help") {
|
||||
result.push([
|
||||
this.env["res.groups"].browse(serverState.groupLivechatId)[0],
|
||||
"LOOKING_FOR_HELP",
|
||||
]);
|
||||
}
|
||||
}
|
||||
return result.filter((channel) => channel !== "im_livechat.looking_for_help");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import { models } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class LivechatChannelRule extends models.ServerModel {
|
||||
_name = "im_livechat.channel.rule";
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
import { mailModels } from "@mail/../tests/mail_test_helpers";
|
||||
import { mailDataHelpers } from "@mail/../tests/mock_server/mail_mock_server";
|
||||
|
||||
import { makeKwArgs } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class MailMessage extends mailModels.MailMessage {
|
||||
_author_to_store(ids, store) {
|
||||
/** @type {import("mock_models").DiscussChannel} */
|
||||
const DiscussChannel = this.env["discuss.channel"];
|
||||
/** @type {import("mock_models").MailMessage} */
|
||||
const MailMessage = this.env["mail.message"];
|
||||
/** @type {import("mock_models").ResPartner} */
|
||||
const ResPartner = this.env["res.partner"];
|
||||
|
||||
const messages_w_author_livechat = MailMessage.browse(ids).filter((message) => {
|
||||
if (!message.author_id || message.model !== "discuss.channel" || !message.res_id) {
|
||||
return false;
|
||||
}
|
||||
const channel = DiscussChannel.browse(message.res_id);
|
||||
return channel.channel_type === "livechat";
|
||||
});
|
||||
super._author_to_store(
|
||||
ids.filter(
|
||||
(id) => !messages_w_author_livechat.map((message) => message.id).includes(id)
|
||||
),
|
||||
store
|
||||
);
|
||||
for (const message of messages_w_author_livechat) {
|
||||
store.add(this.browse(message.id), {
|
||||
author_id: mailDataHelpers.Store.one(
|
||||
ResPartner.browse(message.author_id),
|
||||
makeKwArgs({
|
||||
fields: ["avatar_128", "is_company", "user_livechat_username", "user"],
|
||||
})
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import { serverState } from "@web/../tests/web_test_helpers";
|
||||
import { mailModels } from "@mail/../tests/mail_test_helpers";
|
||||
|
||||
export class ResGroups extends mailModels.ResGroups {
|
||||
_records = [
|
||||
...this._records,
|
||||
{
|
||||
id: serverState.groupLivechatId,
|
||||
name: "Livechat User",
|
||||
privilege_id: false,
|
||||
},
|
||||
{
|
||||
id: serverState.groupLivechatManagerId,
|
||||
name: "Livechat Manager",
|
||||
privilege_id: false,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import { webModels } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class ResGroupsPrivilege extends webModels.ResGroupsPrivilege {}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
import { mailModels } from "@mail/../tests/mail_test_helpers";
|
||||
|
||||
import { getKwArgs, makeKwArgs, serverState } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class ResPartner extends mailModels.ResPartner {
|
||||
/**
|
||||
* @override
|
||||
* @type {typeof mailModels.ResPartner["prototype"]["_search_for_channel_invite_to_store"]}
|
||||
*/
|
||||
_search_for_channel_invite_to_store(ids, store, channel_id) {
|
||||
/** @type {import("mock_models").DiscussChannel} */
|
||||
const DiscussChannel = this.env["discuss.channel"];
|
||||
/** @type {import("mock_models").DiscussChannelMember} */
|
||||
const DiscussChannelMember = this.env["discuss.channel.member"];
|
||||
/** @type {import("mock_models").LivechatChannel} */
|
||||
const LivechatChannel = this.env["im_livechat.channel"];
|
||||
/** @type {import("mock_models").Im_LivechatExpertise} */
|
||||
const Im_LivechatExpertise = this.env["im_livechat.expertise"];
|
||||
/** @type {import("mock_models").ResLang} */
|
||||
const ResLang = this.env["res.lang"];
|
||||
/** @type {import("mock_models").ResPartner} */
|
||||
const ResPartner = this.env["res.partner"];
|
||||
/** @type {import("mock_models").ResUsers} */
|
||||
const ResUsers = this.env["res.users"];
|
||||
|
||||
super._search_for_channel_invite_to_store(ids, store, channel_id);
|
||||
const [channel] = DiscussChannel.browse(channel_id);
|
||||
if (channel?.channel_type !== "livechat") {
|
||||
return;
|
||||
}
|
||||
const activeLivechatPartners = LivechatChannel._filter([])
|
||||
.map(({ available_operator_ids }) => available_operator_ids)
|
||||
.flat()
|
||||
.map((userId) => ResUsers.browse(userId)[0].partner_id);
|
||||
for (const partner of ResPartner.browse(ids)) {
|
||||
const data = {
|
||||
invite_by_self_count: DiscussChannelMember.search_count([
|
||||
["partner_id", "=", partner.id],
|
||||
["create_uid", "=", serverState.userId],
|
||||
]),
|
||||
is_available: activeLivechatPartners.includes(partner.id),
|
||||
};
|
||||
if (partner.lang) {
|
||||
data.lang_name = ResLang.search_read([["code", "=", partner.lang]])[0].name;
|
||||
}
|
||||
if (partner.user_ids.length) {
|
||||
const [user] = ResUsers.browse(partner.user_ids[0]);
|
||||
if (user) {
|
||||
const userLangs = user.livechat_lang_ids
|
||||
.map((langId) => ResLang.browse(langId)[0])
|
||||
.filter((lang) => lang.name !== data.lang_name);
|
||||
data.livechat_languages = userLangs.map((lang) => lang.name);
|
||||
data.livechat_expertise = user.livechat_expertise_ids.map(
|
||||
(expId) => Im_LivechatExpertise.browse(expId)[0].name
|
||||
);
|
||||
}
|
||||
}
|
||||
store.add(this.browse(partner.id), makeKwArgs({ fields: ["user_livechat_username"] }));
|
||||
store.add(this.browse(partner.id), data);
|
||||
store.add(this.browse(partner.id), makeKwArgs({ extra_fields: ["is_in_call"] }));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @override
|
||||
* @type {typeof mailModels.ResPartner["prototype"]["_to_store"]}
|
||||
*/
|
||||
_to_store(store, fields) {
|
||||
const kwargs = getKwArgs(arguments, "store", "fields");
|
||||
fields = kwargs.fields;
|
||||
|
||||
super._to_store(...arguments);
|
||||
if (fields && fields.includes("user_livechat_username")) {
|
||||
store._add_record_fields(
|
||||
this.filter((partner) => !partner.user_livechat_username),
|
||||
["name"]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { mailModels } from "@mail/../tests/mail_test_helpers";
|
||||
import { serverState } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class ResUsers extends mailModels.ResUsers {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_init_store_data(store) {
|
||||
super._init_store_data(...arguments);
|
||||
store.add({
|
||||
has_access_livechat: this.env.user?.group_ids.includes(serverState.groupLivechatId),
|
||||
});
|
||||
store.add(this.browse(this.env.uid), {
|
||||
is_livechat_manager: this.env.user?.group_ids.includes(
|
||||
serverState.groupLivechatManagerId
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue