forked from Mapan/odoo17e
215 lines
10 KiB
Python
215 lines
10 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from operator import itemgetter
|
|
|
|
from markupsafe import Markup
|
|
|
|
from odoo import http
|
|
from odoo.exceptions import AccessError, MissingError, UserError
|
|
from odoo.http import request
|
|
from odoo.tools.translate import _
|
|
from odoo.tools import groupby as groupbyelem
|
|
from odoo.addons.portal.controllers import portal
|
|
from odoo.addons.portal.controllers.portal import pager as portal_pager
|
|
from odoo.osv.expression import OR, AND
|
|
|
|
|
|
class CustomerPortal(portal.CustomerPortal):
|
|
|
|
def _prepare_portal_layout_values(self):
|
|
values = super(CustomerPortal, self)._prepare_portal_layout_values()
|
|
return values
|
|
|
|
def _prepare_home_portal_values(self, counters):
|
|
values = super()._prepare_home_portal_values(counters)
|
|
if 'ticket_count' in counters:
|
|
values['ticket_count'] = (
|
|
request.env['helpdesk.ticket'].search_count(self._prepare_helpdesk_tickets_domain())
|
|
if request.env['helpdesk.ticket'].check_access_rights('read', raise_exception=False)
|
|
else 0
|
|
)
|
|
return values
|
|
|
|
def _prepare_helpdesk_tickets_domain(self):
|
|
return []
|
|
|
|
def _ticket_get_page_view_values(self, ticket, access_token, **kwargs):
|
|
values = {
|
|
'page_name': 'ticket',
|
|
'ticket': ticket,
|
|
'ticket_link_section': [],
|
|
'ticket_closed': kwargs.get('ticket_closed', False),
|
|
'preview_object': ticket,
|
|
}
|
|
return self._get_page_view_values(ticket, access_token, values, 'my_tickets_history', False, **kwargs)
|
|
|
|
def _prepare_my_tickets_values(self, page=1, date_begin=None, date_end=None, sortby=None, filterby='all', search=None, groupby='none', search_in='content'):
|
|
values = self._prepare_portal_layout_values()
|
|
domain = self._prepare_helpdesk_tickets_domain()
|
|
|
|
searchbar_sortings = {
|
|
'date': {'label': _('Newest'), 'order': 'create_date desc'},
|
|
'reference': {'label': _('Reference'), 'order': 'id desc'},
|
|
'name': {'label': _('Subject'), 'order': 'name'},
|
|
'user': {'label': _('Assigned to'), 'order': 'user_id'},
|
|
'stage': {'label': _('Stage'), 'order': 'stage_id'},
|
|
'update': {'label': _('Last Stage Update'), 'order': 'date_last_stage_update desc'},
|
|
}
|
|
searchbar_filters = {
|
|
'all': {'label': _('All'), 'domain': []},
|
|
'assigned': {'label': _('Assigned'), 'domain': [('user_id', '!=', False)]},
|
|
'unassigned': {'label': _('Unassigned'), 'domain': [('user_id', '=', False)]},
|
|
'open': {'label': _('Open'), 'domain': [('close_date', '=', False)]},
|
|
'closed': {'label': _('Closed'), 'domain': [('close_date', '!=', False)]},
|
|
}
|
|
searchbar_inputs = {
|
|
'content': {'input': 'content', 'label': Markup(_('Search <span class="nolabel"> (in Content)</span>'))},
|
|
'ticket_ref': {'input': 'ticket_ref', 'label': _('Search in Reference')},
|
|
'message': {'input': 'message', 'label': _('Search in Messages')},
|
|
'user': {'input': 'user', 'label': _('Search in Assigned to')},
|
|
'status': {'input': 'status', 'label': _('Search in Stage')},
|
|
}
|
|
searchbar_groupby = {
|
|
'none': {'input': 'none', 'label': _('None')},
|
|
'stage': {'input': 'stage_id', 'label': _('Stage')},
|
|
'user': {'input': 'user_id', 'label': _('Assigned to')},
|
|
}
|
|
|
|
# default sort by value
|
|
if not sortby:
|
|
sortby = 'date'
|
|
order = searchbar_sortings[sortby]['order']
|
|
if groupby in searchbar_groupby and groupby != 'none':
|
|
order = f'{searchbar_groupby[groupby]["input"]}, {order}'
|
|
|
|
if filterby in ['last_message_sup', 'last_message_cust']:
|
|
discussion_subtype_id = request.env.ref('mail.mt_comment').id
|
|
messages = request.env['mail.message'].search_read([('model', '=', 'helpdesk.ticket'), ('subtype_id', '=', discussion_subtype_id)], fields=['res_id', 'author_id'], order='date desc')
|
|
last_author_dict = {}
|
|
for message in messages:
|
|
if message['res_id'] not in last_author_dict:
|
|
last_author_dict[message['res_id']] = message['author_id'][0]
|
|
|
|
ticket_author_list = request.env['helpdesk.ticket'].search_read(fields=['id', 'partner_id'])
|
|
ticket_author_dict = dict([(ticket_author['id'], ticket_author['partner_id'][0] if ticket_author['partner_id'] else False) for ticket_author in ticket_author_list])
|
|
|
|
last_message_cust = []
|
|
last_message_sup = []
|
|
ticket_ids = set(last_author_dict.keys()) & set(ticket_author_dict.keys())
|
|
for ticket_id in ticket_ids:
|
|
if last_author_dict[ticket_id] == ticket_author_dict[ticket_id]:
|
|
last_message_cust.append(ticket_id)
|
|
else:
|
|
last_message_sup.append(ticket_id)
|
|
|
|
if filterby == 'last_message_cust':
|
|
domain = AND([domain, [('id', 'in', last_message_cust)]])
|
|
else:
|
|
domain = AND([domain, [('id', 'in', last_message_sup)]])
|
|
|
|
else:
|
|
domain = AND([domain, searchbar_filters[filterby]['domain']])
|
|
|
|
if date_begin and date_end:
|
|
domain = AND([domain, [('create_date', '>', date_begin), ('create_date', '<=', date_end)]])
|
|
|
|
# search
|
|
if search and search_in:
|
|
search_domain = []
|
|
if search_in == 'ticket_ref':
|
|
search_domain = OR([search_domain, [('ticket_ref', 'ilike', search)]])
|
|
if search_in == 'content':
|
|
search_domain = OR([search_domain, ['|', ('name', 'ilike', search), ('description', 'ilike', search)]])
|
|
if search_in == 'user':
|
|
assignees = request.env['res.users'].sudo()._search([('name', 'ilike', search)])
|
|
search_domain = OR([search_domain, [('user_id', 'in', assignees)]])
|
|
if search_in == 'message':
|
|
discussion_subtype_id = request.env.ref('mail.mt_comment').id
|
|
search_domain = OR([search_domain, [('message_ids.body', 'ilike', search), ('message_ids.subtype_id', '=', discussion_subtype_id)]])
|
|
if search_in == 'status':
|
|
search_domain = OR([search_domain, [('stage_id', 'ilike', search)]])
|
|
domain = AND([domain, search_domain])
|
|
|
|
# pager
|
|
tickets_count = request.env['helpdesk.ticket'].search_count(domain)
|
|
pager = portal_pager(
|
|
url="/my/tickets",
|
|
url_args={'date_begin': date_begin, 'date_end': date_end, 'sortby': sortby, 'search_in': search_in, 'search': search, 'groupby': groupby, 'filterby': filterby},
|
|
total=tickets_count,
|
|
page=page,
|
|
step=self._items_per_page
|
|
)
|
|
|
|
tickets = request.env['helpdesk.ticket'].search(domain, order=order, limit=self._items_per_page, offset=pager['offset'])
|
|
request.session['my_tickets_history'] = tickets.ids[:100]
|
|
|
|
if not tickets:
|
|
grouped_tickets = []
|
|
elif groupby != 'none':
|
|
grouped_tickets = [request.env['helpdesk.ticket'].concat(*g) for k, g in groupbyelem(tickets, itemgetter(searchbar_groupby[groupby]['input']))]
|
|
else:
|
|
grouped_tickets = [tickets]
|
|
|
|
values.update({
|
|
'date': date_begin,
|
|
'grouped_tickets': grouped_tickets,
|
|
'page_name': 'ticket',
|
|
'default_url': '/my/tickets',
|
|
'pager': pager,
|
|
'searchbar_sortings': searchbar_sortings,
|
|
'searchbar_filters': searchbar_filters,
|
|
'searchbar_inputs': searchbar_inputs,
|
|
'searchbar_groupby': searchbar_groupby,
|
|
'sortby': sortby,
|
|
'groupby': groupby,
|
|
'search_in': search_in,
|
|
'search': search,
|
|
'filterby': filterby,
|
|
})
|
|
return values
|
|
|
|
@http.route(['/my/tickets', '/my/tickets/page/<int:page>'], type='http', auth="user", website=True)
|
|
def my_helpdesk_tickets(self, page=1, date_begin=None, date_end=None, sortby=None, filterby='all', search=None, groupby='none', search_in='content', **kw):
|
|
values = self._prepare_my_tickets_values(page, date_begin, date_end, sortby, filterby, search, groupby, search_in)
|
|
return request.render("helpdesk.portal_helpdesk_ticket", values)
|
|
|
|
@http.route([
|
|
"/helpdesk/ticket/<int:ticket_id>",
|
|
"/helpdesk/ticket/<int:ticket_id>/<access_token>",
|
|
'/my/ticket/<int:ticket_id>',
|
|
'/my/ticket/<int:ticket_id>/<access_token>'
|
|
], type='http', auth="public", website=True)
|
|
def tickets_followup(self, ticket_id=None, access_token=None, **kw):
|
|
try:
|
|
ticket_sudo = self._document_check_access('helpdesk.ticket', ticket_id, access_token)
|
|
except (AccessError, MissingError):
|
|
return request.redirect('/my')
|
|
|
|
values = self._ticket_get_page_view_values(ticket_sudo, access_token, **kw)
|
|
return request.render("helpdesk.tickets_followup", values)
|
|
|
|
@http.route([
|
|
'/my/ticket/close/<int:ticket_id>',
|
|
'/my/ticket/close/<int:ticket_id>/<access_token>',
|
|
], type='http', auth="public", website=True)
|
|
def ticket_close(self, ticket_id=None, access_token=None, **kw):
|
|
try:
|
|
ticket_sudo = self._document_check_access('helpdesk.ticket', ticket_id, access_token)
|
|
except (AccessError, MissingError):
|
|
return request.redirect('/my')
|
|
|
|
if not ticket_sudo.team_id.allow_portal_ticket_closing:
|
|
raise UserError(_("The team does not allow ticket closing through portal"))
|
|
|
|
if not ticket_sudo.closed_by_partner:
|
|
closing_stage = ticket_sudo.team_id._get_closing_stage()
|
|
if ticket_sudo.stage_id != closing_stage:
|
|
ticket_sudo.write({'stage_id': closing_stage[0].id, 'closed_by_partner': True})
|
|
else:
|
|
ticket_sudo.write({'closed_by_partner': True})
|
|
body = _('Ticket closed by the customer')
|
|
ticket_sudo.with_context(mail_create_nosubscribe=True).message_post(body=body, message_type='comment', subtype_xmlid='mail.mt_note')
|
|
|
|
return request.redirect('/my/ticket/%s/%s?ticket_closed=1' % (ticket_id, access_token or ''))
|