@ -1,266 +0,0 @@ | 
				
			|||
# -*- coding: utf-8 -*- | 
				
			|||
############################################################################# | 
				
			|||
# | 
				
			|||
#    Cybrosys Technologies Pvt. Ltd. | 
				
			|||
# | 
				
			|||
#    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			|||
#    Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) | 
				
			|||
# | 
				
			|||
#    You can modify it under the terms of the GNU LESSER | 
				
			|||
#    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | 
				
			|||
# | 
				
			|||
#    This program is distributed in the hope that it will be useful, | 
				
			|||
#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			|||
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			|||
#    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | 
				
			|||
# | 
				
			|||
#    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | 
				
			|||
#    (LGPL v3) along with this program. | 
				
			|||
#    If not, see <http://www.gnu.org/licenses/>. | 
				
			|||
# | 
				
			|||
############################################################################# | 
				
			|||
import datetime as DT | 
				
			|||
from odoo import http | 
				
			|||
from odoo.http import request | 
				
			|||
 | 
				
			|||
 | 
				
			|||
class HelpDeskDashboard(http.Controller): | 
				
			|||
    """Website helpdesk dashboard""" | 
				
			|||
 | 
				
			|||
    @http.route(['/helpdesk_dashboard'], type='json', auth="public") | 
				
			|||
    def helpdesk_dashboard(self): | 
				
			|||
        """Helpdesk dashboard controller""" | 
				
			|||
        stage_new = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Inbox')], limit=1).id | 
				
			|||
        stage_draft = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Draft')], limit=1).id | 
				
			|||
        stage_inprogress = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'In Progress')], limit=1).id | 
				
			|||
        stage_canceled = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Canceled')], limit=1).id | 
				
			|||
        stage_done = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Done')], limit=1).id | 
				
			|||
        stage_closed = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Closed')], limit=1).id | 
				
			|||
        stage_ids = [stage_new, stage_draft] | 
				
			|||
        new = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', 'in', stage_ids)]) | 
				
			|||
        new_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', 'in', stage_ids)]) | 
				
			|||
        new_id_ls = [data.id for data in new_id] | 
				
			|||
        in_progress = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', '=', stage_inprogress)]) | 
				
			|||
        in_progress_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', '=', stage_inprogress)]) | 
				
			|||
        in_progress_ls = [data.id for data in in_progress_id] | 
				
			|||
        canceled = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', '=', stage_canceled)]) | 
				
			|||
        canceled_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', '=', stage_canceled)]) | 
				
			|||
        canceled_id_ls = [data.id for data in canceled_id] | 
				
			|||
        done = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', '=', stage_done)]) | 
				
			|||
        done_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', '=', stage_done)]) | 
				
			|||
        done_id_ls = [data.id for data in done_id] | 
				
			|||
        closed = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', '=', stage_closed)]) | 
				
			|||
        closed_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', '=', stage_closed)]) | 
				
			|||
        closed_id_ls = [data.id for data in closed_id] | 
				
			|||
        dashboard_values = { | 
				
			|||
            'new': new, | 
				
			|||
            'in_progress': in_progress, | 
				
			|||
            'canceled': canceled, | 
				
			|||
            'done': done, | 
				
			|||
            'closed': closed, | 
				
			|||
            'new_id': new_id_ls, | 
				
			|||
            'in_progress_id': in_progress_ls, | 
				
			|||
            'canceled_id': canceled_id_ls, | 
				
			|||
            'done_id': done_id_ls, | 
				
			|||
            'closed_id': closed_id_ls, | 
				
			|||
        } | 
				
			|||
        return dashboard_values | 
				
			|||
 | 
				
			|||
    @http.route(['/helpdesk_dashboard_week'], type='json', auth="public") | 
				
			|||
    def helpdesk_dashboard_week(self): | 
				
			|||
        """Week based sorting controller""" | 
				
			|||
        today = DT.date.today() | 
				
			|||
        stage_new = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Inbox')], limit=1).id | 
				
			|||
        stage_draft = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Draft')], limit=1).id | 
				
			|||
        stage_inprogress = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'In Progress')], limit=1).id | 
				
			|||
        stage_canceled = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Canceled')], limit=1).id | 
				
			|||
        stage_done = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Done')], limit=1).id | 
				
			|||
        stage_closed = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Closed')], limit=1).id | 
				
			|||
        stage_ids = [stage_new, stage_draft] | 
				
			|||
        week_ago = str(today - DT.timedelta(days=7)) + ' ' | 
				
			|||
        new = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', 'in', stage_ids), ('create_date', '>', week_ago)]) | 
				
			|||
        new_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', 'in', stage_ids), ('create_date', '>', week_ago)]) | 
				
			|||
        new_id_ls = [data.id for data in new_id] | 
				
			|||
        in_progress = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', '=', stage_inprogress), | 
				
			|||
             ('create_date', '>', week_ago)]) | 
				
			|||
        in_progress_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', '=', stage_inprogress), | 
				
			|||
             ('create_date', '>', week_ago)]) | 
				
			|||
        in_progress_ls = [data.id for data in in_progress_id] | 
				
			|||
        canceled = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', '=', stage_canceled), | 
				
			|||
             ('create_date', '>', week_ago)]) | 
				
			|||
        canceled_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', '=', stage_canceled), | 
				
			|||
             ('create_date', '>', week_ago)]) | 
				
			|||
        canceled_id_ls = [data.id for data in canceled_id] | 
				
			|||
        done = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', '=', stage_done), ('create_date', '>', week_ago)]) | 
				
			|||
        done_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', '=', stage_done), ('create_date', '>', week_ago)]) | 
				
			|||
        done_id_ls = [data.id for data in done_id] | 
				
			|||
        closed = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', '=', stage_closed), ('create_date', '>', week_ago)]) | 
				
			|||
        closed_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', '=', stage_closed), ('create_date', '>', week_ago)]) | 
				
			|||
        closed_id_ls = [data.id for data in closed_id] | 
				
			|||
        dashboard_values = { | 
				
			|||
            'new': new, | 
				
			|||
            'in_progress': in_progress, | 
				
			|||
            'canceled': canceled, | 
				
			|||
            'done': done, | 
				
			|||
            'closed': closed, | 
				
			|||
            'new_id': new_id_ls, | 
				
			|||
            'in_progress_id': in_progress_ls, | 
				
			|||
            'canceled_id': canceled_id_ls, | 
				
			|||
            'done_id': done_id_ls, | 
				
			|||
            'closed_id': closed_id_ls, | 
				
			|||
        } | 
				
			|||
        return dashboard_values | 
				
			|||
 | 
				
			|||
    @http.route(['/helpdesk_dashboard_month'], type='json', auth="public") | 
				
			|||
    def helpdesk_dashboard_month(self): | 
				
			|||
        """Month based sorting controller""" | 
				
			|||
        today = DT.date.today() | 
				
			|||
        stage_new = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Inbox')], limit=1).id | 
				
			|||
        stage_draft = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Draft')], limit=1).id | 
				
			|||
        stage_inprogress = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'In Progress')], limit=1).id | 
				
			|||
        stage_canceled = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Canceled')], limit=1).id | 
				
			|||
        stage_done = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Done')], limit=1).id | 
				
			|||
        stage_closed = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Closed')], limit=1).id | 
				
			|||
        stage_ids = [stage_new, stage_draft] | 
				
			|||
        week_ago = str(today - DT.timedelta(days=30)) + ' ' | 
				
			|||
        new = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', 'in', stage_ids), ('create_date', '>', week_ago)]) | 
				
			|||
        new_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', 'in', stage_ids), ('create_date', '>', week_ago)]) | 
				
			|||
        new_id_ls = [data.id for data in new_id] | 
				
			|||
        in_progress = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', '=', stage_inprogress), | 
				
			|||
             ('create_date', '>', week_ago)]) | 
				
			|||
        in_progress_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', '=', stage_inprogress), | 
				
			|||
             ('create_date', '>', week_ago)]) | 
				
			|||
        in_progress_ls = [data.id for data in in_progress_id] | 
				
			|||
        canceled = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', '=', stage_canceled), | 
				
			|||
             ('create_date', '>', week_ago)]) | 
				
			|||
        canceled_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', '=', stage_canceled), | 
				
			|||
             ('create_date', '>', week_ago)]) | 
				
			|||
        canceled_id_ls = [data.id for data in canceled_id] | 
				
			|||
        done = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', '=', stage_done), ('create_date', '>', week_ago)]) | 
				
			|||
        done_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', '=', stage_done), ('create_date', '>', week_ago)]) | 
				
			|||
        done_id_ls = [data.id for data in done_id] | 
				
			|||
        closed = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', '=', stage_closed), ('create_date', '>', week_ago)]) | 
				
			|||
        closed_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', '=', stage_closed), ('create_date', '>', week_ago)]) | 
				
			|||
        closed_id_ls = [data.id for data in closed_id] | 
				
			|||
        dashboard_values = { | 
				
			|||
            'new': new, | 
				
			|||
            'in_progress': in_progress, | 
				
			|||
            'canceled': canceled, | 
				
			|||
            'done': done, | 
				
			|||
            'closed': closed, | 
				
			|||
            'new_id': new_id_ls, | 
				
			|||
            'in_progress_id': in_progress_ls, | 
				
			|||
            'canceled_id': canceled_id_ls, | 
				
			|||
            'done_id': done_id_ls, | 
				
			|||
            'closed_id': closed_id_ls, | 
				
			|||
        } | 
				
			|||
        return dashboard_values | 
				
			|||
 | 
				
			|||
    @http.route(['/helpdesk_dashboard_year'], type='json', auth="public") | 
				
			|||
    def helpdesk_dashboard_year(self): | 
				
			|||
        """Year based sorting""" | 
				
			|||
        today = DT.date.today() | 
				
			|||
        stage_new = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Inbox')], limit=1).id | 
				
			|||
        stage_draft = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Draft')], limit=1).id | 
				
			|||
        stage_inprogress = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'In Progress')], limit=1).id | 
				
			|||
        stage_canceled = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Canceled')], limit=1).id | 
				
			|||
        stage_done = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Done')], limit=1).id | 
				
			|||
        stage_closed = request.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Closed')], limit=1).id | 
				
			|||
        stage_ids = [stage_new, stage_draft] | 
				
			|||
        week_ago = str(today - DT.timedelta(days=360)) + ' ' | 
				
			|||
        new = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', 'in', stage_ids), ('create_date', '>', week_ago)]) | 
				
			|||
        new_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', 'in', stage_ids), ('create_date', '>', week_ago)]) | 
				
			|||
        new_id_ls = [data.id for data in new_id] | 
				
			|||
        in_progress = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', '=', stage_inprogress), | 
				
			|||
             ('create_date', '>', week_ago)]) | 
				
			|||
        in_progress_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', '=', stage_inprogress), | 
				
			|||
             ('create_date', '>', week_ago)]) | 
				
			|||
        in_progress_ls = [data.id for data in in_progress_id] | 
				
			|||
        canceled = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', '=', stage_canceled), | 
				
			|||
             ('create_date', '>', week_ago)]) | 
				
			|||
        canceled_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', '=', stage_canceled), | 
				
			|||
             ('create_date', '>', week_ago)]) | 
				
			|||
        canceled_id_ls = [data.id for data in canceled_id] | 
				
			|||
        done = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', '=', stage_done), ('create_date', '>', week_ago)]) | 
				
			|||
        done_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', '=', stage_done), ('create_date', '>', week_ago)]) | 
				
			|||
        done_id_ls = [data.id for data in done_id] | 
				
			|||
        closed = request.env["help.ticket"].search_count( | 
				
			|||
            [('stage_id', '=', stage_closed), ('create_date', '>', week_ago)]) | 
				
			|||
        closed_id = request.env["help.ticket"].search( | 
				
			|||
            [('stage_id', '=', stage_closed), ('create_date', '>', week_ago)]) | 
				
			|||
        closed_id_ls = [data.id for data in closed_id] | 
				
			|||
        dashboard_values = { | 
				
			|||
            'new': new, | 
				
			|||
            'in_progress': in_progress, | 
				
			|||
            'canceled': canceled, | 
				
			|||
            'done': done, | 
				
			|||
            'closed': closed, | 
				
			|||
            'new_id': new_id_ls, | 
				
			|||
            'in_progress_id': in_progress_ls, | 
				
			|||
            'canceled_id': canceled_id_ls, | 
				
			|||
            'done_id': done_id_ls, | 
				
			|||
            'closed_id': closed_id_ls, | 
				
			|||
        } | 
				
			|||
        return dashboard_values | 
				
			|||
@ -0,0 +1,162 @@ | 
				
			|||
# -*- coding: utf-8 -*- | 
				
			|||
################################################################################ | 
				
			|||
# | 
				
			|||
#    Cybrosys Technologies Pvt. Ltd. | 
				
			|||
# | 
				
			|||
#    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			|||
#    Author: Bhagyadev KP (<https://www.cybrosys.com>) | 
				
			|||
# | 
				
			|||
#    You can modify it under the terms of the GNU LESSER | 
				
			|||
#    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | 
				
			|||
# | 
				
			|||
#    This program is distributed in the hope that it will be useful, | 
				
			|||
#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			|||
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			|||
#    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | 
				
			|||
# | 
				
			|||
#    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | 
				
			|||
#    (LGPL v3) along with this program. | 
				
			|||
#    If not, see <http://www.gnu.org/licenses/>. | 
				
			|||
# | 
				
			|||
################################################################################ | 
				
			|||
import datetime as DT | 
				
			|||
from odoo import http | 
				
			|||
from odoo.http import request | 
				
			|||
 | 
				
			|||
 | 
				
			|||
