19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:31:39 +01:00
parent 5df8c07b59
commit daa394e8b0
2114 changed files with 564841 additions and 299642 deletions

View file

@ -17,15 +17,15 @@
</record>
<record id="chatbot_script_answer_view_tree" model="ir.ui.view">
<field name="name">chatbot.script.answer.view.tree</field>
<field name="name">chatbot.script.answer.view.list</field>
<field name="model">chatbot.script.answer</field>
<field name="arch" type="xml">
<tree editable="bottom">
<list editable="bottom">
<field name="sequence" widget="handle"/>
<field name="script_step_id"/>
<field name="name"/>
<field name="redirect_link" string="Optional Link"/>
</tree>
</list>
</field>
</record>

View file

@ -7,36 +7,37 @@
<field name="arch" type="xml">
<form disable_autofocus="1">
<field name="is_forward_operator_child" invisible="1"/>
<div class="alert alert-info text-center mb-0" role="alert" attrs="{'invisible': [('is_forward_operator_child', '=', False)]}">
<div class="alert alert-info text-center mb-0" role="alert" invisible="not is_forward_operator_child">
<span>Reminder: This step will only be played if no operator is available.</span>
</div>
<div class="alert alert-info text-center mb-0" role="alert" attrs="{'invisible': [('step_type', '!=', 'forward_operator')]}">
<div class="alert alert-info text-center mb-0" role="alert" invisible="not is_forward_operator">
<span>Tip: Plan further steps for the Bot in case no operator is available.</span>
</div>
<sheet>
<group>
<group>
<field name="sequence" invisible="1"/>
<field name="message" widget="text_emojis" placeholder="e.g. 'How can I help you?'"
attrs="{'required': [('step_type', '!=', 'forward_operator')]}"/>
<field name="message" placeholder="e.g. 'How can I help you?'"
required="not is_forward_operator"/>
<field name="chatbot_script_id" invisible="1"/>
<field name="step_type"/>
<field name="operator_expertise_ids" widget="many2many_tags" options="{'edit_tags': True}" invisible="step_type != 'forward_operator'"/>
<field name="triggering_answer_ids" widget="chatbot_triggering_answers_widget"
options="{'no_create': True}">
<tree>
<list>
<!-- added only to correctly fetch the display_name for the tag display -->
<field name="display_name" invisible="1"/>
</tree>
<field name="display_name" column_invisible="True"/>
</list>
</field>
</group>
<group>
<field name="answer_ids" attrs="{'invisible': [('step_type', '!=', 'question_selection')]}" nolabel="1" colspan="2">
<tree editable="bottom">
<field name="answer_ids" invisible="step_type != 'question_selection'" nolabel="1">
<list editable="bottom">
<field name="sequence" widget="handle"/>
<field name="display_name" invisible="1"/>
<field name="display_name" column_invisible="True"/>
<field name="name"/>
<field name="redirect_link" string="Optional Link"/>
</tree>
</list>
</field>
</group>
</group>
@ -46,16 +47,16 @@
</record>
<record id="chatbot_script_step_view_tree" model="ir.ui.view">
<field name="name">chatbot.script.step.view.tree</field>
<field name="name">chatbot.script.step.view.list</field>
<field name="model">chatbot.script.step</field>
<field name="arch" type="xml">
<tree default_order="sequence asc">
<list default_order="sequence asc">
<field name="sequence" widget="handle"/>
<field name="message"/>
<field name="step_type"/>
<field name="answer_ids" widget="many2many_tags"/>
<field name="triggering_answer_ids" widget="many2many_tags"/>
</tree>
</list>
</field>
</record>

View file

@ -10,30 +10,30 @@
</header>
<field name="first_step_warning" invisible="1"/>
<div class="alert alert-info text-center" role="alert"
attrs="{'invisible': [('first_step_warning', '!=', 'first_step_operator')]}">
invisible="first_step_warning != 'first_step_operator'">
<span>Tip: At least one interaction (Question, Email, ...) is needed before the Bot can perform more complex actions (Forward to an Operator, ...). </span>
<span>Use Channel Rules if you want the Bot to interact with visitors only when no operator is available.</span>
</div>
<div class="alert alert-info text-center" role="alert"
attrs="{'invisible': [('first_step_warning', '!=', 'first_step_invalid')]}">
invisible="first_step_warning != 'first_step_invalid'">
<span>Tip: At least one interaction (Question, Email, ...) is needed before the Bot can perform more complex actions (Forward to an Operator, ...).</span>
</div>
<sheet>
<div class="oe_button_box" name="button_box">
<button name="action_view_livechat_channels" type="object" class="oe_stat_button"
icon="fa-comments" attrs="{'invisible': [('livechat_channel_count', '=', 0)]}">
icon="fa-comments" invisible="livechat_channel_count == 0">
<field name="livechat_channel_count" string="Channels" widget="statinfo"/>
</button>
</div>
<field name="active" invisible="1"/>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<widget name="web_ribbon" title="Archived" bg_color="text-bg-danger" invisible="active"/>
<field name="image_1920" widget="image" class="oe_avatar" options="{'preview_image': 'image_128'}"/>
<div class="oe_title">
<label for="title" string="Chatbot Name"/>
<h1><field name="title" default_focus="1" placeholder='e.g. "Meeting Scheduler Bot"'/></h1>
</div>
<notebook>
<page string="Script">
<page string="Script" name="page_script">
<field name="script_step_ids" widget="chatbot_steps_one2many" nolabel="1"
context="{'chatbot_script_answer_display_short_name': 1}"/>
</page>
@ -44,12 +44,12 @@
</record>
<record id="chatbot_script_view_tree" model="ir.ui.view">
<field name="name">chatbot.script.view.tree</field>
<field name="name">chatbot.script.view.list</field>
<field name="model">chatbot.script</field>
<field name="arch" type="xml">
<tree sample="1">
<list sample="1">
<field name="title"/>
</tree>
</list>
</field>
</record>
@ -67,7 +67,7 @@
<record id="chatbot_script_action" model="ir.actions.act_window">
<field name="name">Chatbot</field>
<field name="res_model">chatbot.script</field>
<field name="view_mode">tree,form</field>
<field name="view_mode">list,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a Chatbot

View file

