summaryrefslogtreecommitdiff
path: root/sh_helpdesk/models
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 17:14:58 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 17:14:58 +0700
commit1ca3b3df3421961caec3b747a364071c80f5c7da (patch)
tree6778a1f0f3f9b4c6e26d6d87ccde16e24da6c9d6 /sh_helpdesk/models
parentb57188be371d36d96caac4b8d65a40745c0e972c (diff)
initial commit
Diffstat (limited to 'sh_helpdesk/models')
-rw-r--r--sh_helpdesk/models/__init__.py19
-rw-r--r--sh_helpdesk/models/helpdesk_alarm.py162
-rw-r--r--sh_helpdesk/models/helpdesk_category.py19
-rw-r--r--sh_helpdesk/models/helpdesk_config_settings.py109
-rw-r--r--sh_helpdesk/models/helpdesk_policies.py55
-rw-r--r--sh_helpdesk/models/helpdesk_priority.py20
-rw-r--r--sh_helpdesk/models/helpdesk_so.py18
-rw-r--r--sh_helpdesk/models/helpdesk_stages.py31
-rw-r--r--sh_helpdesk/models/helpdesk_subcategory.py22
-rw-r--r--sh_helpdesk/models/helpdesk_subject_type.py12
-rw-r--r--sh_helpdesk/models/helpdesk_tags.py25
-rw-r--r--sh_helpdesk/models/helpdesk_team.py45
-rw-r--r--sh_helpdesk/models/helpdesk_ticket.py1079
-rw-r--r--sh_helpdesk/models/helpdesk_ticket_dashboard.py21
-rw-r--r--sh_helpdesk/models/helpdesk_ticket_type.py42
-rw-r--r--sh_helpdesk/models/helpdesk_ticket_update_wizard.py87
-rw-r--r--sh_helpdesk/models/res_users.py31
-rw-r--r--sh_helpdesk/models/send_mail_quick_reply.py18
18 files changed, 1815 insertions, 0 deletions
diff --git a/sh_helpdesk/models/__init__.py b/sh_helpdesk/models/__init__.py
new file mode 100644
index 0000000..ecf1ad2
--- /dev/null
+++ b/sh_helpdesk/models/__init__.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+
+from . import helpdesk_team
+from . import helpdesk_ticket_type
+from . import helpdesk_subject_type
+from . import helpdesk_tags
+from . import helpdesk_stages
+from . import helpdesk_category
+from . import helpdesk_subcategory
+from . import helpdesk_priority
+from . import helpdesk_policies
+from . import helpdesk_config_settings
+from . import res_users
+from . import helpdesk_ticket
+from . import helpdesk_alarm
+from . import helpdesk_ticket_dashboard
+from . import send_mail_quick_reply
+from . import helpdesk_ticket_update_wizard
diff --git a/sh_helpdesk/models/helpdesk_alarm.py b/sh_helpdesk/models/helpdesk_alarm.py
new file mode 100644
index 0000000..c7231e6
--- /dev/null
+++ b/sh_helpdesk/models/helpdesk_alarm.py
@@ -0,0 +1,162 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+
+from odoo import fields, models, api, _
+from odoo.exceptions import ValidationError
+from datetime import timedelta
+
+class TicketAlarm(models.Model):
+ _name = "sh.ticket.alarm"
+ _description = "Ticket Reminder"
+
+ name = fields.Char(string="Name", readonly=True)
+ type = fields.Selection([('email', 'Email'), (
+ 'popup', 'Popup')], string="Type", required=True, default='email')
+ sh_remind_before = fields.Integer(
+ string="Reminder Before")
+ sh_reminder_unit = fields.Selection([('Hour(s)', 'Hour(s)'), (
+ 'Minute(s)', 'Minute(s)'), ('Second(s)', 'Second(s)')], string="Reminder Unit", default='Hour(s)',required=True)
+ company_id = fields.Many2one(
+ 'res.company', 'Company', default=lambda self: self.env.company)
+
+ @api.constrains('sh_remind_before')
+ def _check_sh_reminder_unit(self):
+ if self.filtered(lambda c: c.sh_reminder_unit == 'Minute(s)' and c.sh_remind_before < 5):
+ raise ValidationError(_("Reminder Before can't set less than 5 Minutes."))
+ elif self.filtered(lambda c: c.sh_reminder_unit == 'Second(s)' and c.sh_remind_before < 300):
+ raise ValidationError(_("Reminder Before can't set less than 300 Seconds."))
+ elif self.filtered(lambda c: c.sh_reminder_unit == 'Hour(s)' and c.sh_remind_before < 1):
+ raise ValidationError(_("Reminder Before can't set less than 1 Hour."))
+
+ def name_get(self):
+ # Prefetch the fields used by the `name_get`, so `browse` doesn't fetch other fields
+ self.browse(self.ids).read(['sh_remind_before', 'sh_reminder_unit','type'])
+ return [(alarm.id, '%s%s%s' % (str(alarm.sh_remind_before)+' ',str(alarm.sh_reminder_unit)+' ','['+str(alarm.type)+']'))
+ for alarm in self]
+
+ @api.onchange('sh_remind_before','type','sh_reminder_unit')
+ def _onchange_name(self):
+ for rec in self:
+ rec.name = rec.name_get()[0][1]
+
+ @api.model
+ def _run_ticket_reminder(self):
+ if self.env.company.sh_display_ticket_reminder:
+ alarm_ids = self.env['sh.ticket.alarm'].sudo().search([])
+ if alarm_ids:
+ for alarm in alarm_ids:
+ ticket_ids = self.env['helpdesk.ticket'].sudo().search([('sh_ticket_alarm_ids','in',[alarm.id])])
+ if ticket_ids:
+ for ticket in ticket_ids:
+ deadline_date = False
+ if alarm.sh_reminder_unit == 'Hour(s)' and ticket.sh_due_date:
+ deadline_date_hours_added = ticket.sh_due_date + timedelta(hours = 5,minutes=30,seconds=0)
+ deadline_date = deadline_date_hours_added - timedelta(hours = alarm.sh_remind_before)
+ elif alarm.sh_reminder_unit == 'Minute(s)' and ticket.sh_due_date:
+ deadline_date_minutes_added = ticket.sh_due_date + timedelta(hours = 5,minutes=30,seconds=0)
+ deadline_date = deadline_date_minutes_added - timedelta(minutes = alarm.sh_remind_before)
+ elif alarm.sh_reminder_unit == 'Second(s)' and ticket.sh_due_date:
+ deadline_date_seconds_added = ticket.sh_due_date + timedelta(hours = 5,minutes=30,seconds=0)
+ deadline_date = deadline_date_seconds_added - timedelta(seconds = alarm.sh_remind_before)
+ if deadline_date and deadline_date != False:
+ if alarm.type == 'popup':
+ now = fields.Datetime.now() + timedelta(hours = 5,minutes=30,seconds=0)
+ if fields.Date.today() == deadline_date.date() and deadline_date.hour == now.hour and deadline_date.minute == now.minute:
+ notifications = []
+ message="<h2><u>Ticket Information</u></h2></br>"
+ if ticket.create_date:
+ message+="<strong>Create Date :</strong>"+str(ticket.create_date) + "</br>"
+ if ticket.sh_due_date:
+ message+="<strong>Due Date :</strong>"+str(ticket.sh_due_date) + "</br>"
+ if ticket.subject_id:
+ message+="<strong>Subject :</strong>"+str(ticket.subject_id.name) + "</br>"
+ if ticket.ticket_type:
+ message+="<strong>Type :</strong>"+str(ticket.ticket_type.name) + "</br>"
+ if ticket.category_id:
+ message+="<strong>Category :</strong>"+str(ticket.category_id.name) + "</br>"
+ if ticket.sub_category_id:
+ message+="<strong>Sub Category :</strong>"+str(ticket.sub_category_id.name) + "</br>"
+ if ticket.priority:
+ message+="<strong>Priority :</strong>"+str(ticket.priority.name) + "</br>"
+ if ticket.team_id:
+ message+="<strong>Team :</strong>"+str(ticket.team_id.name) + "</br>"
+ if ticket.team_head:
+ message+="<strong>Team Head :</strong>"+str(ticket.team_head.name) + "</br>"
+ if ticket.user_id:
+ message+="<strong>Assigned To :</strong>"+str(ticket.user_id.name) + "</br>"
+ multi_users = []
+ if ticket.sh_user_ids:
+ for user in ticket.sh_user_ids:
+ if user.name not in multi_users:
+ multi_users.append(user.name)
+ if len(multi_users) > 0:
+ message+='<strong>Assigned Users : </strong>'
+ for user_name in multi_users:
+ message+='<span class="badge badge-info" style="padding-right:5px">'+str(user_name) +'</span>'
+ message+='</br>'
+ tags = []
+ if ticket.tag_ids:
+ for tag in ticket.tag_ids:
+ if tag.name not in tags:
+ tags.append(tag.name)
+ if len(tags) > 0:
+ message+='<strong>Tags : </strong>'
+ for tag_name in tags:
+ message+='<span class="badge badge-info" style="padding-right:5px">'+str(tag_name) +'</span>'
+ message+='</br>'
+ products = []
+ if ticket.product_ids:
+ for product in ticket.product_ids:
+ if product.name_get()[0][1] not in products:
+ products.append(product.name_get()[0][1])
+ if len(products) > 0:
+ message+='<strong>Products : </strong>'
+ for product_name in products:
+ message+='<span class="badge badge-info" style="padding-right:5px">'+str(product_name) +'</span>'
+ message+='</br>'
+ if ticket.partner_id:
+ message+="<strong>Partner :</strong>"+str(ticket.partner_id.name) + "</br>"
+ if ticket.person_name:
+ message+="<strong>Person Name :</strong>"+str(ticket.person_name) + "</br>"
+ if ticket.email:
+ message+="<strong>Email :</strong>"+str(ticket.email) + "</br>"
+ model_href = str(self.env['ir.config_parameter'].sudo().get_param('web.base.url')) + '/web#id='+str(ticket.id)+'&model=helpdesk.ticket&view_type=form'
+ message+="<a style='color:#7C7BAD;padding-right:10px' class='btn btn-link' data-dismiss='toast'>Close</a>"
+ message+="<a href="+str(model_href)+" target='_blank' class='btn btn-link' style='padding-right:10px;'>Ticket</a>"
+ partners=[]
+ if ticket.team_head:
+ if ticket.team_head.partner_id.id not in partners:
+ partners.append(ticket.team_head.partner_id.id)
+ if ticket.user_id:
+ if ticket.user_id.partner_id.id not in partners:
+ partners.append(ticket.user_id.partner_id.id)
+ if ticket.sh_user_ids:
+ for user_id in ticket.sh_user_ids:
+ if user_id.partner_id.id not in partners:
+ partners.append(user_id.partner_id.id)
+ if len(partners) > 0:
+ for partner_id in partners:
+ notifications.append([
+ (self._cr.dbname, 'res.partner', partner_id),
+ {'type': 'user_connection', 'title': _('Ticket Reminder '+'('+str(ticket.name)+')'), 'message': message, 'sticky': True, 'warning': False}
+ ])
+ self.env['bus.bus'].sendmany(notifications)
+ elif alarm.type == 'email':
+ now = fields.Datetime.now() + timedelta(hours = 5,minutes=30,seconds=0)
+ email_formatted=[]
+ if ticket.team_head:
+ if str(ticket.team_head.partner_id.email_formatted) not in email_formatted:
+ email_formatted.append(str(ticket.team_head.email_formatted))
+ if ticket.user_id:
+ if str(ticket.user_id.partner_id.email_formatted) not in email_formatted:
+ email_formatted.append(str(ticket.user_id.email_formatted))
+ if ticket.sh_user_ids:
+ for user_id in ticket.sh_user_ids:
+ if str(user_id.partner_id.email_formatted) not in email_formatted:
+ email_formatted.append(str(user_id.partner_id.email_formatted))
+ if fields.Date.today() == deadline_date.date() and deadline_date.hour == now.hour and deadline_date.minute == now.minute:
+ reminder_template = self.env.ref('sh_helpdesk.sh_ticket_reminder_mail_template')
+ if reminder_template and len(email_formatted) > 0:
+ emails = ','.join(email_formatted)
+ email_values = {'email_to':emails}
+ reminder_template.sudo().send_mail(ticket.id, force_send=True,email_values=email_values)
diff --git a/sh_helpdesk/models/helpdesk_category.py b/sh_helpdesk/models/helpdesk_category.py
new file mode 100644
index 0000000..acbb430
--- /dev/null
+++ b/sh_helpdesk/models/helpdesk_category.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+
+from odoo import models, fields, api
+
+
+class HelpdeskCategory(models.Model):
+ _name = 'helpdesk.category'
+ _description = 'Helpdesk Category'
+ _rec_name = 'name'
+
+ sequence = fields.Integer(string="Sequence")
+ name = fields.Char(required=True, string='Name',translate=True)
+
+ @api.model
+ def create(self, values):
+ sequence = self.env['ir.sequence'].next_by_code('helpdesk.category')
+ values['sequence'] = sequence
+ return super(HelpdeskCategory, self).create(values)
diff --git a/sh_helpdesk/models/helpdesk_config_settings.py b/sh_helpdesk/models/helpdesk_config_settings.py
new file mode 100644
index 0000000..0136499
--- /dev/null
+++ b/sh_helpdesk/models/helpdesk_config_settings.py
@@ -0,0 +1,109 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+
+from odoo import models, fields, api
+
+
+class ResCompany(models.Model):
+ _inherit = 'res.company'
+
+ category = fields.Boolean('Category')
+ sub_category = fields.Boolean('Sub Category')
+ customer_rating = fields.Boolean('Customer Rating')
+ auto_close_ticket = fields.Boolean('Auto Close Ticket')
+ close_days = fields.Integer('No of Days')
+ new_stage_id = fields.Many2one(
+ 'helpdesk.stages', string="Draft/New Stage")
+ done_stage_id = fields.Many2one('helpdesk.stages', string="Resolved Stage")
+ cancel_stage_id = fields.Many2one('helpdesk.stages', string="Cancel Stage")
+ allocation_mail_template_id = fields.Many2one(
+ 'mail.template', string='Ticket Allocation To User Mail Template')
+ reply_mail_template_id = fields.Many2one(
+ 'mail.template', string='Ticket Reply Mail Template')
+ dashboard_filter = fields.Many2many(
+ 'helpdesk.stages', 'rel_company_stage_counter', string="Dashbaord Filter", required=True)
+ dashboard_tables = fields.Many2many(
+ 'helpdesk.stages', 'rel_company_stage_tables', string="Dashbaord Tables", required=True)
+ reopen_stage_id = fields.Many2one(
+ 'helpdesk.stages', string="Re-Opened Stage")
+ close_stage_id = fields.Many2one('helpdesk.stages', string="Closed Stage")
+ sh_default_team_id = fields.Many2one(
+ 'helpdesk.team', string="Default Team")
+ sh_default_user_id = fields.Many2one(
+ 'res.users', string="Default Assign User")
+ sh_display_multi_user = fields.Boolean('Display Multi Users ?')
+ sh_configure_activate = fields.Boolean(
+ 'Manage Products')
+ sh_display_ticket_reminder = fields.Boolean('Ticket Reminder ?')
+ sh_ticket_product_detail = fields.Boolean(
+ "Ticket Product details in Message?", default=True)
+ sh_signature = fields.Boolean("Signature?", default=True)
+ sh_display_in_chatter = fields.Boolean(
+ "Display in Chatter Message?", default=True)
+ sh_pdf_in_message = fields.Boolean(
+ "Send Report URL in Message?", default=True)
+ sh_ticket_url_in_message = fields.Boolean("Send Ticket URL in Message?", default=True)
+ sh_receive_email_seeing_ticket = fields.Boolean('Get email when customer view ticket ?')
+ sh_auto_add_customer_as_follower = fields.Boolean('Auto add customer as follower when create ticket ?',default=True)
+
+
+class HelpdeskSettings(models.TransientModel):
+ _inherit = 'res.config.settings'
+
+ company_id = fields.Many2one('res.company', string='Company', required=True,
+ default=lambda self: self.env.company)
+ category = fields.Boolean(
+ string='Category', related='company_id.category', readonly=False)
+ sub_category = fields.Boolean(
+ string='Sub Category', related='company_id.sub_category', readonly=False)
+ customer_rating = fields.Boolean(
+ string='Customer Rating', related='company_id.customer_rating', readonly=False)
+ auto_close_ticket = fields.Boolean(
+ string='Auto Close Ticket', related='company_id.auto_close_ticket', readonly=False)
+ close_days = fields.Integer(
+ string='No of Days', related='company_id.close_days', readonly=False)
+ new_stage_id = fields.Many2one('helpdesk.stages', string="Draft/New Stage",
+ related='company_id.new_stage_id', readonly=False)
+ done_stage_id = fields.Many2one(
+ 'helpdesk.stages', string="Resolved Stage", related='company_id.done_stage_id', readonly=False)
+ cancel_stage_id = fields.Many2one(
+ 'helpdesk.stages', string="Cancel Stage", related='company_id.cancel_stage_id', readonly=False)
+ allocation_mail_template_id = fields.Many2one(
+ 'mail.template', string='Ticket Allocation To User Mail Template', related='company_id.allocation_mail_template_id', readonly=False)
+ reply_mail_template_id = fields.Many2one(
+ 'mail.template', string='Ticket Reply Mail Template', related='company_id.reply_mail_template_id', readonly=False)
+ dashboard_filter = fields.Many2many('helpdesk.stages', 'rel_company_stage_counter',
+ string="Dashbaord Filter", related="company_id.dashboard_filter", readonly=False, required=True)
+ dashboard_tables = fields.Many2many('helpdesk.stages', 'rel_company_stage_tables',
+ string="Dashbaord Tables", related="company_id.dashboard_tables", readonly=False, required=True)
+ reopen_stage_id = fields.Many2one(
+ 'helpdesk.stages', string="Re-Opened Stage", readonly=False, related='company_id.reopen_stage_id')
+ close_stage_id = fields.Many2one(
+ 'helpdesk.stages', string="Closed Stage", readonly=False, related='company_id.close_stage_id')
+ sh_default_team_id = fields.Many2one(
+ 'helpdesk.team', string="Default Team", readonly=False, related='company_id.sh_default_team_id')
+ sh_default_user_id = fields.Many2one(
+ 'res.users', string="Default Assign User", readonly=False, related='company_id.sh_default_user_id')
+ sh_display_multi_user = fields.Boolean(
+ 'Display Multi Users ?', related='company_id.sh_display_multi_user', readonly=False)
+ sh_configure_activate = fields.Boolean(
+ 'Manage Products', related='company_id.sh_configure_activate', readonly=False)
+ sh_display_ticket_reminder = fields.Boolean('Ticket Reminder ?',related='company_id.sh_display_ticket_reminder',readonly=False)
+ sh_ticket_product_detail = fields.Boolean(
+ "Ticket Product details in Message?",related='company_id.sh_ticket_product_detail',readonly=False)
+ sh_signature = fields.Boolean("Signature?",related='company_id.sh_signature',readonly=False)
+ sh_display_in_chatter = fields.Boolean(
+ "Display in Chatter Message?",related='company_id.sh_display_in_chatter',readonly=False)
+ sh_pdf_in_message = fields.Boolean(
+ "Send Report URL in Message?",related='company_id.sh_pdf_in_message',readonly=False)
+ sh_ticket_url_in_message = fields.Boolean("Send Ticket URL in Message?",related='company_id.sh_ticket_url_in_message',readonly=False)
+ sh_receive_email_seeing_ticket = fields.Boolean('Get email when customer view ticket ?',related='company_id.sh_receive_email_seeing_ticket',readonly=False)
+ sh_auto_add_customer_as_follower = fields.Boolean('Auto add customer as follower when create ticket ?',related='company_id.sh_auto_add_customer_as_follower',readonly=False)
+
+ @ api.onchange('sh_default_team_id')
+ def onchange_sh_default_team_id(self):
+ if self.sh_default_team_id:
+ domain = {}
+ domain = {'sh_default_user_id': [
+ ('id', 'in', self.sh_default_team_id.team_members.ids)]}
+ return {'domain': domain}
diff --git a/sh_helpdesk/models/helpdesk_policies.py b/sh_helpdesk/models/helpdesk_policies.py
new file mode 100644
index 0000000..6efa762
--- /dev/null
+++ b/sh_helpdesk/models/helpdesk_policies.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+
+from odoo import models, fields
+
+
+class HelpdeskSLAPolicies(models.Model):
+ _name = 'sh.helpdesk.sla'
+ _description = 'Helpdesk SLA Policies'
+
+ def get_deafult_company(self):
+ company_id = self.env.company
+ return company_id
+
+ name = fields.Char('Name',required=True)
+ sh_team_id = fields.Many2one('helpdesk.team','Helpdesk Team',required=True)
+ sh_ticket_type_id = fields.Many2one('helpdesk.ticket.type','Helpdesk Team Type')
+ sh_sla_target_type = fields.Selection([('reaching_stage','Reaching Stage'),('assign_to','Assigned To')],default='reaching_stage',string='SLA Target Type')
+ sh_stage_id = fields.Many2one('helpdesk.stages',string='Reach Stage')
+ sh_days = fields.Integer('Days',required=True)
+ sh_hours = fields.Integer('Hours',required=True)
+ sh_minutes = fields.Integer('Minutes',required=True)
+ company_id = fields.Many2one(
+ 'res.company', string="Company", default=get_deafult_company)
+ sla_ticket_count = fields.Integer(compute='_compute_helpdesk_ticket_sla')
+
+ def _compute_helpdesk_ticket_sla(self):
+ for record in self:
+ record.sla_ticket_count = 0
+ tickets = self.env['helpdesk.ticket'].search(
+ [('sh_sla_policy_ids', 'in', self.ids)], limit=None)
+ record.sla_ticket_count = len(tickets.ids)
+
+
+ def action_view_tickets(self):
+ self.ensure_one()
+ tickets = self.env['helpdesk.ticket'].sudo().search(
+ [('sh_sla_policy_ids', 'in', self.ids)])
+ action = self.env["ir.actions.actions"]._for_xml_id(
+ "sh_helpdesk.helpdesk_ticket_action")
+ if len(tickets) > 1:
+ action['domain'] = [('id', 'in', tickets.ids)]
+ elif len(tickets) == 1:
+ form_view = [
+ (self.env.ref('sh_helpdesk.helpdesk_ticket_form_view').id, 'form')]
+ if 'views' in action:
+ action['views'] = form_view + \
+ [(state, view)
+ for state, view in action['views'] if view != 'form']
+ else:
+ action['views'] = form_view
+ action['res_id'] = tickets.id
+ else:
+ action = {'type': 'ir.actions.act_window_close'}
+ return action \ No newline at end of file
diff --git a/sh_helpdesk/models/helpdesk_priority.py b/sh_helpdesk/models/helpdesk_priority.py
new file mode 100644
index 0000000..de1bf78
--- /dev/null
+++ b/sh_helpdesk/models/helpdesk_priority.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+
+from odoo import models, fields, api
+
+
+class HelpdeskPriority(models.Model):
+ _name = 'helpdesk.priority'
+ _description = 'Helpdesk Priority'
+ _rec_name = 'name'
+
+ sequence = fields.Integer(string="Sequence")
+ name = fields.Char(required=True, translate=True, string="Name")
+ color = fields.Char(string="Color")
+
+ @api.model
+ def create(self, values):
+ sequence = self.env['ir.sequence'].next_by_code('helpdesk.priority')
+ values['sequence'] = sequence
+ return super(HelpdeskPriority, self).create(values)
diff --git a/sh_helpdesk/models/helpdesk_so.py b/sh_helpdesk/models/helpdesk_so.py
new file mode 100644
index 0000000..07806e9
--- /dev/null
+++ b/sh_helpdesk/models/helpdesk_so.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+
+from odoo import models, fields, api, _
+import random
+import datetime
+from odoo.exceptions import UserError
+from odoo.tools import email_re
+
+
+class HelpdeskSO(models.Model):
+ _name = 'sh.helpdesk.so'
+ _inherit = ['portal.mixin', 'mail.thread', 'mail.activity.mixin']
+ _description = "Helpdesk Sale Order"
+
+
+
+
diff --git a/sh_helpdesk/models/helpdesk_stages.py b/sh_helpdesk/models/helpdesk_stages.py
new file mode 100644
index 0000000..66e4023
--- /dev/null
+++ b/sh_helpdesk/models/helpdesk_stages.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+
+from odoo import models, fields
+
+
+class HelpdeskStages(models.Model):
+ _name = 'helpdesk.stages'
+ _description = "Helpdesk Stages"
+ _order = 'sequence ASC'
+ _rec_name = 'name'
+
+ name = fields.Char("Name", required=True,translate=True)
+ mail_template_ids = fields.Many2many(
+ 'mail.template', string='Mail Template')
+ sh_next_stage = fields.Many2one(
+ comodel_name='helpdesk.stages',
+ string='Next Stage',
+ )
+
+ sh_group_ids = fields.Many2many(
+ comodel_name='res.groups',
+ string='Groups'
+ )
+ is_cancel_button_visible = fields.Boolean(
+ string='Is Cancel Button Visible ?'
+ )
+ is_done_button_visible = fields.Boolean(
+ string='Is Resolved Button Visible ?'
+ )
+ sequence = fields.Integer(string="Sequence")
diff --git a/sh_helpdesk/models/helpdesk_subcategory.py b/sh_helpdesk/models/helpdesk_subcategory.py
new file mode 100644
index 0000000..1dea790
--- /dev/null
+++ b/sh_helpdesk/models/helpdesk_subcategory.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+
+from odoo import models, fields, api
+
+
+class HelpdeskSubCategory(models.Model):
+ _name = 'helpdesk.subcategory'
+ _description = 'Helpdesk SubCategory'
+ _rec_name = 'name'
+
+ sequence = fields.Integer(string="Sequence")
+ name = fields.Char(required=True, translate=True,
+ string='Sub Category Name')
+ parent_category_id = fields.Many2one(
+ 'helpdesk.category', required=True, string="Parent Category")
+
+ @api.model
+ def create(self, values):
+ sequence = self.env['ir.sequence'].next_by_code('helpdesk.subcategory')
+ values['sequence'] = sequence
+ return super(HelpdeskSubCategory, self).create(values)
diff --git a/sh_helpdesk/models/helpdesk_subject_type.py b/sh_helpdesk/models/helpdesk_subject_type.py
new file mode 100644
index 0000000..b5c4174
--- /dev/null
+++ b/sh_helpdesk/models/helpdesk_subject_type.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+
+from odoo import models, fields
+
+
+class HelpdeskSubjectType(models.Model):
+ _name = 'helpdesk.sub.type'
+ _description = 'Helpdesk Subject Type'
+ _rec_name = 'name'
+
+ name = fields.Char('Name', required=True,translate=True)
diff --git a/sh_helpdesk/models/helpdesk_tags.py b/sh_helpdesk/models/helpdesk_tags.py
new file mode 100644
index 0000000..876ca08
--- /dev/null
+++ b/sh_helpdesk/models/helpdesk_tags.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+
+from odoo import models, fields, api
+import random
+
+
+class HelpdeskTags(models.Model):
+ _name = 'helpdesk.tags'
+ _description = 'Helpdesk Tags'
+ _rec_name = 'name'
+
+ name = fields.Char("Name", required=True,translate=True)
+ color = fields.Integer(string='Color Index')
+
+ _sql_constraints = [
+ ('name_uniq', 'unique (name)', "Tag name already exists!"),
+ ]
+
+ @api.model
+ def create(self, vals):
+ res = super(HelpdeskTags, self).create(vals)
+ number = random.randrange(1, 10)
+ res.color = number
+ return res
diff --git a/sh_helpdesk/models/helpdesk_team.py b/sh_helpdesk/models/helpdesk_team.py
new file mode 100644
index 0000000..437cd67
--- /dev/null
+++ b/sh_helpdesk/models/helpdesk_team.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+
+from odoo import models, fields
+
+
+class HelpdeskTeam(models.Model):
+ _name = 'helpdesk.team'
+ _description = 'Helpdesk Team'
+ _rec_name = 'name'
+
+ name = fields.Char('Name', required=True,translate=True)
+ team_head = fields.Many2one('res.users', 'Team Head', required=True,domain=['|',('share','=',False),('sh_portal_user_access','!=',False)])
+ team_members = fields.Many2many('res.users', string="Team Members",domain=['|',('share','=',False),('sh_portal_user_access','!=',False)])
+ sh_resource_calendar_id = fields.Many2one('resource.calendar',string="Working Schedule",required=True,default=lambda self: self.env.company.resource_calendar_id)
+ sla_count = fields.Integer(compute='_compute_helpdesk_sla')
+
+ def _compute_helpdesk_sla(self):
+ for record in self:
+ record.sla_count = 0
+ slas = self.env['helpdesk.ticket'].sudo().search(
+ [('team_id', '=', self.id),('sh_sla_status_ids','!=',False)])
+ record.sla_count = len(slas.ids)
+
+ def action_view_sla(self):
+ self.ensure_one()
+ slas = self.env['helpdesk.ticket'].sudo().search(
+ [('team_id', '=', self.id),('sh_sla_status_ids','!=',False)])
+ action = self.env["ir.actions.actions"]._for_xml_id(
+ "sh_helpdesk.helpdesk_ticket_action")
+ if len(slas) > 1:
+ action['domain'] = [('id', 'in', slas.ids)]
+ elif len(slas) == 1:
+ form_view = [
+ (self.env.ref('sh_helpdesk.helpdesk_ticket_form_view').id, 'form')]
+ if 'views' in action:
+ action['views'] = form_view + \
+ [(state, view)
+ for state, view in action['views'] if view != 'form']
+ else:
+ action['views'] = form_view
+ action['res_id'] = slas.id
+ else:
+ action = {'type': 'ir.actions.act_window_close'}
+ return action \ No newline at end of file
diff --git a/sh_helpdesk/models/helpdesk_ticket.py b/sh_helpdesk/models/helpdesk_ticket.py
new file mode 100644
index 0000000..a2bcb45
--- /dev/null
+++ b/sh_helpdesk/models/helpdesk_ticket.py
@@ -0,0 +1,1079 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+
+from odoo import models, fields, api, _, SUPERUSER_ID
+import random
+from datetime import timedelta
+from odoo.exceptions import UserError
+from odoo.tools import email_re
+import uuid
+
+
+class HelpdeskSLAStatus(models.Model):
+ _name = 'sh.helpdesk.sla.status'
+ _description = "Helpdesk Ticket SLA Status"
+ _table = 'sh_helpdesk_sla_status'
+ _order = 'id ASC'
+ _rec_name = 'sh_sla_id'
+
+ sh_ticket_id = fields.Many2one('helpdesk.ticket',
+ string='Ticket',
+ required=True,
+ ondelete='cascade',
+ index=True)
+ sh_sla_id = fields.Many2one('sh.helpdesk.sla',
+ required=True,
+ ondelete='cascade')
+ sh_sla_stage_id = fields.Many2one('helpdesk.stages',
+ related='sh_sla_id.sh_stage_id',
+ store=True)
+ sh_deadline = fields.Datetime("SLA Deadline",
+ compute='_compute_sh_deadline',
+ compute_sudo=True,
+ store=True)
+ sh_status = fields.Selection([('sla_failed', 'Failed'),
+ ('sla_passed', 'Passed'),
+ ('sh_partially_passed', 'Partially Passed')],
+ string="Status")
+ color = fields.Integer("Color Index", compute='_compute_sh_color')
+ sh_done_sla_date = fields.Datetime('SLA Done Date')
+
+ @api.depends('sh_ticket_id.create_date', 'sh_sla_id')
+ def _compute_sh_deadline(self):
+ for rec in self:
+ sla_deadline = rec.sh_ticket_id.create_date
+ working_schedule = rec.sh_ticket_id.team_id.sh_resource_calendar_id
+ if not working_schedule:
+ rec.sh_deadline = sla_deadline
+ continue
+ if rec.sh_sla_id.sh_days > 0:
+ sla_deadline = working_schedule.plan_days(
+ rec.sh_sla_id.sh_days + 1,
+ sla_deadline,
+ compute_leaves=True)
+ ticket_create_dt = rec.sh_ticket_id.create_date
+ sla_deadline = sla_deadline.replace(
+ hour=ticket_create_dt.hour,
+ minute=ticket_create_dt.minute,
+ second=ticket_create_dt.second,
+ microsecond=ticket_create_dt.microsecond)
+ rec.sh_deadline = working_schedule.plan_hours(
+ rec.sh_sla_id.sh_hours, sla_deadline, compute_leaves=True)
+
+ @api.depends('sh_status')
+ def _compute_sh_color(self):
+ for rec in self:
+ rec._compute_sh_deadline()
+ if rec.sh_status == 'sla_failed':
+ rec.color = 1
+ elif rec.sh_status == 'sla_passed':
+ rec.color = 10
+ elif rec.sh_status == 'sh_partially_passed':
+ rec.color = 4
+ else:
+ rec.color = 0
+
+
+class HelpdeskTicket(models.Model):
+ _name = 'helpdesk.ticket'
+ _inherit = ['portal.mixin', 'mail.thread', 'mail.activity.mixin']
+ _description = "Helpdesk Ticket"
+ _order = 'id DESC'
+ _rec_name = 'name'
+ _primary_email = ['email']
+
+ def get_deafult_company(self):
+ company_id = self.env.company
+ return company_id
+
+ @api.model
+ def get_default_stage(self):
+ company_id = self.env.company
+ stage_id = self.env['helpdesk.stages'].sudo().search(
+ [('id', '=', company_id.new_stage_id.id)], limit=1)
+ return stage_id.id
+
+ @api.model
+ def default_due_date(self):
+ return fields.Datetime.now()
+
+ name = fields.Char("Name", tracking=True)
+ company_id = fields.Many2one('res.company',
+ string="Company",
+ default=get_deafult_company)
+ done_stage_boolean = fields.Boolean('Done Stage',
+ compute='_compute_stage_booleans',
+ store=True)
+ cancel_stage_boolean = fields.Boolean('Cancel Stage',
+ compute='_compute_stage_booleans',
+ store=True)
+ reopen_stage_boolean = fields.Boolean('Reopened Stage',
+ compute='_compute_stage_booleans',
+ store=True)
+ closed_stage_boolean = fields.Boolean('Closed Stage',
+ compute='_compute_stage_booleans',
+ store=True)
+ open_boolean = fields.Boolean('Open Ticket',
+ compute='_compute_stage_booleans',
+ store=True)
+ cancel_button_boolean = fields.Boolean(
+ "Cancel Button",
+ compute='_compute_cancel_button_boolean',
+ search='_search_cancel_button_boolean')
+ done_button_boolean = fields.Boolean(
+ "Done Button",
+ compute='_compute_done_button_boolean',
+ search='_search_done_button_boolean')
+ state = fields.Selection([('customer_replied', 'Customer Replied'),
+ ('staff_replied', 'Staff Replied')],
+ string="Replied Status",
+ default='customer_replied',
+ required=True,
+ tracking=True)
+ active = fields.Boolean(
+ 'Active',
+ default=True,
+ help=
+ "If unchecked, it will allow you to hide the product without removing it."
+ )
+ ticket_from_website = fields.Boolean('Ticket From Website')
+ ticket_from_portal = fields.Boolean('Ticket From Portal')
+ cancel_reason = fields.Char("Cancel Reason", tracking=True, translate=True)
+ tag_ids = fields.Many2many('helpdesk.tags', string="Tags")
+ priority = fields.Many2one('helpdesk.priority',
+ string='Priority',
+ tracking=True)
+ stage_id = fields.Many2one('helpdesk.stages',
+ string="Stage",
+ default=get_default_stage,
+ tracking=True,
+ index=True,
+ group_expand='_read_group_stage_ids')
+ ticket_type = fields.Many2one('helpdesk.ticket.type',
+ string='Ticket Type',
+ tracking=True)
+ team_id = fields.Many2one('helpdesk.team', string='Team', tracking=True)
+ team_head = fields.Many2one('res.users', "Team Head", tracking=True)
+ user_id = fields.Many2one('res.users',
+ string="Assigned User",
+ tracking=True)
+ subject_id = fields.Many2one('helpdesk.sub.type',
+ string='Ticket Subject Type',
+ tracking=True)
+ category_id = fields.Many2one('helpdesk.category',
+ string="Category",
+ tracking=True)
+ sub_category_id = fields.Many2one('helpdesk.subcategory',
+ string="Sub Category")
+ partner_id = fields.Many2one('res.partner',
+ string='Partner',
+ tracking=True,
+ required=True)
+ person_name = fields.Char(string='Person Name', tracking=True)
+ email = fields.Char(string='Email', tracking=True)
+ close_date = fields.Datetime(string='Close Date', tracking=True)
+ close_by = fields.Many2one('res.users', string='Closed By', tracking=True)
+ cancel_date = fields.Datetime(string='Cancelled Date', tracking=True)
+ cancel_by = fields.Many2one('res.users',
+ string='Cancelled By',
+ tracking=True)
+ replied_date = fields.Datetime('Replied Date', tracking=True)
+ product_ids = fields.Many2many('product.product', string='Products')
+
+ comment = fields.Text(string="Comment", tracking=True, translate=True)
+ description = fields.Html('Description', tracking=True)
+ color = fields.Integer(string='Color Index')
+ priority_new = fields.Selection([('1', 'Very Low'), ('2', 'Low'),
+ ('3', 'Normal'), ('4', 'High'),
+ ('5', 'Very High'), ('6', 'Excellent')],
+ string="Customer Rating",
+ tracking=True)
+ customer_comment = fields.Text("Customer Comment", tracking=True)
+
+ attachment_ids = fields.Many2many('ir.attachment', string="Attachments")
+ form_url = fields.Char('Form Url', compute='_compute_form_url')
+ category_bool = fields.Boolean(string='Category Setting',
+ related='company_id.category',
+ store=True)
+ sub_category_bool = fields.Boolean(string='Sub Category Setting',
+ related='company_id.sub_category',
+ store=True)
+ rating_bool = fields.Boolean(string='Rating Setting',
+ related='company_id.customer_rating',
+ store=True)
+ ticket_allocated = fields.Boolean("Allocated")
+ sh_user_ids = fields.Many2many('res.users', string="Assign Multi Users")
+ sh_display_multi_user = fields.Boolean(
+ compute="_compute_sh_display_multi_user")
+ sh_display_product = fields.Boolean(compute='_compute_sh_display_product')
+ sh_status = fields.Selection([('sla_failed', 'Failed'),
+ ('sla_passed', 'Passed'),
+ ('sh_partially_passed', 'Partially Passed')],
+ string="Status")
+ sh_sla_policy_ids = fields.Many2many('sh.helpdesk.sla',
+ 'sh_helpdesk_sla_status',
+ 'sh_ticket_id',
+ 'sh_sla_id',
+ string="Helpdesk SLA Policies",
+ copy=False)
+ sh_sla_status_ids = fields.One2many('sh.helpdesk.sla.status',
+ 'sh_ticket_id',
+ string="Helpdesk SLA Status")
+ sh_sla_deadline = fields.Datetime('SLA Deadline',
+ compute='_compute_sh_sla_deadline',
+ store=True)
+ sh_status_boolean = fields.Boolean(compute='_compute_state_boolean')
+ sh_days_to_reach = fields.Float(string='SLA reached duration',
+ compute='_compute_days_to_reach',
+ store=True)
+ sh_days_to_late = fields.Float(string='SLA late duration',
+ compute='_compute_days_to_late',
+ store=True)
+ sh_due_date = fields.Datetime('Reminder Due Date',
+ default=default_due_date)
+ sh_ticket_alarm_ids = fields.Many2many('sh.ticket.alarm',
+ string='Ticket Reminders')
+ sh_ticket_report_url = fields.Char(compute='_compute_report_url')
+ report_token = fields.Char("Access Token")
+ portal_ticket_url_wp = fields.Char(compute='_compute_ticket_portal_url_wp')
+ mobile_no = fields.Char('Mobile')
+ email_subject = fields.Char('Subject')
+
+ # <-- MULTI ACTION FOR MASS UPDATE ASSIGN-TO,MULTI-USER & STATE // ADD/REMOVE FOLLOWER-->
+
+ def action_mass_update_wizard(self):
+ return {
+ 'name':
+ 'Mass Update Ticket',
+ 'res_model':
+ 'sh.helpdesk.ticket.mass.update.wizard',
+ 'view_mode':
+ 'form',
+ 'context': {
+ 'default_helpdesks_ticket_ids':
+ [(6, 0, self.env.context.get('active_ids'))],
+ 'default_check_sh_display_multi_user':
+ self.env.user.company_id.sh_display_multi_user
+ },
+ 'view_id':
+ self.env.ref(
+ 'sh_helpdesk.sh_helpdesk_ticket_mass_update_wizard_form_view').
+ id,
+ 'target':
+ 'new',
+ 'type':
+ 'ir.actions.act_window'
+ }
+
+ @api.model
+ def _read_group_stage_ids(self, stages, domain, order):
+ all_stages = self.env['helpdesk.stages'].sudo().search([])
+ search_domain = [('id', 'in', all_stages.ids)]
+
+ # perform search
+ stage_ids = stages._search(search_domain,
+ order=order,
+ access_rights_uid=SUPERUSER_ID)
+ return stages.browse(stage_ids)
+
+ def _search_done_button_boolean(self, operator, value):
+ not_done_ids = []
+ done_ids = []
+ for record in self.search([]):
+ if record.stage_id.is_done_button_visible:
+ done_ids.append(record.id)
+ else:
+ not_done_ids.append(record.id)
+ if operator == '=':
+ return [('id', 'in', done_ids)]
+ elif operator == '!=':
+ return [('id', 'in', not_done_ids)]
+ else:
+ return []
+
+ def _search_cancel_button_boolean(self, operator, value):
+ not_cancel_ids = []
+ cancel_ids = []
+ for record in self.search([]):
+ if record.stage_id.is_cancel_button_visible:
+ cancel_ids.append(record.id)
+ else:
+ not_cancel_ids.append(record.id)
+ if operator == '=':
+ return [('id', 'in', cancel_ids)]
+ elif operator == '!=':
+ return [('id', 'in', not_cancel_ids)]
+ else:
+ return []
+
+ def _compute_ticket_portal_url_wp(self):
+ for rec in self:
+ rec.portal_ticket_url_wp = False
+ if rec.company_id.sh_pdf_in_message:
+ base_url = self.env['ir.config_parameter'].sudo().get_param(
+ 'web.base.url')
+ ticket_url = base_url + rec.get_portal_url()
+ self.sudo().write({'portal_ticket_url_wp': ticket_url})
+
+ def _get_token(self):
+ """ Get the current record access token """
+ if self.report_token:
+ return self.report_token
+ else:
+ report_token = str(uuid.uuid4())
+ self.write({'report_token': report_token})
+ return report_token
+
+ def get_download_report_url(self):
+ url = ''
+ if self.id:
+ self.ensure_one()
+ url = '/download/ht/' + '%s?access_token=%s' % (self.id,
+ self._get_token())
+ return url
+
+ def _compute_report_url(self):
+ for rec in self:
+ rec.sh_ticket_report_url = False
+ if rec.company_id.sh_pdf_in_message:
+ base_url = self.env['ir.config_parameter'].sudo().get_param(
+ 'web.base.url')
+ ticket_url = "%0A%0A Click here to download Ticket Document : %0A" + \
+ base_url+rec.get_download_report_url()
+ self.sudo().write({
+ 'sh_ticket_report_url':
+ base_url + rec.get_download_report_url()
+ })
+
+ def action_send_whatsapp(self):
+ self.ensure_one()
+ if not self.partner_id.mobile:
+ raise UserError(_("Partner Mobile Number Not Exist !"))
+ template = self.env.ref('sh_helpdesk.sh_send_whatsapp_email_template')
+
+ ctx = {
+ 'default_model': 'helpdesk.ticket',
+ 'default_res_id': self.ids[0],
+ 'default_use_template': bool(template.id),
+ 'default_template_id': template.id,
+ 'default_composition_mode': 'comment',
+ 'custom_layout': "mail.mail_notification_paynow",
+ 'force_email': True,
+ 'default_is_wp': True,
+ }
+ attachment_ids = self.env['ir.attachment'].sudo().search([
+ ('res_model', '=', 'helpdesk.ticket'),
+ ('res_id', '=', str(self.id))
+ ])
+ if attachment_ids:
+ ctx.update({'attachment_ids': [(6, 0, attachment_ids.ids)]})
+ return {
+ 'type': 'ir.actions.act_window',
+ 'view_mode': 'form',
+ 'res_model': 'mail.compose.message',
+ 'views': [(False, 'form')],
+ 'view_id': False,
+ 'target': 'new',
+ 'context': ctx,
+ }
+
+ def _compute_days_to_reach(self):
+ if self:
+ for rec in self:
+ sh_days_to_reach = 0.0
+ if rec.sh_sla_status_ids:
+ for line in rec.sh_sla_status_ids:
+ if line.sh_deadline and line.sh_done_sla_date:
+ delta = line.sh_done_sla_date - line.sh_deadline
+ sh_days_to_reach += delta.days
+ rec.sh_days_to_reach = sh_days_to_reach
+
+ def _compute_days_to_late(self):
+ if self:
+ for rec in self:
+ sh_days_to_late = 0.0
+ if rec.sh_sla_status_ids:
+ for line in rec.sh_sla_status_ids:
+ if line.sh_deadline and line.sh_done_sla_date:
+ delta = line.sh_done_sla_date - line.sh_deadline
+ sh_days_to_late += delta.days
+ rec.sh_days_to_late = sh_days_to_late
+
+ def _compute_state_boolean(self):
+ if self:
+ for rec in self:
+ rec.sh_status_boolean = False
+ sla_passed = rec.sh_sla_status_ids.filtered(
+ lambda x: x.sh_status == 'sla_passed')
+ sla_failed = rec.sh_sla_status_ids.filtered(
+ lambda x: x.sh_status == 'sla_failed')
+ if sla_passed and sla_failed:
+ rec.sh_status = 'sh_partially_passed'
+
+ @api.depends('sh_sla_status_ids.sh_deadline')
+ def _compute_sh_sla_deadline(self):
+ for rec in self:
+ sh_deadline = False
+ status_ids = rec.sh_sla_status_ids.filtered(
+ lambda x: x.sh_status == False)
+ rec.sh_sla_deadline = min(status_ids.mapped(
+ 'sh_deadline')) if status_ids else sh_deadline
+
+ @api.model
+ def change_sh_status(self):
+ self.ensure_one()
+ if self.sh_sla_status_ids:
+ for line in self.sh_sla_status_ids:
+ if line.sh_sla_id and line.sh_sla_id.sh_sla_target_type == 'reaching_stage':
+ if line.sh_sla_id.sh_stage_id.id == self.stage_id.id:
+ line.sh_done_sla_date = fields.Datetime.now()
+ line.sh_status = False
+ self.sh_status = False
+ if line.sh_done_sla_date and line.sh_deadline:
+ line.sh_status = 'sla_passed' if line.sh_done_sla_date < line.sh_deadline else 'sla_failed'
+ self.sh_status = 'sla_passed' if line.sh_done_sla_date < line.sh_deadline else 'sla_failed'
+ else:
+ line.sh_status = False if (
+ not line.sh_deadline or line.sh_deadline >
+ fields.Datetime.now()) else 'sla_failed'
+ self.sh_status = False if (
+ not line.sh_deadline or line.sh_deadline >
+ fields.Datetime.now()) else 'sla_failed'
+ elif line.sh_sla_id and line.sh_sla_id.sh_sla_target_type == 'assign_to':
+ if self.user_id or self.sh_user_ids:
+ line.sh_done_sla_date = fields.Datetime.now()
+ line.sh_status = False
+ self.sh_status = False
+ if line.sh_done_sla_date and line.sh_deadline:
+ line.sh_status = 'sla_passed' if line.sh_done_sla_date < line.sh_deadline else 'sla_failed'
+ self.sh_status = 'sla_passed' if line.sh_done_sla_date < line.sh_deadline else 'sla_failed'
+ else:
+ line.sh_status = False if (
+ not line.sh_deadline or line.sh_deadline >
+ fields.Datetime.now()) else 'sla_failed'
+ self.sh_status = False if (
+ not line.sh_deadline or line.sh_deadline >
+ fields.Datetime.now()) else 'sla_failed'
+
+ @api.onchange('team_id', 'ticket_type')
+ def _onchange_sh_helpdesk_policy_ids(self):
+ if self:
+ for rec in self:
+ rec.sh_sla_policy_ids = [
+ (6, 0,
+ rec.helpdesk_sla_create(rec.team_id.id,
+ rec.ticket_type.id))
+ ]
+
+ @api.depends('company_id')
+ def _compute_sh_display_multi_user(self):
+ if self:
+ for rec in self:
+ rec.sh_display_multi_user = False
+ if rec.company_id and rec.company_id.sh_display_multi_user:
+ rec.sh_display_multi_user = True
+
+ @api.depends('company_id')
+ def _compute_sh_display_product(self):
+ if self:
+ for rec in self:
+ rec.sh_display_product = False
+ if rec.company_id and rec.company_id.sh_configure_activate:
+ rec.sh_display_product = True
+
+ @api.model
+ def message_new(self, msg_dict, custom_values=None):
+ """ Overrides mail_thread message_new that is called by the mailgateway
+ through message_process.
+ This override updates the document according to the email.
+ """
+ defaults = {
+ 'email': msg_dict.get('from'),
+ 'partner_id': msg_dict.get('author_id', False),
+ 'description': msg_dict.get('body'),
+ 'email_subject': msg_dict.get('subject') or _("No Subject"),
+ 'state': 'customer_replied',
+ 'replied_date': msg_dict.get('date')
+ }
+
+ return super(HelpdeskTicket, self).message_new(msg_dict,
+ custom_values=defaults)
+
+ def _message_post_after_hook(self, message, msg_vals):
+ if self.email and not self.partner_id:
+ # we consider that posting a message with a specified recipient (not a follower, a specific one)
+ # on a document without customer means that it was created through the chatter using
+ # suggested recipients. This heuristic allows to avoid ugly hacks in JS.
+ new_partner = message.partner_ids.filtered(
+ lambda partner: partner.email == self.email)
+ if new_partner:
+ self.search([
+ ('partner_id', '=', False),
+ ('email', '=', new_partner.email),
+ ]).write({'partner_id': new_partner.id})
+
+ return super(HelpdeskTicket,
+ self)._message_post_after_hook(message, msg_vals)
+
+ def _compute_form_url(self):
+ if self:
+ base_url = self.env['ir.config_parameter'].sudo().get_param(
+ 'web.base.url')
+ url_str = ''
+ action = self.env.ref('sh_helpdesk.helpdesk_ticket_action').id
+ if base_url:
+ url_str += str(base_url) + '/web#'
+ for rec in self:
+ url_str += 'id='+str(rec.id)+'&action='+str(action) + \
+ '&model=helpdesk.ticket&view_type=form'
+ rec.form_url = url_str
+
+ def _compute_access_url(self):
+ super(HelpdeskTicket, self)._compute_access_url()
+ for ticket in self:
+ ticket.access_url = '/my/tickets/%s' % (ticket.id)
+
+ def _get_report_base_filename(self):
+ self.ensure_one()
+ return '%s %s' % ('Ticket', self.name)
+
+ @api.model
+ def helpdesk_sla_create(self, team_id, ticket_type):
+ self.ensure_one()
+ sla_policy_ids_list = []
+ if self.sh_sla_status_ids:
+ self.sh_sla_status_ids.unlink()
+ if team_id:
+ sla_policy_ids = self.env['sh.helpdesk.sla'].sudo().search([
+ ('sh_team_id', '=', team_id)
+ ])
+ if sla_policy_ids:
+ for policy_id in sla_policy_ids:
+ if policy_id.id not in sla_policy_ids_list:
+ sla_policy_ids_list.append(policy_id.id)
+ if ticket_type:
+ if team_id:
+ sla_policy_ids = self.env['sh.helpdesk.sla'].sudo().search([
+ ('sh_ticket_type_id', '=', ticket_type),
+ ('sh_team_id', '=', team_id)
+ ])
+ if sla_policy_ids:
+ for policy_id in sla_policy_ids:
+ if policy_id.id not in sla_policy_ids_list:
+ sla_policy_ids_list.append(policy_id.id)
+ elif not team_id:
+ sla_policy_ids = self.env['sh.helpdesk.sla'].sudo().search([
+ ('sh_ticket_type_id', '=', ticket_type)
+ ])
+ if sla_policy_ids:
+ for policy_id in sla_policy_ids:
+ if policy_id.id not in sla_policy_ids_list:
+ sla_policy_ids_list.append(policy_id.id)
+ return sla_policy_ids_list
+
+ @api.model
+ def create(self, vals):
+ if vals.get('partner_id') == False and vals.get('email', False):
+ emails = email_re.findall(vals.get('email') or '')
+ email = emails and emails[0] or ''
+ name = str(vals.get('email')).split('"')
+ partner_id = self.env['res.partner'].create({
+ 'name':
+ name[1],
+ 'email':
+ email,
+ 'company_type':
+ 'person',
+ })
+ vals.update({
+ 'partner_id': partner_id.id,
+ 'email': email,
+ 'person_name': partner_id.name,
+ })
+ if self.env.company.sh_default_team_id and not vals.get(
+ 'team_id') and not vals.get('user_id'):
+ vals.update({
+ 'team_id':
+ self.env.company.sh_default_team_id.id,
+ 'team_head':
+ self.env.company.sh_default_team_id.team_head.id,
+ 'user_id':
+ self.env.company.sh_default_user_id.id,
+ })
+ number = random.randrange(1, 10)
+ company_id = self.env.company
+ if 'company_id' in vals:
+ self = self.with_company(vals['company_id'])
+ vals['name'] = self.env['ir.sequence'].next_by_code(
+ 'helpdesk.ticket') or _('New')
+ if company_id.new_stage_id:
+ vals['stage_id'] = company_id.new_stage_id.id
+
+ vals['color'] = number
+ res = super(HelpdeskTicket, self).create(vals)
+ #code by nida
+ template_id = self.env.ref('sh_helpdesk.sh_ticket_new_template_to_admin').id
+ template = self.env['mail.template'].browse(template_id)
+ template.sudo().send_mail(res.id, force_send=True)
+ # end by nida
+ if res.sh_sla_status_ids:
+ for line in res.sh_sla_status_ids:
+ line.sh_status = res.sh_status
+ if res.ticket_from_website and res.company_id.new_stage_id.mail_template_ids and res.partner_id:
+ for template in res.company_id.new_stage_id.mail_template_ids:
+ template.sudo().send_mail(res.id, force_send=True)
+ else:
+ if not res.ticket_from_website and res.company_id.new_stage_id.mail_template_ids and res.partner_id:
+ for template in res.company_id.new_stage_id.mail_template_ids:
+ template.sudo().send_mail(res.id, force_send=True)
+ if res.team_id and res.team_head and res.user_id and res.sh_user_ids:
+ allocation_template = res.company_id.allocation_mail_template_id
+ email_formatted = []
+ if res.team_head.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(
+ res.team_head.partner_id.email_formatted)
+ if res.user_id.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(res.user_id.partner_id.email_formatted)
+ for user in res.sh_user_ids:
+ if user.id != res.user_id.id:
+ if user.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(user.partner_id.email_formatted)
+ email_formatted_str = ','.join(email_formatted)
+ email_values = {
+ 'email_from': str(res.team_head.partner_id.email_formatted),
+ 'email_to': email_formatted_str
+ }
+ if allocation_template:
+ allocation_template.sudo().send_mail(res.id,
+ force_send=True,
+ email_values=email_values)
+ res.ticket_allocated = True
+ elif res.team_id and res.team_head and res.user_id and not res.sh_user_ids:
+ allocation_template = res.company_id.allocation_mail_template_id
+ email_formatted = []
+ if res.team_head.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(
+ res.team_head.partner_id.email_formatted)
+ if res.user_id.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(res.user_id.partner_id.email_formatted)
+ email_formatted_str = ','.join(email_formatted)
+ email_values = {
+ 'email_from': str(res.team_head.partner_id.email_formatted),
+ 'email_to': email_formatted_str
+ }
+ if allocation_template:
+ allocation_template.sudo().send_mail(res.id,
+ force_send=True,
+ email_values=email_values)
+ res.ticket_allocated = True
+ elif res.team_id and res.team_head and not res.user_id and res.sh_user_ids:
+ allocation_template = res.company_id.allocation_mail_template_id
+ email_formatted = []
+ for user in res.sh_user_ids:
+ if user.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(user.partner_id.email_formatted)
+ email_formatted_str = ','.join(email_formatted)
+ email_values = {
+ 'email_from': str(res.team_head.partner_id.email_formatted),
+ 'email_to': email_formatted_str
+ }
+ if allocation_template:
+ allocation_template.sudo().send_mail(res.id,
+ force_send=True,
+ email_values=email_values)
+ res.ticket_allocated = True
+ elif not res.team_id and not res.team_head and res.user_id and res.sh_user_ids:
+ allocation_template = res.company_id.allocation_mail_template_id
+ email_formatted = []
+ if res.user_id.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(res.user_id.partner_id.email_formatted)
+ for user in res.sh_user_ids:
+ if user.id != res.user_id.id:
+ if user.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(user.partner_id.email_formatted)
+ email_formatted_str = ','.join(email_formatted)
+ email_values = {
+ 'email_from': str(res.company_id.partner_id.email_formatted),
+ 'email_to': email_formatted_str
+ }
+ if allocation_template:
+ allocation_template.sudo().send_mail(res.id,
+ force_send=True,
+ email_values=email_values)
+ res.ticket_allocated = True
+ elif not res.team_id and not res.team_head and res.user_id and not res.sh_user_ids:
+ allocation_template = res.company_id.allocation_mail_template_id
+ allocation_template.sudo().write({
+ 'email_from':
+ str(res.company_id.partner_id.email_formatted),
+ 'email_to':
+ str(res.user_id.partner_id.email_formatted),
+ 'partner_to':
+ str(res.user_id.partner_id.id)
+ })
+ email_values = {
+ 'email_from': str(res.company_id.partner_id.email_formatted),
+ 'email_to': str(res.user_id.partner_id.email_formatted)
+ }
+ if allocation_template:
+ allocation_template.sudo().send_mail(res.id,
+ force_send=True,
+ email_values=email_values)
+ res.ticket_allocated = True
+ elif not res.team_id and not res.team_head and not res.user_id and res.sh_user_ids:
+ allocation_template = res.company_id.allocation_mail_template_id
+ email_formatted = []
+ for user in res.sh_user_ids:
+ if user.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(user.partner_id.email_formatted)
+ email_formatted_str = ','.join(email_formatted)
+ email_values = {
+ 'email_from': str(res.company_id.partner_id.email_formatted),
+ 'email_to': email_formatted_str
+ }
+ if allocation_template:
+ allocation_template.sudo().send_mail(res.id,
+ force_send=True,
+ email_values=email_values)
+ res.ticket_allocated = True
+ if self.env.company.sh_auto_add_customer_as_follower:
+ res.message_subscribe(partner_ids=res.partner_id.ids)
+ return res
+
+ def write(self, vals):
+ user_groups = self.env.user.groups_id.ids
+ if vals.get('stage_id'):
+ stage_id = self.env['helpdesk.stages'].sudo().search(
+ [('id', '=', vals.get('stage_id'))], limit=1)
+ if stage_id and stage_id.sh_group_ids:
+ is_group_exist = False
+ list_user_groups = user_groups
+ list_stage_groups = stage_id.sh_group_ids.ids
+ for item in list_stage_groups:
+ if item in list_user_groups:
+ is_group_exist = True
+ break
+ if not is_group_exist:
+ raise UserError(
+ _('You have not access to edit this support request.'))
+ if vals.get('partner_id'
+ ) and self.env.company.new_stage_id.mail_template_ids:
+ for rec in self:
+ for template in rec.company_id.new_stage_id.mail_template_ids:
+ template.sudo().send_mail(rec.id, force_send=True)
+ res = super(HelpdeskTicket, self).write(vals)
+ if vals.get('team_id') and vals.get('team_head') and vals.get(
+ 'user_id') and vals.get(
+ 'sh_user_ids') and not vals.get('ticket_allocated'):
+ allocation_template = self.env.company.allocation_mail_template_id
+ team_head = self.env['res.users'].sudo().browse(
+ vals.get('team_head'))
+ user_id = self.env['res.users'].sudo().browse(vals.get('user_id'))
+ email_formatted = []
+ if team_head.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(team_head.partner_id.email_formatted)
+ if user_id.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(user_id.partner_id.email_formatted)
+ users = vals.get('sh_user_ids')[0][2]
+ user_ids = self.env['res.users'].sudo().browse(users)
+ for user in user_ids:
+ if user.id != user_id.id:
+ if user.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(user.partner_id.email_formatted)
+ email_formatted_str = ','.join(email_formatted)
+ email_values = {
+ 'email_from': str(team_head.partner_id.email_formatted),
+ 'email_to': email_formatted_str
+ }
+ if allocation_template:
+ for rec in self:
+ allocation_template.sudo().send_mail(
+ rec.id, force_send=True, email_values=email_values)
+ rec.ticket_allocated = True
+ elif vals.get('team_id') and vals.get('team_head') and vals.get(
+ 'user_id'
+ ) and not vals.get('sh_user_ids') and not vals.get('ticket_allocated'):
+ allocation_template = self.env.company.allocation_mail_template_id
+ team_head = self.env['res.users'].sudo().browse(
+ vals.get('team_head'))
+ user_id = self.env['res.users'].sudo().browse(vals.get('user_id'))
+ email_formatted = []
+ if team_head.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(team_head.partner_id.email_formatted)
+ if user_id.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(user_id.partner_id.email_formatted)
+ email_formatted_str = ','.join(email_formatted)
+ email_values = {
+ 'email_from': str(team_head.partner_id.email_formatted),
+ 'email_to': email_formatted_str
+ }
+ if allocation_template:
+ for rec in self:
+ allocation_template.sudo().send_mail(
+ rec.id, force_send=True, email_values=email_values)
+ rec.ticket_allocated = True
+ elif vals.get('team_id') and vals.get(
+ 'team_head') and not vals.get('user_id') and vals.get(
+ 'sh_user_ids') and not vals.get('ticket_allocated'):
+ allocation_template = self.env.company.allocation_mail_template_id
+ email_formatted = []
+ users = vals.get('sh_user_ids')[0][2]
+ user_ids = self.env['res.users'].sudo().browse(users)
+ team_head = self.env['res.users'].sudo().browse(
+ vals.get('team_head'))
+ for user in user_ids:
+ if user.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(user.partner_id.email_formatted)
+ email_formatted_str = ','.join(email_formatted)
+ email_values = {
+ 'email_from': str(team_head.partner_id.email_formatted),
+ 'email_to': email_formatted_str
+ }
+ if allocation_template:
+ for rec in self:
+ allocation_template.sudo().send_mail(
+ rec.id, force_send=True, email_values=email_values)
+ rec.ticket_allocated = True
+ elif not vals.get('team_id') and not vals.get(
+ 'team_head') and vals.get('user_id') and vals.get(
+ 'sh_user_ids') and not vals.get('ticket_allocated'):
+ allocation_template = self.env.company.allocation_mail_template_id
+ email_formatted = []
+ user_id = self.env['res.users'].sudo().browse(vals.get('user_id'))
+ users = vals.get('sh_user_ids')[0][2]
+ user_ids = self.env['res.users'].sudo().browse(users)
+ if user_id.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(user_id.partner_id.email_formatted)
+ for user in user_ids:
+ if user.id != user_id.id:
+ if user.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(user.partner_id.email_formatted)
+ email_formatted_str = ','.join(email_formatted)
+ email_values = {
+ 'email_from': str(self.env.company.partner_id.email_formatted),
+ 'email_to': email_formatted_str
+ }
+ if allocation_template:
+ for rec in self:
+ allocation_template.sudo().send_mail(
+ rec.id, force_send=True, email_values=email_values)
+ rec.ticket_allocated = True
+ elif not vals.get('team_id') and not vals.get(
+ 'team_head') and vals.get('user_id') and not vals.get(
+ 'sh_user_ids') and not vals.get('ticket_allocated'):
+ allocation_template = self.env.company.allocation_mail_template_id
+ user_id = self.env['res.users'].sudo().browse(vals.get('user_id'))
+ email_values = {
+ 'email_from': str(self.env.company.partner_id.email_formatted),
+ 'email_to': str(user_id.partner_id.email_formatted)
+ }
+ if allocation_template:
+ for rec in self:
+ allocation_template.sudo().send_mail(
+ rec.id, force_send=True, email_values=email_values)
+ rec.ticket_allocated = True
+ elif not vals.get('team_id') and not vals.get(
+ 'team_head') and not vals.get('user_id') and vals.get(
+ 'sh_user_ids') and not vals.get('ticket_allocated'):
+ allocation_template = self.env.company.allocation_mail_template_id
+ users = vals.get('sh_user_ids')[0][2]
+
+ user_ids = self.env['res.users'].sudo().browse(users)
+ email_formatted = []
+ for user in user_ids:
+ if user.partner_id.email_formatted not in email_formatted:
+ email_formatted.append(user.partner_id.email_formatted)
+ email_formatted_str = ','.join(email_formatted)
+ email_values = {
+ 'email_from': str(self.env.company.partner_id.email_formatted),
+ 'email_to': email_formatted_str
+ }
+ if allocation_template:
+ for rec in self:
+ allocation_template.sudo().send_mail(
+ rec.id, force_send=True, email_values=email_values)
+ rec.ticket_allocated = True
+ return res
+
+ def preview_ticket(self):
+ self.ensure_one()
+ return {
+ 'type': 'ir.actions.act_url',
+ 'target': 'self',
+ 'url': self.get_portal_url(),
+ }
+
+ @api.depends('stage_id')
+ def _compute_stage_booleans(self):
+ if self:
+ for rec in self:
+ rec.cancel_stage_boolean = False
+ rec.done_stage_boolean = False
+ rec.reopen_stage_boolean = False
+ rec.closed_stage_boolean = False
+ rec.open_boolean = False
+ if rec.stage_id.id == rec.company_id.cancel_stage_id.id:
+ rec.cancel_stage_boolean = True
+ rec.open_boolean = True
+ elif rec.stage_id.id == rec.company_id.done_stage_id.id:
+ rec.done_stage_boolean = True
+ rec.open_boolean = True
+ elif rec.stage_id.id == rec.company_id.reopen_stage_id.id:
+ rec.reopen_stage_boolean = True
+ rec.open_boolean = False
+ elif rec.stage_id.id == rec.company_id.close_stage_id.id:
+ rec.closed_stage_boolean = True
+ rec.open_boolean = True
+
+ @api.depends('stage_id')
+ def _compute_cancel_button_boolean(self):
+ if self:
+ for rec in self:
+ rec.cancel_button_boolean = False
+ if rec.stage_id.is_cancel_button_visible:
+ rec.cancel_button_boolean = True
+
+ @api.depends('stage_id')
+ def _compute_done_button_boolean(self):
+ if self:
+ for rec in self:
+ rec.done_button_boolean = False
+ if rec.stage_id.is_done_button_visible:
+ rec.done_button_boolean = True
+
+ def action_approve(self):
+ self.ensure_one()
+ if self.stage_id.sh_next_stage:
+ self.stage_id = self.stage_id.sh_next_stage.id
+ self.change_sh_status()
+ self._compute_sh_sla_deadline()
+ if self.stage_id.mail_template_ids:
+ for template in self.stage_id.mail_template_ids:
+ template.sudo().send_mail(self.id, force_send=True)
+
+ def aciton_draft(self):
+ self.ensure_one()
+ if self.company_id and self.company_id.new_stage_id:
+ self.stage_id = self.company_id.new_stage_id.id
+
+ def action_done(self):
+ self.ensure_one()
+ if self.company_id and self.company_id.done_stage_id and self.company_id.done_stage_id.mail_template_ids:
+ for template in self.company_id.done_stage_id.mail_template_ids:
+ template.sudo().send_mail(self.id, force_send=True)
+ self.stage_id = self.company_id.done_stage_id.id
+
+ def action_reply(self):
+ self.ensure_one()
+ ir_model_data = self.env['ir.model.data']
+ template_id = self.company_id.reply_mail_template_id.id
+ try:
+ compose_form_id = ir_model_data.get_object_reference(
+ 'mail', 'email_compose_message_wizard_form')[1]
+ except ValueError:
+ compose_form_id = False
+ ctx = {
+ 'default_model': 'helpdesk.ticket',
+ 'default_res_id': self.ids[0],
+ 'default_use_template': bool(template_id),
+ 'default_template_id': template_id,
+ 'default_composition_mode': 'comment',
+ 'force_email': True
+ }
+ return {
+ 'type': 'ir.actions.act_window',
+ 'view_mode': 'form',
+ 'res_model': 'mail.compose.message',
+ 'views': [(compose_form_id, 'form')],
+ 'view_id': compose_form_id,
+ 'target': 'new',
+ 'context': ctx,
+ }
+
+ def action_closed(self):
+ self.ensure_one()
+ if self.company_id and self.company_id.close_stage_id and self.company_id.close_stage_id.mail_template_ids:
+ for template in self.company_id.close_stage_id.mail_template_ids:
+ template.sudo().send_mail(self.id, force_send=True)
+ self.write({
+ 'close_date': fields.Datetime.now(),
+ 'close_by': self.env.user.id,
+ 'closed_stage_boolean': True,
+ 'stage_id': self.company_id.close_stage_id.id
+ })
+
+ def action_cancel(self):
+ self.ensure_one()
+ if self.company_id and self.company_id.cancel_stage_id and self.company_id.cancel_stage_id.mail_template_ids:
+ for template in self.company_id.cancel_stage_id.mail_template_ids:
+ template.sudo().send_mail(self.id, force_send=True)
+ stage_id = self.company_id.cancel_stage_id
+ self.stage_id = stage_id.id
+ self.cancel_date = fields.Datetime.now()
+ self.cancel_by = self.env.user.id
+ self.cancel_stage_boolean = True
+
+ def action_open(self):
+ if self.company_id and self.company_id.reopen_stage_id and self.company_id.reopen_stage_id.mail_template_ids:
+ for template in self.company_id.reopen_stage_id.mail_template_ids:
+ template.sudo().send_mail(self.id, force_send=True)
+ self.write({
+ 'stage_id': self.company_id.reopen_stage_id.id,
+ 'open_boolean': True,
+ })
+
+ @api.onchange('team_id')
+ def onchange_team(self):
+ if self.team_id:
+ self.team_head = self.team_id.team_head
+ user_ids = self.env['helpdesk.team'].sudo().search([
+ ('id', '=', self.team_id.id)
+ ])
+ return {
+ 'domain': {
+ 'user_id': [('id', 'in', user_ids.team_members.ids)],
+ 'sh_user_ids': [('id', 'in', user_ids.team_members.ids)]
+ }
+ }
+ else:
+ self.team_head = False
+
+ @api.onchange('category_id')
+ def onchange_category(self):
+ if self.category_id:
+ sub_category_ids = self.env['helpdesk.subcategory'].sudo().search([
+ ('parent_category_id', '=', self.category_id.id)
+ ]).ids
+ return {
+ 'domain': {
+ 'sub_category_id': [('id', 'in', sub_category_ids)]
+ }
+ }
+ else:
+ self.sub_category_id = False
+
+ @api.onchange('partner_id')
+ def onchange_partner_id(self):
+ if self.partner_id:
+ self.person_name = self.partner_id.name
+ self.email = self.partner_id.email
+ self.mobile_no = self.partner_id.mobile
+ else:
+ self.person_name = False
+ self.email = False
+ self.mobile_no = False
+
+ @api.model
+ def _run_auto_close_ticket(self):
+ tikcet_ids = self.env['helpdesk.ticket'].sudo().search([
+ ('done_stage_boolean', '=', False),
+ ('cancel_stage_boolean', '=', False)
+ ])
+ for ticket in tikcet_ids:
+ replied_date = ticket.replied_date
+ if replied_date and ticket.company_id.auto_close_ticket == True:
+ no_of_days = ticket.company_id.close_days
+ end_date = replied_date + timedelta(days=no_of_days)
+ if end_date < fields.Datetime.now(
+ ) and ticket.state == 'staff_replied':
+ ticket.action_closed()
diff --git a/sh_helpdesk/models/helpdesk_ticket_dashboard.py b/sh_helpdesk/models/helpdesk_ticket_dashboard.py
new file mode 100644
index 0000000..8a175ac
--- /dev/null
+++ b/sh_helpdesk/models/helpdesk_ticket_dashboard.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+
+from odoo import models, fields, _
+
+
+class TicketDashboard(models.Model):
+ _name = 'ticket.dashboard'
+ _description = 'Ticket Dashboard'
+
+ name = fields.Char('Name')
+
+ def get_ticket_data(self, ids):
+ return {
+ 'name': _('Tickets'),
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'helpdesk.ticket',
+ 'view_mode': 'tree,form',
+ 'domain': [('id', 'in', ids)],
+ 'target': 'current'
+ }
diff --git a/sh_helpdesk/models/helpdesk_ticket_type.py b/sh_helpdesk/models/helpdesk_ticket_type.py
new file mode 100644
index 0000000..8b061e3
--- /dev/null
+++ b/sh_helpdesk/models/helpdesk_ticket_type.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+
+from odoo import models, fields
+
+
+class HelpdeskTicketType(models.Model):
+ _name = 'helpdesk.ticket.type'
+ _description = 'Helpdesk Ticket Type'
+ _rec_name = 'name'
+
+ name = fields.Char('Name', required=True,translate=True)
+ sla_count = fields.Integer(compute='_compute_helpdesk_sla')
+
+ def _compute_helpdesk_sla(self):
+ for record in self:
+ record.sla_count = 0
+ slas = self.env['helpdesk.ticket'].sudo().search(
+ [('ticket_type', '=', self.id),('sh_sla_status_ids','!=',False)])
+ record.sla_count = len(slas.ids)
+
+ def action_view_sla(self):
+ self.ensure_one()
+ slas = self.env['helpdesk.ticket'].sudo().search(
+ [('ticket_type', '=', self.id),('sh_sla_status_ids','!=',False)])
+ action = self.env["ir.actions.actions"]._for_xml_id(
+ "sh_helpdesk.helpdesk_ticket_action")
+ if len(slas) > 1:
+ action['domain'] = [('id', 'in', slas.ids)]
+ elif len(slas) == 1:
+ form_view = [
+ (self.env.ref('sh_helpdesk.helpdesk_ticket_form_view').id, 'form')]
+ if 'views' in action:
+ action['views'] = form_view + \
+ [(state, view)
+ for state, view in action['views'] if view != 'form']
+ else:
+ action['views'] = form_view
+ action['res_id'] = slas.id
+ else:
+ action = {'type': 'ir.actions.act_window_close'}
+ return action
diff --git a/sh_helpdesk/models/helpdesk_ticket_update_wizard.py b/sh_helpdesk/models/helpdesk_ticket_update_wizard.py
new file mode 100644
index 0000000..5e9c342
--- /dev/null
+++ b/sh_helpdesk/models/helpdesk_ticket_update_wizard.py
@@ -0,0 +1,87 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+from odoo import fields, models, _, api
+from odoo.exceptions import UserError
+
+
+class MassUpdateWizard(models.TransientModel):
+
+ _name = "sh.helpdesk.ticket.mass.update.wizard"
+ _description = "Mass Update Wizard"
+
+ helpdesks_ticket_ids = fields.Many2many(comodel_name='helpdesk.ticket')
+ check_assign_to = fields.Boolean(string='Asssign To', default=False)
+ assign_to = fields.Many2one(comodel_name='res.users',
+ string='Assign To',
+ domain=[('share', '=', False)])
+ check_sh_display_multi_user = fields.Boolean()
+ check_assign_to_multiuser = fields.Boolean(default=False,
+ string="Assign Multi User")
+ ticket_update_type = fields.Selection([
+ ('add', 'Add'),
+ ('replace', 'Replace'),
+ ],
+ default="add",
+ string="Ticket Type Update")
+ assign_to_multiuser = fields.Many2many('res.users',
+ string="Assign Multi Users",
+ domain=[('share', '=', False)])
+
+ check_helpdesks_state = fields.Boolean(default=False, string="Stage")
+ helpdesk_stages = fields.Many2one('helpdesk.stages', string="Stage")
+
+ check_add_remove = fields.Boolean(string="Add/Remove", default=False)
+ followers = fields.Many2many('res.partner', string="Followers")
+
+ ticket_follower_update_type = fields.Selection([
+ ('add', 'Add'),
+ ('remove', 'Remove'),
+ ],
+ default="add",
+ string="Ticket Type Update")
+
+ def update_record(self):
+
+ # <-- ASSIGN TO UPDATE -->
+
+ if self.check_assign_to == True:
+ self.helpdesks_ticket_ids.write({'user_id': self.assign_to.id})
+
+ # <-- ASSIGN MULTIUSER UPDATE -->
+
+ if self.check_assign_to_multiuser == True:
+
+ if self.ticket_update_type == 'add':
+ get_list = []
+ for rec in self.helpdesks_ticket_ids.sh_user_ids:
+ if rec:
+ get_list.append(rec.id)
+ for rec1 in self.assign_to_multiuser:
+ if rec1:
+ get_list.append(rec1.id)
+ self.helpdesks_ticket_ids.write(
+ {'sh_user_ids': [(6, 0, get_list)]})
+
+ if self.ticket_update_type == "replace":
+ self.helpdesks_ticket_ids.write(
+ {'sh_user_ids': [(6, 0, self.assign_to_multiuser.ids)]})
+
+ # <-- STATE UPDATE -->
+
+ if self.check_helpdesks_state == True:
+ for rec in self.helpdesks_ticket_ids:
+ if self.helpdesk_stages:
+ rec.stage_id = self.helpdesk_stages.id
+
+ # <-- ADD/REMOVE FOLLOWER UPDATE -->
+
+ for rec in self.helpdesks_ticket_ids:
+ ids_list = []
+ if self.ticket_follower_update_type == "add":
+ rec.message_subscribe(partner_ids=self.followers.ids)
+ if self.ticket_follower_update_type == "remove":
+ for follower in self.followers.ids:
+ if follower in rec.message_partner_ids.ids:
+ ids_list.append(follower)
+ final_list = ids_list
+ rec.message_unsubscribe(partner_ids=final_list) \ No newline at end of file
diff --git a/sh_helpdesk/models/res_users.py b/sh_helpdesk/models/res_users.py
new file mode 100644
index 0000000..d80a80d
--- /dev/null
+++ b/sh_helpdesk/models/res_users.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+
+from odoo import models, fields, api
+
+
+class ResUsers(models.Model):
+ _inherit = 'res.users'
+
+ sh_portal_user = fields.Boolean(string='Portal',compute='_compute_sh_portal_user',search='_search_sh_portal_user')
+ sh_portal_user_access = fields.Selection([('user','Portal Support User'),('manager','Portal Manager'),('leader','Portal Leader')],string='Portal Access')
+ sign = fields.Text('Signature')
+
+ @api.depends('groups_id')
+ def _compute_sh_portal_user(self):
+ if self:
+ for rec in self:
+ if self.env.ref('base.group_portal').id in rec.groups_id.ids:
+ rec.sh_portal_user = True
+ else:
+ rec.sh_portal_user = False
+
+ def _search_sh_portal_user(self, operator, value):
+ user_obj = self.env['res.users']
+ domain = []
+ domain.append(('sh_portal_user', operator, value))
+ users = user_obj.sudo().search(domain).ids
+ if users:
+ return [('id', 'in', users)]
+ else:
+ return [] \ No newline at end of file
diff --git a/sh_helpdesk/models/send_mail_quick_reply.py b/sh_helpdesk/models/send_mail_quick_reply.py
new file mode 100644
index 0000000..607bf87
--- /dev/null
+++ b/sh_helpdesk/models/send_mail_quick_reply.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+# Part of Softhealer Technologies.
+
+from odoo import models, fields
+
+
+class SendQuickReply(models.Model):
+ _name = 'sh.quick.reply'
+ _description = 'Quick Reply'
+
+ name = fields.Char('Title', required=True)
+ commom_for_all = fields.Boolean(string='Commom For All', default=False)
+ sh_user_id = fields.Many2one('res.users',
+ string='User',
+ required=True,
+ default=lambda self: self.env.user.id)
+ active = fields.Boolean(default=True)
+ sh_description = fields.Html('Body')