class HelpDeskDashboard(http.Controller): | 
				
			|||
    """Controller for handling Help Desk dashboard requests.""" | 
				
			|||
 | 
				
			|||
    @http.route(['/helpdesk_dashboard'], type='json', auth="public") | 
				
			|||
    def helpdesk_dashboard(self): | 
				
			|||
        """Retrieves statistics for tickets in different stages. | 
				
			|||
        Returns:dict: Dashboard statistics including counts and IDs for each | 
				
			|||
        stage. | 
				
			|||
        """ | 
				
			|||
        stage_names = ['Inbox', 'Draft', 'In Progress', 'Canceled', 'Done', | 
				
			|||
                       'Closed'] | 
				
			|||
        stage_ids = { | 
				
			|||
            name: request.env['ticket.stage'].search([('name', '=', name)], | 
				
			|||
                                                     limit=1).id for name in | 
				
			|||
            stage_names} | 
				
			|||
        new_stages = [stage_ids['Inbox'], stage_ids['Draft']] | 
				
			|||
        def get_ticket_data(stage_ids): | 
				
			|||
            tickets = request.env["ticket.helpdesk"].search( | 
				
			|||
                [('stage_id', 'in', stage_ids)]) | 
				
			|||
            return len(tickets), [ticket.id for ticket in tickets] | 
				
			|||
        dashboard_values = { | 
				
			|||
            'new': (get_ticket_data(new_stages))[0], | 
				
			|||
            'new_id': (get_ticket_data(new_stages))[1], | 
				
			|||
            'in_progress': (get_ticket_data([stage_ids['In Progress']]))[0], | 
				
			|||
            'in_progress_id': (get_ticket_data([stage_ids['In Progress']]))[1], | 
				
			|||
            'canceled': (get_ticket_data([stage_ids['Canceled']]))[0], | 
				
			|||
            'canceled_id': (get_ticket_data([stage_ids['Canceled']]))[1], | 
				
			|||
            'done': (get_ticket_data([stage_ids['Done']]))[0], | 
				
			|||
            'done_id': (get_ticket_data([stage_ids['Done']]))[1], | 
				
			|||
            'closed': (get_ticket_data([stage_ids['Closed']]))[0], | 
				
			|||
            'closed_id': (get_ticket_data([stage_ids['Closed']]))[1]} | 
				
			|||
        return dashboard_values | 
				
			|||
 | 
				
			|||
    def helpdesk_dashboard_week(self): | 
				
			|||
        """ Retrieves statistics for tickets created in the past week. | 
				
			|||
        Returns: | 
				
			|||
        dict: Dashboard statistics including counts and IDs for each stage.""" | 
				
			|||
        today = DT.date.today() | 
				
			|||
        week_ago = str(today - DT.timedelta(days=7)) + ' ' | 
				
			|||
        stage_names = ['Inbox', 'Draft', 'In Progress', 'Canceled', 'Done', | 
				
			|||
                       'Closed'] | 
				
			|||
        stages = { | 
				
			|||
            name: request.env['ticket.stage'].search([('name', '=', name)], | 
				
			|||
                                                     limit=1).id for name in | 
				
			|||
            stage_names} | 
				
			|||
        stage_ids = [stages['Inbox'], stages['Draft']] | 
				
			|||
        def get_ticket_data(stage_id): | 
				
			|||
            count = request.env["ticket.helpdesk"].search_count( | 
				
			|||
                [('stage_id', '=', stage_id), ('create_date', '>', week_ago)]) | 
				
			|||
            ids = request.env["ticket.helpdesk"].search( | 
				
			|||
                [('stage_id', '=', stage_id), | 
				
			|||
                 ('create_date', '>', week_ago)]).ids | 
				
			|||
            return count, ids | 
				
			|||
        new_count, new_ids = get_ticket_data(stage_ids) | 
				
			|||
        in_progress_count, in_progress_ids = get_ticket_data( | 
				
			|||
            stages['In Progress']) | 
				
			|||
        canceled_count, canceled_ids = get_ticket_data(stages['Canceled']) | 
				
			|||
        done_count, done_ids = get_ticket_data(stages['Done']) | 
				
			|||
        closed_count, closed_ids = get_ticket_data(stages['Closed']) | 
				
			|||
        dashboard_values = { | 
				
			|||
            'new': new_count, | 
				
			|||
            'in_progress': in_progress_count, | 
				
			|||
            'canceled': canceled_count, | 
				
			|||
            'done': done_count, | 
				
			|||
            'closed': closed_count, | 
				
			|||
            'new_id': new_ids, | 
				
			|||
            'in_progress_id': in_progress_ids, | 
				
			|||
            'canceled_id': canceled_ids, | 
				
			|||
            'done_id': done_ids, | 
				
			|||
            'closed_id': closed_ids, | 
				
			|||
        } | 
				
			|||
        return dashboard_values | 
				
			|||
 | 
				
			|||
    @http.route(['/helpdesk_dashboard_month'], type='json', auth="public") | 
				
			|||
    def helpdesk_dashboard_month(self): | 
				
			|||
        """Retrieves statistics for tickets created in the past month. | 
				
			|||
        Returns: | 
				
			|||
          dict: Dashboard statistics including counts and IDs for each stage.""" | 
				
			|||
        today = DT.date.today() | 
				
			|||
        month_ago = today - DT.timedelta(days=30) | 
				
			|||
        week_ago = str(month_ago) + ' ' | 
				
			|||
        stages = request.env['ticket.stage'].search([('name', 'in', | 
				
			|||
                                                      ['Inbox', 'Draft', | 
				
			|||
                                                       'In Progress', | 
				
			|||
                                                       'Canceled', 'Done', | 
				
			|||
                                                       'Closed'])]) | 
				
			|||
        stage_ids = {stage.name: stage.id for stage in stages} | 
				
			|||
        def get_stage_data(stage_names): | 
				
			|||
            stage_ids_list = [stage_ids[name] for name in stage_names] | 
				
			|||
            tickets = request.env["ticket.helpdesk"].search( | 
				
			|||
                [('stage_id', 'in', stage_ids_list), | 
				
			|||
                 ('create_date', '>', week_ago)]) | 
				
			|||
            return len(tickets), [ticket.id for ticket in tickets] | 
				
			|||
        new_count, new_ids = get_stage_data(['Inbox', 'Draft']) | 
				
			|||
        in_progress_count, in_progress_ids = get_stage_data(['In Progress']) | 
				
			|||
        canceled_count, canceled_ids = get_stage_data(['Canceled']) | 
				
			|||
        done_count, done_ids = get_stage_data(['Done']) | 
				
			|||
        closed_count, closed_ids = get_stage_data(['Closed']) | 
				
			|||
        dashboard_values = { | 
				
			|||
            'new': new_count, | 
				
			|||
            'in_progress': in_progress_count, | 
				
			|||
            'canceled': canceled_count, | 
				
			|||
            'done': done_count, | 
				
			|||
            'closed': closed_count, | 
				
			|||
            'new_id': new_ids, | 
				
			|||
            'in_progress_id': in_progress_ids, | 
				
			|||
            'canceled_id': canceled_ids, | 
				
			|||
            'done_id': done_ids, | 
				
			|||
            'closed_id': closed_ids, | 
				
			|||
        } | 
				
			|||
        return dashboard_values | 
				
			|||
 | 
				
			|||
    @http.route(['/helpdesk_dashboard_year'], type='json', auth="public") | 
				
			|||
    def helpdesk_dashboard_year(self): | 
				
			|||
        """Retrieves statistics for tickets created in the past year. | 
				
			|||
        Returns: | 
				
			|||
            dict: Dashboard statistics including counts and IDs for each stage. | 
				
			|||
        """ | 
				
			|||
        today = DT.date.today() | 
				
			|||
        year_ago = today - DT.timedelta(days=360) | 
				
			|||
        stages = ['Inbox', 'Draft', 'In Progress', 'Canceled', 'Done', 'Closed'] | 
				
			|||
        stage_ids = { | 
				
			|||
            stage: request.env['ticket.stage'].search([('name', '=', stage)], | 
				
			|||
                                                      limit=1).id for stage in | 
				
			|||
            stages} | 
				
			|||
        def get_ticket_data(stage_name): | 
				
			|||
            stage_id = stage_ids[stage_name] | 
				
			|||
            tickets = request.env["ticket.helpdesk"].search( | 
				
			|||
                [('stage_id', '=', stage_id), ('create_date', '>', year_ago)]) | 
				
			|||
            return len(tickets), [ticket.id for ticket in tickets] | 
				
			|||
        dashboard_values = {} | 
				
			|||
        for stage in stages: | 
				
			|||
            count, ids = get_ticket_data(stage) | 
				
			|||
            dashboard_values[stage.lower()] = count | 
				
			|||
            dashboard_values[f'{stage.lower()}_id'] = ids | 
				
			|||
        return dashboard_values | 
				
			|||
@ -1,173 +0,0 @@ | 
				
			|||
# -*- coding: utf-8 -*- | 
				
			|||
############################################################################# | 
				
			|||
# | 
				
			|||
#    Cybrosys Technologies Pvt. Ltd. | 
				
			|||
# | 
				
			|||
#    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			|||
#    Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) | 
				
			|||
# | 
				
			|||
#    You can modify it under the terms of the GNU LESSER | 
				
			|||
#    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | 
				
			|||
# | 
				
			|||
#    This program is distributed in the hope that it will be useful, | 
				
			|||
#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			|||
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			|||
#    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | 
				
			|||
# | 
				
			|||
#    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | 
				
			|||
#    (LGPL v3) along with this program. | 
				
			|||
#    If not, see <http://www.gnu.org/licenses/>. | 
				
			|||
# | 
				
			|||
############################################################################# | 
				
			|||
import base64 | 
				
			|||
import json | 
				
			|||
from odoo import _, http | 
				
			|||
from psycopg2 import IntegrityError | 
				
			|||
from odoo.http import request | 
				
			|||
from odoo.exceptions import ValidationError | 
				
			|||
from odoo.addons.website.controllers.form import WebsiteForm | 
				
			|||
 | 
				
			|||
 | 
				
			|||
class HelpdeskProduct(http.Controller): | 
				
			|||
    """It controls the website products and return the product.""" | 
				
			|||
    @http.route('/product', auth='public', type='json') | 
				
			|||
    def product(self): | 
				
			|||
        """Product control function""" | 
				
			|||
        products = request.env['product.template'].sudo().search_read([], | 
				
			|||
                                                                      ['name', | 
				
			|||
                                                                       'id']) | 
				
			|||
        return products | 
				
			|||
 | 
				
			|||
 | 
				
			|||
class WebsiteFormInherit(WebsiteForm): | 
				
			|||
    """This module extends the functionality of the website form controller | 
				
			|||
    to handle the creation of new help desk tickets. It provides a new | 
				
			|||
    controller to display a list of tickets for the current user in their | 
				
			|||
    portal, and overrides the website form controller's method for handling | 
				
			|||
    form submissions to create a new help desk ticket instead.""" | 
				
			|||
    def _handle_website_form(self, model_name, **kwargs): | 
				
			|||
        """Website Help Desk Form""" | 
				
			|||
        if model_name == 'help.ticket': | 
				
			|||
            tickets = request.env['ticket.stage'].sudo().search([]) | 
				
			|||
            for rec in tickets: | 
				
			|||
                sequence = tickets.mapped('sequence') | 
				
			|||
                lowest_sequence = tickets.filtered( | 
				
			|||
                    lambda x: x.sequence == min(sequence)) | 
				
			|||
                if rec == lowest_sequence: | 
				
			|||
                    lowest_stage_id = lowest_sequence | 
				
			|||
            products = kwargs.get('product') | 
				
			|||
            partner_create = request.env['res.partner'].sudo().create({ | 
				
			|||
                'name':kwargs.get('customer_name'), | 
				
			|||
                'company_name':kwargs.get('company'), | 
				
			|||
                'phone':kwargs.get('phone'), | 
				
			|||
                'email':kwargs.get('email_from') | 
				
			|||
            }) | 
				
			|||
            if products: | 
				
			|||
                splited_product = products.split(',') | 
				
			|||
                product_list = [int(i) for i in splited_product] | 
				
			|||
                rec_val = { | 
				
			|||
                    'customer_name': kwargs.get('customer_name'), | 
				
			|||
                    'subject': kwargs.get('subject'), | 
				
			|||
                    'description': kwargs.get('description'), | 
				
			|||
                    'email': kwargs.get('email_from'), | 
				
			|||
                    'phone': kwargs.get('phone'), | 
				
			|||
                    'priority': kwargs.get('priority'), | 
				
			|||
                    'product_ids': product_list, | 
				
			|||
                    'stage_id': lowest_stage_id.id, | 
				
			|||
                    'customer_id': partner_create.id, | 
				
			|||
                    'ticket_type': kwargs.get('ticket_type'), | 
				
			|||
                    'category_id': kwargs.get('category'), | 
				
			|||
                } | 
				
			|||
                ticket_id = request.env['help.ticket'].sudo().create(rec_val) | 
				
			|||
                request.session['ticket_number'] = ticket_id.name | 
				
			|||
                request.session['ticket_id'] = ticket_id.id | 
				
			|||
                model_record = request.env['ir.model'].sudo().search( | 
				
			|||
                    [('model', '=', model_name)]) | 
				
			|||
                data = self.extract_data(model_record, request.params) | 
				
			|||
                if ('ticket_attachment' in request.params or | 
				
			|||
                        request.httprequest.files or data.get( | 
				
			|||
                        'attachments')): | 
				
			|||
                    attached_files = data.get('attachments') | 
				
			|||
                    for attachment in attached_files: | 
				
			|||
                        attached_file = attachment.read() | 
				
			|||
                        request.env['ir.attachment'].sudo().create({ | 
				
			|||
                            'name': attachment.filename, | 
				
			|||
                            'res_model': 'help.ticket', | 
				
			|||
                            'res_id': ticket_id.id, | 
				
			|||
                            'type': 'binary', | 
				
			|||
                            'datas': base64.encodebytes(attached_file), | 
				
			|||
                        }) | 
				
			|||
                request.session[ | 
				
			|||
                    'form_builder_model_model'] = model_record.model | 
				
			|||
                request.session['form_builder_model'] = model_record.name | 
				
			|||
                request.session['form_builder_id'] = ticket_id.id | 
				
			|||
                return json.dumps({'id': ticket_id.id}) | 
				
			|||
            else: | 
				
			|||
                rec_val = { | 
				
			|||
                    'customer_name': kwargs.get('customer_name'), | 
				
			|||
                    'subject': kwargs.get('subject'), | 
				
			|||
                    'description': kwargs.get('description'), | 
				
			|||
                    'email': kwargs.get('email_from'), | 
				
			|||
                    'phone': kwargs.get('phone'), | 
				
			|||
                    'priority': kwargs.get('priority'), | 
				
			|||
                    'stage_id': lowest_stage_id.id, | 
				
			|||
                    'customer_id': partner_create.id, | 
				
			|||
                    'ticket_type': kwargs.get('ticket_type'), | 
				
			|||
                    'category_id': kwargs.get('category'), | 
				
			|||
                } | 
				
			|||
                ticket_id = request.env['help.ticket'].sudo().create(rec_val) | 
				
			|||
                request.session['ticket_number'] = ticket_id.name | 
				
			|||
                request.session['ticket_id'] = ticket_id.id | 
				
			|||
                model_record = request.env['ir.model'].sudo().search( | 
				
			|||
                    [('model', '=', model_name)]) | 
				
			|||
                data = self.extract_data(model_record, request.params) | 
				
			|||
                if ('ticket_attachment' in request.params or | 
				
			|||
                        request.httprequest.files or data.get( | 
				
			|||
                        'attachments')): | 
				
			|||
                    attached_files = data.get('attachments') | 
				
			|||
                    for attachment in attached_files: | 
				
			|||
                        attached_file = attachment.read() | 
				
			|||
                        request.env['ir.attachment'].sudo().create({ | 
				
			|||
                            'name': attachment.filename, | 
				
			|||
                            'res_model': 'help.ticket', | 
				
			|||
                            'res_id': ticket_id.id, | 
				
			|||
                            'type': 'binary', | 
				
			|||
                            'datas': base64.encodebytes(attached_file), | 
				
			|||
                        }) | 
				
			|||
                request.session['form_builder_model_model'] = model_record.model | 
				
			|||
                request.session['form_builder_model'] = model_record.name | 
				
			|||
                request.session['form_builder_id'] = ticket_id.id | 
				
			|||
                return json.dumps({'id': ticket_id.id}) | 
				
			|||
        else: | 
				
			|||
            model_record = request.env['ir.model'].sudo().search( | 
				
			|||
                [('model', '=', model_name)]) | 
				
			|||
            if not model_record: | 
				
			|||
                return json.dumps({ | 
				
			|||
                    'error': _("The form's specified model does not exist") | 
				
			|||
                }) | 
				
			|||
            try: | 
				
			|||
                data = self.extract_data(model_record, request.params) | 
				
			|||
            # If we encounter an issue while extracting data | 
				
			|||
            except ValidationError as e: | 
				
			|||
                return json.dumps({'error_fields': e.args[0]}) | 
				
			|||
            try: | 
				
			|||
                id_record = self.insert_record(request, model_record, | 
				
			|||
                                               data['record'], data['custom'], | 
				
			|||
                                               data.get('meta')) | 
				
			|||
                if id_record: | 
				
			|||
                    self.insert_attachment(model_record, id_record, | 
				
			|||
                                           data['attachments']) | 
				
			|||
                    # In case of an email, we want to send it immediately instead of waiting | 
				
			|||
                    # For the email queue to process | 
				
			|||
                    if model_name == 'mail.mail': | 
				
			|||
                        request.env[model_name].sudo().browse(id_record).send() | 
				
			|||
 | 
				
			|||
            # Some fields have additional SQL constraints that we can't check generically | 
				
			|||
            # Ex: crm.lead.probability which is a float between 0 and 1 | 
				
			|||
            # TODO: How to get the name of the erroneous field ? | 
				
			|||
            except IntegrityError: | 
				
			|||
                return json.dumps(False) | 
				
			|||
            request.session['form_builder_model_model'] = model_record.model | 
				
			|||
            request.session['form_builder_model'] = model_record.name | 
				
			|||
            request.session['form_builder_id'] = id_record | 
				
			|||
            return json.dumps({'id': id_record}) | 
				
			|||