@ -0,0 +1,377 @@
<?xml version="1.0"?>
<odoo>
<data>
<record id="discuss_channel_view_search" model="ir.ui.view">
<field name="name">discuss.channel.search</field>
<field name="model">discuss.channel</field>
<field name="arch" type="xml">
<search string="Search history">
<field name="livechat_agent_partner_ids" string="Agent"/>
<field name="livechat_agent_requesting_help_history"/>
<field name="livechat_agent_providing_help_history"/>
<field name="country_id" string="Country"/>
<field name="livechat_customer_partner_ids" string="Customer"/>
<filter name="filter_my_sessions" domain="[('livechat_operator_id.user_ids', '=', uid)]" string="My Sessions"/>
<separator/>
<filter name="ongoing" string="Ongoing" domain="[('livechat_end_dt', '=', False)]"/>
<separator/>
<filter name="filter_session_rating_happy" domain="[('rating_ids', '!=', False), ('rating_avg', '&gt;=', 3.66)]" string="Happy"/>
<filter name="filter_session_rating_neutral" domain="[('rating_ids', '!=', False), ('rating_avg', '&gt;=', 2.33), ('rating_avg', '&lt;', 3.66)]" string="Neutral"/>
<filter name="fiter_session_rating_unhappy" domain="[('rating_ids', '!=', False), ('rating_avg', '&lt;', 2.33) ]" string="Unhappy"/>
<filter name="filter_session_unrated" domain="[('rating_ids', '=', False)]" string="Unrated"/>
<separator />
<filter name="filter_session_date" date="create_date" string="Session Date">
<filter name="rated_on_last_24_hours" string="Last 24 Hours" domain="[('create_date', '&gt;', '-1d')]"/>
<filter name="rated_on_last_7_days" string="Last 7 Days" domain="[('create_date', '&gt;', 'today -7d +1d')]"/>
<filter name="rated_on_last_30_days" string="Last 30 Days" domain="[('create_date', '&gt;', 'today -30d +1d')]"/>
<filter name="rated_on_last_365_days" string="Last 365 Days" domain="[('create_date', '&gt;', 'today -365d +1d')]"/>
</filter>
<separator/>
<group>
<filter name="group_by_channel" string="Channel" domain="[]" context="{'group_by':'livechat_channel_id'}"/>
<filter name="group_by_agent" string="Agent" domain="[]" context="{'group_by':'livechat_agent_partner_ids'}"/>
<filter name="group_by_agent_requesting_help" domain="[]" context="{'group_by': 'livechat_agent_requesting_help_history'}"/>
<filter name="group_by_agent_providing_help" domain="[]" context="{'group_by': 'livechat_agent_providing_help_history'}"/>
<filter name="group_by_rating" string="Rating" domain="[]" context="{'group_by':'rating_last_text'}"/>
<filter name="group_by_country" string="Country" domain="[]" context="{'group_by':'country_id'}"/>
<filter name="group_by_customer_partner" string="Customer" domain="[]" context="{'group_by':'livechat_customer_partner_ids'}"/>
<separator orientation="vertical"/>
<filter name="group_by_month" string="Session Date" domain="[]" context="{'group_by':'create_date:month'}"/>
</group>
<group>
<filter name="escalated" string="Escalated" domain="[('livechat_is_escalated', '=', True)]" invisible="1"/>
<filter name="handled_by_agent" string="Handled by Agent" domain="[('livechat_agent_history_ids', '!=', False)]" invisible="1"/>
<filter name="handled_by_bot" string="Handled by Bot" domain="[('livechat_channel_member_history_ids.livechat_member_type', '=', 'bot'), ('livechat_agent_history_ids', '=', False)]" invisible="1"/>
<filter name="in_call" string="In Call" domain="[('livechat_agent_history_ids.call_history_ids.end_dt', '=', False)]" invisible="1"/>
</group>
</search>
</field>
</record>
<record id="discuss_channel_view_tree" model="ir.ui.view">
<field name="name">discuss.channel.list</field>
<field name="model">discuss.channel</field>
<field name="arch" type="xml">
<list js_class="im_livechat.discuss_channel_list" sample="1" string="History" create="false" default_order="create_date desc, id desc">
<field name="create_date" string="Date"/>
<field name="livechat_customer_history_ids" string="Customer" widget="many2many_tags_avatar" optional="show"/>
<field name="livechat_agent_history_ids" string="Agents" widget="many2many_tags_avatar" optional="show"/>
<field name="livechat_agent_requesting_help_history" widget="many2one_avatar" optional="hide"/>
<field name="livechat_agent_providing_help_history" widget="many2one_avatar" optional="hide"/>
<field name="livechat_bot_history_ids" string="Chatbot" widget="many2many_tags_avatar" optional="hide"/>
<field name="country_id" optional="show"/>
<field name="livechat_lang_id" optional="show"/>
<field name="livechat_expertise_ids" string="Expertise" widget="many2many_tags" optional="show"/>
<field name="livechat_conversation_tag_ids" string="Tags" widget="many2many_tags" options="{'color_field': 'color'}" optional="hide"/>
<field name="livechat_channel_id" optional="hide"/>
<field name="duration" widget="float_time" options="{'displaySeconds': True}" optional="show"/>
<field name="message_count" string="Messages" optional="show"/>
<field name="rating_last_text" string="Rating" decoration-danger="rating_last_text == 'ko'"
decoration-warning="rating_last_text == 'ok'" decoration-success="rating_last_text == 'top'"
widget="badge" optional="show"/>
<field name="rating_last_feedback" string="Comment" optional="hide"/>
</list>
</field>
</record>
<record id="discuss_channel_view_kanban" model="ir.ui.view">
<field name="name">discuss.channel.kanban</field>
<field name="model">discuss.channel</field>
<field name="arch" type="xml">
<kanban js_class="im_livechat.discuss_channel_kanban" class="o_kanban_mobile" sample="1" quick_create="false" create="False" default_order="create_date desc">
<templates>
<t t-name="card">
<div class="d-flex">
<div class="d-flex flex-column">
<field class="fw-bolder" name="livechat_customer_history_ids" widget="im_livechat.one2many_names"/>
<span class="fw-bold">Date: <field name="create_date" class="fw-normal"/></span>
<span class="fw-bold">Duration: <field class="d-inline fw-normal" name="duration" widget="float_time" options="{'displaySeconds': True}"/></span>
<span class="fw-bold">Messages: <field name="message_count" class="fw-normal"/></span>
<field name="livechat_failure" invisible="1"/>
<field name="livechat_is_escalated" invisible="1"/>
<span t-if="record.livechat_is_escalated.raw_value or record.livechat_failure.raw_value" class="fw-bold">
Status:
<span class="fw-normal">
<t t-if="record.livechat_is_escalated.raw_value">Escalated</t>
<t t-elif="record.livechat_failure.raw_value === 'no_failure'">Success</t>
<t t-else="" t-esc="record.livechat_failure.value"/>
</span>
</span>
</div>
<field name="rating_last_image" string="Rating" widget="image" options='{"size": [40, 40], "img_class": "bg-transparent"}' class="ms-auto" invisible="not rating_last_image"/>
</div>
<footer class="pt-0">
<t t-if="record.country_id.raw_value">
<span class="fw-bold">Country: </span><field string="Country" name="country_id"/>
</t>
<field name="livechat_agent_partner_ids" widget="many2many_avatar_user" class="ms-auto me-1"/>
</footer>
</t>
</templates>
</kanban>
</field>
</record>
<record id="discuss_channel_view_form" model="ir.ui.view">
<field name="name">discuss.channel.form</field>
<field name="model">discuss.channel</field>
<field name="arch" type="xml">
<form string="Session Form" create="false" edit="false" js_class="livechat_session_form">
<sheet>
<div style="width:50%" class="float-end">
<field name="rating_last_image" widget="image" options='{"img_class": "bg-transparent"}' class="float-end bg-view" readonly="1" nolabel="1"/>
<field name="rating_last_feedback" nolabel="1"/>
</div>
<div style="width:50%" class="float-start">
<group>
<field name="name" string="Participants"/>
<field name="create_date" readonly="1" string="Session Date"/>
</group>
</div>
</sheet>
</form>
</field>
</record>
<record id="discuss_channel_view_pivot" model="ir.ui.view">
<field name="name">discuss.channel.pivot</field>
<field name="model">discuss.channel</field>
<field name="arch" type="xml">
<pivot string="Sessions" display_quantity="1" sample="1">
<field name="livechat_operator_id" type="row"/>
<field name="create_date" interval="day" type="col"/>
<field name="rating_last_value" type="measure" string="Rating (%)" widget="im_livechat.rating_percentage"/>
</pivot>
</field>
</record>
<record id="discuss_channel_view_graph" model="ir.ui.view">
<field name="name">discuss.channel.graph</field>
<field name="model">discuss.channel</field>
<field name="arch" type="xml">
<graph string="Sessions" sample="1">
<field name="create_date" interval="day"/>
<field name="rating_last_value" type="measure" string="Rating (%)" widget="im_livechat.rating_percentage"/>
</graph>
</field>
</record>
<record id="discuss_channel_action" model="ir.actions.act_window">
<field name="name">Sessions</field>
<field name="res_model">discuss.channel</field>
<field name="view_mode">kanban,list,pivot,graph,form</field>
<field name="search_view_id" ref="im_livechat.discuss_channel_view_search"/>
<field name="domain">[('livechat_channel_id', '!=', None)]</field>
<field name="context">
{
"search_default_filter_session_date": "custom_rated_on_last_30_days",
"im_livechat_hide_partner_company": True,
}
</field>
<field name="help" type="html">
<p class="o_view_nocontent_empty_folder">
No data yet!
</p><p>
Start a conversation to populate your chat history.
</p>
</field>
</record>
<record id="discuss_channel_action_kanban" model="ir.actions.act_window.view">
<field name="sequence">1</field>
<field name="view_mode">kanban</field>
<field name="view_id" ref="im_livechat.discuss_channel_view_kanban"/>
<field name="act_window_id" ref="im_livechat.discuss_channel_action"/>
</record>
<record id="discuss_channel_action_tree" model="ir.actions.act_window.view">
<field name="sequence">2</field>
<field name="view_mode">list</field>
<field name="view_id" ref="im_livechat.discuss_channel_view_tree"/>
<field name="act_window_id" ref="im_livechat.discuss_channel_action"/>
</record>
<record id="discuss_channel_action_pivot" model="ir.actions.act_window.view">
<field name="sequence">3</field>
<field name="view_mode">pivot</field>
<field name="view_id" ref="im_livechat.discuss_channel_view_pivot"/>
<field name="act_window_id" ref="im_livechat.discuss_channel_action"/>
</record>
<record id="discuss_channel_action_graph" model="ir.actions.act_window.view">
<field name="sequence">4</field>
<field name="view_mode">graph</field>
<field name="view_id" ref="im_livechat.discuss_channel_view_graph"/>
<field name="act_window_id" ref="im_livechat.discuss_channel_action"/>
</record>
<record id="discuss_channel_action_form" model="ir.actions.act_window.view">
<field name="sequence">5</field>
<field name="view_mode">form</field>
<field name="view_id" ref="im_livechat.discuss_channel_view_form"/>
<field name="act_window_id" ref="im_livechat.discuss_channel_action"/>
</record>
<record id="discuss_channel_action_from_livechat_channel" model="ir.actions.act_window">
<field name="name">Sessions</field>
<field name="res_model">discuss.channel</field>
<field name="view_mode">kanban,list,pivot,graph,form</field>
<field name="domain">[('livechat_channel_id', 'in', [active_id])]</field>
<field name="context">{
'search_default_livechat_channel_id': [active_id],
'default_livechat_channel_id': active_id,
}</field>
<field name="search_view_id" ref="discuss_channel_view_search"/>
<field name="help" type="html">
<p class="o_view_nocontent_empty_folder">No data yet!</p>
<p>Start a conversation to populate your chat history.</p>
</field>
</record>
<record id="discuss_channel_action_livechat_kanban" model="ir.actions.act_window.view">
<field name="sequence">1</field>
<field name="view_mode">kanban</field>
<field name="view_id" ref="im_livechat.discuss_channel_view_kanban"/>
<field name="act_window_id" ref="im_livechat.discuss_channel_action_from_livechat_channel"/>
</record>
<record id="discuss_channel_action_livechat_tree" model="ir.actions.act_window.view">
<field name="sequence">2</field>
<field name="view_mode">list</field>
<field name="view_id" ref="im_livechat.discuss_channel_view_tree"/>
<field name="act_window_id" ref="im_livechat.discuss_channel_action_from_livechat_channel"/>
</record>
<record id="discuss_channel_action_livechat_pivot" model="ir.actions.act_window.view">
<field name="sequence">3</field>
<field name="view_mode">pivot</field>
<field name="view_id" ref="im_livechat.discuss_channel_view_pivot"/>
<field name="act_window_id" ref="im_livechat.discuss_channel_action_from_livechat_channel"/>
</record>
<record id="discuss_channel_action_livechat_graph" model="ir.actions.act_window.view">
<field name="sequence">4</field>
<field name="view_mode">graph</field>
<field name="view_id" ref="im_livechat.discuss_channel_view_graph"/>
<field name="act_window_id" ref="im_livechat.discuss_channel_action_from_livechat_channel"/>
</record>
<record id="discuss_channel_action_livechat_form" model="ir.actions.act_window.view">
<field name="sequence">5</field>
<field name="view_mode">form</field>
<field name="view_id" ref="im_livechat.discuss_channel_view_form"/>
<field name="act_window_id" ref="im_livechat.discuss_channel_action_from_livechat_channel"/>
</record>
<record id="discuss_channel_looking_for_help_view_search" model="ir.ui.view">
<field name="name">discuss.channel.looking.for.help.view.search</field>
<field name="model">discuss.channel</field>
<field name="arch" type="xml">
<search string="Search history">
<field name="livechat_agent_partner_ids" string="Agent"/>
<field name="description"/>
<field name="country_id"/>
<field name="livechat_lang_id"/>
<field name="livechat_expertise_ids" string="Expertise"/>
<field name="livechat_conversation_tag_ids" string="Tags"/>
<field name="livechat_bot_partner_ids" string="Chatbot"/>
<field name="livechat_customer_partner_ids" string="Customer"/>
<filter name="filter_my_sessions" domain="[('livechat_operator_id.user_ids', '=', uid)]" string="My Sessions"/>
<filter name="filter_my_languages" string="My Languages" domain="[('livechat_matches_self_lang', '=', True)]"/>
<filter name="filter_my_expertise" string="My Expertise" domain="[('livechat_matches_self_expertise', '=', True)]"/>
<separator />
<filter name="filter_session_date" date="create_date" string="Session Date">
<filter name="created_on_last_24_hours" string="Last 24 Hours" domain="[('create_date', '&gt;', '-24H')]"/>
<filter name="created_on_last_7_days" string="Last 7 Days" domain="[('create_date', '&gt;=', 'today -7d +1d')]"/>
<filter name="created_on_last_30_days" string="Last 30 Days" domain="[('create_date', '&gt;=', 'today -30d +1d')]"/>
<filter name="created_on_last_365_days" string="Last 365 Days" domain="[('create_date', '&gt;=', 'today -365d +1d')]"/>
</filter>
<separator/>
<group>
<filter name="group_by_channel" string="Channel" domain="[]" context="{'group_by':'livechat_channel_id'}"/>
<filter name="group_by_agent" string="Agent" domain="[]" context="{'group_by':'livechat_agent_partner_ids'}"/>
<filter name="group_by_country" string="Country" domain="[]" context="{'group_by':'country_id'}"/>
<filter name="group_by_lang" string="Language" domain="[]" context="{'group_by':'livechat_lang_id'}"/>
<filter name="group_by_expertise" string="Expertise" domain="[]" context="{'group_by':'livechat_expertise_ids'}"/>
<filter name="group_by_tags" string="Tags" domain="[]" context="{'group_by':'livechat_conversation_tag_ids'}"/>
<filter name="group_by_chatbot" string="Chatbot" domain="[]" context="{'group_by':'livechat_bot_partner_ids'}"/>
<filter name="group_by_customer_partner" string="Customer" domain="[]" context="{'group_by':'livechat_customer_partner_ids'}"/>
<separator orientation="vertical"/>
<filter name="group_by_month" string="Session Date" domain="[]" context="{'group_by':'create_date:month'}"/>
</group>
</search>
</field>
</record>
<record id="discuss_channel_looking_for_help_action" model="ir.actions.act_window">
<field name="name">Looking for Help</field>
<field name="res_model">discuss.channel</field>
<field name="view_mode">list,kanban,form</field>
<field name="domain">[("livechat_status", "=", "need_help")]</field>
<field name="context">
{
"search_default_filter_session_date": "custom_created_on_last_30_days",
"im_livechat_hide_partner_company": True,
}
</field>
<field name="search_view_id" ref="im_livechat.discuss_channel_looking_for_help_view_search"/>
<field name="help" type="html">
<p class="o_view_nocontent_empty_folder">No conversations found</p>
<p>Help out by joining requests from teammates, or mark your own conversations as needing help.</p>
</field>
</record>
<record id="discuss_channel_looking_for_help_view_list" model="ir.ui.view">
<field name="name">discuss.channel.looking.for.help.list</field>
<field name="model">discuss.channel</field>
<field name="arch" type="xml">
<list js_class="im_livechat.discuss_channel_looking_for_help_list" sample="1" string="History" create="false" default_order="create_date asc">
<field name="create_date" string="Date"/>
<field name="description" string="Description" optional="show"/>
<field name="livechat_agent_history_ids" string="Agents" widget="many2many_tags_avatar" optional="show"/>
<field name="livechat_bot_history_ids" string="Bot" widget="many2many_tags_avatar" optional="hide"/>
<field name="livechat_customer_history_ids" string="Customer" widget="many2many_tags_avatar" optional="show"/>
<field name="country_id" optional="show"/>
<field name="livechat_lang_id"/>
<field name="livechat_expertise_ids" string="Expertise" widget="many2many_tags" optional="show"/>
<field name="livechat_conversation_tag_ids" string="Tags" widget="many2many_tags" options="{'color_field': 'color'}" optional="hide"/>
<field name="livechat_channel_id" optional="hide"/>
<field name="duration" widget="float_time" options="{'displaySeconds': True}" optional="hide"/>
<field name="message_count" string="Messages" optional="hide"/>
</list>
</field>
</record>
<record id="discuss_channel_looking_for_help_action_list" model="ir.actions.act_window.view">
<field name="sequence">1</field>
<field name="view_mode">list</field>
<field name="view_id" ref="im_livechat.discuss_channel_looking_for_help_view_list"/>
<field name="act_window_id" ref="im_livechat.discuss_channel_looking_for_help_action"/>
</record>
<record id="discuss_channel_looking_for_help_view_kanban" model="ir.ui.view">
<field name="name">discuss.channel.kanban</field>
<field name="model">discuss.channel</field>
<field name="arch" type="xml">
<kanban js_class="im_livechat.discuss_channel_looking_for_help_kanban" class="o_kanban_mobile" sample="1" quick_create="false" create="False" default_order="create_date desc">
<templates>
<t t-name="card">
<field class="fw-bolder" name="livechat_customer_history_ids" widget="im_livechat.one2many_names"/>
<span class="fw-bold">Date: <field name="create_date" class="fw-normal"/></span>
<span class="fw-bold" t-if="record.country_id.raw_value">Country: <field name="country_id" class="fw-normal"/></span>
<span class="fw-bold" t-if="record.livechat_lang_id.raw_value">Language: <field name="livechat_lang_id" class="fw-normal"/></span>
<div class="d-flex gap-1 fw-bold" t-if="record.livechat_expertise_ids.raw_value.length">Expertise: <field name="livechat_expertise_ids" class="fw-normal"/></div>
<footer class="pt-0">
<field name="livechat_agent_partner_ids" widget="many2many_avatar_user" class="ms-auto me-1"/>
</footer>
</t>
</templates>
</kanban>
</field>
</record>
<record id="discuss_channel_looking_for_help_action_kanban" model="ir.actions.act_window.view">
<field name="sequence">2</field>
<field name="view_mode">kanban</field>
<field name="view_id" ref="im_livechat.discuss_channel_looking_for_help_view_kanban"/>
<field name="act_window_id" ref="im_livechat.discuss_channel_looking_for_help_action"/>
</record>
<record id="discuss_channel_looking_for_help_action_form" model="ir.actions.act_window.view">
<field name="sequence">3</field>
<field name="view_mode">form</field>
<field name="view_id" ref="im_livechat.discuss_channel_view_form"/>
<field name="act_window_id" ref="im_livechat.discuss_channel_looking_for_help_action"/>
</record>
</data>
</odoo>

