[REF] im_livechat : refactoring, make it compatbile with the nw mail module, change reporting sql view (split them in 2), adapt view, ...
This commit is contained in:
@@ -53,7 +53,6 @@ class ImBus(models.Model):
|
||||
"message": json_dump(message)
|
||||
}
|
||||
self.sudo().create(values)
|
||||
self.env.cr.commit()
|
||||
if random.random() < 0.01:
|
||||
self.gc()
|
||||
if channels:
|
||||
|
||||
@@ -24,13 +24,17 @@ Help your customers with this chat, and analyse their feedback.
|
||||
"views/mail_channel_views.xml",
|
||||
"views/im_livechat_channel_views.xml",
|
||||
"views/im_livechat_channel_templates.xml",
|
||||
"report/im_livechat_report_views.xml",
|
||||
"report/im_livechat_report_channel_views.xml",
|
||||
"report/im_livechat_report_operator_views.xml",
|
||||
"data/im_livechat_channel_data.xml"
|
||||
],
|
||||
'demo': [
|
||||
"data/im_livechat_channel_demo.xml",
|
||||
],
|
||||
'depends': ["mail", "rating"],
|
||||
'qweb': [
|
||||
'static/src/xml/im_livechat_backend.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'application': True,
|
||||
|
||||
@@ -11,7 +11,8 @@ class LivechatController(http.Controller):
|
||||
@http.route('/im_livechat/support/<string:dbname>/<int:channel_id>', type='http', auth='none')
|
||||
def support_page(self, dbname, channel_id, **kwargs):
|
||||
Channel = request.env['im_livechat.channel']
|
||||
info = Channel.get_channel_infos(channel_id)
|
||||
info = kwargs
|
||||
info.update(Channel.get_channel_infos(channel_id))
|
||||
info["dbname"] = dbname
|
||||
info["channel"] = channel_id
|
||||
info["channel_name"] = Channel.browse(channel_id).name
|
||||
@@ -39,9 +40,9 @@ class LivechatController(http.Controller):
|
||||
# don't return the initialization script, since its blocked (in the country)
|
||||
return
|
||||
rule_data = {
|
||||
'action' : rule.action,
|
||||
'auto_popup_timer' : rule.auto_popup_timer,
|
||||
'regex_url' : rule.regex_url,
|
||||
'action': rule.action,
|
||||
'auto_popup_timer': rule.auto_popup_timer,
|
||||
'regex_url': rule.regex_url,
|
||||
}
|
||||
info['rule'] = json.dumps(rule and rule_data or False)
|
||||
return request.render('im_livechat.loader', info)
|
||||
@@ -54,7 +55,7 @@ class LivechatController(http.Controller):
|
||||
# if the user is identifiy (eg: portal user on the frontend), don't use the anonymous name. The user will be added to session.
|
||||
if request.session.uid:
|
||||
anonymous_name = False
|
||||
return request.env['im_livechat.channel'].sudo(request.session.uid).get_channel_session(channel_id, anonymous_name)
|
||||
return request.env['im_livechat.channel'].sudo(request.session.uid or SUPERUSER_ID).get_mail_channel(channel_id, anonymous_name)
|
||||
|
||||
@http.route('/im_livechat/available', type='json', auth="none")
|
||||
def available(self, db, channel):
|
||||
@@ -62,35 +63,34 @@ class LivechatController(http.Controller):
|
||||
channel = request.env['im_livechat.channel'].sudo(user_id).browse(channel)
|
||||
return len(channel.get_available_users()) > 0
|
||||
|
||||
@http.route('/rating/livechat/feedback', type='json', auth='none')
|
||||
def rating_livechat_feedback(self, uuid, rate, reason=None, **kwargs):
|
||||
Session = request.env['im_chat.session']
|
||||
@http.route('/im_livechat/feedback', type='json', auth='none')
|
||||
def feedback(self, uuid, rate, reason=None, **kwargs):
|
||||
Channel = request.env['mail.channel']
|
||||
Rating = request.env['rating.rating']
|
||||
session_ids = Session.sudo().search([('uuid', '=', uuid)])
|
||||
if session_ids:
|
||||
session = session_ids[0]
|
||||
channel = Channel.sudo().search([('uuid', '=', uuid)], limit=1)
|
||||
print "RATING"
|
||||
print channel
|
||||
if channel:
|
||||
# limit the creation : only ONE rating per session
|
||||
values = {
|
||||
'rating': rate,
|
||||
}
|
||||
if not session.rating_ids:
|
||||
if not channel.rating_ids:
|
||||
values.update({
|
||||
'res_id': session.id,
|
||||
'res_model': 'im_chat.session',
|
||||
'res_id': channel.id,
|
||||
'res_model': 'mail.channel',
|
||||
'rating': rate,
|
||||
'feedback': reason,
|
||||
})
|
||||
# find the partner related to the user of the conversation
|
||||
rated_partner_id = False
|
||||
if session.user_ids:
|
||||
rated_partner_id = session.user_ids[0] and session.user_ids[0].partner_id.id or False
|
||||
values['rated_partner_id'] = rated_partner_id
|
||||
# find the partner (operator)
|
||||
if channel.channel_partner_ids:
|
||||
values['rated_partner_id'] = channel.channel_partner_ids[0] and channel.channel_partner_ids[0].id or False
|
||||
# create the rating
|
||||
rating = Rating.sudo().create(values)
|
||||
else:
|
||||
if reason:
|
||||
values['feedback'] = reason
|
||||
rating = session.rating_ids[0]
|
||||
rating = channel.rating_ids[0]
|
||||
rating.write(values)
|
||||
return rating.id
|
||||
return False
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False"/>
|
||||
<field name="model">im_chat.session</field>
|
||||
<field name="model">mail.channel</field>
|
||||
<field name="function">cron_remove_empty_session</field>
|
||||
<field name="active" eval="True"/>
|
||||
</record>
|
||||
@@ -28,47 +28,20 @@
|
||||
</data>
|
||||
|
||||
<data>
|
||||
<!-- Custom Filters -->
|
||||
<record id="im_livechat_report_filter_session_by_day" model="ir.filters">
|
||||
<field name="name">Sessions by day</field>
|
||||
<field name="model_id">im_livechat.report</field>
|
||||
<field name="domain">[('nbr_speakers','>', 1)]</field>
|
||||
<field name="context">{'group_by': ['start_date:day', 'session_name']}</field>
|
||||
<field name="is_default">v</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
</record>
|
||||
|
||||
<record id="im_livechat_report_filter_session_last_24h" model="ir.filters">
|
||||
<field name="name">Last 24h stats</field>
|
||||
<field name="model_id">im_livechat.report</field>
|
||||
<field name="domain">[('start_date','>', (context_today() - datetime.timedelta(days=1)).strftime('%Y-%m-%d') )]</field>
|
||||
<field name="context">{'group_by': ['start_date:day', 'session_name']}</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
</record>
|
||||
|
||||
<record id="im_livechat_report_filter_operator_stats" model="ir.filters">
|
||||
<field name="name">Operators stats</field>
|
||||
<field name="model_id">im_livechat.report</field>
|
||||
<field name="domain">[('nbr_speakers','>', 1), ('user_id', '!=', False)]</field>
|
||||
<field name="context">{'group_by': ['start_date:month', 'user_id', 'uuid']}</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Smiley for rating to be displayed in the conversation -->
|
||||
<record id="im_chat_shortcode_rating_0" model="im_chat.shortcode">
|
||||
<record id="mail_shortcode_rating_0" model="mail.shortcode">
|
||||
<field name="source">:rating_0</field>
|
||||
<field name="substitution"><img src='/rating/static/src/img/rating_0.png'/></field>
|
||||
<field name="description">Rating Smiley Bad</field>
|
||||
</record>
|
||||
|
||||
<record id="im_chat_shortcode_rating_5" model="im_chat.shortcode">
|
||||
<record id="mail_shortcode_rating_5" model="mail.shortcode">
|
||||
<field name="source">:rating_5</field>
|
||||
<field name="substitution"><img src='/rating/static/src/img/rating_5.png'/></field>
|
||||
<field name="description">Rating Smiley Okay</field>
|
||||
</record>
|
||||
|
||||
<record id="im_chat_shorcode_rating_10" model="im_chat.shortcode">
|
||||
<record id="mail_shorcode_rating_10" model="mail.shortcode">
|
||||
<field name="source">:rating_10</field>
|
||||
<field name="substitution"><img src='/rating/static/src/img/rating_10.png'/></field>
|
||||
<field name="description">Rating Smiley Good</field>
|
||||
|
||||
@@ -24,13 +24,12 @@ class ImLivechatChannel(models.Model):
|
||||
def _default_user_ids(self):
|
||||
return [(6, 0, [self._uid])]
|
||||
|
||||
|
||||
# attribute fields
|
||||
name = fields.Char('Name', required=True, help="The name of the channel")
|
||||
button_text = fields.Char('Text of the Button', default='Have a Question? Chat with us.',
|
||||
help="Default text displayed on the Livechat Support Button")
|
||||
default_message = fields.Char('Welcome Message', default='How may I help you?',
|
||||
help="This is an automated 'welcome' message that your visitor will see when they initiate a new chat session.")
|
||||
help="This is an automated 'welcome' message that your visitor will see when they initiate a new conversation.")
|
||||
input_placeholder = fields.Char('Chat Input Placeholder')
|
||||
|
||||
# computed fields
|
||||
@@ -39,7 +38,7 @@ class ImLivechatChannel(models.Model):
|
||||
are_you_inside = fields.Boolean(string='Are you inside the matrix?',
|
||||
compute='_are_you_inside', store=False, readonly=True)
|
||||
script_external = fields.Text('Script (external)', compute='_compute_script_external', store=False, readonly=True)
|
||||
nbr_session = fields.Integer('Number of session', compute='_compute_nbr_session', store=False, readonly=True)
|
||||
nbr_channel = fields.Integer('Number of conversation', compute='_compute_nbr_channel', store=False, readonly=True)
|
||||
rating_percentage_satisfaction = fields.Integer('% Happy', compute='_compute_percentage_satisfaction', store=False, default=-1)
|
||||
|
||||
# images fields
|
||||
@@ -56,7 +55,7 @@ class ImLivechatChannel(models.Model):
|
||||
|
||||
# relationnal fields
|
||||
user_ids = fields.Many2many('res.users', 'im_livechat_channel_im_user', 'channel_id', 'user_id', string='Operators', default=_default_user_ids)
|
||||
session_ids = fields.One2many('im_chat.session', 'channel_id', 'Sessions')
|
||||
channel_ids = fields.One2many('mail.channel', 'livechat_channel_id', 'Sessions')
|
||||
rule_ids = fields.One2many('im_livechat.channel.rule', 'channel_id', 'Rules')
|
||||
|
||||
|
||||
@@ -92,16 +91,16 @@ class ImLivechatChannel(models.Model):
|
||||
record.web_page = "%s/im_livechat/support/%s/%i" % (base_url, self._cr.dbname, record.id)
|
||||
|
||||
@api.multi
|
||||
@api.depends('session_ids')
|
||||
def _compute_nbr_session(self):
|
||||
@api.depends('channel_ids')
|
||||
def _compute_nbr_channel(self):
|
||||
for record in self:
|
||||
record.nbr_session = len(record.session_ids)
|
||||
record.nbr_channel = len(record.channel_ids)
|
||||
|
||||
@api.multi
|
||||
@api.depends('session_ids.rating_ids')
|
||||
@api.depends('channel_ids.rating_ids')
|
||||
def _compute_percentage_satisfaction(self):
|
||||
for record in self:
|
||||
repartition = record.session_ids.rating_get_grades()
|
||||
repartition = record.channel_ids.rating_get_grades()
|
||||
total = sum(repartition.values())
|
||||
if total > 0:
|
||||
happy = repartition['great']
|
||||
@@ -109,7 +108,6 @@ class ImLivechatChannel(models.Model):
|
||||
else:
|
||||
record.rating_percentage_satisfaction = -1
|
||||
|
||||
|
||||
# --------------------------
|
||||
# Action Methods
|
||||
# --------------------------
|
||||
@@ -131,7 +129,7 @@ class ImLivechatChannel(models.Model):
|
||||
"""
|
||||
self.ensure_one()
|
||||
action = self.env['ir.actions.act_window'].for_xml_id('rating', 'action_view_rating')
|
||||
action['domain'] = [('res_id', 'in', [s.id for s in self.session_ids]), ('res_model', '=', 'im_chat.session')]
|
||||
action['domain'] = [('res_id', 'in', [s.id for s in self.channel_ids]), ('res_model', '=', 'mail.channel')]
|
||||
return action
|
||||
|
||||
# --------------------------
|
||||
@@ -146,20 +144,36 @@ class ImLivechatChannel(models.Model):
|
||||
return self.sudo().user_ids.filtered(lambda user: user.im_status == 'online')
|
||||
|
||||
@api.model
|
||||
def get_channel_session(self, channel_id, anonymous_name):
|
||||
""" return a session given a channel : create on with a registered user, or return false otherwise """
|
||||
def get_mail_channel(self, livechat_channel_id, anonymous_name):
|
||||
""" Return a mail.channel given a livechat channel. It creates one with a connected operator, or return false otherwise
|
||||
:param livechat_channel_id : the identifier if the im_livechat.channel
|
||||
:param anonymous_name : the name of the anonymous person of the channel
|
||||
:type livechat_channel_id : int
|
||||
:type anonymous_name : str
|
||||
:return : channel header
|
||||
:rtype : dict
|
||||
"""
|
||||
# get the avalable user of the channel
|
||||
users = self.sudo().browse(channel_id).get_available_users()
|
||||
users = self.sudo().browse(livechat_channel_id).get_available_users()
|
||||
if len(users) == 0:
|
||||
return False
|
||||
user_id = random.choice(users).id
|
||||
# user to add to the session
|
||||
user_to_add = [(4, user_id)]
|
||||
if self.env.uid:
|
||||
user_to_add.append((4, self.env.uid))
|
||||
# choose the res.users operator and get its partner id
|
||||
user = random.choice(users)
|
||||
operator_partner_id = user.partner_id.id
|
||||
# partner to add to the mail.channel
|
||||
channel_partner_to_add = [(4, operator_partner_id)]
|
||||
if self.env.uid: # if the user if logged (portal user), he can be identify
|
||||
channel_partner_to_add.append((4, self.env.user.partner_id.id))
|
||||
# create the session, and add the link with the given channel
|
||||
session = self.env["im_chat.session"].sudo().create({'user_ids': user_to_add, 'channel_id': channel_id, 'anonymous_name': anonymous_name})
|
||||
return session.sudo().with_context(im_livechat_operator_id=user_id).session_info()
|
||||
mail_channel = self.env["mail.channel"].with_context(mail_create_nosubscribe=False).sudo().create({
|
||||
'channel_partner_ids': channel_partner_to_add,
|
||||
'livechat_channel_id': livechat_channel_id,
|
||||
'anonymous_name': anonymous_name,
|
||||
'channel_type': 'livechat',
|
||||
'name': ', '.join([anonymous_name, user.name]),
|
||||
'public': 'public',
|
||||
})
|
||||
return mail_channel.sudo().with_context(im_livechat_operator_partner_id=operator_partner_id).channel_info()[0]
|
||||
|
||||
@api.model
|
||||
def get_channel_infos(self, channel_id):
|
||||
@@ -174,7 +188,6 @@ class ImLivechatChannel(models.Model):
|
||||
}
|
||||
|
||||
|
||||
|
||||
class ImLivechatChannelRule(models.Model):
|
||||
""" Channel Rules
|
||||
Rules defining access to the channel (countries, and url matching). It also provide the 'auto pop'
|
||||
@@ -202,7 +215,6 @@ class ImLivechatChannelRule(models.Model):
|
||||
sequence = fields.Integer('Matching order', default=10,
|
||||
help="Given the order to find a matching rule. If 2 rules are matching for the given url/country, the one with the lowest sequence will be chosen.")
|
||||
|
||||
|
||||
def match_rule(self, channel_id, url, country_id=False):
|
||||
""" determine if a rule of the given channel match with the given url
|
||||
:param channel_id : the identifier of the channel_id
|
||||
|
||||
@@ -3,79 +3,69 @@ from openerp import api, fields, models
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
|
||||
class ImChatSession(models.Model):
|
||||
class MailChannel(models.Model):
|
||||
""" Chat Session
|
||||
Reprensenting a conversation between users.
|
||||
It extends the base method for anonymous usage.
|
||||
"""
|
||||
|
||||
_name = 'im_chat.session'
|
||||
_inherit = ['im_chat.session', 'rating.mixin']
|
||||
|
||||
_name = 'mail.channel'
|
||||
_inherit = ['mail.channel', 'rating.mixin']
|
||||
|
||||
anonymous_name = fields.Char('Anonymous Name')
|
||||
create_date = fields.Datetime('Create Date', required=True)
|
||||
channel_id = fields.Many2one('im_livechat.channel', 'Channel')
|
||||
fullname = fields.Char('Complete Name', compute='_compute_fullname')
|
||||
channel_type = fields.Selection(selection_add=[('livechat', 'Livechat Conversation')])
|
||||
livechat_channel_id = fields.Many2one('im_livechat.channel', 'Channel')
|
||||
|
||||
@api.multi
|
||||
@api.depends('anonymous_name', 'user_ids')
|
||||
def _compute_fullname(self):
|
||||
""" built the complete name of the session """
|
||||
for session in self:
|
||||
names = []
|
||||
for user in session.user_ids:
|
||||
names.append(user.name)
|
||||
if session.anonymous_name:
|
||||
names.append(session.anonymous_name)
|
||||
session.fullname = ', '.join(names)
|
||||
|
||||
@api.multi
|
||||
def is_in_session(self):
|
||||
""" Return True if the current user is in the user_ids of the session. False otherwise.
|
||||
If this is executed as sudo, this might be the anonymous user.
|
||||
def _channel_message_notifications(self, message):
|
||||
""" When a anonymous user create a mail.channel, the operator is not notify (to avoid massive polling when
|
||||
clicking on livechat button). So when the anonymous person is sending its FIRST message, the channel header
|
||||
should be added to the notification, since the user cannot be listining to the channel.
|
||||
"""
|
||||
self.ensure_one()
|
||||
if self.anonymous_name and self._uid == SUPERUSER_ID:
|
||||
return True
|
||||
else:
|
||||
return super(ImChatSession, self).is_in_session()
|
||||
notifications = super(MailChannel, self)._channel_message_notifications(message)
|
||||
if not message.author_id:
|
||||
unpinned_channel_partner = self.mapped('channel_last_seen_partner_ids').filtered(lambda cp: not cp.is_pinned)
|
||||
if unpinned_channel_partner:
|
||||
unpinned_channel_partner.write({'is_pinned': True})
|
||||
notifications = self._channel_channel_notifications(unpinned_channel_partner.mapped('partner_id').ids) + notifications
|
||||
return notifications
|
||||
|
||||
@api.multi
|
||||
def session_user_info(self):
|
||||
""" Get the user infos for all the identified user in the session + the anonymous if anonymous session
|
||||
:returns a list of user infos
|
||||
def channel_info(self):
|
||||
""" Extends the channel header by adding the livechat operator and the 'anonymous' profile
|
||||
:rtype : list(dict)
|
||||
"""
|
||||
self.ensure_one()
|
||||
users_infos = super(ImChatSession, self).session_user_info()
|
||||
# identify the operator for the 'welcome message'
|
||||
for user_profile in users_infos:
|
||||
user_profile['is_operator'] = bool(user_profile['id'] == self.env.context.get('im_livechat_operator_id'))
|
||||
if self.anonymous_name:
|
||||
users_infos.append({'id': False, 'name': self.anonymous_name, 'im_status': 'online', 'is_operator': False})
|
||||
return users_infos
|
||||
channel_infos = super(MailChannel, self).channel_info()
|
||||
# add the operator id
|
||||
if self.env.context.get('im_livechat_operator_partner_id'):
|
||||
partner_name = self.env['res.partner'].browse(self.env.context.get('im_livechat_operator_partner_id')).name_get()[0]
|
||||
for channel_info in channel_infos:
|
||||
channel_info['operator_pid'] = partner_name
|
||||
# add the anonymous name
|
||||
channel_infos_dict = dict((c['id'], c) for c in channel_infos)
|
||||
for channel in self:
|
||||
if channel.anonymous_name:
|
||||
channel_infos_dict[channel.id]['anonymous_name'] = channel.anonymous_name
|
||||
return channel_infos_dict.values()
|
||||
|
||||
@api.model
|
||||
def quit_user(self, uuid):
|
||||
""" Remove the current user from the given session.
|
||||
Note : an anonymous user cannot leave the session, since he is not registered.
|
||||
Required to modify the base comportement, since a session can contain only 1 identified user.
|
||||
:param uuid : the uuid of the session to quit
|
||||
"""
|
||||
session = self.search([('uuid', '=', uuid)], limit=1)
|
||||
if session.anonymous_name:
|
||||
# an identified user can leave an anonymous session if there is still another idenfied user in it
|
||||
if self._uid and self._uid in [u.id for u in session.user_ids] and len(session.user_ids) > 1:
|
||||
self._remove_user()
|
||||
return True
|
||||
return False
|
||||
else:
|
||||
return super(ImChatSession, self).quit_user(uuid)
|
||||
def channel_fetch_slot(self):
|
||||
values = super(MailChannel, self).channel_fetch_slot()
|
||||
pinned_channels = self.env['mail.channel.partner'].search([('partner_id', '=', self.env.user.partner_id.id), ('is_pinned', '=', True)]).mapped('channel_id')
|
||||
values['channel_livechat'] = self.search([('channel_type', '=', 'livechat'), ('public', 'in', ['public']), ('id', 'in', pinned_channels.ids)]).channel_info()
|
||||
return values
|
||||
|
||||
@api.model
|
||||
def cron_remove_empty_session(self):
|
||||
groups = self.env['im_chat.message'].read_group([], ['to_id'], ['to_id'])
|
||||
not_empty_session_ids = [group['to_id'][0] for group in groups]
|
||||
empty_sessions = self.search([('id', 'not in', not_empty_session_ids), ('channel_id', '!=', False)])
|
||||
empty_sessions.unlink()
|
||||
self.env.cr.execute("""
|
||||
SELECT id as id
|
||||
FROM mail_channel C
|
||||
WHERE NOT EXISTS (
|
||||
SELECT *
|
||||
FROM mail_message_mail_channel_rel R
|
||||
WHERE R.mail_channel_id = C.id
|
||||
) AND C.channel_type = 'livechat' AND livechat_channel_id IS NOT NULL;
|
||||
""")
|
||||
empty_channel_ids = [item['id'] for item in self.env.cr.dictfetchall()]
|
||||
self.browse(empty_channel_ids).unlink()
|
||||
|
||||
@@ -11,9 +11,8 @@ class Rating(models.Model):
|
||||
def _compute_res_name(self):
|
||||
# cannot change the rec_name of session since it is use to create the bus channel
|
||||
# so, need to override this method to set the same alternative rec_name as in reporting
|
||||
if self.res_model == 'im_chat.session':
|
||||
if self.res_model == 'mail.channel':
|
||||
current_object = self.env[self.res_model].sudo().browse(self.res_id)
|
||||
self.res_name = ('%s / %s') % (current_object.channel_id.name, current_object.id)
|
||||
self.res_name = ('%s / %s') % (current_object.livechat_channel_id.name, current_object.id)
|
||||
else:
|
||||
super(Rating, self)._compute_res_name()
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import im_livechat_report
|
||||
import im_livechat_report_channel
|
||||
import im_livechat_report_operator
|
||||
|
||||
@@ -1,55 +1,51 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from openerp import api, fields, models, tools
|
||||
from openerp import fields, models, tools
|
||||
|
||||
|
||||
class im_livechat_report(models.Model):
|
||||
""" Livechat Support Report """
|
||||
class ImLivechatReportChannel(models.Model):
|
||||
""" Livechat Support Report on the Channels """
|
||||
|
||||
_name = "im_livechat.report"
|
||||
_name = "im_livechat.report.channel"
|
||||
_description = "Livechat Support Report"
|
||||
_order = 'start_date, session_name'
|
||||
_order = 'start_date, technical_name'
|
||||
_auto = False
|
||||
|
||||
session_name = fields.Char('Session Name', readonly=True)
|
||||
uuid = fields.Char('UUID', readonly=True)
|
||||
channel_id = fields.Many2one('mail.channel', 'Conversation', readonly=True)
|
||||
channel_name = fields.Char('Channel Name', readonly=True)
|
||||
technical_name = fields.Char('Code', readonly=True)
|
||||
livechat_channel_id = fields.Many2one('im_livechat.channel', 'Channel', readonly=True)
|
||||
start_date = fields.Datetime('Start Date of session', readonly=True, help="Start date of the conversation")
|
||||
start_date_hour = fields.Char('Hour of start Date of session', readonly=True)
|
||||
duration = fields.Float('Average duration', digits=(16, 2), readonly=True, group_operator="avg", help="Duration of the conversation (in seconds)")
|
||||
time_in_session = fields.Float('Time in session', digits=(16, 2), readonly=True, group_operator="avg", help="Average time the user spend in the conversation")
|
||||
time_to_answer = fields.Float('Time to answer', digits=(16, 2), readonly=True, group_operator="avg", help="Average time to give the first answer to the visitor")
|
||||
nbr_messages = fields.Integer('Average message', readonly=True, group_operator="avg", help="Number of message in the conversation")
|
||||
nbr_user_messages = fields.Integer('Average of messages/user', readonly=True, group_operator="avg", help="Average number of message per user")
|
||||
nbr_speakers = fields.Integer('# of speakers', readonly=True, group_operator="avg", help="Number of different speakers")
|
||||
user_id = fields.Many2one('res.users', 'User', readonly=True)
|
||||
session_id = fields.Many2one('im_chat.session', 'Session', readonly=True)
|
||||
channel_id = fields.Many2one('im_livechat.channel', 'Channel', readonly=True)
|
||||
|
||||
nbr_speaker = fields.Integer('# of speakers', readonly=True, group_operator="avg", help="Number of different speakers")
|
||||
nbr_message = fields.Integer('Average message', readonly=True, group_operator="avg", help="Number of message in the conversation")
|
||||
partner_id = fields.Many2one('res.partner', 'Opertor', readonly=True)
|
||||
|
||||
def init(self, cr):
|
||||
# Note : start_date_hour must be remove when the read_group will allow grouping on the hour of a datetime. Don't forget to change the view !
|
||||
tools.drop_view_if_exists(cr, 'im_livechat_report')
|
||||
tools.drop_view_if_exists(cr, 'im_livechat_report_channel')
|
||||
cr.execute("""
|
||||
CREATE OR REPLACE VIEW im_livechat_report AS (
|
||||
CREATE OR REPLACE VIEW im_livechat_report_channel AS (
|
||||
SELECT
|
||||
min(M.id) as id,
|
||||
S.uuid as uuid,
|
||||
CONCAT(C.name, ' / ', S.id) as session_name,
|
||||
S.create_date as start_date,
|
||||
to_char(date_trunc('hour', S.create_date), 'YYYY-MM-DD HH24:MI:SS') as start_date_hour,
|
||||
EXTRACT('epoch' from ((SELECT (max(create_date)-min(create_date)) FROM im_chat_message WHERE to_id=S.id AND from_id = U.id))) as time_in_session,
|
||||
EXTRACT('epoch' from ((SELECT min(create_date) FROM im_chat_message WHERE to_id=S.id AND from_id IS NOT NULL)-(SELECT min(create_date) FROM im_chat_message WHERE to_id=S.id AND from_id IS NULL))) as time_to_answer,
|
||||
EXTRACT('epoch' from (max((SELECT (max(create_date)) FROM im_chat_message WHERE to_id=S.id))-S.create_date)) as duration,
|
||||
(SELECT count(distinct COALESCE(from_id, 0)) FROM im_chat_message WHERE to_id=S.id) as nbr_speakers,
|
||||
(SELECT count(id) FROM im_chat_message WHERE to_id=S.id) as nbr_messages,
|
||||
count(M.id) as nbr_user_messages,
|
||||
U.id as user_id,
|
||||
S.channel_id as channel_id,
|
||||
S.id as session_id
|
||||
FROM im_chat_message M
|
||||
LEFT JOIN im_chat_session S on (S.id = M.to_id)
|
||||
LEFT JOIN res_users U on (U.id = M.from_id)
|
||||
LEFT JOIN im_livechat_channel C on (S.channel_id = C.id)
|
||||
WHERE S.channel_id IS NOT NULL
|
||||
GROUP BY U.id, M.to_id, S.id, C.name, S.uuid
|
||||
C.id as id,
|
||||
C.uuid as uuid,
|
||||
C.id as channel_id,
|
||||
C.name as channel_name,
|
||||
CONCAT(L.name, ' / ', C.id) as technical_name,
|
||||
C.livechat_channel_id as livechat_channel_id,
|
||||
C.create_date as start_date,
|
||||
to_char(date_trunc('hour', C.create_date), 'YYYY-MM-DD HH24:MI:SS') as start_date_hour,
|
||||
EXTRACT('epoch' FROM (max((SELECT (max(M.create_date)) FROM mail_message M JOIN mail_message_mail_channel_rel R ON (R.mail_message_id = M.id) WHERE R.mail_channel_id = C.id))-C.create_date)) as duration,
|
||||
count(distinct P.id) as nbr_speaker,
|
||||
count(distinct M.id) as nbr_message,
|
||||
MAX(S.partner_id) as partner_id
|
||||
FROM mail_channel C
|
||||
JOIN mail_message_mail_channel_rel R ON (C.id = R.mail_channel_id)
|
||||
JOIN mail_message M ON (M.id = R.mail_message_id)
|
||||
JOIN mail_channel_partner S ON (S.channel_id = C.id)
|
||||
JOIN im_livechat_channel L ON (L.id = C.livechat_channel_id)
|
||||
LEFT JOIN res_partner P ON (M.author_id = P.id)
|
||||
GROUP BY C.id, C.name, C.livechat_channel_id, L.name, C.create_date, C.uuid
|
||||
)
|
||||
""")
|
||||
|
||||
@@ -2,42 +2,42 @@
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<record id="im_livechat_report_view_pivot" model="ir.ui.view">
|
||||
<field name="name">im_livechat.report.pivot</field>
|
||||
<field name="model">im_livechat.report</field>
|
||||
<record id="im_livechat_report_channel_view_pivot" model="ir.ui.view">
|
||||
<field name="name">im_livechat.report.channel.pivot</field>
|
||||
<field name="model">im_livechat.report.channel</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Livechat Support Statistics" disable_linking="True">
|
||||
<field name="session_name" type="row"/>
|
||||
<field name="technical_name" type="row"/>
|
||||
<field name="duration" type="measure"/>
|
||||
<field name="nbr_messages" type="measure"/>
|
||||
<field name="time_to_answer" type="measure"/>
|
||||
<field name="nbr_message" type="measure"/>
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="im_livechat_report_view_graph" model="ir.ui.view">
|
||||
<field name="name">im_livechat.report.graph</field>
|
||||
<field name="model">im_livechat.report</field>
|
||||
<record id="im_livechat_report_channel_view_graph" model="ir.ui.view">
|
||||
<field name="name">im_livechat.report.channel.graph</field>
|
||||
<field name="model">im_livechat.report.channel</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Livechat Support Statistics">
|
||||
<field name="session_name"/>
|
||||
<field name="nbr_messages" type="measure"/>
|
||||
<field name="technical_name"/>
|
||||
<field name="nbr_message" type="measure"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="im_livechat_report_view_search" model="ir.ui.view">
|
||||
<field name="name">im_livechat.report.search</field>
|
||||
<field name="model">im_livechat.report</field>
|
||||
<record id="im_livechat_report_channel_view_search" model="ir.ui.view">
|
||||
<field name="name">im_livechat.report.channel.search</field>
|
||||
<field name="model">im_livechat.report.channel</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search report">
|
||||
<filter name="missed_session" string="Missed sessions" domain="[('nbr_speakers','<=', 1)]"/>
|
||||
<filter name="treated_session" string="Treated sessions" domain="[('nbr_speakers','>', 1)]"/>
|
||||
<filter name="missed_session" string="Missed sessions" domain="[('nbr_speaker','<=', 1)]"/>
|
||||
<filter name="treated_session" string="Treated sessions" domain="[('nbr_speaker','>', 1)]"/>
|
||||
<filter name="last_24h" string="Last 24h" domain="[('start_date','>', (context_today() - datetime.timedelta(days=1)).strftime('%%Y-%%m-%%d') )]"/>
|
||||
<filter name="last_week" string="Last Week" domain="[('start_date','>', (context_today() - datetime.timedelta(weeks=1)).strftime('%%Y-%%m-%%d') )]"/>
|
||||
<group expand="0" string="Group By...">
|
||||
<filter name="group_by_session" string="Session" domain="[]" context="{'group_by':'session_name'}"/>
|
||||
<filter name="group_by_channel" string="Channel" domain="[]" context="{'group_by':'channel_id'}"/>
|
||||
<filter name="group_by_user" string="Operator" domain="[('user_id','!=', False)]" context="{'group_by':'user_id'}"/>
|
||||
<filter name="group_by_operator" string="Operator" domain="[('partner_id','!=', False)]" context="{'group_by':'partner_id'}"/>
|
||||
<separator orientation="vertical" />
|
||||
<filter name="group_by_hour" string="Creation date (hour)" domain="[]" context="{'group_by':'start_date_hour'}"/>
|
||||
<filter name="group_by_day" string="Creation date (day)" domain="[]" context="{'group_by':'start_date:day'}"/>
|
||||
@@ -49,22 +49,29 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="im_livechat_report_action" model="ir.actions.act_window">
|
||||
<field name="name">Livechat Support Report</field>
|
||||
<field name="res_model">im_livechat.report</field>
|
||||
<record id="im_livechat_report_channel_action" model="ir.actions.act_window">
|
||||
<field name="name">Livechat Support Report Channel</field>
|
||||
<field name="res_model">im_livechat.report.channel</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">pivot,graph</field>
|
||||
<field name="help">Livechat Support Analysis allows you to easily check and analyse your company livechat session performance. Extract informations about the missed sessions, the audiance, the duration of a session, etc.</field>
|
||||
<field name="context">{"search_default_last_week":1}</field>
|
||||
<field name="help">Livechat Support Channel Statistics allows you to easily check and analyse your company livechat session performance. Extract informations about the missed sessions, the audiance, the duration of a session, etc.</field>
|
||||
</record>
|
||||
|
||||
|
||||
<menuitem
|
||||
id="menu_reporting_livechat"
|
||||
name="Report"
|
||||
parent="menu_livechat_root"
|
||||
sequence="50"
|
||||
groups="im_livechat_group_manager"
|
||||
action="im_livechat_report_action"/>
|
||||
groups="im_livechat_group_manager"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_reporting_livechat_channel"
|
||||
name="Session Statistics"
|
||||
parent="menu_reporting_livechat"
|
||||
sequence="10"
|
||||
action="im_livechat_report_channel_action"/>
|
||||
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from openerp import fields, models, tools
|
||||
|
||||
|
||||
class ImLivechatReportOperator(models.Model):
|
||||
""" Livechat Support Report on the Operator """
|
||||
|
||||
_name = "im_livechat.report.operator"
|
||||
_description = "Livechat Support Report"
|
||||
_order = 'livechat_channel_id, partner_id'
|
||||
_auto = False
|
||||
|
||||
partner_id = fields.Many2one('res.partner', 'Operator', readonly=True)
|
||||
livechat_channel_id = fields.Many2one('im_livechat.channel', 'Channel', readonly=True)
|
||||
nbr_channel = fields.Integer('# of channel', readonly=True, group_operator="sum", help="Number of conversation")
|
||||
channel_id = fields.Many2one('mail.channel', 'Conversation', readonly=True)
|
||||
start_date = fields.Datetime('Start Date of session', readonly=True, help="Start date of the conversation")
|
||||
time_to_answer = fields.Float('Time to answer', digits=(16, 2), readonly=True, group_operator="avg", help="Average time to give the first answer to the visitor")
|
||||
duration = fields.Float('Average duration', digits=(16, 2), readonly=True, group_operator="avg", help="Duration of the conversation (in seconds)")
|
||||
|
||||
def init(self, cr):
|
||||
# Note : start_date_hour must be remove when the read_group will allow grouping on the hour of a datetime. Don't forget to change the view !
|
||||
tools.drop_view_if_exists(cr, 'im_livechat_report_operator')
|
||||
cr.execute("""
|
||||
CREATE OR REPLACE VIEW im_livechat_report_operator AS (
|
||||
SELECT
|
||||
row_number() OVER () AS id,
|
||||
P.id as partner_id,
|
||||
L.id as livechat_channel_id,
|
||||
count(C.id) as nbr_channel,
|
||||
C.id as channel_id,
|
||||
C.create_date as start_date,
|
||||
EXTRACT('epoch' FROM (max((SELECT (max(M.create_date)) FROM mail_message M JOIN mail_message_mail_channel_rel R ON (R.mail_message_id = M.id) WHERE R.mail_channel_id = C.id))-C.create_date)) as duration,
|
||||
EXTRACT('epoch' from ((SELECT min(M.create_date) FROM mail_message M, mail_message_mail_channel_rel R WHERE M.author_id=P.id AND R.mail_channel_id = C.id AND R.mail_message_id = M.id)-(SELECT min(M.create_date) FROM mail_message M, mail_message_mail_channel_rel R WHERE M.author_id IS NULL AND R.mail_channel_id = C.id AND R.mail_message_id = M.id))) as time_to_answer
|
||||
FROM im_livechat_channel_im_user O
|
||||
JOIN res_users U ON (O.user_id = U.id)
|
||||
JOIN res_partner P ON (U.partner_id = P.id)
|
||||
LEFT JOIN im_livechat_channel L ON (L.id = O.channel_id)
|
||||
LEFT JOIN mail_channel C ON (C.livechat_channel_id = L.id)
|
||||
GROUP BY P.id, L.id, C.id, C.create_date
|
||||
)
|
||||
""")
|
||||
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0"?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<record id="im_livechat_report_operator_view_pivot" model="ir.ui.view">
|
||||
<field name="name">im_livechat.report.operator.pivot</field>
|
||||
<field name="model">im_livechat.report.operator</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Livechat Support Statistics" disable_linking="True">
|
||||
<field name="partner_id" type="row"/>
|
||||
<field name="duration" type="measure"/>
|
||||
<field name="nbr_channel" type="measure"/>
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="im_livechat_report_operator_view_graph" model="ir.ui.view">
|
||||
<field name="name">im_livechat.report.operator.graph</field>
|
||||
<field name="model">im_livechat.report.operator</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Livechat Support Statistics">
|
||||
<field name="partner_id"/>
|
||||
<field name="nbr_channel" type="measure"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="im_livechat_report_operator_view_search" model="ir.ui.view">
|
||||
<field name="name">im_livechat.report.operator.search</field>
|
||||
<field name="model">im_livechat.report.operator</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search report">
|
||||
<filter name="last_24h" string="Last 24h" domain="[('start_date','>', (context_today() - datetime.timedelta(days=1)).strftime('%%Y-%%m-%%d') )]"/>
|
||||
<filter name="last_week" string="Last Week" domain="[('start_date','>', (context_today() - datetime.timedelta(weeks=1)).strftime('%%Y-%%m-%%d') )]"/>
|
||||
<group expand="0" string="Group By...">
|
||||
<filter name="group_by_channel" string="Channel" domain="[]" context="{'group_by':'channel_id'}"/>
|
||||
<filter name="group_by_operator" string="Operator" domain="[('partner_id','!=', False)]" context="{'group_by':'partner_id'}"/>
|
||||
<separator orientation="vertical" />
|
||||
<filter name="group_by_hour" string="Creation date (hour)" domain="[]" context="{'group_by':'start_date_hour'}"/>
|
||||
<filter name="group_by_day" string="Creation date (day)" domain="[]" context="{'group_by':'start_date:day'}"/>
|
||||
<filter name="group_by_week" string="Creation date (week)" domain="[]" context="{'group_by':'start_date:week'}"/>
|
||||
<filter name="group_by_month" string="Creation date (month)" domain="[]" context="{'group_by':'start_date:month'}" />
|
||||
<filter name="group_by_year" string="Creation date (year)" domain="[]" context="{'group_by':'start_date:year'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="im_livechat_report_operator_action" model="ir.actions.act_window">
|
||||
<field name="name">Livechat Support Report Channel</field>
|
||||
<field name="res_model">im_livechat.report.operator</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">pivot,graph</field>
|
||||
<field name="context">{"search_default_last_week":1}</field>
|
||||
<field name="help">Livechat Support Channel Statistics allows you to easily check and analyse your company livechat session performance. Extract informations about the missed sessions, the audiance, the duration of a session, etc.</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="menu_reporting_livechat_operator"
|
||||
name="Operator Analysis"
|
||||
parent="menu_reporting_livechat"
|
||||
sequence="10"
|
||||
action="im_livechat_report_operator_action"/>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -21,22 +21,22 @@
|
||||
<field name="users" eval="[(4, ref('base.user_root'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="im_chat_message_rule_manager" model="ir.rule">
|
||||
<record id="mail_message_rule_manager" model="ir.rule">
|
||||
<field name="name">Live Support Managers can read messages from live support</field>
|
||||
<field name="model_id" ref="im_chat.model_im_chat_message"/>
|
||||
<field name="model_id" ref="mail.model_mail_message"/>
|
||||
<field name="groups" eval="[(6,0,[ref('im_livechat.im_livechat_group_manager')])]"/>
|
||||
<field name="domain_force">[('to_id.channel_id', '!=', None)]</field>
|
||||
<field name="domain_force">[('mail.channel_ids.livechat_channel_id', '!=', None)]</field>
|
||||
<field name="perm_unlink" eval="0"/>
|
||||
<field name="perm_write" eval="0"/>
|
||||
<field name="perm_read" eval="1"/>
|
||||
<field name="perm_create" eval="0"/>
|
||||
</record>
|
||||
|
||||
<record id="im_chat_session_rule_manager" model="ir.rule">
|
||||
<record id="mail_channel_rule_manager" model="ir.rule">
|
||||
<field name="name">Live Support Managers can see all session from live support</field>
|
||||
<field name="model_id" ref="im_chat.model_im_chat_session"/>
|
||||
<field name="model_id" ref="mail.model_mail_channel"/>
|
||||
<field name="groups" eval="[(6,0,[ref('im_livechat.im_livechat_group_manager')])]"/>
|
||||
<field name="domain_force">[('channel_id', '!=', None)]</field>
|
||||
<field name="domain_force">[('mail.channel_ids.livechat_channel_id', '!=', None)]</field>
|
||||
<field name="perm_unlink" eval="1"/>
|
||||
<field name="perm_write" eval="0"/>
|
||||
<field name="perm_read" eval="1"/>
|
||||
|
||||
@@ -2,7 +2,8 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_livechat_channel,im_livechat.channel,model_im_livechat_channel,,1,0,0,0
|
||||
access_livechat_channel_user,im_livechat.channel,model_im_livechat_channel,im_livechat_group_user,1,1,1,0
|
||||
access_livechat_channel_manager,im_livechat.channel,model_im_livechat_channel,im_livechat_group_manager,1,1,1,1
|
||||
access_livechat_support_report,im_livechat.report,model_im_livechat_report,im_livechat_group_manager,1,1,1,1
|
||||
access_livechat_support_report_channel,im_livechat.report.channel,model_im_livechat_report_channel,im_livechat_group_manager,1,1,1,1
|
||||
access_livechat_support_report_operator,im_livechat.report.operator,model_im_livechat_report_operator,im_livechat_group_manager,1,1,1,1
|
||||
access_livechat_channel_rule,im_livechat.channel.rule,model_im_livechat_channel_rule,,1,0,0,0
|
||||
access_livechat_channel_rule_user,im_livechat.channel.rule,model_im_livechat_channel_rule,im_livechat_group_user,1,1,1,0
|
||||
access_livechat_channel_rule_manager,im_livechat.channel.rule,model_im_livechat_channel_rule,im_livechat_group_user,1,1,1,1
|
||||
|
||||
|
@@ -1,42 +1,75 @@
|
||||
|
||||
.openerp { /* base style of openerp */
|
||||
font-family: "Lucida Grande", Helvetica, Verdana, Arial, sans-serif;
|
||||
color: #4c4c4c;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.o_mail_chat_im_window * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
.oe_chat_button {
|
||||
width: 230px;
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
right: 6px;
|
||||
display: inline-block;
|
||||
min-width: 100px;
|
||||
background-color: rgba(60, 60, 60, 0.6);
|
||||
font-family: 'Lucida Grande', 'Lucida Sans Unicode', Arial, Verdana, sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
padding: 10px;
|
||||
color: white;
|
||||
text-shadow: rgb(59, 76, 88) 1px 1px 0px;
|
||||
border: 1px solid rgb(80, 80, 80);
|
||||
border-bottom: 0px;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
cursor: pointer;
|
||||
z-index:500;
|
||||
}
|
||||
|
||||
/* Livechat Rating : feedback smiley */
|
||||
.oe_im_chatview .oe_livechat_rating{
|
||||
.o_mail_chat_im_window_content .o_livechat_rating{
|
||||
padding: 15px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.oe_im_chatview .oe_livechat_rating .oe_im_feedback_text {
|
||||
color: white;
|
||||
.o_mail_chat_im_window_content .o_livechat_rating .o_livechat_rating_feedback_text {
|
||||
vertical-align: middle;
|
||||
font-size: 14px;
|
||||
}
|
||||
.oe_im_chatview .oe_livechat_rating .oe_livechat_rating_choices{
|
||||
.o_mail_chat_im_window_content .o_livechat_rating .o_livechat_rating_choices{
|
||||
height:40px;
|
||||
text-align: center;
|
||||
margin: 10px 0 30px 0;
|
||||
}
|
||||
.oe_im_chatview .oe_livechat_rating .oe_livechat_rating_choices img{
|
||||
.o_mail_chat_im_window_content .o_livechat_rating .o_livechat_rating_choices img{
|
||||
width: 50px;
|
||||
opacity: 0.60;
|
||||
cursor: pointer;
|
||||
margin: 5px;
|
||||
}
|
||||
.oe_im_chatview .oe_livechat_rating .oe_livechat_rating_choices img:hover{
|
||||
.o_mail_chat_im_window_content .o_livechat_rating .o_livechat_rating_choices img:hover{
|
||||
opacity:1;
|
||||
}
|
||||
.oe_im_chatview .oe_livechat_rating .oe_livechat_rating_choices img.selected{
|
||||
.o_mail_chat_im_window_content .o_livechat_rating .o_livechat_rating_choices img.selected{
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* feedback reason */
|
||||
.oe_im_chatview .oe_livechat_rating .oe_livechat_rating_reason {
|
||||
.o_mail_chat_im_window_content .o_livechat_rating .o_livechat_rating_reason {
|
||||
margin: 10px 0;
|
||||
display: none; /* hidden by default */
|
||||
}
|
||||
.oe_im_chatview .oe_livechat_rating .oe_livechat_rating_reason textarea {
|
||||
.o_mail_chat_im_window_content .o_livechat_rating .o_livechat_rating_reason textarea {
|
||||
width: 100%;
|
||||
height: 70px;
|
||||
resize: none;
|
||||
}
|
||||
.oe_im_chatview .oe_livechat_rating .oe_livechat_rating_reason_button input{
|
||||
.o_mail_chat_im_window_content .o_livechat_rating .o_livechat_rating_reason_button input{
|
||||
float: right;
|
||||
margin-left : 10px;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ var user_session = require('web.session');
|
||||
var time = require('web.time');
|
||||
var utils = require('web.utils');
|
||||
var Widget = require('web.Widget');
|
||||
var im_chat_common = require('mail.chat_common');
|
||||
var mail_chat_common = require('mail.chat_common');
|
||||
|
||||
var _t = core._t;
|
||||
var QWeb = core.qweb;
|
||||
@@ -19,11 +19,12 @@ var COOKIE_NAME = 'livechat_conversation';
|
||||
The state of anonymous session is hold by the client and not the server.
|
||||
Override the method managing the state of normal conversation.
|
||||
*/
|
||||
im_chat_common.Conversation.include({
|
||||
init: function(){
|
||||
mail_chat_common.Conversation.include({
|
||||
init: function(parent, session, options){
|
||||
this._super.apply(this, arguments);
|
||||
this.shown = true;
|
||||
this.feedback = false;
|
||||
this.options.default_username = session.anonymous_name || this.options.default_username;
|
||||
},
|
||||
show: function(){
|
||||
this._super.apply(this, arguments);
|
||||
@@ -33,7 +34,7 @@ im_chat_common.Conversation.include({
|
||||
this._super.apply(this, arguments);
|
||||
this.shown = false;
|
||||
},
|
||||
session_update_state: function(state){
|
||||
session_fold: function(state){
|
||||
// set manually the new state
|
||||
if(state === 'closed'){
|
||||
this.destroy();
|
||||
@@ -54,14 +55,14 @@ im_chat_common.Conversation.include({
|
||||
this._super(state);
|
||||
utils.set_cookie(COOKIE_NAME, JSON.stringify(this.get('session')), 60*60);
|
||||
},
|
||||
click_close: function(event) {
|
||||
on_click_close: function(event) {
|
||||
if(!this.feedback && (this.get('messages').length > 1)){
|
||||
this.feedback = new Feedback(this);
|
||||
this.$(".oe_im_chatview_content").empty();
|
||||
this.$(".oe_im_chatview_input").prop('disabled', true);
|
||||
this.feedback.appendTo( this.$(".oe_im_chatview_content"));
|
||||
this.$(".o_mail_chat_im_window_content").empty();
|
||||
this.$(".o_mail_chat_im_window_input").prop('disabled', true);
|
||||
this.feedback.appendTo(this.$(".o_mail_chat_im_window_content"));
|
||||
// bind event to close conversation
|
||||
this.feedback.on("feedback_sent", this, this.click_close);
|
||||
this.feedback.on("feedback_sent", this, this.on_click_close);
|
||||
}else{
|
||||
this._super.apply(this, arguments);
|
||||
utils.set_cookie(COOKIE_NAME, "", -1);
|
||||
@@ -72,7 +73,7 @@ im_chat_common.Conversation.include({
|
||||
|
||||
// To avoid exeption when the anonymous has close his
|
||||
// conversation and when operator send him a message.
|
||||
im_chat_common.ConversationManager.include({
|
||||
var LivechatConversationManager = mail_chat_common.ConversationManager.extend({
|
||||
message_receive: function(message) {
|
||||
try{
|
||||
this._super(message);
|
||||
@@ -95,7 +96,7 @@ var LiveSupport = Widget.extend({
|
||||
this.load_template(db, channel, options, rule);
|
||||
},
|
||||
_get_template_list: function(){
|
||||
return ['/im_livechat/static/src/xml/im_livechat.xml', '/im_chat/static/src/xml/im_chat.xml'];
|
||||
return ['/im_livechat/static/src/xml/im_livechat.xml', '/mail/static/src/xml/mail_chat_common.xml'];
|
||||
},
|
||||
load_template: function(db, channel, options, rule){
|
||||
var self = this;
|
||||
@@ -153,7 +154,7 @@ var ChatButton = Widget.extend({
|
||||
start: function() {
|
||||
this.$().append(QWeb.render("im_livechat.chatButton", {widget: this}));
|
||||
// set up the manager
|
||||
this.manager = new im_chat_common.ConversationManager(this, this.options);
|
||||
this.manager = new LivechatConversationManager(this, this.options);
|
||||
this.manager.set("bottom_offset", $('.oe_chat_button').outerHeight());
|
||||
if(this.session){
|
||||
this.set_conversation(this.session);
|
||||
@@ -200,20 +201,20 @@ var ChatButton = Widget.extend({
|
||||
},
|
||||
send_welcome_message: function(){
|
||||
var self = this;
|
||||
if(this.session.users.length > 0){
|
||||
if (self.options.defaultMessage) {
|
||||
setTimeout(function(){
|
||||
var operator = _.last(_.filter(self.session.users, function(user){return user.is_operator}));
|
||||
self.conv.message_receive({
|
||||
id : 1,
|
||||
type: "message",
|
||||
message: self.options.defaultMessage,
|
||||
create_date: time.datetime_to_str(new Date()),
|
||||
from_id: [operator.id, operator.name],
|
||||
to_id: [0, self.session.uuid]
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
if(this.session.operator_pid && self.options.defaultMessage) {
|
||||
setTimeout(function(){
|
||||
self.conv.message_receive({
|
||||
id : 1,
|
||||
message_type: "comment",
|
||||
model: 'mail.channel',
|
||||
body: self.options.defaultMessage,
|
||||
date: time.datetime_to_str(new Date()),
|
||||
author_id: self.session.operator_pid,
|
||||
channel_ids: [self.session.id],
|
||||
tracking_value_ids: [],
|
||||
attachment_ids: [],
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -231,20 +232,20 @@ var Feedback = Widget.extend({
|
||||
start: function(){
|
||||
this._super.apply(this.arguments);
|
||||
// bind events
|
||||
this.$('.oe_livechat_rating_choices img').on('click', _.bind(this.click_smiley, this));
|
||||
this.$('.o_livechat_rating_choices img').on('click', _.bind(this.click_smiley, this));
|
||||
this.$('#rating_submit').on('click', _.bind(this.click_send, this));
|
||||
},
|
||||
click_smiley: function(ev){
|
||||
var self = this;
|
||||
this.rating = parseInt($(ev.currentTarget).data('value'));
|
||||
this.$('.oe_livechat_rating_choices img').removeClass('selected');
|
||||
this.$('.oe_livechat_rating_choices img[data-value="'+this.rating+'"]').addClass('selected');
|
||||
this.$('.o_livechat_rating_choices img').removeClass('selected');
|
||||
this.$('.o_livechat_rating_choices img[data-value="'+this.rating+'"]').addClass('selected');
|
||||
// only display textearea if bad smiley selected
|
||||
var close_conv = false;
|
||||
if(this.rating === 0){
|
||||
this.$('.oe_livechat_rating_reason').show();
|
||||
this.$('.o_livechat_rating_reason').show();
|
||||
}else{
|
||||
this.$('.oe_livechat_rating_reason').hide();
|
||||
this.$('.o_livechat_rating_reason').hide();
|
||||
close_conv = true;
|
||||
}
|
||||
this._send_feedback(close_conv).then(function(){
|
||||
@@ -260,7 +261,7 @@ var Feedback = Widget.extend({
|
||||
_send_feedback: function(close){
|
||||
var self = this;
|
||||
var uuid = this.conversation.get('session').uuid;
|
||||
return user_session.rpc('/rating/livechat/feedback', {uuid: uuid, rate: this.rating, reason : this.reason}).then(function(res) {
|
||||
return user_session.rpc('/im_livechat/feedback', {uuid: uuid, rate: this.rating, reason : this.reason}).then(function(res) {
|
||||
if(close){
|
||||
self.trigger("feedback_sent"); // will close the conversation
|
||||
self.conversation.message_send(_.str.sprintf(_t("I rated you with :rating_%d"), self.rating), "message");
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
odoo.define('im_livechat.chat_backend', function (require) {
|
||||
"use strict";
|
||||
|
||||
var mail_chat_backend = require('mail.chat_backend');
|
||||
|
||||
|
||||
/**
|
||||
* Patch for the client action to integrate Livechat Mail Channel in a particular slot
|
||||
*/
|
||||
mail_chat_backend.ChatMailThread.include({
|
||||
init: function(parent, action){
|
||||
this._super.apply(this, arguments);
|
||||
this.set('channel_livechat', []);
|
||||
},
|
||||
start: function(){
|
||||
var self = this;
|
||||
this.on("change:channel_livechat", this, function(){
|
||||
self.channel_render('channel_livechat');
|
||||
});
|
||||
return this._super.apply(this, arguments).then(function(){
|
||||
self.$el.on('click', '.o_mail_chat_channel_unpin', _.bind(self.on_click_channel_unpin, self));
|
||||
});
|
||||
},
|
||||
on_click_channel_unpin: function(event){
|
||||
var self = this;
|
||||
var channel_id = this.$(event.currentTarget).data('channel-id');
|
||||
var channel = this.channels[channel_id];
|
||||
return this.channel_pin(channel.uuid, false).then(function(){
|
||||
self.channel_remove(channel_id);
|
||||
// if unpin current channel, switch to inbox
|
||||
if(self.get('current_channel_id') === channel_id){
|
||||
self.set('current_channel_id', 'channel_inbox');
|
||||
}
|
||||
});
|
||||
},
|
||||
channel_change: function(){
|
||||
// update the default username
|
||||
var current_channel = this.channels[this.get('current_channel_id')];
|
||||
if(current_channel){
|
||||
this.options.default_username = current_channel.anonymous_name || this.options.default_username
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
// utils function
|
||||
get_channel_slot: function(channel){
|
||||
if(channel.channel_type === 'livechat'){
|
||||
return 'channel_livechat';
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
});
|
||||
@@ -7,18 +7,18 @@
|
||||
</t>
|
||||
|
||||
<t t-name="im_livechat.feedback">
|
||||
<div class="oe_livechat_rating">
|
||||
<div class="oe_im_feedback_text">
|
||||
<div class="o_livechat_rating">
|
||||
<div class="o_livechat_rating_feedback_text">
|
||||
Did we correctly answer your question ?
|
||||
</div>
|
||||
<div class="oe_livechat_rating_choices">
|
||||
<div class="o_livechat_rating_choices">
|
||||
<img t-att-src="widget.server_origin + '/rating/static/src/img/rating_10.png'" alt="Good" data-value="10"/>
|
||||
<img t-att-src="widget.server_origin + '/rating/static/src/img/rating_5.png'" alt="OK" data-value="5"/>
|
||||
<img t-att-src="widget.server_origin + '/rating/static/src/img/rating_0.png'" alt="Bad" data-value="0" />
|
||||
</div>
|
||||
<div class="oe_livechat_rating_reason">
|
||||
<div class="o_livechat_rating_reason">
|
||||
<textarea id="reason" placeholder="Explain your note"></textarea>
|
||||
<div class="oe_livechat_rating_reason_button">
|
||||
<div class="o_livechat_rating_reason_button">
|
||||
<input type="button" id="rating_submit" value="Send" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<template>
|
||||
|
||||
<t t-extend="mail.chat.ChatMailThread.channels">
|
||||
<t t-jquery="li > a" t-operation="append">
|
||||
<t t-if="channel.channel_type === 'livechat'">
|
||||
<span class="fa fa-times pull-right o_mail_chat_channel_unpin" t-att-title="_t('Untoggle')" t-att-data-channel-id="channel.id"/>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-extend="mail.chat.ChatMailThread">
|
||||
<t t-jquery=".o_mail_chat_sidebar" t-operation="append">
|
||||
<!-- Livechat list -->
|
||||
<h4 class="o_mail_chat_sidebar_title"><t t-esc="_t('Livechat')"/></h4>
|
||||
<t t-call="mail.chat.ChatMailThread.channels">
|
||||
<t t-set="channel_slot" t-value="'channel_livechat'"/>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
</template>
|
||||
@@ -2,6 +2,15 @@
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<!--
|
||||
Integrate Livechat Conversation in the Mail Chat Client Action
|
||||
-->
|
||||
<template id="assets_backend" name="im_livechat assets" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/im_livechat/static/src/js/im_livechat_backend.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Template rendering the external HTML support page -->
|
||||
<template id="support_page" name="Livechat Support Page">
|
||||
<!DOCTYPE html>
|
||||
@@ -76,9 +85,9 @@
|
||||
<!-- css style -->
|
||||
<link t-att-href="'%s/web/css/im_livechat.external_lib' % (url)" rel="stylesheet"/>
|
||||
<!-- js of all the required lib (internal and external) -->
|
||||
<script t-att-src="'%s/web/js/im_livechat.external_lib' % (url)" type="text/javascript" async="async" />
|
||||
<script t-att-src="'%s/web/js/im_livechat.external_lib' % (url)" type="text/javascript" />
|
||||
<!-- the loader -->
|
||||
<script t-att-src="'%s/im_livechat/loader/%s/%i' % (url, dbname, channel)" type="text/javascript" async="async" />
|
||||
<script t-att-src="'%s/im_livechat/loader/%s/%i' % (url, dbname, channel)" type="text/javascript" />
|
||||
</template>
|
||||
|
||||
<!-- Template rendering all the scripts required to execute the Livechat from a page containing Odoo -->
|
||||
@@ -128,17 +137,17 @@
|
||||
<script type="text/javascript" src="/web/static/lib/moment/moment.js"></script>
|
||||
<!-- IM module -->
|
||||
<script type="text/javascript" src="/bus/static/src/js/bus.js"></script>
|
||||
<script type="text/javascript" src="/im_chat/static/src/js/im_chat_common.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/src/js/mail_utils.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/src/js/mail_chat_common.js"></script>
|
||||
<script type="text/javascript" src="/im_livechat/static/src/js/im_livechat.js"></script>
|
||||
<!-- CSS -->
|
||||
<link rel="stylesheet" href="/im_chat/static/src/css/im_chat_common.css"></link>
|
||||
<link rel="stylesheet" href="/mail/static/src/css/mail_chat_common.css"></link>
|
||||
<link rel="stylesheet" href="/im_livechat/static/src/css/im_livechat.css"/>
|
||||
</template>
|
||||
|
||||
<!-- the js code to initialize the LiveSupport object -->
|
||||
<template id="loader" name="Javascript initializing the LiveSupport">
|
||||
<t t-translate="off">
|
||||
$(function() {
|
||||
odoo.define('im_livechat.livesupport', function (require) {
|
||||
var im_livechat = require('im_livechat.im_livechat');
|
||||
window.livesupport = new im_livechat.LiveSupport(
|
||||
@@ -155,7 +164,6 @@
|
||||
<t t-raw="rule"/>
|
||||
);
|
||||
});
|
||||
});
|
||||
</t>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<field name="web_page" widget="url"/>
|
||||
<field name="are_you_inside"/>
|
||||
<field name="user_ids"/>
|
||||
<field name="nbr_session"/>
|
||||
<field name="nbr_channel"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div class="oe_kanban_global_click">
|
||||
@@ -44,7 +44,7 @@
|
||||
<t t-esc="(record.user_ids.raw_value || []).length"/> Operators
|
||||
<br/>
|
||||
<i class="fa fa-comments"></i>
|
||||
<t t-esc="record.nbr_session.raw_value"/> Sessions
|
||||
<t t-esc="record.nbr_channel.raw_value"/> Sessions
|
||||
</p>
|
||||
</div>
|
||||
<div class="o_kanban_button">
|
||||
@@ -66,8 +66,8 @@
|
||||
<form>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button class="oe_stat_button" type="action" attrs="{'invisible':[('nbr_session','=', 0)]}" name="%(im_chat_session_action_from_channel)d" icon="fa-comments">
|
||||
<field string="Sessions" name="nbr_session" widget="statinfo"/>
|
||||
<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_percentage_satisfaction','=', -1)]}" class="oe_stat_button" type="object" icon="fa-smile-o">
|
||||
<field string="% Happy" name="rating_percentage_satisfaction" widget="statinfo"/>
|
||||
@@ -192,7 +192,7 @@
|
||||
id="session_history"
|
||||
name="History"
|
||||
parent="menu_livechat_root"
|
||||
action="im_chat_session_action"
|
||||
action="mail_channel_action"
|
||||
groups="im_livechat_group_user"
|
||||
sequence="10"/>
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="im_chat_session_view_search" model="ir.ui.view">
|
||||
<field name="name">im_chat.session.search</field>
|
||||
<field name="model">im_chat.session</field>
|
||||
<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">
|
||||
<filter name="id" string="My sessions" domain="[('user_ids','in', uid)]"/>
|
||||
@@ -20,28 +20,28 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="im_chat_session_view_tree" model="ir.ui.view">
|
||||
<field name="name">im_chat.session.tree</field>
|
||||
<field name="model">im_chat.session</field>
|
||||
<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">
|
||||
<field name="id"/>
|
||||
<field name="fullname"/>
|
||||
<field name="name"/>
|
||||
<field name="create_date"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="im_chat_session_view_form" model="ir.ui.view">
|
||||
<field name="name">im_chat.session.form</field>
|
||||
<field name="model">im_chat.session</field>
|
||||
<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>
|
||||
<group>
|
||||
<group string="General">
|
||||
<field name="id"/>
|
||||
<field name="fullname" />
|
||||
<field name="name" />
|
||||
<field name="create_date" readonly="1"/>
|
||||
</group>
|
||||
<group string="Feedback">
|
||||
@@ -68,8 +68,8 @@
|
||||
<field name="message_ids" type="tree">
|
||||
<tree string="History">
|
||||
<field name="create_date" />
|
||||
<field name="from_id" />
|
||||
<field name="message" />
|
||||
<field name="author_id" />
|
||||
<field name="body" />
|
||||
</tree>
|
||||
</field>
|
||||
</sheet>
|
||||
@@ -78,25 +78,25 @@
|
||||
</record>
|
||||
|
||||
|
||||
<record id="im_chat_session_action" model="ir.actions.act_window">
|
||||
<record id="mail_channel_action" model="ir.actions.act_window">
|
||||
<field name="name">History</field>
|
||||
<field name="res_model">im_chat.session</field>
|
||||
<field name="res_model">mail.channel</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="domain">[('channel_id', '!=', None)]</field>
|
||||
<field name="context">{'group_by': ['channel_id', 'create_date:month']}</field>
|
||||
<field name="domain">[('livechat_channel_id', '!=', None)]</field>
|
||||
<field name="context">{'group_by': ['livechat_channel_id', 'create_date:month']}</field>
|
||||
</record>
|
||||
|
||||
<record id="im_chat_session_action_from_channel" model="ir.actions.act_window">
|
||||
<record id="mail_channel_action_from_livechat_channel" model="ir.actions.act_window">
|
||||
<field name="name">Sessions</field>
|
||||
<field name="res_model">im_chat.session</field>
|
||||
<field name="res_model">mail.channel</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="domain">[('channel_id', 'in', [active_id])]</field>
|
||||
<field name="domain">[('livechat_channel_id', 'in', [active_id])]</field>
|
||||
<field name="context">{
|
||||
'search_default_channel_id': [active_id],
|
||||
'default_channel_id': active_id,
|
||||
'search_default_livechat_channel_id': [active_id],
|
||||
'default_livechat_channel_id': active_id,
|
||||
}</field>
|
||||
<field name="search_view_id" ref="im_chat_session_view_search"/>
|
||||
<field name="search_view_id" ref="mail_channel_view_search"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
||||
@@ -174,7 +174,7 @@ class Channel(models.Model):
|
||||
self.filtered(lambda channel: channel.channel_type == 'direct_message').mapped('channel_last_seen_partner_ids').write({'is_pinned': True})
|
||||
# apply shortcode (text only) subsitution
|
||||
body = self.env['mail.shortcode'].apply_shortcode(body, shortcode_type='text')
|
||||
message = super(Channel, self).message_post(body=body, message_type=message_type, subtype=subtype, content_subtype=content_subtype, **kwargs)
|
||||
message = super(Channel, self.with_context(mail_create_nosubscribe=True)).message_post(body=body, subject=subject, message_type=message_type, subtype=subtype, parent_id=parent_id, attachments=attachments, content_subtype=content_subtype, **kwargs)
|
||||
return message
|
||||
|
||||
#------------------------------------------------------
|
||||
@@ -192,13 +192,22 @@ class Channel(models.Model):
|
||||
""" Broadcast the current channel header to the given partner ids
|
||||
:param partner_ids : the partner to notify
|
||||
"""
|
||||
notifications = self._channel_channel_notifications(partner_ids)
|
||||
self.env['bus.bus'].sendmany(notifications)
|
||||
|
||||
@api.multi
|
||||
def _channel_channel_notifications(self, partner_ids):
|
||||
""" Generate the bus notifications of current channel for the given partner ids
|
||||
:param partner_ids : the partner to send the current channel header
|
||||
:returns list of bus notifications (tuple (bus_channe, message_content))
|
||||
"""
|
||||
notifications = []
|
||||
for partner in self.env['res.partner'].browse(partner_ids):
|
||||
user_id = partner.user_ids and partner.user_ids[0] or False
|
||||
if user_id:
|
||||
for channel_info in self.sudo(user_id).channel_info():
|
||||
notifications.append([(self._cr.dbname, 'res.partner', partner.id), channel_info])
|
||||
self.env['bus.bus'].sendmany(notifications)
|
||||
return notifications
|
||||
|
||||
@api.multi
|
||||
def _notify(self, message):
|
||||
@@ -209,8 +218,16 @@ class Channel(models.Model):
|
||||
:param : mail.message to broadcast
|
||||
"""
|
||||
message.ensure_one()
|
||||
message_values = message.message_format()[0]
|
||||
notifications = self._channel_message_notifications(message)
|
||||
self.env['bus.bus'].sendmany(notifications)
|
||||
|
||||
@api.multi
|
||||
def _channel_message_notifications(self, message):
|
||||
""" Generate the bus notifications for the given message
|
||||
:param message : the mail.message to sent
|
||||
:returns list of bus notifications (tuple (bus_channe, message_content))
|
||||
"""
|
||||
message_values = message.message_format()[0]
|
||||
notifications = []
|
||||
for channel in self:
|
||||
message_values['channel_ids'] = [channel.id]
|
||||
@@ -218,7 +235,7 @@ class Channel(models.Model):
|
||||
# add uuid to allow anonymous to listen
|
||||
if channel.public == 'public':
|
||||
notifications.append([channel.uuid, dict(message_values)])
|
||||
self.env['bus.bus'].sendmany(notifications)
|
||||
return notifications
|
||||
|
||||
@api.multi
|
||||
def channel_info(self):
|
||||
@@ -335,7 +352,6 @@ class Channel(models.Model):
|
||||
session_state.write({
|
||||
'fold_state': state,
|
||||
'is_minimized': bool(state != 'closed'),
|
||||
'seen_datetime': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT), # TODO JEM (to check) set seen_datetime to read needaction
|
||||
})
|
||||
self.env['bus.bus'].sendone((self._cr.dbname, 'res.partner', self.env.user.partner_id.id), session_state.channel_id.channel_info()[0])
|
||||
|
||||
|
||||
@@ -411,6 +411,7 @@ var ChatMailThread = Widget.extend(mail_thread.MailThreadMixin, ControlPanelMixi
|
||||
'display_document_link': true,
|
||||
'display_needaction_button': true,
|
||||
'emoji_list': this.conv_manager.emoji_list,
|
||||
'default_username': _t('Anonymous'),
|
||||
});
|
||||
this.emoji_set_substitution(this.conv_manager.emoji_list);
|
||||
// channel business
|
||||
|
||||
@@ -27,7 +27,7 @@ var ConversationManager = Widget.extend({
|
||||
this.options = _.clone(options) || {};
|
||||
_.defaults(this.options, {
|
||||
placeholder: _t("Say something..."),
|
||||
default_username: _t("Visitor"),
|
||||
default_username: _t("Anonymous"),
|
||||
load_history: true,
|
||||
focus: false,
|
||||
});
|
||||
@@ -171,6 +171,7 @@ var Conversation = Widget.extend({
|
||||
this._super(parent);
|
||||
this.options = _.defaults(options || {}, {
|
||||
'emoji': {},
|
||||
'default_username': _t('Anonymous'),
|
||||
'placeholder': _t('Write something ...'),
|
||||
'loading_history': true,
|
||||
'focus': true,
|
||||
|
||||
@@ -552,6 +552,7 @@ var MailThreadMixin = {
|
||||
'display_needaction_button': false,
|
||||
'internal_subtypes': [],
|
||||
'emoji_list': [],
|
||||
'default_username': _t('Anonymous'),
|
||||
});
|
||||
},
|
||||
start: function(){
|
||||
|
||||
@@ -41,9 +41,12 @@
|
||||
<div class="o_mail_chat_im_message_core">
|
||||
<!-- author -->
|
||||
<span class="text-muted">
|
||||
<t t-if="message.author_id">
|
||||
<t t-if="message.author_id && message.author_id[0]">
|
||||
<strong><t t-esc="message.author_id[1]"/></strong> -
|
||||
</t>
|
||||
<t t-if="!message.author_id || !message.author_id[0]">
|
||||
<strong><t t-esc="default_username || widget.options.default_username"/></strong> -
|
||||
</t>
|
||||
<t t-if="!message.author_id">
|
||||
<strong><t t-esc="message.email_from"/></strong> -
|
||||
</t>
|
||||
|
||||
@@ -153,14 +153,18 @@
|
||||
Note by
|
||||
</t>
|
||||
<!-- author : partner or email_from -->
|
||||
<t t-if="message.author_id">
|
||||
<strong class="o_mail_redirect" data-oe-model="res.partner" t-att-data-oe-id="message.author_id[0]"><t t-esc="message.author_id[1]"/></strong> -
|
||||
<t t-if="message.author_id && message.author_id[1]">
|
||||
<strong class="o_mail_redirect" data-oe-model="res.partner" t-att-data-oe-id="message.author_id[0]"><t t-esc="message.author_id[1]"/></strong>
|
||||
</t>
|
||||
<t t-if="!message.author_id">
|
||||
<strong><t t-esc="message.email_from"/></strong> -
|
||||
<t t-if="message.author_id && !message.author_id[1] && message.email_from">
|
||||
<strong><t t-esc="message.email_from"/></strong>
|
||||
</t>
|
||||
<t t-if="message.author_id && !message.author_id[1] && !message.email_from">
|
||||
<strong><t t-esc="widget.options.default_username"/></strong>
|
||||
</t>
|
||||
|
||||
<small t-att-title="moment(message.date, 'YYYY-MM-DD hh:mm:ss').format('LLL')">
|
||||
<t t-esc="moment(message.date, 'YYYY-MM-DD hh:mm:ss').format('hh:mm')"/>
|
||||
- <t t-esc="moment(message.date, 'YYYY-MM-DD hh:mm:ss').format('hh:mm')"/>
|
||||
</small>
|
||||
<t t-if="message.model && (message.model != 'mail.channel') && widget.options.display_document_link">
|
||||
on <a class="o_mail_redirect" t-att-data-oe-model="message.model" t-att-data-oe-id="message.res_id" href="#"><t t-esc="message.record_name"/></a>
|
||||
|
||||
@@ -45,7 +45,6 @@ class Invite(models.TransientModel):
|
||||
|
||||
model_ids = self.env['ir.model'].search([('model', '=', wizard.res_model)])
|
||||
model_name = model_ids.name_get()[0][1]
|
||||
print "@@@@@", wizard.message
|
||||
# send an email if option checked and if a message exists (do not send void emails)
|
||||
if wizard.send_mail and wizard.message and not wizard.message == '<br>': # when deleting the message, cleditor keeps a <br>
|
||||
# TDE FIXME: use a template + _notification methods
|
||||
|
||||
@@ -19,7 +19,7 @@ class WebsiteLivechat(http.Controller):
|
||||
@http.route('/livechat/channel/<model("im_livechat.channel"):channel>', type='http', auth='public', website=True)
|
||||
def channel_rating(self, channel, **kw):
|
||||
# get the last 100 ratings and the repartition per grade
|
||||
ratings = request.env['rating.rating'].search([('res_model', '=', 'im_chat.session'), ('res_id', 'in', channel.sudo().session_ids.ids)], order='create_date desc', limit=100)
|
||||
ratings = request.env['rating.rating'].search([('res_model', '=', 'mail.channel'), ('res_id', 'in', channel.sudo().session_ids.ids)], order='create_date desc', limit=100)
|
||||
repartition = channel.sudo().session_ids.rating_get_grades()
|
||||
|
||||
# compute percentage
|
||||
|
||||
Reference in New Issue
Block a user