@ -0,0 +1,169 @@ | 
				
			|||
# -*- coding: utf-8 -*- | 
				
			|||
################################################################################ | 
				
			|||
# | 
				
			|||
#    Cybrosys Technologies Pvt. Ltd. | 
				
			|||
# | 
				
			|||
#    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			|||
#    Author: Bhagyadev KP (<https://www.cybrosys.com>) | 
				
			|||
# | 
				
			|||
#    You can modify it under the terms of the GNU LESSER | 
				
			|||
#    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | 
				
			|||
# | 
				
			|||
#    This program is distributed in the hope that it will be useful, | 
				
			|||
#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			|||
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			|||
#    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | 
				
			|||
# | 
				
			|||
#    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | 
				
			|||
#    (LGPL v3) along with this program. | 
				
			|||
#    If not, see <http://www.gnu.org/licenses/>. | 
				
			|||
# | 
				
			|||
################################################################################ | 
				
			|||
import base64 | 
				
			|||
import json | 
				
			|||
from psycopg2 import IntegrityError | 
				
			|||
from odoo import http, _ | 
				
			|||
from odoo.http import request | 
				
			|||
from odoo.exceptions import ValidationError | 
				
			|||
from odoo.addons.website.controllers.form import WebsiteForm | 
				
			|||
 | 
				
			|||
 | 
				
			|||
class HelpdeskProduct(http.Controller): | 
				
			|||
    """    Controller for handling helpdesk products. | 
				
			|||
    """ | 
				
			|||
 | 
				
			|||
    @http.route('/product', auth='public', type='json') | 
				
			|||
    def product(self): | 
				
			|||
        prols = [] | 
				
			|||
        acc = request.env['product.template'].sudo().search([]) | 
				
			|||
        for i in acc: | 
				
			|||
            dic = {'name': i['name'], | 
				
			|||
                   'id': i['id']} | 
				
			|||
            prols.append(dic) | 
				
			|||
        return prols | 
				
			|||
 | 
				
			|||
 | 
				
			|||
class WebsiteFormInherit(WebsiteForm): | 
				
			|||
 | 
				
			|||
    def _handle_website_form(self, model_name, **kwargs): | 
				
			|||
        """ | 
				
			|||
        Handle the submission of website forms. | 
				
			|||
        :param model_name: The name of the model associated with the form. | 
				
			|||
        :type model_name: str | 
				
			|||
        :param kwargs: Keyword arguments containing form data. | 
				
			|||
        :type kwargs: dict | 
				
			|||
        :return: JSON response indicating the success or failure of form submission. | 
				
			|||
        :rtype: str | 
				
			|||
        """ | 
				
			|||
        lowest_stage_id = None | 
				
			|||
        if model_name == 'ticket.helpdesk': | 
				
			|||
            tickets = request.env['ticket.stage'].sudo().search([]) | 
				
			|||
            if tickets: | 
				
			|||
                sequence = tickets.mapped('sequence') | 
				
			|||
                lowest_sequence = tickets.filtered( | 
				
			|||
                    lambda x: x.sequence == min(sequence)) | 
				
			|||
                if lowest_sequence: | 
				
			|||
                    lowest_stage_id = lowest_sequence[0] | 
				
			|||
            if lowest_stage_id is None: | 
				
			|||
                return json.dumps( | 
				
			|||
                    {'error': "No stage found with the lowest sequence."}) | 
				
			|||
            products = kwargs.get('product') | 
				
			|||
            partner_create = request.env['res.partner'].sudo().create({ | 
				
			|||
                'name': kwargs.get('customer_name'), | 
				
			|||
                'company_name': kwargs.get('company'), | 
				
			|||
                'phone': kwargs.get('phone'), | 
				
			|||
                'email': kwargs.get('email_from') | 
				
			|||
            }) | 
				
			|||
            if products: | 
				
			|||
                split_product = products.split(',') | 
				
			|||
                product_list = [int(i) for i in split_product] | 
				
			|||
                rec_val = { | 
				
			|||
                    'customer_name': kwargs.get('customer_name'), | 
				
			|||
                    'subject': kwargs.get('subject'), | 
				
			|||
                    'description': kwargs.get('description'), | 
				
			|||
                    'email': kwargs.get('email_from'), | 
				
			|||
                    'phone': kwargs.get('phone'), | 
				
			|||
                    'priority': kwargs.get('priority'), | 
				
			|||
                    'product_ids': product_list, | 
				
			|||
                    'stage_id': lowest_stage_id.id, | 
				
			|||
                    'customer_id': partner_create.id, | 
				
			|||
                    'ticket_type_id': kwargs.get('ticket_type_id'), | 
				
			|||
                    'category_id': kwargs.get('category'), | 
				
			|||
                } | 
				
			|||
            else: | 
				
			|||
                rec_val = { | 
				
			|||
                    'customer_name': kwargs.get('customer_name'), | 
				
			|||
                    'subject': kwargs.get('subject'), | 
				
			|||
                    'description': kwargs.get('description'), | 
				
			|||
                    'email': kwargs.get('email_from'), | 
				
			|||
                    'phone': kwargs.get('phone'), | 
				
			|||
                    'priority': kwargs.get('priority'), | 
				
			|||
                    'stage_id': lowest_stage_id.id, | 
				
			|||
                    'customer_id': partner_create.id, | 
				
			|||
                    'ticket_type_id': kwargs.get('ticket_type_id'), | 
				
			|||
                    'category_id': kwargs.get('category'), | 
				
			|||
                } | 
				
			|||
            ticket_id = request.env['ticket.helpdesk'].sudo().create(rec_val) | 
				
			|||
            if ticket_id and partner_create.email: | 
				
			|||
                request.env['mail.mail'].sudo().create({ | 
				
			|||
                    'subject': 'Your Ticket Has Been Created', | 
				
			|||
                    'body_html': f"<p>Hello {partner_create.name},</p><p>Your ticket <strong>{ticket_id.name}</strong> with the subject <strong>{ticket_id.subject}</strong> has been successfully submitted. Our support team will contact you soon.</p> <p>Thank You.</p>", | 
				
			|||
                    'email_to': partner_create.email, | 
				
			|||
                    'email_from': request.env.user.email or 'support@example.com', | 
				
			|||
                }).send() | 
				
			|||
                ticket_id.message_post( | 
				
			|||
                    body="A confirmation email regarding the ticket creation has been sent to the customer.", | 
				
			|||
                    subject="Ticket Confirmation Email", | 
				
			|||
                    message_type='email', | 
				
			|||
                    subtype_xmlid="mail.mt_comment", | 
				
			|||
                ) | 
				
			|||
            request.session['ticket_number'] = ticket_id.name | 
				
			|||
            request.session['ticket_id'] = ticket_id.id | 
				
			|||
            model_record = request.env['ir.model'].sudo().search( | 
				
			|||
                [('model', '=', model_name)]) | 
				
			|||
            attachments = [] | 
				
			|||
            attachment_index = 0 | 
				
			|||
            while f"ticket_attachment[0][{attachment_index}]" in kwargs: | 
				
			|||
                attachment_key = f"ticket_attachment[0][{attachment_index}]" | 
				
			|||
                if attachment_key in kwargs: | 
				
			|||
                    attachment = kwargs[attachment_key] | 
				
			|||
                    attachments.append(attachment) | 
				
			|||
                attachment_index += 1 | 
				
			|||
            for attachment in attachments: | 
				
			|||
                attached_file = attachment.read() | 
				
			|||
                request.env['ir.attachment'].sudo().create({ | 
				
			|||
                    'name': attachment.filename, | 
				
			|||
                    'res_model': 'ticket.helpdesk', | 
				
			|||
                    'res_id': ticket_id.id, | 
				
			|||
                    'type': 'binary', | 
				
			|||
                    'datas': base64.encodebytes(attached_file), | 
				
			|||
                }) | 
				
			|||
            request.session['form_builder_model_model'] = model_record.model | 
				
			|||
            request.session['form_builder_model'] = model_record.name | 
				
			|||
            request.session['form_builder_id'] = ticket_id.id | 
				
			|||
            return json.dumps({'id': ticket_id.id}) | 
				
			|||
        else: | 
				
			|||
            model_record = request.env['ir.model'].sudo().search( | 
				
			|||
                [('model', '=', model_name)]) | 
				
			|||
            if not model_record: | 
				
			|||
                return json.dumps( | 
				
			|||
                    {'error': _("The form's specified model does not exist")}) | 
				
			|||
            try: | 
				
			|||
                data = self.extract_data(model_record, request.params) | 
				
			|||
            except ValidationError as e: | 
				
			|||
                return json.dumps({'error_fields': e.args[0]}) | 
				
			|||
            try: | 
				
			|||
                id_record = self.insert_record(request, model_record, | 
				
			|||
                                               data['record'], data['custom'], | 
				
			|||
                                               data.get('meta')) | 
				
			|||
                if id_record: | 
				
			|||
                    self.insert_attachment(model_record, id_record, | 
				
			|||
                                           data['attachments']) | 
				
			|||
                    if model_name == 'mail.mail': | 
				
			|||
                        request.env[model_name].sudo().browse(id_record).send() | 
				
			|||
            except IntegrityError: | 
				
			|||
                return json.dumps(False) | 
				
			|||
            request.session['form_builder_model_model'] = model_record.model | 
				
			|||
            request.session['form_builder_model'] = model_record.name | 
				
			|||
            request.session['form_builder_id'] = id_record | 
				
			|||
            return json.dumps({'id': id_record}) | 
				
			|||
@ -0,0 +1,74 @@ | 
				
			|||
# -*- coding: utf-8 -*- | 
				
			|||
################################################################################ | 
				
			|||
# | 
				
			|||
#    Cybrosys Technologies Pvt. Ltd. | 
				
			|||
# | 
				
			|||
#    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			|||
#    Author: Bhagyadev KP (<https://www.cybrosys.com>) | 
				
			|||
# | 
				
			|||
#    You can modify it under the terms of the GNU LESSER | 
				
			|||
#    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | 
				
			|||
# | 
				
			|||
#    This program is distributed in the hope that it will be useful, | 
				
			|||
#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			|||
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			|||
#    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | 
				
			|||
# | 
				
			|||
#    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | 
				
			|||
#    (LGPL v3) along with this program. | 
				
			|||
#    If not, see <http://www.gnu.org/licenses/>. | 
				
			|||
# | 
				
			|||
################################################################################ | 
				
			|||
from odoo import http | 
				
			|||
from odoo.http import request | 
				
			|||
 | 
				
			|||
 | 
				
			|||
class WebsiteDesk(http.Controller): | 
				
			|||
    @http.route(['/helpdesk_ticket'], type='http', auth="public", website=True, | 
				
			|||
                sitemap=True) | 
				
			|||
    def helpdesk_ticket(self, **kwargs): | 
				
			|||
        """ | 
				
			|||
        Route to display the helpdesk ticket creation form. | 
				
			|||
        Returns: | 
				
			|||
            http.Response: The HTTP response rendering the helpdesk ticket form. | 
				
			|||
        """ | 
				
			|||
        types = request.env['helpdesk.type'].sudo().search([]) | 
				
			|||
        categories = request.env['helpdesk.category'].sudo().search([]) | 
				
			|||
        product = request.env['product.template'].sudo().search([]) | 
				
			|||
        values = {} | 
				
			|||
        values.update({ | 
				
			|||
            'types': types, | 
				
			|||
            'categories': categories, | 
				
			|||
            'product_website': product | 
				
			|||
        }) | 
				
			|||
        return request.render('odoo_website_helpdesk.ticket_form', values) | 
				
			|||
 | 
				
			|||
    @http.route(['/rating/<int:ticket_id>'], type='http', auth="public", | 
				
			|||
                website=True, | 
				
			|||
                sitemap=True) | 
				
			|||
    def rating(self, ticket_id): | 
				
			|||
        """ | 
				
			|||
        Route to display the rating form for a specific ticket. Args: | 
				
			|||
        ticket_id (int): The ID of the ticket for which the rating form is | 
				
			|||
        displayed. Returns: http.Response: The HTTP response rendering the | 
				
			|||
        rating form. | 
				
			|||
        """ | 
				
			|||
        ticket = request.env['ticket.helpdesk'].browse(ticket_id) | 
				
			|||
        data = { | 
				
			|||
            'ticket': ticket.id, | 
				
			|||
        } | 
				
			|||
        return request.render('odoo_website_helpdesk.rating_form', data) | 
				
			|||
 | 
				
			|||
    @http.route(['/rating/<int:ticket_id>/submit'], type='http', auth="user", | 
				
			|||
                website=True, csrf=False, | 
				
			|||
                sitemap=True) | 
				
			|||
    def rating_backend(self, ticket_id, **post): | 
				
			|||
        """ | 
				
			|||
        Customer Rating | 
				
			|||
        """ | 
				
			|||
        ticket = request.env['ticket.helpdesk'].browse(ticket_id) | 
				
			|||
        ticket.write({ | 
				
			|||
            'customer_rating': post['rating'], | 
				
			|||
            'review': post['message'], | 
				
			|||
        }) | 
				
			|||
        return request.render('odoo_website_helpdesk.rating_thanks') | 
				
			|||
@ -0,0 +1,13 @@ | 
				
			|||
<?xml version="1.0" encoding="utf-8"?> | 
				
			|||
<odoo> | 
				
			|||
    <data noupdate="1"> | 
				
			|||
        <!--        Record for a helpdesk ticket category representing internal tickets.--> | 
				
			|||
        <record id="ticket_categories_1" model="helpdesk.category"> | 
				
			|||
            <field name="name">Internal</field> | 
				
			|||
        </record> | 
				
			|||
        <!--        Record for a helpdesk ticket category representing technical tickets.--> | 
				
			|||
        <record id="ticket_categories_2" model="helpdesk.category"> | 
				
			|||
            <field name="name">Technical</field> | 
				
			|||
        </record> | 
				
			|||
    </data> | 
				
			|||