View file

@ -0,0 +1,152 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="im_livechat_channel_member_history_view_search" model="ir.ui.view">
<field name="name">im_livechat.channel.member.history.view.search</field>
<field name="model">im_livechat.channel.member.history</field>
<field name="arch" type="xml">
<search string="Search History">
<field name="channel_id"/>
<field name="partner_id"/>
<field name="chatbot_script_id"/>
<field name="guest_id"/>
<field name="livechat_member_type" string="Member Type"/>
</search>
</field>
</record>
<record id="im_livechat_channel_member_history_view_tree" model="ir.ui.view">
<field name="name">im_livechat.channel.member.history.view.list</field>
<field name="model">im_livechat.channel.member.history</field>
<field name="arch" type="xml">
<list default_order="create_date desc" string="Member History" sample="1">
<field name="create_date"/>
<field name="channel_id"/>
<field name="partner_id"/>
<field name="chatbot_script_id"/>
<field name="guest_id"/>
<field name="session_duration_hour" widget="float_time" options="{'displaySeconds': True}"/>
<field name="livechat_member_type" string="Member Type"/>
</list>
</field>
</record>
<record id="im_livechat_channel_member_history_action" model="ir.actions.act_window">
<field name="name">Member History</field>
<field name="res_model">im_livechat.channel.member.history</field>
<field name="search_view_id" ref="im_livechat_channel_member_history_view_search"/>
<field name="view_mode">list,form</field>
<field name="context">{"create": False}</field>
</record>
<menuitem
action="im_livechat_channel_member_history_action"
id="im_livechat.menu_member_history"
name="Member History"
parent="im_livechat.livechat_technical"
sequence="15"
/>
<record id="im_livechat_agent_history_view_search" model="ir.ui.view">
<field name="name">im_livechat.agent.history.search</field>
<field name="model">im_livechat.channel.member.history</field>
<field name="arch" type="xml">
<search string="Search Agent">
<field name="partner_id" string="Agent"/>
<field name="session_livechat_channel_id"/>
<field name="session_country_id"/>
<field name="agent_expertise_ids" string="Expertise"/>
<field name="conversation_tag_ids" string="Tags"/>
<filter name="my_session" domain="[('partner_id.user_ids', '=', uid)]" string="My Sessions"/>
<separator/>
<filter name="escalated" string="Escalated" domain="[('session_outcome', '=', 'escalated')]"/>
<filter name="no_answer" string="Not Answered" domain="[('session_outcome', '=', 'no_answer')]"/>
<separator/>
<filter name="rating_happy" string="Happy" domain="[('rating_text','=', 'top')]"/>
<filter name="rating_neutral" string="Neutral" domain="[('rating_text','=', 'ok')]"/>
<filter name="rating_unhappy" string="Unhappy" domain="[('rating_text','=', 'ko')]"/>
<separator />
<filter name="filter_start_date" string="Date" date="create_date"/>
<filter name="filter_date_last_month" invisible="1" string="Date: Last month"
domain="[('create_date', '&gt;=', 'today -1m')]"/>
<filter name="filter_date_last_week" invisible="1" string="Date: Last week"
domain="[('create_date', '&gt;=', 'today -1w')]"/>
<group>
<filter name="group_by_channel" string="Channel" domain="[]" context="{'group_by':'session_livechat_channel_id'}"/>
<filter name="group_by_agent" string="Agent" domain="[]" context="{'group_by':'partner_id'}"/>
<filter name="group_by_help_status" domain="[]" context="{'group_by': 'help_status'}"/>
<filter name="group_by_rating_text" string="Rating" domain="[]" context="{'group_by':'rating_text'}"/>
<filter name="group_by_country" string="Country" domain="[]" context="{'group_by':'session_country_id'}"/>
<filter name="group_by_outcome" string="Status" domain="[]" context="{'group_by':'session_outcome'}"/>
<filter name="group_by_expertise" string="Expertise" domain="[]" context="{'group_by':'agent_expertise_ids'}"/>
<filter name="group_by_conversation_tag" string="Tags" domain="[]" context="{'group_by':'conversation_tag_ids'}"/>
<separator orientation="vertical" />
<filter name="group_by_start_hour" string="Hour of Day" domain="[]" context="{'group_by':'session_start_hour'}"/>
<filter name="group_by_week_day" string="Day of Week" domain="[]" context="{'group_by':'session_week_day'}"/>
<filter name="group_by_month" string="Date" domain="[]" context="{'group_by':'create_date:month'}" />
</group>
</search>
</field>
</record>
<record id="im_livechat_agent_history_view_graph" model="ir.ui.view">
<field name="name">im_livechat.agent.history.graph</field>
<field name="model">im_livechat.channel.member.history</field>
<field name="arch" type="xml">
<graph js_class="im_livechat.agent_history_graph" string="Livechat Support Statistics" type="line" stacked="1" sample="1">
<field name="has_call" invisible="1"/>
<field name="session_start_hour" invisible="1"/>
<field name="session_week_day" invisible="1"/>
<field name="call_duration_hour" type="measure" widget="float_time"/>
<field name="call_percentage" type="measure" widget="percentage"/>
<field name="rating" string="Rating (%)" type="measure" widget="im_livechat.rating_percentage"/>
<field name="response_time_hour" string="Response Time" type="measure" widget="float_time" />
<field name="session_duration_hour" type="measure" widget="float_time"/>
</graph>
</field>
</record>
<record id="im_livechat_agent_history_view_pivot" model="ir.ui.view">
<field name="name">im_livechat.agent.history.pivot</field>
<field name="model">im_livechat.channel.member.history</field>
<field name="arch" type="xml">
<pivot js_class="im_livechat.agent_history_pivot" string="Livechat Support Statistics" sample="1" display_quantity="1">
<field name="has_call" invisible="1"/>
<field name="session_start_hour" invisible="1"/>
<field name="session_week_day" invisible="1"/>
<field name="partner_id" type="row"/>
<field name="call_duration_hour" type="measure" widget="float_time" options="{'displaySeconds': True}"/>
<field name="call_percentage" type="measure" widget="percentage"/>
<field name="response_time_hour" string="Response Time" type="measure" widget="float_time" options="{'displaySeconds': True}" />
<field name="session_duration_hour" type="measure" widget="float_time" options="{'displaySeconds': True}"/>
<field name="rating" string="Rating (%)" type="measure" widget="im_livechat.rating_percentage"/>
<field name="call_count" type="measure" widget="integer"/>
</pivot>
</field>
</record>
<record id="im_livechat_agent_history_action" model="ir.actions.act_window">
<field name="name">Agents</field>
<field name="res_model">im_livechat.channel.member.history</field>
<field name="view_mode">pivot,graph</field>
<field name="domain">[('livechat_member_type', '=', 'agent')]</field>
<field name="context">
{
"search_default_group_by_agent": 1,
"search_default_filter_date_last_month": 1,
"graph_measure": "__count__",
"pivot_measures": ["__count", "response_time_hour", "session_duration_hour", "rating", "call_count"],
"im_livechat_hide_partner_company": True
}
</field>
<field name="search_view_id" ref="im_livechat_agent_history_view_search"/>
<field name="help" type="html">
<p class="o_view_nocontent_empty_folder">No data yet!</p>
<p>Track and improve live chat performance with insights on session activity, response times, customer ratings, and call interactions.</p>
</field>
</record>
<menuitem
id="menu_reporting_livechat_agent"
name="Agents"
parent="menu_reporting_livechat"
sequence="10"
action="im_livechat_agent_history_action"
/>
</data>
</odoo>

