Skip to content
Browse files

[IMP] im_livechat: ensure that visitors always gets the same operator

Task #1919871


If a visitor comes on the website and launches a livechat, it will be randomly assigned operator A.
If he comes the next day and opens a livechat again, we want him to have the same operator if he's available.

To handle that use case, we added a cookie that stores the "previous operator id" information for 7 days.
  • Loading branch information...
awa-odoo committed Jan 9, 2019
1 parent eef0850 commit 6a446bb74810a1378a5fa27abe64b42641263afe
@@ -81,7 +81,7 @@ def livechat_init(self, channel_id):

@http.route('/im_livechat/get_session', type="json", auth='public', cors="*")
def get_session(self, channel_id, anonymous_name, **kwargs):
def get_session(self, channel_id, anonymous_name, previous_operator_id=None, **kwargs):
user_id = None
country_id = None
# if the user is identifiy (eg: portal user on the frontend), don't use the anonymous name. The user will be added to session.
@@ -95,7 +95,7 @@ def get_session(self, channel_id, anonymous_name, **kwargs):
country = request.env[''].sudo().search([('code', '=', country_code)], limit=1) if country_code else None
if country:
anonymous_name, country_id = _("%s (%s)") % (anonymous_name,,
return request.env[""].with_context(lang=False).sudo().browse(channel_id)._get_mail_channel(anonymous_name, user_id, country_id)
return request.env[""].with_context(lang=False).sudo().browse(channel_id)._get_mail_channel(anonymous_name, previous_operator_id, user_id, country_id)

@http.route('/im_livechat/feedback', type='json', auth='public', cors="*")
def feedback(self, uuid, rate, reason=None, **kwargs):
@@ -132,19 +132,34 @@ def _get_available_users(self):
return self.user_ids.filtered(lambda user: user.im_status == 'online')

def _get_mail_channel(self, anonymous_name, user_id=None, country_id=None):
def _get_mail_channel(self, anonymous_name, previous_operator_id=None, user_id=None, country_id=None):
""" Return a given a livechat channel. It creates one with a connected operator, or return false otherwise
:param anonymous_name : the name of the anonymous person of the channel
:param previous_operator_id : of the previous operator that this visitor had in the past
:param user_id : the id of the logged in visitor, if any
:param country_code : the country of the anonymous person of the channel
:type anonymous_name : str
:return : channel header
:rtype : dict
If this visitor already had an operator within the last 7 days (information stored with the 'im_livechat_previous_operator_pid' cookie),
the system will first try to assign that operator if he's available (to improve user experience).
operator = self._get_random_operator()

operator = False
if previous_operator_id:
previous_operator_id = int(previous_operator_id)
available_users = self._get_available_users()
# previous_operator_id is the partner_id of the previous operator, need to convert to user
if previous_operator_id in available_users.mapped('partner_id').ids:
operator = next(available_user for available_user in available_users if == previous_operator_id)
if not operator:
operator = self._get_random_operator()
if not operator:
# no one available
return False

operator_partner_id =
# partner to add to the
channel_partner_to_add = [(4, operator_partner_id)]
@@ -215,6 +215,7 @@ var LivechatButton = Widget.extend({
def = session.rpc('/im_livechat/get_session', {
channel_id : this.options.channel_id,
anonymous_name : this.options.default_username,
previous_operator_id: this._get_previous_operator_id(),
}, {shadow: true});
def.then(function (livechatData) {
@@ -234,13 +235,38 @@ var LivechatButton = Widget.extend({

utils.set_cookie('im_livechat_session', JSON.stringify(self._livechat.toData()), 60*60);
utils.set_cookie('im_livechat_auto_popup', JSON.stringify(false), 60*60);
if (livechatData.operator_pid[0]) {
// livechatData.operator_pid contains a tuple (id, name)
// we are only interested in the id
var operatorPidId = livechatData.operator_pid[0];
var oneWeek = 7*24*60*60;
utils.set_cookie('im_livechat_previous_operator_pid', operatorPidId, oneWeek);
}).then(function () {
self._openingChat = false;
}).guardedCatch(function() {
self._openingChat = false;
}, 200, true),
* Will try to get a previous operator for this visitor.
* If the visitor already had visitor A, it's better for his user experience
* to get operator A again.
* The information is stored in the 'im_livechat_previous_operator_pid' cookie.
* @private
* @return {integer} if the cookie is set
_get_previous_operator_id: function () {
var cookie = utils.get_cookie('im_livechat_previous_operator_pid');
if (cookie) {
return cookie;

return null;
* @private

0 comments on commit 6a446bb

Please sign in to comment.
You can’t perform that action at this time.