</odoo> | 
				
			|||
@ -0,0 +1,21 @@ | 
				
			|||
<?xml version="1.0" encoding="utf-8"?> | 
				
			|||
<odoo> | 
				
			|||
    <data noupdate="1"> | 
				
			|||
        <!--    Record for a helpdesk ticket type representing a general question.--> | 
				
			|||
        <record id="ticket_type_1" model="helpdesk.type"> | 
				
			|||
            <field name="name">Question</field> | 
				
			|||
        </record> | 
				
			|||
        <!--     Record for a helpdesk ticket type representing an issue.--> | 
				
			|||
        <record id="ticket_type_2" model="helpdesk.type"> | 
				
			|||
            <field name="name">Issue</field> | 
				
			|||
        </record> | 
				
			|||
        <!--        Record for a helpdesk ticket type representing a repair request.--> | 
				
			|||
        <record id="ticket_type_3" model="helpdesk.type"> | 
				
			|||
            <field name="name">Repair</field> | 
				
			|||
        </record> | 
				
			|||
        <!--        Record for a helpdesk ticket type representing a maintenance request.--> | 
				
			|||
        <record id="ticket_type_4" model="helpdesk.type"> | 
				
			|||
            <field name="name">Maintenance</field> | 
				
			|||
        </record> | 
				
			|||
    </data> | 
				
			|||
</odoo> | 
				
			|||
@ -1,22 +0,0 @@ | 
				
			|||
<?xml version="1.0" encoding="utf-8"?> | 
				
			|||
<odoo> | 
				
			|||
<!--    Ticket types--> | 
				
			|||
    <record id="helpdesk_types_question" model="helpdesk.types"> | 
				
			|||
        <field name="name">Question</field> | 
				
			|||
    </record> | 
				
			|||
    <record id="helpdesk_types_issue" model="helpdesk.types"> | 
				
			|||
        <field name="name">Issue</field> | 
				
			|||
    </record> | 
				
			|||
    <record id="helpdesk_types_repair" model="helpdesk.types"> | 
				
			|||
        <field name="name">Repair</field> | 
				
			|||
    </record> | 
				
			|||
    <record id="helpdesk_types_maintenance" model="helpdesk.types"> | 
				
			|||
        <field name="name">Maintenance</field> | 
				
			|||
    </record> | 
				
			|||
    <record id="helpdesk_categories_internal" model="helpdesk.categories"> | 
				
			|||
        <field name="name">Internal</field> | 
				
			|||
    </record> | 
				
			|||
    <record id="helpdesk_categories_technical" model="helpdesk.categories"> | 
				
			|||
        <field name="name">Technical</field> | 
				
			|||
    </record> | 
				
			|||
</odoo> | 
				
			|||
@ -1,17 +1,15 @@ | 
				
			|||
<?xml version="1.0" encoding="UTF-8" ?> | 
				
			|||
<odoo> | 
				
			|||
    <data noupdate="1"> | 
				
			|||
<!--        Auto close ticket--> | 
				
			|||
        <record id="ir_cron_auto_close_ticket" model="ir.cron"> | 
				
			|||
<!--        Scheduled task (cron job) for automatically closing tickets--> | 
				
			|||
            <record id="auto_close_ticket" model="ir.cron"> | 
				
			|||
            <field name="name">Auto Close Ticket</field> | 
				
			|||
            <field name="model_id" | 
				
			|||
                   ref="odoo_website_helpdesk.model_help_ticket"/> | 
				
			|||
            <field name="model_id" ref="odoo_website_helpdesk.model_ticket_helpdesk"/> | 
				
			|||
            <field name="state">code</field> | 
				
			|||
            <field name="code">model.auto_close_ticket()</field> | 
				
			|||
            <field name="user_id" ref="base.user_root"/> | 
				
			|||
            <field name="interval_number">1</field> | 
				
			|||
            <field name="interval_type">days</field> | 
				
			|||
            <field name="numbercall">-1</field> | 
				
			|||
        </record> | 
				
			|||
    </data> | 
				
			|||
</odoo> | 
				
			|||
 | 
				
			|||
@ -1,20 +1,23 @@ | 
				
			|||
<?xml version="1.0" encoding="UTF-8" ?> | 
				
			|||
<odoo> | 
				
			|||
<!--    Sequence of ticket--> | 
				
			|||
    <record id="sequence_help_ticket_seq" model="ir.sequence"> | 
				
			|||
        <field name="name">Helpdesk</field> | 
				
			|||
        <field name="code">help.ticket</field> | 
				
			|||
        <field name="prefix">TKT</field> | 
				
			|||
        <field name="padding">5</field> | 
				
			|||
        <field name="number_increment">1</field> | 
				
			|||
    </record> | 
				
			|||
<!--     Sequence of invoiced ticket --> | 
				
			|||
    <record id="sequence_help_ticket_inv_seq" model="ir.sequence"> | 
				
			|||
        <field name="name">Helpdesk Invoice</field> | 
				
			|||
        <field name="code">ticket.invoice</field> | 
				
			|||
        <field name="prefix">INV/TKT/%(year)s/</field> | 
				
			|||
        <field name="padding">3</field> | 
				
			|||
        <field eval="1" name="number_increment"/> | 
				
			|||
        <field eval="False" name="company_id"/> | 
				
			|||
    </record> | 
				
			|||
    <data noupdate="1"> | 
				
			|||
        <!-- Define a sequence for help tickets --> | 
				
			|||
        <record id="sequence_help_ticket_seq" model="ir.sequence"> | 
				
			|||
            <field name="name">Helpdesk</field> | 
				
			|||
            <field name="code">ticket.helpdesk</field> | 
				
			|||
            <field name="prefix">TKT</field> | 
				
			|||
            <field name="padding">5</field> | 
				
			|||
            <field eval="1" name="number_increment"/> | 
				
			|||
            <field eval="False" name="company_id"/> | 
				
			|||
        </record> | 
				
			|||
        <!-- Define a sequence for help ticket invoices --> | 
				
			|||
        <record id="sequence_help_ticket_inv_seq" model="ir.sequence"> | 
				
			|||
            <field name="name">Helpdesk Invoice</field> | 
				
			|||
            <field name="code">ticket.invoice</field> | 
				
			|||
            <field name="prefix">INV/TKT/%(year)s/</field> | 
				
			|||
            <field name="padding">3</field> | 
				
			|||
            <field eval="1" name="number_increment"/> | 
				
			|||
            <field eval="False" name="company_id"/> | 
				
			|||
        </record> | 
				
			|||
    </data> | 
				
			|||
</odoo> | 
				
			|||
 | 
				
			|||
@ -1,39 +1,39 @@ | 
				
			|||
<?xml version="1.0" encoding="utf-8"?> | 
				
			|||
<odoo> | 
				
			|||
    <!-- Project Stages --> | 
				
			|||
    <record id="ticket_stage_inbox" model="ticket.stage"> | 
				
			|||
        <field name="sequence">10</field> | 
				
			|||
        <field name="name">Inbox</field> | 
				
			|||
    </record> | 
				
			|||
<!--    Draft--> | 
				
			|||
    <record id="ticket_stage_draft" model="ticket.stage"> | 
				
			|||
        <field name="sequence">15</field> | 
				
			|||
        <field name="name">Draft</field> | 
				
			|||
    </record> | 
				
			|||
<!--In progress--> | 
				
			|||
    <record id="ticket_stage_in_progress" model="ticket.stage"> | 
				
			|||
        <field name="sequence">20</field> | 
				
			|||
        <field name="starting_stage" eval="True"/> | 
				
			|||
        <field name="name">In Progress</field> | 
				
			|||
    </record> | 
				
			|||
<!--Done--> | 
				
			|||
    <record id="ticket_stage_done" model="ticket.stage"> | 
				
			|||
        <field name="sequence">25</field> | 
				
			|||
        <field name="name">Done</field> | 
				
			|||
        <field name="folded" eval="True"/> | 
				
			|||
    </record> | 
				
			|||
<!--Cancelled--> | 
				
			|||
    <record id="ticket_stage_cancel" model="ticket.stage"> | 
				
			|||
        <field name="sequence">30</field> | 
				
			|||
        <field name="name">Canceled</field> | 
				
			|||
        <field name="cancel_stage" eval="True"/> | 
				
			|||
        <field name="folded" eval="True"/> | 
				
			|||
    </record> | 
				
			|||
<!--    Closed--> | 
				
			|||
    <record id="ticket_stage_closed" model="ticket.stage"> | 
				
			|||
        <field name="sequence">29</field> | 
				
			|||
        <field name="name">Closed</field> | 
				
			|||
        <field name="closing_stage" eval="True"/> | 
				
			|||
        <field name="folded" eval="True"/> | 
				
			|||
    </record> | 
				
			|||
</odoo> | 
				
			|||
    <data noupdate="1"> | 
				
			|||
        <!-- Project Stages --> | 
				
			|||
        <!--    - stage_inbox: Initial stage where tickets are received.--> | 
				
			|||
        <record id="stage_inbox" model="ticket.stage"> | 
				
			|||
            <field name="sequence">10</field> | 
				
			|||
            <field name="name">Inbox</field> | 
				
			|||
        </record> | 
				
			|||
        <!--    - stage_draft: Tickets in the drafting phase.--> | 
				
			|||
        <record id="stage_draft" model="ticket.stage"> | 
				
			|||
            <field name="sequence">15</field> | 
				
			|||
            <field name="name">Draft</field> | 
				
			|||
        </record> | 
				
			|||
        <!--    - stage_done: Final stage indicating completion.--> | 
				
			|||
        <record id="stage_done" model="ticket.stage"> | 
				
			|||
            <field name="sequence">25</field> | 
				
			|||
            <field name="name">Done</field> | 
				
			|||
        </record> | 
				
			|||
        <!--    - stage_in_progress: Tickets actively being worked on.--> | 
				
			|||
        <record id="stage_in_progress" model="ticket.stage"> | 
				
			|||
            <field name="sequence">20</field> | 
				
			|||
            <field name="starting_stage" eval="True"/> | 
				
			|||
            <field name="name">In Progress</field> | 
				
			|||
        </record> | 
				
			|||
        <!--    - stage_closed: Closing stage for resolved tickets.--> | 
				
			|||
        <record id="stage_closed" model="ticket.stage"> | 
				
			|||
            <field name="sequence">30</field> | 
				
			|||
            <field name="closing_stage">True</field> | 
				
			|||
            <field name="name">Closed</field> | 
				
			|||
        </record> | 
				
			|||
        <!--    - stage_canceled: Stage for canceled or invalidated tickets.--> | 
				
			|||
        <record id="stage_canceled" model="ticket.stage"> | 
				
			|||
            <field name="sequence">35</field> | 
				
			|||
            <field name="cancel_stage">True</field> | 
				
			|||
            <field name="name">Canceled</field> | 
				
			|||
        </record> | 
				
			|||
    </data> | 
				
			|||
</odoo> | 
				
			|||
@ -1,11 +1,25 @@ | 
				
			|||
## Module <odoo_website_helpdesk> | 
				
			|||
 | 
				
			|||
#### 04.12.2023 | 
				
			|||
#### Version 16.0.1.0.0 | 
				
			|||
#### 30.10.2024 | 
				
			|||
#### Version 18.0.1.0.0 | 
				
			|||
#### ADD | 
				
			|||
 | 
				
			|||
- Initial commit for Website Helpdesk Support Ticket Management | 
				
			|||
 | 
				
			|||
#### 12.02.2025 | 
				
			|||
#### Version 16.0.3.0.1 | 
				
			|||
#### UPDT | 
				
			|||
#### Version 18.0.1.0.1 | 
				
			|||
##### UPDT | 
				
			|||
-A new contact record is created upon form submission. | 
				
			|||
 | 
				
			|||
#### 13.05.2025 | 
				
			|||
#### Version 18.0.1.0.2 | 
				
			|||
##### UPDT | 
				
			|||
-A confirmation email will be sent to the customer upon ticket creation. | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
@ -1,65 +0,0 @@ | 
				
			|||
# -*- coding: utf-8 -*- | 
				
			|||
############################################################################# | 
				
			|||
# | 
				
			|||
#    Cybrosys Technologies Pvt. Ltd. | 
				
			|||
# | 
				
			|||
#    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			|||
#    Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) | 
				
			|||
# | 
				
			|||
#    You can modify it under the terms of the GNU LESSER | 
				
			|||
#    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | 
				
			|||
# | 
				
			|||
#    This program is distributed in the hope that it will be useful, | 
				
			|||
#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			|||
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			|||
#    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | 
				
			|||
# | 
				
			|||
#    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | 
				
			|||
#    (LGPL v3) along with this program. | 
				
			|||
#    If not, see <http://www.gnu.org/licenses/>. | 
				
			|||
# | 
				
			|||
############################################################################# | 
				
			|||
from odoo import api, fields, models | 
				
			|||
 | 
				
			|||
 | 
				
			|||
class HelpTeam(models.Model): | 
				
			|||
    """ This class represents a Helpdesk Team in the system, providing | 
				
			|||
     information about the team members, leader, and related project.""" | 
				
			|||
    _name = 'help.team' | 
				
			|||
    _description = 'Helpdesk Team' | 
				
			|||
 | 
				
			|||
    name = fields.Char(string='Name', help='Name of the Helpdesk Team. It ' | 
				
			|||
                                           'identify the helpdesk team') | 
				
			|||
    team_lead_id = fields.Many2one( | 
				
			|||
        'res.users', | 
				
			|||
        string='Team Leader', | 
				
			|||
        help='Name of the Helpdesk Team Leader.', | 
				
			|||
        domain=lambda self: [('groups_id', 'in', self.env.ref( | 
				
			|||
            'odoo_website_helpdesk.helpdesk_team_leader').id)]) | 
				
			|||
    member_ids = fields.Many2many( | 
				
			|||
        'res.users', | 
				
			|||
        string='Members', | 
				
			|||
        help='Users who belong to that Helpdesk Team', | 
				
			|||
        domain=lambda self: [('groups_id', 'in', self.env.ref( | 
				
			|||
            'odoo_website_helpdesk.helpdesk_user').id)]) | 
				
			|||
    email = fields.Char(string='Email', help='Email') | 
				
			|||
    project_id = fields.Many2one('project.project', | 
				
			|||
                                 string='Project', | 
				
			|||
                                 help='The Project they are currently in') | 
				
			|||
    create_task = fields.Boolean(string="Create Task", | 
				
			|||
                                 help="Enable for allowing team to " | 
				
			|||
                                      "create tasks from tickets") | 
				
			|||
 | 
				
			|||
    @api.onchange('team_lead_id') | 
				
			|||
    def members_choose(self): | 
				
			|||
        """ This method is triggered when the Team Leader is changed. It | 
				
			|||
        updates the available team members based on the selected leader and | 
				
			|||
        filters out the leader from the list of potential members.""" | 
				
			|||
        fetch_members = self.env['res.users'].search([]) | 
				
			|||
        filtered_members = fetch_members.filtered( | 
				
			|||
            lambda x: x.id != self.team_lead_id.id) | 
				
			|||
        return {'domain': {'member_ids': [ | 
				
			|||
            ('id', '=', filtered_members.ids), | 
				
			|||
            ('groups_id', 'in', self.env.ref('base.group_user').id), | 
				
			|||
            ('groups_id', 'not in', self.env.ref( | 
				
			|||
                'odoo_website_helpdesk.helpdesk_team_leader').id)]}} | 
				
			|||
