@ -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" ?> | 
					<?xml version="1.0" encoding="UTF-8" ?> | 
				
			||||
<odoo> | 
					<odoo> | 
				
			||||
    <data noupdate="1"> | 
					    <data noupdate="1"> | 
				
			||||
<!--        Auto close ticket--> | 
					<!--        Scheduled task (cron job) for automatically closing tickets--> | 
				
			||||
        <record id="ir_cron_auto_close_ticket" model="ir.cron"> | 
					            <record id="auto_close_ticket" model="ir.cron"> | 
				
			||||
            <field name="name">Auto Close Ticket</field> | 
					            <field name="name">Auto Close Ticket</field> | 
				
			||||
            <field name="model_id" | 
					            <field name="model_id" ref="odoo_website_helpdesk.model_ticket_helpdesk"/> | 
				
			||||
                   ref="odoo_website_helpdesk.model_help_ticket"/> | 
					 | 
				
			||||
            <field name="state">code</field> | 
					            <field name="state">code</field> | 
				
			||||
            <field name="code">model.auto_close_ticket()</field> | 
					            <field name="code">model.auto_close_ticket()</field> | 
				
			||||
            <field name="user_id" ref="base.user_root"/> | 
					            <field name="user_id" ref="base.user_root"/> | 
				
			||||
            <field name="interval_number">1</field> | 
					            <field name="interval_number">1</field> | 
				
			||||
            <field name="interval_type">days</field> | 
					            <field name="interval_type">days</field> | 
				
			||||
            <field name="numbercall">-1</field> | 
					 | 
				
			||||
        </record> | 
					        </record> | 
				
			||||
    </data> | 
					    </data> | 
				
			||||
</odoo> | 
					</odoo> | 
				
			||||
 | 
				
			|||||
@ -1,39 +1,39 @@ | 
				
			|||||
<?xml version="1.0" encoding="utf-8"?> | 
					<?xml version="1.0" encoding="utf-8"?> | 
				
			||||
<odoo> | 
					<odoo> | 
				
			||||
 | 
					    <data noupdate="1"> | 
				
			||||
        <!-- Project Stages --> | 
					        <!-- Project Stages --> | 
				
			||||
    <record id="ticket_stage_inbox" model="ticket.stage"> | 
					        <!--    - stage_inbox: Initial stage where tickets are received.--> | 
				
			||||
 | 
					        <record id="stage_inbox" model="ticket.stage"> | 
				
			||||
            <field name="sequence">10</field> | 
					            <field name="sequence">10</field> | 
				
			||||
            <field name="name">Inbox</field> | 
					            <field name="name">Inbox</field> | 
				
			||||
        </record> | 
					        </record> | 
				
			||||
<!--    Draft--> | 
					        <!--    - stage_draft: Tickets in the drafting phase.--> | 
				
			||||
    <record id="ticket_stage_draft" model="ticket.stage"> | 
					        <record id="stage_draft" model="ticket.stage"> | 
				
			||||
            <field name="sequence">15</field> | 
					            <field name="sequence">15</field> | 
				
			||||
            <field name="name">Draft</field> | 
					            <field name="name">Draft</field> | 
				
			||||
        </record> | 
					        </record> | 
				
			||||
<!--In progress--> | 
					        <!--    - stage_done: Final stage indicating completion.--> | 
				
			||||
    <record id="ticket_stage_in_progress" model="ticket.stage"> | 
					        <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="sequence">20</field> | 
				
			||||
            <field name="starting_stage" eval="True"/> | 
					            <field name="starting_stage" eval="True"/> | 
				
			||||
            <field name="name">In Progress</field> | 
					            <field name="name">In Progress</field> | 
				
			||||
        </record> | 
					        </record> | 
				
			||||
<!--Done--> | 
					        <!--    - stage_closed: Closing stage for resolved tickets.--> | 
				
			||||
    <record id="ticket_stage_done" model="ticket.stage"> | 
					        <record id="stage_closed" 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="sequence">30</field> | 
				
			||||
        <field name="name">Canceled</field> | 
					            <field name="closing_stage">True</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="name">Closed</field> | 
				
			||||
        <field name="closing_stage" eval="True"/> | 
					 | 
				
			||||
        <field name="folded" eval="True"/> | 
					 | 
				
			||||
        </record> | 
					        </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> | 
					</odoo> | 
				
			||||
@ -1,11 +1,25 @@ | 
				
			|||||
## Module <odoo_website_helpdesk> | 
					## Module <odoo_website_helpdesk> | 
				
			||||
 | 
					
 | 
				
			||||
#### 04.12.2023 | 
					#### 30.10.2024 | 
				
			||||
#### Version 16.0.1.0.0 | 
					#### Version 18.0.1.0.0 | 
				
			||||
#### ADD | 
					#### ADD | 
				
			||||
 | 
					
 | 
				
			||||
- Initial commit for Website Helpdesk Support Ticket Management | 
					- Initial commit for Website Helpdesk Support Ticket Management | 
				
			||||
 | 
					
 | 
				
			||||
#### 12.02.2025 | 
					#### 12.02.2025 | 
				
			||||
#### Version 16.0.3.0.1 | 
					#### Version 18.0.1.0.1 | 
				
			||||
#### UPDT | 
					##### UPDT | 
				
			||||
-A new contact record is created upon form submission. | 
					-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  |