View file

@ -20,6 +20,10 @@
<!-- Call the external Bundle to render the css, js, and js loader tags -->
<t t-out="channel.script_external"/>
<script>
window.odoo ??= {};
window.odoo.csrf_token = "<t t-out="request.csrf_token(None)"/>";
</script>
<style type="text/css">
body {
height: 100%;
@ -82,25 +86,28 @@
Template rendering all the scripts required to execute the Livechat from an external page (which not contain Odoo)
-->
<template id="external_loader" name="Livechat : external_script field of livechat channel">
<!-- css style -->
<link t-attf-href="{{url}}/im_livechat/external_lib.css" rel="stylesheet"/>
<!-- js of all the required lib (internal and external) -->
<script t-attf-src="{{url}}/im_livechat/external_lib.js" type="text/javascript" />
<!-- the loader -->
<script t-attf-src="{{url}}/im_livechat/loader/{{channel_id}}" type="text/javascript"/>
<script defer="defer" t-attf-src="{{url}}/im_livechat/loader/{{channel_id}}" type="text/javascript"/>
<!-- js of all the required lib (internal and external) -->
<script defer="defer" t-attf-src="{{url}}/im_livechat/assets_embed.js" type="text/javascript" />
</template>
<!-- the js code to initialize the LiveSupport object -->
<template id="loader" name="Livechat : Javascript appending the livechat button">
<t t-translation="off">
window.addEventListener('load', function () {
odoo.define('im_livechat.loaderData', function() {
return {
isAvailable: <t t-out="'true' if info['available'] else 'false'"/>,
serverUrl: "<t t-out="info['server_url']"/>",
options: <t t-out="json.dumps(info.get('options', {}))"/>,
};
});
if (!window.odoo) {
window.odoo = {};
}
odoo.__session_info__ = odoo.__session_info__ || {
websocket_worker_version: <t t-out="json.dumps(info.get('websocket_worker_version', ''))"/>
}
odoo.__session_info__ = Object.assign(odoo.__session_info__, {
livechatData: {
can_load_livechat: <t t-out="'true' if info['available'] else 'false'"/>,
serverUrl: "<t t-out="info['server_url']"/>",
options: <t t-out="json.dumps(info.get('options', {}))"/>,
},
test_mode: <t t-out="'true' if test_mode_enabled else 'false'"/>,
});
</t>
</template>

View file

@ -3,7 +3,8 @@
<data>
<record id="im_livechat_channel_action" model="ir.actions.act_window">
<field name="name">Website Live Chat Channels</field>
<field name="name">Live Chat Channels</field>
<field name="path">livechat</field>
<field name="res_model">im_livechat.channel</field>
<field name="view_mode">kanban,form</field>
<field name="help" type="html">
@ -21,41 +22,35 @@
<field name="name">im_livechat.channel.kanban</field>
<field name="model">im_livechat.channel</field>
<field name="arch" type="xml">
<kanban>
<field name="id"/>
<field name="name"/>
<field name="web_page" widget="url"/>
<kanban js_class="im_livechat.livechat_channel_kanban" action="im_livechat.discuss_channel_action_from_livechat_channel" type="action">
<field name="are_you_inside"/>
<field name="user_ids"/>
<field name="nbr_channel"/>
<field name="rating_percentage_satisfaction"/>
<field name="rating_count"/>
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_global_click">
<div class="o_kanban_image">
<img t-att-src="kanban_image('im_livechat.channel', 'image_128', record.id.raw_value)" class="img-fluid" alt="Channel"/>
</div>
<div class="oe_kanban_details">
<div class="float-end">
<button t-if="record.are_you_inside.raw_value" name="action_quit" type="object" class="btn btn-primary">Leave</button>
<button t-if="!record.are_you_inside.raw_value" name="action_join" type="object" class="btn btn-primary">Join</button>
</div>
<strong class="o_kanban_record_title" style="word-wrap: break-word;"><field name="name"/></strong>
<t t-name="menu">
<a type="open" class="dropdown-item" role="menuitem">
<span groups="im_livechat.im_livechat_group_manager">Configure Channel</span>
<span groups="!im_livechat.im_livechat_group_manager">View Channel</span>
</a>
</t>
<t t-name="card" class="p-0 row g-0">
<main class="pe-4 py-2 ps-4 col" t-att-class="{'o-livechat-ChannelKanban-highlighted': record.available_operator_ids.raw_value.length > 0}">
<div class="d-flex justify-content-between">
<div>
<div>
<i class="fa fa-user" role="img" aria-label="User" title="User"></i> <t t-esc="(record.user_ids.raw_value || []).length"/> Operators
<br/>
<i class="fa fa-comments" role="img" aria-label="Comments" title="Comments"></i> <t t-esc="record.nbr_channel.raw_value"/> Sessions
<div t-if="record.rating_count.raw_value &gt; 0" class="float-end">
<a name="action_view_rating" type="object" tabindex="10">
<i class="fa fa-smile-o text-success" title="Percentage of happy ratings" role="img" aria-label="Happy face"/> <t t-esc="record.rating_percentage_satisfaction.raw_value"/>%
</a>
</div>
</div>
<field name="name" class="fs-4" style="word-wrap: break-word;"/>
<p class="fst-italic fs-5"><field name="nbr_channel"/> Sessions</p>
</div>
<div class="pe-1">
<button t-if="record.are_you_inside.raw_value" name="action_quit" type="object" class="btn btn-primary">Leave</button>
<button t-else="" name="action_join" type="object" class="btn btn-secondary" groups="im_livechat.im_livechat_group_user">Join</button>
</div>
</div>
</div>
<footer class="pt-0">
<field name="available_operator_ids" widget="many2many_avatar_user" readonly="True"/>
<a t-if="record.rating_count.raw_value > 0" name="action_view_rating" class="ms-auto fs-6" type="object" tabindex="10">
<i class="fa fa-smile-o text-success" title="Percentage of happy ratings" role="img" aria-label="Happy face"/> <field name="rating_percentage_satisfaction"/>%
</a>
</footer>
</main>
</t>
</templates>
</kanban>
@ -68,25 +63,30 @@
<field name="arch" type="xml">
<form>
<header>
<button type="object" name="action_join" class="oe_highlight" string="Join Channel" attrs='{"invisible": [["are_you_inside", "=", True]]}'/>
<button type="object" name="action_quit" string="Leave Channel" attrs='{"invisible": [["are_you_inside", "=", False]]}'/>
<button type="object" name="action_join" class="oe_highlight" string="Join Channel" invisible="are_you_inside"/>
<button type="object" name="action_quit" class="btn btn-primary" string="Leave Channel" invisible="not are_you_inside"/>
<field name="are_you_inside" invisible="1"/>
</header>
<sheet>
<field name="rating_count" invisible="1"/>
<div class="oe_button_box" name="button_box">
<button class="oe_stat_button" type="object" name="action_view_chatbot_scripts" icon="fa-android"
attrs="{'invisible': [('chatbot_script_count', '=', 0)]}">
invisible="chatbot_script_count == 0" groups="im_livechat.im_livechat_group_manager">
<field string="Chatbots" name="chatbot_script_count" widget="statinfo"/>
</button>
<button class="oe_stat_button" type="action" attrs="{'invisible':[('nbr_channel','=', 0)]}" name="%(mail_channel_action_from_livechat_channel)d" icon="fa-comments">
<field string="Sessions" name="nbr_channel" widget="statinfo"/>
</button>
<button name="action_view_rating" attrs="{'invisible':[('rating_count', '=', 0)]}" class="oe_stat_button" type="object" icon="fa-smile-o">
<field string="% Happy" name="rating_percentage_satisfaction" widget="statinfo"/>
<button class="oe_stat_button" type="action" invisible="nbr_channel == 0" name="%(discuss_channel_action_from_livechat_channel)d" icon="fa-comments">
<div>
<div class="o_stat_info flex-row-reverse align-items-baseline gap-1 me-1">
<span class="o_stat_value"><field name="nbr_channel"/></span>
<span class="o_stat_text">Sessions</span>
</div>
<div class="o_stat_info flex-row-reverse align-items-baseline gap-1 me-1" invisible="rating_count == 0">
<span class="o_stat_value"><field name="rating_percentage_satisfaction"/>%</span>
<span class="o_stat_text">Happy</span>
</div>
</div>
</button>
</div>
<field name="image_128" widget="image" class="oe_avatar"/>
<div class="oe_title">
<label for="name"/>
<h1>
@ -94,71 +94,128 @@
</h1>
</div>
<notebook>
<page string="Operators" name="operators">
<field name="user_ids" nolabel="1" colspan="2" domain="[['groups_id', 'not in', %(base.group_portal)d]]">
<kanban>
<field name="id"/>
<field name="name"/>
<page string="Agents" name="Agents">
<field name="user_ids"
nolabel="1"
colspan="2"
domain="[['all_group_ids', 'in', %(im_livechat.im_livechat_group_user)d]]"
mode="list,kanban"
context="{'add_livechat_channel_ctx': True}">
<list no_open="1" create="0">
<field name="partner_id" string="Agent" widget="many2one_avatar_user" width="175px" context="{'im_livechat_hide_partner_company': True}"/>
<field name="livechat_is_in_call" widget="boolean_phone" nolabel="1"/>
<field string="Languages" name="livechat_lang_ids" widget="many2many_tags" optional="show"/>
<field string="Expertise" name="livechat_expertise_ids" widget="many2many_tags" optional="show"/>
<field string="Ongoing Sessions" name="livechat_ongoing_session_count" width="150px" optional="show"/>
</list>
<kanban class="o_kanban_mobile" can_open="False" create="0">
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_global_click">
<div class="o_kanban_image">
<img t-att-src="kanban_image('res.users', 'avatar_1024', record.id.raw_value)" alt="User"/>
<t t-name="card" class="flex-row">
<aside>
<field name="avatar_1024" widget="image" alt="User"/>
</aside>
<main class="ps-1">
<div class="d-flex justify-content-between align-items-baseline">
<field name="name" class="fw-bold fs-5"/>
<a class="btn p-0 opacity-75 opacity-100-hover" role="button" groups="im_livechat.im_livechat_group_manager" type="delete">
<i title="Remove operator" class="fa fa-fw fa-lg fa-close"/>
</a>
</div>
<div class="o_kanban_details">
<h4 class="o_kanban_record_title"><field name="name"/></h4>
<field t-if="record.livechat_lang_ids.raw_value.length > 0" name="livechat_lang_ids" widget="many2many_tags"/>
<field t-if="record.livechat_expertise_ids.raw_value.length > 0" name="livechat_expertise_ids" widget="many2many_tags"/>
<div class="d-flex justify-content-between align-items-baseline">
<div class="column">
<span>Ongoing Sessions:</span><field name="livechat_ongoing_session_count" class="ms-1"/>
</div>
<field name="livechat_is_in_call" class="me-1" widget="boolean_phone"/>
</div>
</div>
</main>
</t>
</templates>
</kanban>
</field>
<p class="text-muted" colspan="2">
Operators that do not show any activity In Odoo for more than 30 minutes will be considered as disconnected.
</p>
<group>
<group class="order-1 order-lg-0">
<p class="text-muted" colspan="2">
Agents who are inactive in Odoo for more than 30 minutes will be considered disconnected.
</p>
</group>
<group class="oe_subtotal_footer d-flex justify-content-end">
<div class="container">
<div class="row mb-2">
<div class="col"><label class="fw-bold" for="ongoing_session_count"/></div>
<div class="col me-1"><field name="ongoing_session_count" nolabel="1"/></div>
</div>
<div class="row mb-2" invisible="max_sessions_mode!='limited'">
<div class="col"><label class="fw-bold" for="remaining_session_capacity"/></div>
<div class="col me-1"><field name="remaining_session_capacity" nolabel="1"/></div>
</div>
</div>
</group>
</group>
</page>
<page string="Options" name="options">
<page string="Options" name="options" groups="im_livechat.im_livechat_group_manager">
<group>
<group string="Livechat Button">
<field name="button_text"/>
<label for="button_background_color" string="Livechat Button Color" />
<group string="Live Chat Button">
<field name="button_text" string="Notification Text" placeholder="e.g. Need help? Chat with us."/>
<label for="button_background_color" string="Button Colors" />
<div class="o_livechat_layout_colors d-flex align-items-center align-middle">
<field name="button_background_color" widget="color" class="mb-4 w-auto o_im_livechat_field_widget_color"/>
<field name="button_text_color" widget="color" class="mb-4 w-auto o_im_livechat_field_widget_color"/>
<widget name="colors_reset_button" options="{'default_colors': {'button_background_color': '#878787', 'button_text_color': '#FFFFFF'}}" />
</div>
</group>
<group string="Livechat Window">
<group string="Live Chat Window">
<field name="default_message" placeholder="e.g. Hello, how may I help you?"/>
<field name="input_placeholder"/>
<label for="header_background_color" string="Channel Header Color" />
<label for="header_background_color" string="Window Colors" />
<div class="o_livechat_layout_colors d-flex align-items-center align-middle">
<field name="header_background_color" widget="color" class="mb-4 w-auto o_im_livechat_field_widget_color"/>
<field name="title_color" widget="color" class="mb-4 w-auto o_im_livechat_field_widget_color"/>
<widget name="colors_reset_button" options="{'default_colors': {'header_background_color': '#875A7B', 'title_color': '#FFFFFF'}}" />
</div>
<field name="review_link" placeholder="Do not redirect visitors"/>
</group>
</group>
<group string="Session Limits">
<group>
<field name="max_sessions_mode" widget="radio" options="{'horizontal': true}"/>
<field name="max_sessions" invisible="max_sessions_mode != 'limited'"/>
<field name="block_assignment_during_call"/>
</group>
</group>
</page>
<page string="Channel Rules" name="channel_rules">
<page string="Rules" name="channel_rules" groups="im_livechat.im_livechat_group_manager">
<field name="rule_ids" colspan="2"/>
<div class="text-muted" colspan="2">Define rules for your live support channel. You can apply an action for the given URL, and per country.<br />To identify the country, GeoIP must be installed on your server, otherwise, the countries of the rule will not be taken into account.</div>
<div class="text-muted" colspan="2">
To apply the rule only to certain pages of your website, enter a URL regex like /shop. This will match any page that starts with /shop, such as /shop/product. Leave the field empty to apply the rule to all pages.<br/>
For on-premise databases, GeoIP must be installed on your server to geolocate visitors. Without it, rules that include country restrictions will be ignored.
<widget name="documentation_link" path="/administration/on_premise/geo_ip.html" icon="fa-fw fa-info-circle"/>
</div>
</page>
<page string="Widget" name="configuration_widget">
<div class="alert alert-warning mt4 mb16" role="alert" attrs='{"invisible": [["web_page", "!=", False]]}'>
<page string="Widget" name="configuration_widget" groups="im_livechat.im_livechat_group_manager">
<div class="alert alert-warning mt4 mb16" role="alert" invisible="web_page">
Save your Channel to get your configuration widget.
</div>
<div attrs='{"invisible": [["web_page", "=", False]]}'>
<separator string="How to use the Website Live Chat widget?"/>
<div invisible="not web_page">
<p>
Copy and paste this code into your website, within the &lt;head&gt; tag:
Learn how to display a live chat bubble on your website and start chatting with visitors in a few easy steps.
</p>
<field name="script_external" readonly="1" widget="CopyClipboardText"/>
<separator string="FOR WEBSITES BUILT WITH ODOO" />
<ol>
<li>Go to <strong>Website</strong> > <strong>Configuration</strong> > <strong>Settings</strong> > <strong>Email</strong> &amp; <strong>Marketing.</strong></li>
<li>Turn on the <strong>Live Chat</strong> feature.</li>
<li>Choose the live chat channel you want to display on your website.</li>
</ol>
<separator string="FOR OTHER WEBSITES" />
<p>
or copy this url and send it by email to your customers or suppliers:
Add the following code to the &lt;head&gt; section of your website:
</p>
<field name="web_page" readonly="1" widget="CopyClipboardChar"/>
<p>For websites built with the Odoo CMS, go to Website > Configuration > Settings and select the Website Live Chat Channel you want to add to your website.</p>
<field class="text-muted" name="script_external" readonly="1" widget="CopyClipboardChar"/>
<br/><br/>
<p>
Alternatively, share this URL with your customers or suppliers via email:
</p>
<field class="text-muted" name="web_page" readonly="1" widget="CopyClipboardChar"/>
</div>
</page>
</notebook>
@ -179,15 +236,16 @@
<!-- im_livechat.channel.rule -->
<record id="im_livechat_channel_rule_view_tree" model="ir.ui.view">
<field name="name">im.livechat.channel.rule.tree</field>
<field name="name">im.livechat.channel.rule.list</field>
<field name="model">im_livechat.channel.rule</field>
<field name="arch" type="xml">
<tree string="Rules">
<list string="Rules">
<field name="sequence" widget="handle"/>
<field name="regex_url"/>
<field name="action"/>
<field name="chatbot_script_id"/>
<field name="regex_url"/>
<field name="country_ids" widget="many2many_tags"/>
</tree>
</list>
</field>
</record>
@ -196,16 +254,11 @@
<field name="model">im_livechat.channel.rule</field>
<field name="arch" type="xml">
<kanban>
<field name="regex_url"/>
<field name="action"/>
<field name="country_ids"/>
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_global_click">
<div><field name="action"/></div>
<field name="regex_url" />
<field name="country_ids" widget="many2many_tags" />
</div>
<t t-name="card">
<field name="action"/>
<field name="regex_url" />
<field name="country_ids" widget="many2many_tags" />
</t>
</templates>
</kanban>
@ -215,68 +268,34 @@
<record id="im_livechat_channel_rule_view_form" model="ir.ui.view">
<field name="name">im_livechat.channel.rule.form</field>
<field name="model">im_livechat.channel.rule</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Channel Rule" class="o_livechat_rules_form">
<sheet>
<group>
<field name="action" widget="radio"/>
<label for="chatbot_script_id" string="Chatbot" attrs="{'invisible': [('action', '=', 'hide_button')]}"/>
<div attrs="{'invisible': [('action', '=', 'hide_button')]}">
<label for="auto_popup_timer" class="oe_inline" invisible="action != 'auto_popup'"/>
<div class="oe_inline" invisible="action != 'auto_popup'">
<field name="auto_popup_timer" class="oe_inline"/> seconds
</div>
<label for="chatbot_script_id" string="Chatbot" invisible="action == 'hide_button'"/>
<div invisible="action == 'hide_button'">
<field name="chatbot_script_id" class="oe_inline" style="width: 60% !important;"
options="{'no_create': True, 'no_open': True}"/>
</div>
<label for="chatbot_only_if_no_operator" class="oe_inline" attrs="{'invisible': [('chatbot_script_id', '=', False)]}" string="Enabled only if no operator"/>
<div class="oe_inline" attrs="{'invisible': [('chatbot_script_id', '=', False)]}">
<field name="chatbot_only_if_no_operator"/>
</div>
<field name="chatbot_enabled_condition" invisible="not chatbot_script_id" widget="radio"/>
<field name="regex_url" placeholder="e.g. /contactus"/>
<label for="auto_popup_timer" class="oe_inline" attrs="{'invisible': [('action', '!=', 'auto_popup')]}"/>
<div class="oe_inline" attrs="{'invisible': [('action', '!=', 'auto_popup')]}">
<field name="auto_popup_timer" class="oe_inline"/> seconds
</div>
<field name="country_ids" widget="many2many_tags" options="{'no_open': True, 'no_create': True}"/>
<field name="country_ids" placeholder="All countries" widget="many2many_tags" options="{'no_open': True, 'no_create': True}"/>
</group>
</sheet>
</form>
</field>
</record>
<!-- Canned responses -->
<record id="im_livechat_canned_response_view_tree" model="ir.ui.view">
<field name="name">im_livechat.canned_response.tree</field>
<field name="model">mail.shortcode</field>
<field name="arch" type="xml">
<tree editable="bottom">
<field name="source"/>
<field name="substitution"/>
</tree>
</field>
</record>
<record id="im_livechat_canned_response_action" model="ir.actions.act_window">
<field name="name">Canned Responses</field>
<field name="res_model">mail.shortcode</field>
<field name="view_mode">tree</field>
<field name="view_id" ref="im_livechat_canned_response_view_tree"/>
<field name="domain">[]</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a new canned response
</p><p>
Canned responses allow you to insert prewritten responses in
your messages by typing <i>:shortcut</i>. The shortcut is
replaced directly in your message, so that you can still edit
it before sending.
</p>
</field>
</record>
<!-- Menu items -->
<menuitem
id="menu_livechat_root"
name="Live Chat"
web_icon="im_livechat,static/description/icon.svg"
web_icon="im_livechat,static/description/icon.png"
groups="im_livechat_group_user"
sequence="240"/>
@ -288,39 +307,52 @@
groups="im_livechat_group_user"
sequence="5"/>
<menuitem
id="menu_livechat_sessions"
name="Sessions"
parent="menu_livechat_root"
groups="im_livechat_group_user"
sequence="10"/>
<menuitem
id="menu_livechat_all_conversations"
name="All Conversations"
action="discuss_channel_action"
parent="menu_livechat_sessions"
sequence="25"/>
<menuitem
id="menu_livechat_looking_for_help"
name="Looking for Help"
action="discuss_channel_looking_for_help_action"
parent="menu_livechat_sessions"
sequence="50"/>
<menuitem
id="menu_reporting_livechat"
name="Report"
name="Reporting"
parent="menu_livechat_root"
sequence="50"
groups="im_livechat_group_manager"/>
<menuitem
id="session_history"
name="Sessions History"
parent="menu_reporting_livechat"
action="mail_channel_action"
groups="im_livechat_group_user"
sequence="5"/>
<menuitem id="rating_rating_menu_livechat"
name="Customer Ratings"
action="rating_rating_action_livechat_report"
parent="menu_reporting_livechat"
sequence="40"/>
<menuitem
id="livechat_config"
name="Configuration"
parent="menu_livechat_root"
sequence="55"/>
<menuitem
id="livechat_technical"
name="Technical"
parent="menu_livechat_root"
groups="base.group_no_one"
sequence="75"/>
<menuitem
id="canned_responses"
name="Canned Responses"
parent="livechat_config"
action="im_livechat_canned_response_action"
action="mail.mail_canned_response_action"
groups="im_livechat_group_user"
sequence="15"/>
@ -329,8 +361,16 @@
name="Chatbots"
parent="livechat_config"
action="chatbot_script_action"
groups="im_livechat_group_user"
groups="im_livechat_group_manager"
sequence="20"/>
<menuitem
id="menu_livechat_conversation_tag"
name="Tags"
parent="livechat_config"
action="livechat_conversation_tag_action"
groups="im_livechat_group_user"
sequence="30"/>
</data>
</odoo>

View file

@ -2,23 +2,26 @@
<odoo>
<data>
<template id="chatbot_test_script_page">
<script>
<t t-call="im_livechat.loader">
<t t-set="info" t-value="{ 'available': True, 'options': { 'isTestChatbot': True, 'testChatbotChannelData': channel_data, 'testChatbotData': chatbot_data }, 'server_url': server_url }"/>
</t>
</script>
<t t-call="web.frontend_layout">
<t t-set="no_livechat" t-value="True"/>
<t t-set="title" t-value="chatbot_data['chatbot_name']"/>
<t t-set="chatbot_name" t-value="chatbot_script.title" />
<t t-set="head">
<script>
<t t-call="im_livechat.loader">
<t t-set="info" t-value="{ 'available': True, 'options': { 'chatbot_test_store': chatbot_test_store }, 'server_url': server_url }"/>
</t>
</script>
</t>
<t t-set="title" t-value="chatbot_name"/>
<div id="wrap">
<div groups="im_livechat.im_livechat_group_user" t-ignore="true"
class="alert alert-info alert-dismissible rounded-0 fade show d-print-none css_editable_mode_hidden mb-0">
<div t-ignore="true" class="text-center">
<a t-attf-href="/web#view_type=form&amp;model=chatbot.script&amp;id=#{chatbot_data['chatbot_script_id']}&amp;action=im_livechat.chatbot_script_action">
<a t-attf-href="/odoo/action-im_livechat.chatbot_script_action/#{chatbot_script.id}">
<span>You are currently testing</span>
<span t-out="chatbot_data['chatbot_name']"/>
<i class="fa fa-fw fa-arrow-right"/>Back to edit mode
<span t-out="chatbot_name"/>
<i class="oi oi-fw oi-arrow-right"/>Back to edit mode
</a>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>

View file

@ -0,0 +1,36 @@
<?xml version="1.0"?>
<odoo>
<data>
<record id="im_livechat_channel_conversation_tag_view_list" model="ir.ui.view">
<field name="name">im.livechat.channel.conversation.tag.list</field>
<field name="model">im_livechat.conversation.tag</field>
<field name="arch" type="xml">
<list string="Tags" editable="bottom" sample="1" duplicate="0">
<field name="name"/>
<field name="color" widget="color_picker"/>
</list>
</field>
</record>
<record id="im_livechat_channel_conversation_tag_view_form" model="ir.ui.view">
<field name="name">im.livechat.channel.conversation.tag.form</field>
<field name="model">im_livechat.conversation.tag</field>
<field name="arch" type="xml">
<form string="Tags">
<sheet>
<group>
<field name="name"/>
<field name="color" widget="color_picker"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="livechat_conversation_tag_action" model="ir.actions.act_window">
<field name="name">Tags</field>
<field name="res_model">im_livechat.conversation.tag</field>
<field name="view_mode">list,form</field>
</record>
</data>
</odoo>

View file

@ -0,0 +1,44 @@
<?xml version="1.0"?>
<odoo>
<data>
<record id="im_livechat_expertise_view_list" model="ir.ui.view">
<field name="name">im.livechat.expertise.list</field>
<field name="model">im_livechat.expertise</field>
<field name="arch" type="xml">
<list editable="bottom">
<field name="name"/>
<field name="user_ids" widget="many2many_tags" options="{'no_create': True}" domain="[['all_group_ids', 'in', %(im_livechat.im_livechat_group_user)d]]"/>
</list>
</field>
</record>
<record id="im_livechat_expertise_view_form" model="ir.ui.view">
<field name="name">im.livechat.expertise.form</field>
<field name="model">im_livechat.expertise</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="name"/>
<field name="user_ids" widget="many2many_tags" options="{'no_create': True}" domain="[['all_group_ids', 'in', %(im_livechat.im_livechat_group_user)d]]"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="expertise_action" model="ir.actions.act_window">
<field name="name">Expertise</field>
<field name="res_model">im_livechat.expertise</field>
<field name="view_mode">list,form</field>
</record>
<menuitem
id="expertise_menu"
name="Expertise"
parent="livechat_config"
action="im_livechat.expertise_action"
sequence="25"
/>
</data>
</odoo>

View file

@ -1,155 +0,0 @@
<?xml version="1.0"?>
<odoo>
<data>
<record id="mail_channel_view_search" model="ir.ui.view">
<field name="name">mail.channel.search</field>
<field name="model">mail.channel</field>
<field name="arch" type="xml">
<search string="Search history">
<field name="name"/>
<group expand="0" string="Group By...">
<filter name="group_by_channel" string="Channel" domain="[]" context="{'group_by':'livechat_channel_id'}"/>
<separator orientation="vertical"/>
<filter name="group_by_month" string="Creation Date" domain="[]" context="{'group_by':'create_date:month'}"/>
</group>
</search>
</field>
</record>
<record id="mail_channel_view_tree" model="ir.ui.view">
<field name="name">mail.channel.tree</field>
<field name="model">mail.channel</field>
<field name="arch" type="xml">
<tree string="History" create="false" default_order="create_date desc">
<field name="create_date" string="Session Date"/>
<field name="name" string="Attendees"/>
<field name="message_ids" string="# Messages"/>
<field name="rating_last_image" string="Rating" widget="image" options='{"size": [20, 20]}' class="bg-view"/>
</tree>
</field>
</record>
<record id="mail_channel_view_form" model="ir.ui.view">
<field name="name">mail.channel.form</field>
<field name="model">mail.channel</field>
<field name="arch" type="xml">
<form string="Session Form" create="false" edit="false">
<sheet>
<div style="width:50%" class="float-end">
<field name="rating_last_image" widget="image" class="float-end bg-view" readonly="1" nolabel="1"/>
<field name="rating_last_feedback" nolabel="1"/>
</div>
<div style="width:50%" class="float-start">
<group>
<field name="name" string="Attendees"/>
<field name="create_date" readonly="1" string="Session Date"/>
</group>
</div>
<group string="History" class="o_history_container">
<div class="o_history_kanban_container w-100 p-3" colspan="2">
<div class="o_history_kanban_sub_container">
<field name="message_ids" mode="kanban">
<kanban default_order="create_date DESC">
<field name="author_id"/>
<field name="body"/>
<field name="create_date"/>
<field name="id"/>
<field name="author_avatar"/>
<templates>
<t t-name="kanban-box">
<div class="oe_module_vignette">
<div class="o_kanban_image">
<div>
<t t-if="record.author_avatar.raw_value">
<img t-att-src="kanban_image('mail.message', 'author_avatar', record.id.raw_value)" alt="Avatar" class="o_image_64_cover rounded-circle"/>
</t>
<t t-else=""><img alt="Anonymous" src="/mail/static/src/img/smiley/avatar.jpg" class="o_image_64_cover rounded-circle"/></t>
</div>
</div>
<div class="oe_module_desc">
<div class="float-end"><p><field name="date"/></p></div>
<div>
<p><strong>
<t t-if="record.author_id.raw_value"><field name="author_id"/></t>
<t t-else="">Anonymous</t>
</strong></p>
<p>
<t t-if="record.body.raw_value"><field name="body" widget="html"/><br/></t>
</p>
</div>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</div>
</div>
</group>
</sheet>
</form>
</field>
</record>
<record id="mail_channel_action" model="ir.actions.act_window">
<field name="name">History</field>
<field name="res_model">mail.channel</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="im_livechat.mail_channel_view_search"/>
<field name="domain">[('livechat_channel_id', '!=', None)]</field>
<field name="context">{'search_default_session_not_empty': 1}</field>
<field name="help" type="html">
<p class="o_view_nocontent_empty_folder">
Your chatter history is empty
</p><p>
Create a channel and start chatting to fill up your history.
</p>
</field>
</record>
<record id="mail_channel_action_tree" model="ir.actions.act_window.view">
<field name="sequence">1</field>
<field name="view_mode">tree</field>
<field name="view_id" ref="im_livechat.mail_channel_view_tree"/>
<field name="act_window_id" ref="im_livechat.mail_channel_action"/>
</record>
<record id="mail_channel_action_form" model="ir.actions.act_window.view">
<field name="sequence">2</field>
<field name="view_mode">form</field>
<field name="view_id" ref="im_livechat.mail_channel_view_form"/>
<field name="act_window_id" ref="im_livechat.mail_channel_action"/>
</record>
<record id="mail_channel_action_from_livechat_channel" model="ir.actions.act_window">
<field name="name">Sessions</field>
<field name="res_model">mail.channel</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('livechat_channel_id', 'in', [active_id])]</field>
<field name="context">{
'search_default_livechat_channel_id': [active_id],
'default_livechat_channel_id': active_id,
}</field>
<field name="search_view_id" ref="mail_channel_view_search"/>
</record>
<record id="mail_channel_action_livechat_tree" model="ir.actions.act_window.view">
<field name="sequence">1</field>
<field name="view_mode">tree</field>
<field name="view_id" ref="im_livechat.mail_channel_view_tree"/>
<field name="act_window_id" ref="im_livechat.mail_channel_action_from_livechat_channel"/>
</record>
<record id="mail_channel_action_livechat_form" model="ir.actions.act_window.view">
<field name="sequence">2</field>
<field name="view_mode">form</field>
<field name="view_id" ref="im_livechat.mail_channel_view_form"/>
<field name="act_window_id" ref="im_livechat.mail_channel_action_from_livechat_channel"/>
</record>
</data>
</odoo>

View file

@ -1,79 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="rating_rating_view_search_livechat" model="ir.ui.view">
<field name="name">rating.rating.search.livechat</field>
<field name="model">rating.rating</field>
<field name="inherit_id" ref="rating.rating_rating_view_search"/>
<field name="mode">primary</field>
<field name="priority">64</field>
<field name="arch" type="xml">
<xpath expr="//filter[@name='resource']" position="replace">
<filter string="Code" name="resource" context="{'group_by':'res_name'}"/>
</xpath>
<xpath expr="//filter[@name='resource']" position="after">
<filter string="Livechat Channel" name="groupby_livechat_channel" context="{'group_by': 'parent_res_name'}"/>
</xpath>
<xpath expr="/search" position="inside">
<filter string="This Week" name="creation_date_filter" domain="[
('create_date', '>=', (datetime.datetime.combine(context_today() + relativedelta(weeks=-1,days=1,weekday=0), datetime.time(0,0,0)).to_utc()).strftime('%Y-%m-%d %H:%M:%S')),
('create_date', '&lt;', (datetime.datetime.combine(context_today() + relativedelta(days=1,weekday=0), datetime.time(0,0,0)).to_utc()).strftime('%Y-%m-%d %H:%M:%S'))]"/>
</xpath>
</field>
</record>
<record id="rating_rating_action_livechat" model="ir.actions.act_window">
<field name="name">Ratings for livechat channel</field>
<field name="res_model">rating.rating</field>
<field name="view_mode">kanban,tree,graph,pivot,form</field>
<field name="domain">[('parent_res_model', '=', 'im_livechat.channel'), ('consumed','=',True)]</field>
<field name="search_view_id" ref="rating_rating_view_search_livechat"/>
<field name="help" type="html">
<p class="o_view_nocontent_empty_folder">
There is no rating for this channel at the moment
</p>
</field>
<field name="context">{'search_default_rating_last_7_days': 1}</field>
</record>
<record id="rating_rating_action_livechat_view_kanban" model="ir.actions.act_window.view">
<field name="sequence" eval="1"/>
<field name="view_mode">kanban</field>
<field name="act_window_id" ref="rating_rating_action_livechat"/>
<field name="view_id" ref="rating.rating_rating_view_kanban"/>
</record>
<record id="rating_rating_action_livechat_view_form" model="ir.actions.act_window.view">
<field name="sequence">5</field>
<field name="view_mode">form</field>
<field name="act_window_id" ref="rating_rating_action_livechat"/>
<field name="view_id" ref="rating.rating_rating_view_form_text"/>
</record>
<record id="rating_rating_action_livechat_report" model="ir.actions.act_window">
<field name="name">Customer Ratings</field>
<field name="res_model">rating.rating</field>
<field name="view_mode">kanban,tree,pivot,graph,form</field>
<field name="domain">[('parent_res_model','=','im_livechat.channel'), ('consumed', '=', True)]</field>
<field name="search_view_id" ref="rating_rating_view_search_livechat"/>
<field name="help" type="html">
<p class="o_view_nocontent_empty_folder">
No customer ratings on live chat session yet
</p>
</field>
</record>
<record id="rating_rating_action_livechat_report_view_kanban" model="ir.actions.act_window.view">
<field name="sequence">1</field>
<field name="view_mode">kanban</field>
<field name="act_window_id" ref="rating_rating_action_livechat_report"/>
<field name="view_id" ref="rating.rating_rating_view_kanban"/>
</record>
<record id="rating_rating_action_livechat_report_view_form" model="ir.actions.act_window.view">
<field name="sequence">5</field>
<field name="view_mode">form</field>
<field name="act_window_id" ref="rating_rating_action_livechat_report"/>
<field name="view_id" ref="rating.rating_rating_view_form_text"/>
</record>
</odoo>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_partner_form" model="ir.ui.view">
<field name="name">res.partner.view.buttons</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form" />
<field name="priority" eval="20"/>
<field name="arch" type="xml">
<div name="button_box" position="inside">
<button
groups="im_livechat.im_livechat_group_user"
class="oe_stat_button"
type="object"
name="action_view_livechat_sessions"
invisible="not livechat_channel_count"
icon="fa-comments"
title="Live Chat History"
>
<field string="Live Chat" name="livechat_channel_count" widget="statinfo"/>
</button>
</div>
</field>
</record>
</data>
</odoo>

View file

@ -8,9 +8,17 @@
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form_simple_modif"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='tz']" position="after">
<field name="livechat_username" string="Online Chat Name" readonly="0"
attrs="{'invisible': [('share', '=', True)]}"/>
<xpath expr="//field[@name='outgoing_mail_server_type']" position="after">
<field name="has_access_livechat" invisible="1"/>
<field name="livechat_username" string="Livechat Name" invisible="not has_access_livechat"/>
<field name="livechat_lang_ids" string="Spoken Languages"
options="{'no_create': True, 'no_edit': True, 'no_create_edit': True}"
widget="many2many_tags"
invisible="not has_access_livechat"/>
<field name="livechat_expertise_ids" string="Expertise"
widget="many2many_tags"
options="{'no_create': True}"
invisible="not has_access_livechat"/>
</xpath>
</field>
</record>
@ -21,12 +29,18 @@
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form"/>
<field name="arch" type="xml">
<xpath expr="//group[@name='messaging']" position="after">
<group name="livechat" string="Livechat"
attrs="{'invisible': [('share', '=', True)]}">
<field name="livechat_username"/>
</group>
</xpath>
<xpath expr="//field[@name='outgoing_mail_server_type']" position="after">
<field name="has_access_livechat" invisible="1"/>
<field name="livechat_username" string="Livechat Name" invisible="not has_access_livechat"/>
<field name="livechat_lang_ids" string="Spoken Languages"
options="{'no_create': True, 'no_edit': True}"
widget="many2many_tags"
invisible="not has_access_livechat"/>
<field name="livechat_expertise_ids" string="Expertise"
widget="many2many_tags"
options="{'no_create': True}"
invisible="not has_access_livechat"/>
</xpath>
</field>
</record>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="im_livechat.unit_embed_suite">
<t t-call="web.layout">
<t t-set="html_data" t-value="{'style': 'height: 100%;'}"/>
<t t-set="title">Livechat External Tests</t>
<t t-set="head">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
<script type="text/javascript">
odoo.__session_info__ = <t t-out="json.dumps(session_info)"/>;
</script>
<t t-call-assets="im_livechat.embed_assets_unit_tests_setup" />
<t t-call-assets="im_livechat.embed_assets_unit_tests" defer_load="True" />
</t>
</t>
</template>
</odoo>