@ -1,465 +0,0 @@ | 
				
			|||
# -*- coding: utf-8 -*- | 
				
			|||
############################################################################# | 
				
			|||
# | 
				
			|||
#    Cybrosys Technologies Pvt. Ltd. | 
				
			|||
# | 
				
			|||
#    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			|||
#    Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) | 
				
			|||
# | 
				
			|||
#    You can modify it under the terms of the GNU LESSER | 
				
			|||
#    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | 
				
			|||
# | 
				
			|||
#    This program is distributed in the hope that it will be useful, | 
				
			|||
#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			|||
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			|||
#    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | 
				
			|||
# | 
				
			|||
#    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | 
				
			|||
#    (LGPL v3) along with this program. | 
				
			|||
#    If not, see <http://www.gnu.org/licenses/>. | 
				
			|||
# | 
				
			|||
############################################################################# | 
				
			|||
import logging | 
				
			|||
from odoo import api, fields, models, _ | 
				
			|||
from odoo.exceptions import UserError | 
				
			|||
from odoo.exceptions import ValidationError | 
				
			|||
 | 
				
			|||
_logger = logging.getLogger(__name__) | 
				
			|||
 | 
				
			|||
PRIORITIES = [ | 
				
			|||
    ('0', 'Very Low'), | 
				
			|||
    ('1', 'Low'), | 
				
			|||
    ('2', 'Normal'), | 
				
			|||
    ('3', 'High'), | 
				
			|||
    ('4', 'Very High'), | 
				
			|||
] | 
				
			|||
RATING = [ | 
				
			|||
    ('0', 'Very Low'), | 
				
			|||
    ('1', 'Low'), | 
				
			|||
    ('2', 'Normal'), | 
				
			|||
    ('3', 'High'), | 
				
			|||
    ('4', 'Very High'), | 
				
			|||
    ('5', 'Extreme High') | 
				
			|||
] | 
				
			|||
 | 
				
			|||
 | 
				
			|||
class HelpTicket(models.Model): | 
				
			|||
    """This model represents the Helpdesk Ticket, which allows users to raise | 
				
			|||
    tickets related to products, services or any other issues. Each ticket has a | 
				
			|||
    name, customer information, description, team responsible for handling | 
				
			|||
    requests, associated project, priority level, stage, cost per hour, service | 
				
			|||
    product, start and end dates, and related tasks and invoices.""" | 
				
			|||
 | 
				
			|||
    _name = 'help.ticket' | 
				
			|||
    _description = 'Help Ticket' | 
				
			|||
    _inherit = ['mail.thread', 'mail.activity.mixin'] | 
				
			|||
 | 
				
			|||
    name = fields.Char(string='Name', default=lambda self: _('New'), | 
				
			|||
                       help='The name of the help ticket. By default, a new ' | 
				
			|||
                            'unique sequence number is assigned to each ' | 
				
			|||
                            'help ticket, unless a name is provided.', | 
				
			|||
                       readonly=True) | 
				
			|||
    active = fields.Boolean(default=True, help='Active', string='Active') | 
				
			|||
    customer_id = fields.Many2one('res.partner', | 
				
			|||
                                  string='Customer Name', | 
				
			|||
                                  help='Select the Customer Name') | 
				
			|||
    customer_name = fields.Char(string='Customer Name', | 
				
			|||
                                help='Add the Customer Name') | 
				
			|||
    subject = fields.Text(string='Subject', required=True, | 
				
			|||
                          help='Subject of the Ticket') | 
				
			|||
    description = fields.Text(string='Description', required=True, | 
				
			|||
                              help='Issue Description') | 
				
			|||
    email = fields.Char(string='Email', help='Email of the User.') | 
				
			|||
    phone = fields.Char(string='Phone', help='Phone Number of the user') | 
				
			|||
    team_id = fields.Many2one('help.team', string='Helpdesk Team', | 
				
			|||
                              help='The helpdesk team responsible for ' | 
				
			|||
                                   'handling requests related to this ' | 
				
			|||
                                   'record') | 
				
			|||
    product_ids = fields.Many2many('product.template', | 
				
			|||
                                   string='Product', | 
				
			|||
                                   help='The product associated with this ' | 
				
			|||
                                        'record.This field allows you to select' | 
				
			|||
                                        'an existing product from the product ' | 
				
			|||
                                        'catalog.') | 
				
			|||
    project_id = fields.Many2one('project.project', | 
				
			|||
                                 string='Project', | 
				
			|||
                                 readonly=False, | 
				
			|||
                                 related='team_id.project_id', | 
				
			|||
                                 store=True, | 
				
			|||
                                 help='The project associated with this team.' | 
				
			|||
                                      'This field is automatically filled ' | 
				
			|||
                                      'based on the project assigned to ' | 
				
			|||
                                      'the team.') | 
				
			|||
    priority = fields.Selection(PRIORITIES, | 
				
			|||
                                default='1', | 
				
			|||
                                help='Set the priority level', | 
				
			|||
                                string='Priority') | 
				
			|||
    stage_id = fields.Many2one('ticket.stage', string='Stage', | 
				
			|||
                               default=lambda self: self.env[ | 
				
			|||
                                   'ticket.stage'].search( | 
				
			|||
                                   [('name', '=', 'Draft')], limit=1).id, | 
				
			|||
                               tracking=True, | 
				
			|||
                               group_expand='_read_group_stage_ids', | 
				
			|||
                               help='Stages of the ticket.') | 
				
			|||
    user_id = fields.Many2one('res.users', | 
				
			|||
                              default=lambda self: self.env.user, | 
				
			|||
                              check_company=True, | 
				
			|||
                              index=True, tracking=True, | 
				
			|||
                              help='Login User') | 
				
			|||
    cost = fields.Float(string='Cost per hour', | 
				
			|||
                        help='The cost per hour for this record. This field ' | 
				
			|||
                             'specifies the hourly cost associated with the' | 
				
			|||
                             'record, which can be used in various ' | 
				
			|||
                             'calculations or reports.') | 
				
			|||
    service_product_id = fields.Many2one('product.product', | 
				
			|||
                                         string='Service Product', | 
				
			|||
                                         help='The product associated with this' | 
				
			|||
                                              'service. Only service products ' | 
				
			|||
                                              'are available for selection.', | 
				
			|||
                                         domain=[ | 
				
			|||
                                             ('detailed_type', '=', 'service')]) | 
				
			|||
    create_date = fields.Datetime(string='Creation Date', help='Created date of' | 
				
			|||
                                                               'the Ticket') | 
				
			|||
    start_date = fields.Datetime(string='Start Date', help='Start Date of the ' | 
				
			|||
                                                           'Ticket') | 
				
			|||
    end_date = fields.Datetime(string='End Date', help='End Date of the Ticket') | 
				
			|||
    public_ticket = fields.Boolean(string="Public Ticket", help='Public Ticket') | 
				
			|||
    invoice_ids = fields.Many2many('account.move', | 
				
			|||
                                   string='Invoices', | 
				
			|||
                                   help='To Generate Invoice based on hours ' | 
				
			|||
                                        'spent on the ticket' | 
				
			|||
                                   ) | 
				
			|||
    task_ids = fields.Many2many('project.task', | 
				
			|||
                                string='Tasks', | 
				
			|||
                                help='Related Task of the Ticket') | 
				
			|||
    color = fields.Integer(string="Color", help='Color') | 
				
			|||
    replied_date = fields.Datetime(string='Replied date', | 
				
			|||
                                   help='Replied Date of the Ticket') | 
				
			|||
    last_update_date = fields.Datetime(string='Last Update Date', | 
				
			|||
                                       help='Last Update Date of Ticket') | 
				
			|||
    ticket_type = fields.Many2one('helpdesk.types', | 
				
			|||
                                  string='Ticket Type', help='Ticket Type') | 
				
			|||
    team_head = fields.Many2one('res.users', string='Team Leader', | 
				
			|||
                                compute='_compute_team_head', | 
				
			|||
                                help='Team Leader Name') | 
				
			|||
    assigned_user = fields.Many2one( | 
				
			|||
        'res.users', | 
				
			|||
        string='Assigned User', | 
				
			|||
        domain=lambda self: [('groups_id', 'in', self.env.ref( | 
				
			|||
            'odoo_website_helpdesk.helpdesk_user').id)], | 
				
			|||
        help='Choose the Assigned User Name') | 
				
			|||
    category_id = fields.Many2one('helpdesk.categories', | 
				
			|||
                                  help='Choose the Category', string='Category') | 
				
			|||
    tags = fields.Many2many('helpdesk.tag', help='Choose the Tags', | 
				
			|||
                            string='Tag') | 
				
			|||
    assign_user = fields.Boolean(string='Assigned User', help='Assign User') | 
				
			|||
    attachment_ids = fields.One2many('ir.attachment', | 
				
			|||
                                     'res_id', | 
				
			|||
                                     help='Attachment Line', | 
				
			|||
                                     string='Attachment') | 
				
			|||
    merge_ticket_invisible = fields.Boolean(string='Merge Ticket', | 
				
			|||
                                            help='Merge Ticket Invisible or ' | 
				
			|||
                                                 'Not') | 
				
			|||
    merge_count = fields.Integer(string='Merge Count', help='Merged Tickets ' | 
				
			|||
                                                           'Count') | 
				
			|||
 | 
				
			|||
    @api.onchange('team_id', 'team_head') | 
				
			|||
    def team_leader_domain(self): | 
				
			|||
        """Update the domain for the assigned user based on the selected team. | 
				
			|||
 | 
				
			|||
        This onchange method is triggered when the helpdesk team or team leader | 
				
			|||
        is changed. It updates the domain for the assigned user field to include | 
				
			|||
        only the members of the selected team.""" | 
				
			|||
        teams = [] | 
				
			|||
        for rec in self.team_id.member_ids: | 
				
			|||
            teams.append(rec.id) | 
				
			|||
        return {'domain': {'assigned_user': [('id', 'in', teams)]}} | 
				
			|||
 | 
				
			|||
    @api.depends('team_id') | 
				
			|||
    def _compute_team_head(self): | 
				
			|||
        """Compute the team head based on the selected team. | 
				
			|||
 | 
				
			|||
        This method is triggered when the helpdesk team is changed. It computes | 
				
			|||
        and updates the team head field based on the team's lead. | 
				
			|||
       """ | 
				
			|||
        self.team_head = self.team_id.team_lead_id.id | 
				
			|||
 | 
				
			|||
    @api.onchange('stage_id') | 
				
			|||
    def mail_snd(self): | 
				
			|||
        """Send an email when the stage of the ticket is changed. | 
				
			|||
 | 
				
			|||
        This onchange method is triggered when the stage of the ticket is | 
				
			|||
        changed. It updates the last update date, start date, and end date | 
				
			|||
        fields accordingly. If a template is associated with the stage, it | 
				
			|||
        sends an email using that template.""" | 
				
			|||
        rec_id = self._origin.id | 
				
			|||
        data = self.env['help.ticket'].search([('id', '=', rec_id)]) | 
				
			|||
        data.last_update_date = fields.Datetime.now() | 
				
			|||
        if self.stage_id.starting_stage: | 
				
			|||
            data.start_date = fields.Datetime.now() | 
				
			|||
        if self.stage_id.closing_stage or self.stage_id.cancel_stage: | 
				
			|||
            data.end_date = fields.Datetime.now() | 
				
			|||
        if self.stage_id.template_id: | 
				
			|||
            mail_template = self.stage_id.template_id | 
				
			|||
            mail_template.send_mail(self._origin.id, force_send=True) | 
				
			|||
 | 
				
			|||
    def assign_to_teamleader(self): | 
				
			|||
        """Assign the ticket to the team leader and send a notification. | 
				
			|||
 | 
				
			|||
        This function checks if a helpdesk team is selected and assigns the | 
				
			|||
        team leader to the ticket. It then sends a notification email to the | 
				
			|||
        team leader.""" | 
				
			|||
        if self.team_id: | 
				
			|||
            self.team_head = self.team_id.team_lead_id.id | 
				
			|||
            mail_template = self.env.ref( | 
				
			|||
                'odoo_website_helpdesk.' | 
				
			|||
                'mail_template_odoo_website_helpdesk_assign') | 
				
			|||
            mail_template.sudo().write({ | 
				
			|||
                'email_to': self.team_head.email, | 
				
			|||
                'subject': self.name | 
				
			|||
            }) | 
				
			|||
            mail_template.sudo().send_mail(self.id, force_send=True) | 
				
			|||
        else: | 
				
			|||
            raise ValidationError("Please choose a Helpdesk Team") | 
				
			|||
 | 
				
			|||
    def _default_show_create_task(self): | 
				
			|||
        """Get the default value for the 'show_create_task' field. | 
				
			|||
 | 
				
			|||
        This method retrieves the default value for the 'show_create_task' | 
				
			|||
        field from the configuration settings.""" | 
				
			|||
        return self.env['ir.config_parameter'].sudo().get_param( | 
				
			|||
            'odoo_website_helpdesk.show_create_task') | 
				
			|||
 | 
				
			|||
    show_create_task = fields.Boolean(string="Create Task", | 
				
			|||
                                      default=_default_show_create_task, | 
				
			|||
                                      compute='_compute_show_create_task', | 
				
			|||
                                      help='Determines whether the Create Task' | 
				
			|||
                                           ' button should be shown for this ' | 
				
			|||
                                           'ticket.') | 
				
			|||
    create_task = fields.Boolean(string="Create Task", readonly=False, | 
				
			|||
                                 related='team_id.create_task', | 
				
			|||
                                 store=True, | 
				
			|||
                                 help='Defines if a task should be created when' | 
				
			|||
                                      ' this ticket is created.') | 
				
			|||
    billable = fields.Boolean(string="Billable", help='Indicates whether the ' | 
				
			|||
                                                      'ticket is billable or ' | 
				
			|||
                                                      'not.') | 
				
			|||
 | 
				
			|||
    def _default_show_category(self): | 
				
			|||
        """Its display the default category""" | 
				
			|||
        return self.env['ir.config_parameter'].sudo().get_param( | 
				
			|||
            'odoo_website_helpdesk.show_category') | 
				
			|||
 | 
				
			|||
    show_category = fields.Boolean(default=_default_show_category, | 
				
			|||
                                   compute='_compute_show_category', | 
				
			|||
                                   help='Display the default category') | 
				
			|||
    customer_rating = fields.Selection(RATING, default='0', readonly=True, | 
				
			|||
                                       string='Customer Rating', | 
				
			|||
                                       help='Display the customer rating.') | 
				
			|||
 | 
				
			|||
    review = fields.Char(string='Review', readonly=True, | 
				
			|||
                         help='Customer review of the ticket.') | 
				
			|||
    kanban_state = fields.Selection([ | 
				
			|||
        ('normal', 'Ready'), | 
				
			|||
        ('done', 'In Progress'), | 
				
			|||
        ('blocked', 'Blocked'), ], default='normal') | 
				
			|||
 | 
				
			|||
    def _compute_show_category(self): | 
				
			|||
        """Compute show category""" | 
				
			|||
        show_category = self._default_show_category() | 
				
			|||
        for rec in self: | 
				
			|||
            rec.show_category = show_category | 
				
			|||
 | 
				
			|||
    def _compute_show_create_task(self): | 
				
			|||
        """Compute the value of the 'show_create_task' field for each record in | 
				
			|||
        the current recordset.""" | 
				
			|||
        show_create_task = self._default_show_create_task() | 
				
			|||
        for record in self: | 
				
			|||
            record.show_create_task = show_create_task | 
				
			|||
 | 
				
			|||
    def auto_close_ticket(self): | 
				
			|||
        """Automatically closing the ticket based on the closing date.""" | 
				
			|||
        auto_close = self.env['ir.config_parameter'].sudo().get_param( | 
				
			|||
            'odoo_website_helpdesk.auto_close_ticket') | 
				
			|||
        if auto_close: | 
				
			|||
            no_of_days = self.env['ir.config_parameter'].sudo().get_param( | 
				
			|||
                'odoo_website_helpdesk.no_of_days') | 
				
			|||
            records = self.env['help.ticket'].search([]) | 
				
			|||
            for rec in records: | 
				
			|||
                days = (fields.Datetime.today() - rec.create_date).days | 
				
			|||
                if days >= int(no_of_days): | 
				
			|||
                    close_stage_id = self.env['ticket.stage'].search( | 
				
			|||
                        [('closing_stage', '=', True)]) | 
				
			|||
                    if close_stage_id: | 
				
			|||
                        rec.stage_id = close_stage_id | 
				
			|||
 | 
				
			|||
    def default_stage_id(self): | 
				
			|||
        """Search your stage""" | 
				
			|||
        return self.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Draft')], limit=1).id | 
				
			|||
 | 
				
			|||
    @api.model | 
				
			|||
    def _read_group_stage_ids(self, stages, domain, order): | 
				
			|||
        """ | 
				
			|||
        Return the available stages for grouping. | 
				
			|||
 | 
				
			|||
        This static method is used to provide the available stages for | 
				
			|||
        grouping when displaying records in a grouped view. | 
				
			|||
 | 
				
			|||
        """ | 
				
			|||
        stage_ids = self.env['ticket.stage'].search([]) | 
				
			|||
        return stage_ids | 
				
			|||
 | 
				
			|||
    @api.model | 
				
			|||
    def create(self, vals_list): | 
				
			|||
        """Create a new helpdesk ticket. | 
				
			|||
        This method is called when creating a new helpdesk ticket. It | 
				
			|||
        generates a unique name for the ticket using a sequence if no | 
				
			|||
        name is provided. | 
				
			|||
        """ | 
				
			|||
        if vals_list.get('name', _('New')) == _('New'): | 
				
			|||
            vals_list['name'] = self.env['ir.sequence'].next_by_code( | 
				
			|||
                'help.ticket') or _('New') | 
				
			|||
        return super().create(vals_list) | 
				
			|||
 | 
				
			|||
    def action_create_invoice(self): | 
				
			|||
        """Create Invoice for Help Desk Ticket. | 
				
			|||
        This function creates an invoice for the help desk ticket based on | 
				
			|||
        the associated tasks with billed hours. | 
				
			|||
        """ | 
				
			|||
        tasks = self.env['project.task'].search( | 
				
			|||
            [('project_id', '=', self.project_id.id), | 
				
			|||
             ('ticket_id', '=', self.id)]).filtered( | 
				
			|||
            lambda line: line.ticket_billed == True) | 
				
			|||
        if not tasks: | 
				
			|||
            raise UserError('No Tasks to Bill') | 
				
			|||
        total = sum(x.effective_hours for x in tasks if x.effective_hours > 0) | 
				
			|||
        invoice_no = self.env['ir.sequence'].next_by_code( | 
				
			|||
            'ticket.invoice') | 
				
			|||
        self.env['account.move'].create([ | 
				
			|||
            { | 
				
			|||
                'name': invoice_no, | 
				
			|||
                'move_type': 'out_invoice', | 
				
			|||
                'partner_id': self.customer_id.id, | 
				
			|||
                'ticket_id': self.id, | 
				
			|||
                'date': fields.Date.today(), | 
				
			|||
                'invoice_date': fields.Date.today(), | 
				
			|||
                'invoice_line_ids': | 
				
			|||
                    [(0, 0, {'product_id': self.service_product_id.id, | 
				
			|||
                             'name': self.service_product_id.name, | 
				
			|||
                             'quantity': total, | 
				
			|||
                             'product_uom_id': self.service_product_id.uom_id.id, | 
				
			|||
                             'price_unit': self.cost, | 
				
			|||
                             'account_id': | 
				
			|||
                                 self.service_product_id.categ_id.property_account_income_categ_id.id, | 
				
			|||
                             })], | 
				
			|||
            }, ]) | 
				
			|||
        for task in tasks: | 
				
			|||
            task.ticket_billed = True | 
				
			|||
        return { | 
				
			|||
            'effect': { | 
				
			|||
                'fadeout': 'medium', | 
				
			|||
                'message': 'Billed Successfully!', | 
				
			|||
                'type': 'rainbow_man', | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
    def action_create_tasks(self): | 
				
			|||
        """Create Task for HelpDesk Ticket | 
				
			|||
        This function creates a task associated with the helpdesk ticket | 
				
			|||
        and updates the task_ids field. | 
				
			|||
        """ | 
				
			|||
        task_id = self.env['project.task'].create({ | 
				
			|||
            'name': self.name + '-' + self.subject, | 
				
			|||
            'project_id': self.project_id.id, | 
				
			|||
            'company_id': self.env.company.id, | 
				
			|||
            'ticket_id': self.id, | 
				
			|||
        }) | 
				
			|||
        self.write({ | 
				
			|||
            'task_ids': [(4, task_id.id)] | 
				
			|||
        }) | 
				
			|||
        return { | 
				
			|||
            'name': 'Tasks', | 
				
			|||
            'res_model': 'project.task', | 
				
			|||
            'view_id': False, | 
				
			|||
            'res_id': task_id.id, | 
				
			|||
            'view_mode': 'form', | 
				
			|||
            'type': 'ir.actions.act_window', | 
				
			|||
            'target': 'new', | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
    def action_open_tasks(self): | 
				
			|||
        """Smart Button of Task to view the Tasks of HelpDesk Ticket""" | 
				
			|||
        return { | 
				
			|||
            'name': 'Tasks', | 
				
			|||
            'domain': [('ticket_id', '=', self.id)], | 
				
			|||
            'res_model': 'project.task', | 
				
			|||
            'view_id': False, | 
				
			|||
            'view_mode': 'tree,form', | 
				
			|||
            'type': 'ir.actions.act_window', | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
    def action_open_invoices(self): | 
				
			|||
        """Smart Button of Invoice to view the Invoices for HelpDesk Ticket""" | 
				
			|||
        return { | 
				
			|||
            'name': 'Invoice', | 
				
			|||
            'domain': [('ticket_id', '=', self.id)], | 
				
			|||
            'res_model': 'account.move', | 
				
			|||
            'view_id': False, | 
				
			|||
            'view_mode': 'tree,form', | 
				
			|||
            'type': 'ir.actions.act_window', | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
    def action_open_merged_tickets(self): | 
				
			|||
        """ Smart button of the merged tickets""" | 
				
			|||
        ticket_ids = self.env['support.tickets'].search( | 
				
			|||
            [('merged_ticket', '=', self.id)]) | 
				
			|||
        # Get the display_name matching records from the support.tickets | 
				
			|||
        helpdesk_ticket_ids = ticket_ids.mapped('display_name') | 
				
			|||
        # Get the IDs of the help.ticket records matching the display names | 
				
			|||
        help_ticket_records = self.env['help.ticket'].search( | 
				
			|||
            [('name', 'in', helpdesk_ticket_ids)]) | 
				
			|||
        return { | 
				
			|||
            'type': 'ir.actions.act_window', | 
				
			|||
            'name': 'Helpdesk Ticket', | 
				
			|||
            'view_mode': 'tree,form', | 
				
			|||
            'res_model': 'help.ticket', | 
				
			|||
            'domain': [('id', 'in', help_ticket_records.ids)], | 
				
			|||
            'context': self.env.context, | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
    def action_send_reply(self): | 
				
			|||
        """Compose and send a reply to the customer. | 
				
			|||
        This function opens a window for composing and sending a reply to | 
				
			|||
        the customer. It uses the configured email template for replies. | 
				
			|||
       """ | 
				
			|||
        template_id = self.env['ir.config_parameter'].sudo().get_param( | 
				
			|||
            'odoo_website_helpdesk.reply_template_id' | 
				
			|||
        ) | 
				
			|||
        template_id = self.env['mail.template'].browse(int(template_id)) | 
				
			|||
        if template_id: | 
				
			|||
            return { | 
				
			|||
                'type': 'ir.actions.act_window', | 
				
			|||
                'name': 'mail', | 
				
			|||
                'res_model': 'mail.compose.message', | 
				
			|||
                'view_mode': 'form', | 
				
			|||
                'target': 'new', | 
				
			|||
                'views': [[False, 'form']], | 
				
			|||
                'context': { | 
				
			|||
                    'default_model': 'help.ticket', | 
				
			|||
                    'default_res_id': self.id, | 
				
			|||
                    'default_template_id': template_id.id | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
        return { | 
				
			|||
            'type': 'ir.actions.act_window', | 
				
			|||
            'name': 'mail', | 
				
			|||
            'res_model': 'mail.compose.message', | 
				
			|||
            'view_mode': 'form', | 
				
			|||
            'target': 'new', | 
				
			|||
            'views': [[False, 'form']], | 
				
			|||
            'context': { | 
				
			|||
                'default_model': 'help.ticket', | 
				
			|||
                'default_res_id': self.id, | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
@ -0,0 +1,59 @@ | 
				
			|||
# -*- coding: utf-8 -*- | 
				
			|||
################################################################################ | 
				
			|||
# | 
				
			|||
#    Cybrosys Technologies Pvt. Ltd. | 
				
			|||
# | 
				
			|||
#    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			|||
#    Author: Bhagyadev KP (<https://www.cybrosys.com>) | 
				
			|||
# | 
				
			|||
#    You can modify it under the terms of the GNU LESSER | 
				
			|||
#    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | 
				
			|||
# | 
				
			|||
#    This program is distributed in the hope that it will be useful, | 
				
			|||
#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			|||
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			|||
#    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | 
				
			|||
# | 
				
			|||
#    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | 
				
			|||
#    (LGPL v3) along with this program. | 
				
			|||
#    If not, see <http://www.gnu.org/licenses/>. | 
				
			|||
# | 
				
			|||
################################################################################ | 
				
			|||
from odoo import api, fields, models | 
				
			|||
 | 
				
			|||
 | 
				
			|||
class TeamHelpDesk(models.Model): | 
				
			|||
    """Helpdesk team""" | 
				
			|||
    _name = 'team.helpdesk' | 
				
			|||
    _description = 'Helpdesk Team' | 
				
			|||
 | 
				
			|||
    name = fields.Char('Name', help='Helpdesk Team Name') | 
				
			|||
    team_lead_id = fields.Many2one('res.users', string='Team Leader', | 
				
			|||
                                   help='Team Leader Name', | 
				
			|||
                                   domain=lambda self: [ | 
				
			|||
                                       ('groups_id', 'in', self.env.ref( | 
				
			|||
                                           'odoo_website_helpdesk.helpdesk_team_leader').id)]) | 
				
			|||
    member_ids = fields.Many2many('res.users', string='Members', | 
				
			|||
                                  help='Team Members', | 
				
			|||
                                  domain=lambda self: [ | 
				
			|||
                                      ('groups_id', 'in', self.env.ref( | 
				
			|||
                                          'odoo_website_helpdesk.helpdesk_user').id)]) | 
				
			|||
    email = fields.Char('Email', help='Email of the team member.') | 
				
			|||
    project_id = fields.Many2one('project.project', | 
				
			|||
                                 string='Project', | 
				
			|||
                                 help='Projects related helpdesk team.') | 
				
			|||
    create_task = fields.Boolean(string="Create Task", | 
				
			|||
                                 help="Task created or not") | 
				
			|||
 | 
				
			|||
    @api.onchange('team_lead_id') | 
				
			|||
    def _onchange_team_lead_id(self): | 
				
			|||
        """Members selection function""" | 
				
			|||
        fetch_members = self.env['res.users'].search([]) | 
				
			|||
        filtered_members = fetch_members.filtered( | 
				
			|||
            lambda x: x.id != self.team_lead_id.id) | 
				
			|||
        return {'domain': {'member_ids': | 
				
			|||
                               [('id', '=', filtered_members.ids), ( | 
				
			|||
                                   'groups_id', 'in', | 
				
			|||
                                   self.env.ref('base.group_user').id), | 
				
			|||
                                ('groups_id', 'not in', self.env.ref( | 
				
			|||
                                    'odoo_website_helpdesk.helpdesk_team_leader').id)]}} | 
				
			|||
@ -0,0 +1,387 @@ | 
				
			|||
# -*- coding: utf-8 -*- | 
				
			|||
################################################################################ | 
				
			|||
# | 
				
			|||
#    Cybrosys Technologies Pvt. Ltd. | 
				
			|||
# | 
				
			|||
#    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | 
				
			|||
#    Author: Bhagyadev KP (<https://www.cybrosys.com>) | 
				
			|||
# | 
				
			|||
#    You can modify it under the terms of the GNU LESSER | 
				
			|||
#    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | 
				
			|||
# | 
				
			|||
#    This program is distributed in the hope that it will be useful, | 
				
			|||
#    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
				
			|||
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
				
			|||
#    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | 
				
			|||
# | 
				
			|||
#    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | 
				
			|||
#    (LGPL v3) along with this program. | 
				
			|||
#    If not, see <http://www.gnu.org/licenses/>. | 
				
			|||
# | 
				
			|||
################################################################################ | 
				
			|||
import logging | 
				
			|||
from odoo import api, fields, models, _ | 
				
			|||
from odoo.exceptions import UserError | 
				
			|||
from odoo.exceptions import ValidationError | 
				
			|||
 | 
				
			|||
_logger = logging.getLogger(__name__) | 
				
			|||
 | 
				
			|||
PRIORITIES = [ | 
				
			|||
    ('0', 'Very Low'), | 
				
			|||
    ('1', 'Low'), | 
				
			|||
    ('2', 'Normal'), | 
				
			|||
    ('3', 'High'), | 
				
			|||
    ('4', 'Very High'), | 
				
			|||
] | 
				
			|||
RATING = [ | 
				
			|||
    ('0', 'Very Low'), | 
				
			|||
    ('1', 'Low'), | 
				
			|||
    ('2', 'Normal'), | 
				
			|||
    ('3', 'High'), | 
				
			|||
    ('4', 'Very High'), | 
				
			|||
    ('5', 'Extreme High') | 
				
			|||
] | 
				
			|||
 | 
				
			|||
 | 
				
			|||
class TicketHelpDesk(models.Model): | 
				
			|||
    """Help_ticket model""" | 
				
			|||
    _name = 'ticket.helpdesk' | 
				
			|||
    _description = 'Helpdesk Ticket' | 
				
			|||
    _inherit = ['mail.thread', 'mail.activity.mixin'] | 
				
			|||
 | 
				
			|||
    def _default_show_create_task(self): | 
				
			|||
        """Task creation""" | 
				
			|||
        return self.env['ir.config_parameter'].sudo().get_param( | 
				
			|||
            'odoo_website_helpdesk.show_create_task') | 
				
			|||
 | 
				
			|||
    def _default_show_category(self): | 
				
			|||
        """Show category default""" | 
				
			|||
        return self.env['ir.config_parameter'].sudo().get_param( | 
				
			|||
            'odoo_website_helpdesk.show_category') | 
				
			|||
 | 
				
			|||
    name = fields.Char('Name', default=lambda self: self.env['ir.sequence']. | 
				
			|||
                       next_by_code('ticket.helpdesk') or _('New'), | 
				
			|||
                       help='Ticket Name') | 
				
			|||
    customer_id = fields.Many2one('res.partner', | 
				
			|||
                                  string='Customer Name', | 
				
			|||
                                  help='Customer Name') | 
				
			|||
    customer_name = fields.Char('Customer Name', help='Customer Name') | 
				
			|||
    subject = fields.Text('Subject', required=True, | 
				
			|||
                          help='Subject of the Ticket') | 
				
			|||
    description = fields.Text('Description', required=True, | 
				
			|||
                              help='Description') | 
				
			|||
    email = fields.Char('Email', help='Email') | 
				
			|||
    phone = fields.Char('Phone', help='Contact Number') | 
				
			|||
    team_id = fields.Many2one('team.helpdesk', string='Helpdesk Team', | 
				
			|||
                              help='Helpdesk Team Name') | 
				
			|||
    product_ids = fields.Many2many('product.template', | 
				
			|||
                                   string='Product', | 
				
			|||
                                   help='Product Name') | 
				
			|||
    project_id = fields.Many2one('project.project', | 
				
			|||
                                 string='Project', | 
				
			|||
                                 readonly=False, | 
				
			|||
                                 related='team_id.project_id', | 
				
			|||
                                 store=True, | 
				
			|||
                                 help='Project Name') | 
				
			|||
    priority = fields.Selection(PRIORITIES, default='1', help='Priority of the' | 
				
			|||
                                                              ' Ticket') | 
				
			|||
    stage_id = fields.Many2one('ticket.stage', string='Stage', | 
				
			|||
                               tracking=True, | 
				
			|||
                               group_expand='_read_group_stage_ids', | 
				
			|||
                               help='Stages') | 
				
			|||
    user_id = fields.Many2one('res.users', | 
				
			|||
                              default=lambda self: self.env.user, | 
				
			|||
                              check_company=True, | 
				
			|||
                              index=True, tracking=True, | 
				
			|||
                              help='Login User', string='User') | 
				
			|||
    cost = fields.Float('Cost per hour', help='Cost Per Unit') | 
				
			|||
    service_product_id = fields.Many2one('product.product', | 
				
			|||
                                         string='Service Product', | 
				
			|||
                                         help='Service Product', | 
				
			|||
                                         domain=[ | 
				
			|||
                                             ('type', '=', 'service')]) | 
				
			|||
    create_date = fields.Datetime('Creation Date', help='Created date') | 
				
			|||
    start_date = fields.Datetime('Start Date', help='Start Date') | 
				
			|||
    end_date = fields.Datetime('End Date', help='End Date') | 
				
			|||
    public_ticket = fields.Boolean(string="Public Ticket", | 
				
			|||
                                   help='Public Ticket') | 
				
			|||
    invoice_ids = fields.Many2many('account.move', | 
				
			|||
                                   string='Invoices', | 
				
			|||
                                   help='Invoicing id' | 
				
			|||
                                   ) | 
				
			|||
    task_ids = fields.Many2many('project.task', | 
				
			|||
                                string='Tasks', | 
				
			|||
                                help='Task id') | 
				
			|||
    color = fields.Integer(string="Color", help='Color') | 
				
			|||
    replied_date = fields.Datetime('Replied date', help='Replied Date') | 
				
			|||
    last_update_date = fields.Datetime('Last Update Date', | 
				
			|||
                                       help='Last Update Date') | 
				
			|||
    ticket_type_id = fields.Many2one('helpdesk.type', | 
				
			|||
                                     string='Ticket Type', help='Ticket Type') | 
				
			|||
    team_head_id = fields.Many2one('res.users', string='Team Leader', | 
				
			|||
                                   compute='_compute_team_head_id', | 
				
			|||
                                   help='Team Leader Name') | 
				
			|||
    assigned_user_id = fields.Many2one('res.users', string='Assigned User', | 
				
			|||
                                       domain=lambda self: [('groups_id', 'in', | 
				
			|||
                                                             self.env.ref( | 
				
			|||
                                                                 'odoo_website_helpdesk.helpdesk_user').id)], | 
				
			|||
                                       help='Assigned User Name') | 
				
			|||
    category_id = fields.Many2one('helpdesk.category', string='Category', | 
				
			|||
                                  help='Category') | 
				
			|||
    tags_ids = fields.Many2many('helpdesk.tag', help='Tags', string='Tags') | 
				
			|||
    assign_user = fields.Boolean(default=False, help='Assign User', | 
				
			|||
                                 string='Assign User') | 
				
			|||
    attachment_ids = fields.One2many('ir.attachment', 'res_id', | 
				
			|||
                                     help='Attachment Line', | 
				
			|||
                                     string='Attachments') | 
				
			|||
    merge_ticket_invisible = fields.Boolean(string='Merge Ticket', | 
				
			|||
                                            help='Merge Ticket Invisible or ' | 
				
			|||
                                                 'Not', default=False) | 
				
			|||
    merge_count = fields.Integer(string='Merge Count', help='Merged Tickets ' | 
				
			|||
                                                            'Count') | 
				
			|||
    active = fields.Boolean(default=True, help='Active', string='Active') | 
				
			|||
 | 
				
			|||
    show_create_task = fields.Boolean(string="Show Create Task", | 
				
			|||
                                      help='Show created task or not', | 
				
			|||
                                      default=_default_show_create_task, | 
				
			|||
                                      compute='_compute_show_create_task') | 
				
			|||
    create_task = fields.Boolean(string="Create Task", readonly=False, | 
				
			|||
                                 help='Create task or not', | 
				
			|||
                                 related='team_id.create_task', store=True) | 
				
			|||
    billable = fields.Boolean(string="Billable", default=False, | 
				
			|||
                              help='Is billable or not', ) | 
				
			|||
    show_category = fields.Boolean(default=_default_show_category, | 
				
			|||
                                   string="Show Category", | 
				
			|||
                                   help='Show category or not', | 
				
			|||
                                   compute='_compute_show_category') | 
				
			|||
    customer_rating = fields.Selection(RATING, default='0', readonly=True) | 
				
			|||
    review = fields.Char('Review', readonly=True, help='Ticket review') | 
				
			|||
    kanban_state = fields.Selection([ | 
				
			|||
        ('normal', 'Ready'), | 
				
			|||
        ('done', 'In Progress'), | 
				
			|||
        ('blocked', 'Blocked'), ], default='normal') | 
				
			|||
 | 
				
			|||
    @api.onchange('team_id', 'team_head_id') | 
				
			|||
    def _onchange_team_id(self): | 
				
			|||
        """Changing the team leader when selecting the team""" | 
				
			|||
        li = self.team_id.member_ids.mapped(id) | 
				
			|||
        return {'domain': {'assigned_user_id': [('id', 'in', li)]}} | 
				
			|||
 | 
				
			|||
    @api.depends('team_id') | 
				
			|||
    def _compute_team_head_id(self): | 
				
			|||
        """Compute the team head function""" | 
				
			|||
        self.team_head_id = self.team_id.team_lead_id.id | 
				
			|||
 | 
				
			|||
    @api.onchange('stage_id') | 
				
			|||
    def _onchange_stage_id(self): | 
				
			|||
        """Sending mail to the user function""" | 
				
			|||
        rec_id = self._origin.id | 
				
			|||
        data = self.env['ticket.helpdesk'].search([('id', '=', rec_id)]) | 
				
			|||
        data.last_update_date = fields.Datetime.now() | 
				
			|||
        if self.stage_id.starting_stage: | 
				
			|||
            data.start_date = fields.Datetime.now() | 
				
			|||
        if self.stage_id.closing_stage or self.stage_id.cancel_stage: | 
				
			|||
            data.end_date = fields.Datetime.now() | 
				
			|||
        if self.stage_id.template_id: | 
				
			|||
            mail_template = self.stage_id.template_id | 
				
			|||
            mail_template.send_mail(self._origin.id, force_send=True) | 
				
			|||
 | 
				
			|||
    def assign_to_teamleader(self): | 
				
			|||
        """Assigning team leader function""" | 
				
			|||
        if self.team_id: | 
				
			|||
            self.team_head_id = self.team_id.team_lead_id.id | 
				
			|||
            mail_template = self.env.ref( | 
				
			|||
                'odoo_website_helpdesk.odoo_website_helpdesk_assign') | 
				
			|||
            mail_template.sudo().write({ | 
				
			|||
                'email_to': self.team_head_id.email, | 
				
			|||
                'subject': self.name | 
				
			|||
            }) | 
				
			|||
            mail_template.sudo().send_mail(self.id, force_send=True) | 
				
			|||
        else: | 
				
			|||
            raise ValidationError("Please choose a Helpdesk Team") | 
				
			|||
 | 
				
			|||
    def _compute_show_category(self): | 
				
			|||
        """Compute show category""" | 
				
			|||
        show_category = self._default_show_category() | 
				
			|||
        for rec in self: | 
				
			|||
            rec.show_category = show_category | 
				
			|||
 | 
				
			|||
    def _compute_show_create_task(self): | 
				
			|||
        """Compute the created task""" | 
				
			|||
        show_create_task = self._default_show_create_task() | 
				
			|||
        for record in self: | 
				
			|||
            record.show_create_task = show_create_task | 
				
			|||
 | 
				
			|||
    def auto_close_ticket(self): | 
				
			|||
        """Automatically closing the ticket""" | 
				
			|||
        auto_close = self.env['ir.config_parameter'].sudo().get_param( | 
				
			|||
            'odoo_website_helpdesk.auto_close_ticket') | 
				
			|||
        if auto_close: | 
				
			|||
            no_of_days = self.env['ir.config_parameter'].sudo().get_param( | 
				
			|||
                'odoo_website_helpdesk.no_of_days') | 
				
			|||
            records = self.env['ticket.helpdesk'].search([]) | 
				
			|||
            for rec in records: | 
				
			|||
                days = (fields.Datetime.today() - rec.create_date).days | 
				
			|||
                if days >= int(no_of_days): | 
				
			|||
                    close_stage_id = self.env['ticket.stage'].search( | 
				
			|||
                        [('closing_stage', '=', True)]) | 
				
			|||
                    if close_stage_id: | 
				
			|||
                        rec.stage_id = close_stage_id | 
				
			|||
 | 
				
			|||
    def default_stage_id(self): | 
				
			|||
        """Method to return the default stage""" | 
				
			|||
        return self.env['ticket.stage'].search( | 
				
			|||
            [('name', '=', 'Draft')], limit=1).id | 
				
			|||
 | 
				
			|||
    def _read_group_stage_ids(self, stages, domain): | 
				
			|||
        """ | 
				
			|||
        return the stages to stage_ids | 
				
			|||
        """ | 
				
			|||
        stage_ids = self.env['ticket.stage'].search([]) | 
				
			|||
        return stage_ids | 
				
			|||
 | 
				
			|||
    @api.model_create_multi | 
				
			|||
    def create(self, vals_list): | 
				
			|||
        """Create function""" | 
				
			|||
        for vals in vals_list: | 
				
			|||
            if vals.get('name', _('New')) == _('New'): | 
				
			|||
                vals['name'] = self.env['ir.sequence'].next_by_code( | 
				
			|||
                    'ticket.helpdesk') | 
				
			|||
        return super(TicketHelpDesk, self).create(vals_list) | 
				
			|||
 | 
				
			|||
    def write(self, vals): | 
				
			|||
        """Write function""" | 
				
			|||
        result = super(TicketHelpDesk, self).write(vals) | 
				
			|||
        return result | 
				
			|||
 | 
				
			|||
    def action_create_invoice(self): | 
				
			|||
        """Create Invoice based on the ticket""" | 
				
			|||
        tasks = self.env['project.task'].search( | 
				
			|||
            [('project_id', '=', self.project_id.id), | 
				
			|||
             ('ticket_id', '=', self.id)]).filtered( | 
				
			|||
            lambda line: not line.ticket_billed) | 
				
			|||
        if not tasks: | 
				
			|||
            raise UserError('No Tasks to Bill') | 
				
			|||
        total = sum(x.effective_hours for x in tasks if | 
				
			|||
                     x.effective_hours > 0 and not x.some_flag) | 
				
			|||
        invoice_no = self.env['ir.sequence'].next_by_code( | 
				
			|||
            'ticket.invoice') | 
				
			|||
        self.env['account.move'].create([ | 
				
			|||
            { | 
				
			|||
                'name': invoice_no, | 
				
			|||
                'move_type': 'out_invoice', | 
				
			|||
                'partner_id': self.customer_id.id, | 
				
			|||
                'ticket_id': self.id, | 
				
			|||
                'date': fields.Date.today(), | 
				
			|||
                'invoice_date': fields.Date.today(), | 
				
			|||
                'invoice_line_ids': [(0, 0, | 
				
			|||
                                      { | 
				
			|||
                                          'product_id': self.service_product_id.id, | 
				
			|||
                                          'name': self.service_product_id.name, | 
				
			|||
                                          'quantity': total, | 
				
			|||
                                          'product_uom_id': self.service_product_id.uom_id.id, | 
				
			|||
                                          'price_unit': self.cost, | 
				
			|||
                                          'account_id': self.service_product_id.categ_id.property_account_income_categ_id.id, | 
				
			|||
                                      })], | 
				
			|||
            }, ]) | 
				
			|||
        for task in tasks: | 
				
			|||
            task.ticket_billed = True | 
				
			|||
        return { | 
				
			|||
            'effect': { | 
				
			|||
                'fadeout': 'medium', | 
				
			|||
                'message': 'Billed Successfully!', | 
				
			|||
                'type': 'rainbow_man', | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
    def action_create_tasks(self): | 
				
			|||
        """Task creation""" | 
				
			|||
        task_id = self.env['project.task'].create({ | 
				
			|||
            'name': self.name + '-' + self.subject, | 
				
			|||
            'project_id': self.project_id.id, | 
				
			|||
            'company_id': self.env.company.id, | 
				
			|||
            'ticket_id': self.id, | 
				
			|||
        }) | 
				
			|||
        self.write({ | 
				
			|||
            'task_ids': [(4, task_id.id)] | 
				
			|||
        }) | 
				
			|||
        return { | 
				
			|||
            'name': 'Tasks', | 
				
			|||
            'res_model': 'project.task', | 
				
			|||
            'view_id': False, | 
				
			|||
            'res_id': task_id.id, | 
				
			|||
            'view_mode': 'form', | 
				
			|||
            'type': 'ir.actions.act_window', | 
				
			|||
            'target': 'new', | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
    def action_open_tasks(self): | 
				
			|||
        """View the Created task """ | 
				
			|||
        return { | 
				
			|||
            'name': 'Tasks', | 
				
			|||
            'domain': [('ticket_id', '=', self.id)], | 
				
			|||
            'res_model': 'project.task', | 
				
			|||
            'view_id': False, | 
				
			|||
            'view_mode': 'list,form', | 
				
			|||
            'type': 'ir.actions.act_window', | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
    def action_open_invoices(self): | 
				
			|||
        """View the Created invoice""" | 
				
			|||
        return { | 
				
			|||
            'name': 'Invoice', | 
				
			|||
            'domain': [('ticket_id', '=', self.id)], | 
				
			|||
            'res_model': 'account.move', | 
				
			|||
            'view_id': False, | 
				
			|||
            'view_mode': 'list,form', | 
				
			|||
            'type': 'ir.actions.act_window', | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
    def action_open_merged_tickets(self): | 
				
			|||
        """Open the merged tickets list view""" | 
				
			|||
        ticket_ids = self.env['support.ticket'].search( | 
				
			|||
            [('merged_ticket', '=', self.id)]) | 
				
			|||
        helpdesk_ticket_ids = ticket_ids.mapped('display_name') | 
				
			|||
        help_ticket_records = self.env['ticket.helpdesk'].search( | 
				
			|||
            [('name', 'in', helpdesk_ticket_ids)]) | 
				
			|||
        return { | 
				
			|||
            'type': 'ir.actions.act_window', | 
				
			|||
            'name': 'Helpdesk Ticket', | 
				
			|||
            'view_mode': 'list,form', | 
				
			|||
            'res_model': 'ticket.helpdesk', | 
				
			|||
            'domain': [('id', 'in', help_ticket_records.ids)], | 
				
			|||
            'context': self.env.context, | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
    def action_send_reply(self): | 
				
			|||
        """Action to sent reply button""" | 
				
			|||
        template_id = self.env['ir.config_parameter'].sudo().get_param( | 
				
			|||
            'odoo_website_helpdesk.reply_template_id' | 
				
			|||
        ) | 
				
			|||
        template_id = self.env['mail.template'].browse(int(template_id)) | 
				
			|||
        if template_id: | 
				
			|||
            return { | 
				
			|||
                'type': 'ir.actions.act_window', | 
				
			|||
                'name': 'mail', | 
				
			|||
                'res_model': 'mail.compose.message', | 
				
			|||
                'view_mode': 'form', | 
				
			|||
                'target': 'new', | 
				
			|||
                'views': [[False, 'form']], | 
				
			|||
                'context': { | 
				
			|||
                    'default_model': 'ticket.helpdesk', | 
				
			|||
                    'default_res_ids': self.ids, | 
				
			|||
                    'default_template_id': template_id.id | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
        return { | 
				
			|||
            'type': 'ir.actions.act_window', | 
				
			|||
            'name': 'mail', | 
				
			|||
            'res_model': 'mail.compose.message', | 
				
			|||
            'view_mode': 'form', | 
				
			|||
            'target': 'new', | 
				
			|||
            'views': [[False, 'form']], | 
				
			|||
            'context': { | 
				
			|||
                'default_model': 'ticket.helpdesk', | 
				
			|||
                'default_res_ids': self.ids, | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
@ -1,110 +0,0 @@ | 
				
			|||
<odoo> | 
				
			|||
<!--    Pdf report template--> | 
				
			|||
    <template id="report_helpdesk_ticket"> | 
				
			|||
        <t t-call="web.html_container"> | 
				
			|||
            <t t-foreach="help" t-as="o"> | 
				
			|||
                <t t-call="web.external_layout"> | 
				
			|||
                    <div class="page"> | 
				
			|||
                        <div style="margin-bottom: 10px;"> | 
				
			|||
                            <div class="text-center" | 
				
			|||
                                 style="font-weight: 400 !important; font-size: 2rem !important;"> | 
				
			|||
                                <t t-esc="o.name"/> | 
				
			|||
                                - <t t-esc="o.subject"/> | 
				
			|||
                            </div><br/> | 
				
			|||
                            <table class="table table-bordered mt32"> | 
				
			|||
                                <thead> | 
				
			|||
                                    <tr> | 
				
			|||
                                        <th class="text-center"> | 
				
			|||
                                            <span>Customer :</span> | 
				
			|||
                                        </th> | 
				
			|||
                                        <th class="text-center"> | 
				
			|||
                                            <span>Description :</span> | 
				
			|||
                                        </th> | 
				
			|||
                                        <th class="text-center"> | 
				
			|||
                                            <span>Priority :</span> | 
				
			|||
                                        </th> | 
				
			|||
                                        <th class="text-center"> | 
				
			|||
                                            <span>Products :</span> | 
				
			|||
                                        </th> | 
				
			|||
                                    </tr> | 
				
			|||
                                </thead> | 
				
			|||
                                <tbody> | 
				
			|||
                                    <tr class="text-center"> | 
				
			|||
                                        <td> | 
				
			|||
                                            <span t-field="o.customer_id" | 
				
			|||
                                                  t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}'/> | 
				
			|||
                                        </td> | 
				
			|||
                                        <td> | 
				
			|||
                                            <h3 t-field="o.description"/> | 
				
			|||
                                        </td> | 
				
			|||
                                        <td> | 
				
			|||
                                            <h3 t-field="o.priority"/> | 
				
			|||
                                        </td> | 
				
			|||
                                        <td> | 
				
			|||
                                            <h3 t-field="o.product_ids"/> | 
				
			|||
                                        </td> | 
				
			|||
                                    </tr> | 
				
			|||
                                </tbody> | 
				
			|||
                            </table> | 
				
			|||
                        </div> | 
				
			|||
                        <t t-set="tasks" | 
				
			|||
                           t-value="request.env['project.task'].sudo().search([('ticket_id', '=', o.id)])"/> | 
				
			|||
 | 
				
			|||
                        <t t-if="tasks"> | 
				
			|||
                            <div> | 
				
			|||
                                <h3 class="text-center"> | 
				
			|||
                                    <strong>Tasks</strong> | 
				
			|||
                                </h3> | 
				
			|||
                            </div> | 
				
			|||
                            <table class="table table-bordered mt32"> | 
				
			|||
                                <thead> | 
				
			|||
                                    <tr> | 
				
			|||
                                        <th class="text-center"> | 
				
			|||
                                            <span>Task Name</span> | 
				
			|||
                                        </th> | 
				
			|||
                                        <th class="text-center"> | 
				
			|||
                                            <span>Analytic Account</span> | 
				
			|||
                                        </th> | 
				
			|||
                                        <th class="text-center"> | 
				
			|||
                                            <span>Assigned to</span> | 
				
			|||
                                        </th> | 
				
			|||
                                        <th class="text-center"> | 
				
			|||
                                            <span>Total Hours Spend</span> | 
				
			|||
                                        </th> | 
				
			|||
                                    </tr> | 
				
			|||
                                </thead> | 
				
			|||
                                <t t-foreach="tasks" t-as="task"> | 
				
			|||
                                    <tbody> | 
				
			|||
                                        <tr class="text-center"> | 
				
			|||
                                            <td> | 
				
			|||
                                                <span t-field="task.name"/> | 
				
			|||
                                            </td> | 
				
			|||
                                            <td> | 
				
			|||
                                                <span t-field="task.analytic_account_id"/> | 
				
			|||
                                            </td> | 
				
			|||
                                            <td> | 
				
			|||
                                                <span t-esc="', '.join(map(lambda x: (x.name), task.user_ids))"/> | 
				
			|||
                                            </td> | 
				
			|||
                                            <td> | 
				
			|||
                                                <span t-field="task.effective_hours"/> | 
				
			|||
                                            </td> | 
				
			|||
                                        </tr> | 
				
			|||
                                    </tbody> | 
				
			|||
                                </t> | 
				
			|||
                            </table> | 
				
			|||
                        </t> | 
				
			|||
                    </div> | 
				
			|||
                </t> | 
				
			|||
            </t> | 
				
			|||
        </t> | 
				
			|||
    </template> | 
				
			|||
<!--    Pdf report action--> | 
				
			|||
     <record id="action_report_helpdesk_ticket" model="ir.actions.report"> | 
				
			|||
            <field name="name">Helpdesk Ticket Report</field> | 
				
			|||
            <field name="model">help.ticket</field> | 
				
			|||
            <field name="report_type">qweb-pdf</field> | 
				
			|||
            <field name="report_name">odoo_website_helpdesk.report_helpdesk_ticket</field> | 
				
			|||
            <field name="report_file">odoo_website_helpdesk.report_helpdesk_ticket</field> | 
				
			|||
            <field name="binding_type">report</field> | 
				
			|||
        </record> | 
				
			|||
</odoo> | 
				
			|||
		
		
			
  | 
@ -0,0 +1,38 @@ | 
				
			|||
<?xml version="1.0" encoding="utf-8"?> | 
				
			|||
<odoo> | 
				
			|||
    <!-- Helpdesk Access Groups Category --> | 
				
			|||
    <record id="module_category_helpdesk" model="ir.module.category"> | 
				
			|||
        <field name="name">Helpdesk</field> | 
				
			|||
        <field name="description">Helpdesk Access Groups</field> | 
				
			|||
        <field name="sequence">20</field> | 
				
			|||
    </record> | 
				
			|||
    <!-- Helpdesk User Group --> | 
				
			|||
    <record id="helpdesk_user" model="res.groups"> | 
				
			|||
        <field name="name">User</field> | 
				
			|||
        <field name="category_id" ref="odoo_website_helpdesk.module_category_helpdesk"/> | 
				
			|||
    </record> | 
				
			|||
    <!-- Helpdesk Team Leader Group --> | 
				
			|||
    <record id="helpdesk_team_leader" model="res.groups"> | 
				
			|||
        <field name="name">Team Leader</field> | 
				
			|||
        <field name="category_id" ref="odoo_website_helpdesk.module_category_helpdesk"/> | 
				
			|||
        <field name="implied_ids" eval="[(4, ref('odoo_website_helpdesk.helpdesk_user'))]"/> | 
				
			|||
    </record> | 
				
			|||
    <!-- Helpdesk Manager Group --> | 
				
			|||
    <record id="helpdesk_manager" model="res.groups"> | 
				
			|||
        <field name="name">Manager</field> | 
				
			|||
        <field name="category_id" ref="odoo_website_helpdesk.module_category_helpdesk"/> | 
				
			|||
        <field name="implied_ids" eval="[(4, ref('odoo_website_helpdesk.helpdesk_team_leader'))]"/> | 
				
			|||
    </record> | 
				
			|||
    <!-- Group Show Category --> | 
				
			|||
    <record id="group_show_category" model="res.groups"> | 
				
			|||
        <field name="name">group_show_category</field> | 
				
			|||
    </record> | 
				
			|||
    <!-- Group Show Subcategory --> | 
				
			|||
    <record id="group_show_subcategory" model="res.groups"> | 
				
			|||
        <field name="name">group_show_subcategory</field> | 
				
			|||
    </record> | 
				
			|||
    <!-- Default User with Helpdesk Manager Group --> | 
				
			|||
    <record id="base.default_user" model="res.users"> | 
				
			|||
        <field name="groups_id" eval="[(4,ref('odoo_website_helpdesk.helpdesk_manager'))]"/> | 
				
			|||
    </record> | 
				
			|||
</odoo> | 
				
			|||
| 
		 After Width: | Height: | Size: 2.2 KiB  | 
| 
		 After Width: | Height: | Size: 28 KiB  | 
| 
		 After Width: | Height: | Size: 628 KiB  | 
| 
		 After Width: | Height: | Size: 1.1 KiB  | 
| 
		 After Width: | Height: | Size: 210 KiB  | 
| 
		 After Width: | Height: | Size: 209 KiB  | 
| 
		 After Width: | Height: | Size: 109 KiB  | 
| 
		 After Width: | Height: | Size: 495 B  | 
| 
		 After Width: | Height: | Size: 1.0 KiB  | 
| 
		 After Width: | Height: | Size: 624 B  | 
| 
		 After Width: | Height: | Size: 136 KiB  | 
| 
		 After Width: | Height: | Size: 214 KiB  | 
| 
		 After Width: | Height: | Size: 36 KiB  | 
| 
		 After Width: | Height: | Size: 929 B  | 
| 
		 After Width: | Height: | Size: 3.3 KiB  | 
| 
		 After Width: | Height: | Size: 17 KiB  | 
| 
		 After Width: | Height: | Size: 542 B  | 
| 
		 After Width: | Height: | Size: 4.3 KiB  | 
| 
		 After Width: | Height: | Size: 1.2 KiB  | 
| 
		 After Width: | Height: | Size: 4.0 KiB  | 
| 
		 After Width: | Height: | Size: 1.7 KiB  | 
| 
		 After Width: | Height: | Size: 738 KiB  | 
| 
		 After Width: | Height: | Size: 2.2 KiB  | 
| 
		 After Width: | Height: | Size: 1.2 KiB  | 
| 
		 Before Width: | Height: | Size: 3.4 KiB  | 
| 
		 After Width: | Height: | Size: 600 B  | 
| 
		 After Width: | Height: | Size: 2.0 KiB  | 
| 
		 After Width: | Height: | Size: 462 B  | 
| 
		 After Width: | Height: | Size: 2.1 KiB  | 
| 
		 After Width: | Height: | Size: 926 B  | 
| 
		 After Width: | Height: | Size: 9.0 KiB  | 
| 
		 After Width: | Height: | Size: 23 KiB  | 
| 
		 After Width: | Height: | Size: 7.0 KiB  | 
| 
		 After Width: | Height: | Size: 1.2 KiB  | 
| 
		 After Width: | Height: | Size: 800 B  | 
| 
		 After Width: | Height: | Size: 189 KiB  | 
| 
		 After Width: | Height: | Size: 4.3 KiB  | 
| 
		 After Width: | Height: | Size: 1.7 KiB  | 
| 
		 After Width: | Height: | Size: 5.9 KiB  | 
| 
		 After Width: | Height: | Size: 1.6 KiB  | 
| 
		 After Width: | Height: | Size: 34 KiB  | 
| 
		 After Width: | Height: | Size: 26 KiB  | 
| 
		 Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB  | 
| 
		 After Width: | Height: | Size: 23 KiB  | 
| 
		 After Width: | Height: | Size: 1.9 KiB  | 
| 
		 After Width: | Height: | Size: 2.3 KiB  | 
| 
		 After Width: | Height: | Size: 1.1 KiB  | 
| 
		 After Width: | Height: | Size: 3.7 KiB  | 
| 
		 Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB  | 
| 
		 After Width: | Height: | Size: 875 B  | 
| 
		 Before Width: | Height: | Size: 1.5 KiB  | 
| 
		 Before Width: | Height: | Size: 1.1 KiB  | 
| 
		 Before Width: | Height: | Size: 1.9 KiB  | 
| 
		 Before Width: | Height: | Size: 1.1 KiB  | 
| 
		 Before Width: | Height: | Size: 2.1 KiB  | 
| 
		 Before Width: | Height: | Size: 4.4 KiB  | 
| 
		 Before Width: | Height: | Size: 589 B  | 
| 
		 Before Width: | Height: | Size: 3.4 KiB  |