[ADD] HELPDESK: Added kanban view for helpdesk
This commit is contained in:
@@ -5,6 +5,7 @@ from base.methods import is_reportingmanager
|
||||
from helpdesk.filter import TicketFilter, TicketReGroup
|
||||
from helpdesk.models import TICKET_STATUS, Ticket
|
||||
from horilla_views.cbv_methods import login_required
|
||||
from horilla_views.generic.cbv.kanban import HorillaKanbanView
|
||||
from horilla_views.generic.cbv.pipeline import Pipeline
|
||||
from horilla_views.generic.cbv.views import (
|
||||
HorillaListView,
|
||||
@@ -39,6 +40,7 @@ class TicketPipelineNav(HorillaNavView):
|
||||
filter_body_template = "cbv/pipeline/ticket_filter_form.html"
|
||||
filter_instance = TicketFilter()
|
||||
filter_form_context_name = "form"
|
||||
|
||||
group_by_fields = [
|
||||
("employee_id", "Owner"),
|
||||
("ticket_type", "Ticket Type"),
|
||||
@@ -48,6 +50,7 @@ class TicketPipelineNav(HorillaNavView):
|
||||
("assigned_to", "Assigner"),
|
||||
("employee_id__employee_work_info__company_id", "Company"),
|
||||
]
|
||||
|
||||
actions = [
|
||||
{
|
||||
"action": "Archive",
|
||||
@@ -88,6 +91,25 @@ class TicketPipelineNav(HorillaNavView):
|
||||
data-target="#objectCreateModal"
|
||||
"""
|
||||
|
||||
self.view_types = [
|
||||
{
|
||||
"type": "list",
|
||||
"icon": "list-outline",
|
||||
"url": f'{reverse_lazy("ticket-tab")}?view_type=list',
|
||||
"attrs": f"""
|
||||
title ='List'
|
||||
""",
|
||||
},
|
||||
{
|
||||
"type": "card",
|
||||
"icon": "grid-outline",
|
||||
"url": f'{reverse_lazy("ticket-tab")}?view_type=card',
|
||||
"attrs": f"""
|
||||
title ='Card'
|
||||
""",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@method_decorator(login_required, name="dispatch")
|
||||
class TicketTabView(HorillaTabView):
|
||||
@@ -98,16 +120,21 @@ class TicketTabView(HorillaTabView):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
view_type = self.request.GET.get("view_type", "list")
|
||||
url = reverse("ticket-tab-card")
|
||||
if view_type == "list":
|
||||
url = reverse("ticket-tab-list")
|
||||
|
||||
self.tabs = [
|
||||
{
|
||||
"title": "My Tickets",
|
||||
# "url":f'{ reverse("ticket-pipeline-view")}?ticket_tab=my_tickets&',
|
||||
"url": f'{ reverse("ticket-tab-list")}?ticket_tab=my_tickets&',
|
||||
"url": f"{url}?ticket_tab=my_tickets",
|
||||
},
|
||||
{
|
||||
"title": "Suggested Tickets",
|
||||
# "url":f'{ reverse("ticket-pipeline-view")}?ticket_tab=suggested_tickets&',
|
||||
"url": f'{ reverse("ticket-tab-list")}?ticket_tab=suggested_tickets&',
|
||||
"url": f"{url}?ticket_tab=suggested_tickets",
|
||||
},
|
||||
]
|
||||
|
||||
@@ -118,7 +145,7 @@ class TicketTabView(HorillaTabView):
|
||||
{
|
||||
"title": "All Tickets",
|
||||
# "url":f'{ reverse("ticket-pipeline-view")}?ticket_tab=all_tickets&',
|
||||
"url": f'{ reverse("ticket-tab-list")}?ticket_tab=all_tickets&',
|
||||
"url": f"{url}?ticket_tab=all_tickets",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -167,6 +194,7 @@ class TicketListView(HorillaListView):
|
||||
|
||||
model = Ticket
|
||||
filter_class = TicketFilter
|
||||
filter_keys_to_remove = ["ticket_tab", "view_type"]
|
||||
# custom_empty_template = "cbv/pipeline/empty_list.html"
|
||||
bulk_update_fields = [
|
||||
"ticket_type",
|
||||
@@ -197,6 +225,9 @@ class TicketListView(HorillaListView):
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super().get_queryset()
|
||||
if self.request.GET.get("is_active") != "false":
|
||||
self.queryset = self.queryset.filter(is_active=True)
|
||||
|
||||
ticket_tab = self.request.GET.get("ticket_tab", "my_tickets")
|
||||
if ticket_tab == "my_tickets":
|
||||
return queryset.filter(employee_id=self.request.user.employee_get)
|
||||
@@ -227,3 +258,64 @@ class TicketListView(HorillaListView):
|
||||
|
||||
elif ticket_tab == "all_tickets":
|
||||
return queryset.all()
|
||||
|
||||
|
||||
class TicketCardView(HorillaKanbanView):
|
||||
model = Ticket
|
||||
filter_class = TicketFilter
|
||||
group_key = "status"
|
||||
records_per_page = 10
|
||||
show_kanban_confirmation = False
|
||||
filter_keys_to_remove = ["ticket_tab", "view_type"]
|
||||
|
||||
details = {
|
||||
"title": "{title} ({ticket_type__prefix}-{pk})",
|
||||
"Owner": "{employee_id__get_full_name}",
|
||||
"Priority": "{get_priority_stars}",
|
||||
}
|
||||
|
||||
kanban_attrs = """
|
||||
onclick="window.location.href = `{get_ticket_detail_url}`"
|
||||
"""
|
||||
|
||||
action_method = "kanban_action_method"
|
||||
|
||||
def get_queryset(self):
|
||||
self.queryset = super().get_queryset()
|
||||
if self.request.GET.get("is_active") != "false":
|
||||
self.queryset = self.queryset.filter(is_active=True)
|
||||
|
||||
ticket_tab = self.request.GET.get("ticket_tab", "my_tickets")
|
||||
|
||||
if ticket_tab == "my_tickets":
|
||||
self.queryset = self.queryset.filter(
|
||||
employee_id=self.request.user.employee_get
|
||||
)
|
||||
return self.queryset
|
||||
|
||||
elif ticket_tab == "suggested_tickets":
|
||||
employee = self.request.user.employee_get
|
||||
qs_cpy = self.queryset
|
||||
queryset = self.queryset.none()
|
||||
if hasattr(employee, "employee_work_info"):
|
||||
work_info = employee.employee_work_info
|
||||
department = work_info.department_id
|
||||
job_position = work_info.job_position_id
|
||||
|
||||
if department:
|
||||
queryset |= qs_cpy.filter(
|
||||
raised_on=department.id, assigning_type="department"
|
||||
)
|
||||
|
||||
if job_position:
|
||||
queryset |= qs_cpy.filter(
|
||||
raised_on=job_position.id, assigning_type="job_position"
|
||||
)
|
||||
|
||||
queryset |= qs_cpy.filter(
|
||||
raised_on=employee.id, assigning_type="individual"
|
||||
)
|
||||
self.queryset = queryset.distinct()
|
||||
return self.queryset
|
||||
|
||||
return self.queryset
|
||||
|
||||
@@ -329,6 +329,20 @@ class Ticket(HorillaModel):
|
||||
{"ticket": self, "tab": tab_name, "claim_request": claim_request},
|
||||
)
|
||||
|
||||
def kanban_action_method(self):
|
||||
"""
|
||||
This method is used to get the ticket kanban actions
|
||||
"""
|
||||
request = getattr(_thread_locals, "request", None)
|
||||
tab_name = request.GET.get("ticket_tab", "my_tickets")
|
||||
claim_request = self.claimrequest_set.filter(
|
||||
employee_id=request.user.employee_get
|
||||
).first()
|
||||
return render_template(
|
||||
"cbv/pipeline/kanban_action_method.html",
|
||||
{"ticket": self, "tab": tab_name, "claim_request": claim_request},
|
||||
)
|
||||
|
||||
def get_status_col(self):
|
||||
"""
|
||||
This method is used to get the status column
|
||||
@@ -461,7 +475,7 @@ class Attachment(HorillaModel):
|
||||
def save(self, *args, **kwargs):
|
||||
self.get_file_format()
|
||||
|
||||
super().save(self, *args, **kwargs)
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
return os.path.basename(self.file.name)
|
||||
|
||||
94
helpdesk/templates/cbv/pipeline/kanban_action_method.html
Normal file
94
helpdesk/templates/cbv/pipeline/kanban_action_method.html
Normal file
@@ -0,0 +1,94 @@
|
||||
{% load static i18n helpdeskfilters %}
|
||||
{% if tab != 'my_tickets' %}
|
||||
{% if perms.helpdesk.change_ticket or perms.helpdesk.change_claimrequest or request.user.employee_get|is_department_manager:ticket %}
|
||||
<li>
|
||||
<p
|
||||
class="w-full text-left px-3 py-1 hover:text-primary-600 font-semibold"
|
||||
>
|
||||
<a
|
||||
hx-get = "{% url "view-ticket-claim-request" ticket.id %}"
|
||||
hx-target="#objectDetailsModalTarget"
|
||||
data-toggle="oh-modal-toggle"
|
||||
data-target="#objectDetailsModal"
|
||||
>
|
||||
{% trans "Claim Requests" %}
|
||||
</a>
|
||||
</p>
|
||||
</li>
|
||||
{% else %}
|
||||
{% if claim_request or request.user.employee_get in ticket.assigned_to.all %}
|
||||
{% else %}
|
||||
<li>
|
||||
<p
|
||||
class="w-full text-left px-3 py-1 hover:text-primary-600 font-semibold"
|
||||
>
|
||||
<a
|
||||
href = "{% url 'claim-ticket' ticket.id %}"
|
||||
>
|
||||
{% trans "Claim" %}
|
||||
</a>
|
||||
</p>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if perms.helpdesk.change_ticket or request.user.employee_get|is_department_manager:ticket %}
|
||||
<li>
|
||||
<p
|
||||
class="w-full text-left px-3 py-1 hover:text-primary-600 font-semibold"
|
||||
>
|
||||
<a
|
||||
hx-get = "{% url 'ticket-update' ticket.id %}"
|
||||
hx-target="#objectCreateModalTarget"
|
||||
data-toggle="oh-modal-toggle"
|
||||
data-target="#objectCreateModal"
|
||||
>
|
||||
{% trans "Edit" %}
|
||||
</a>
|
||||
</p>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% if perms.helpdesk.change_ticket or request.user.employee_get|is_department_manager:ticket %}
|
||||
<li>
|
||||
<p
|
||||
class="w-full text-left px-3 py-1 hover:text-primary-600 font-semibold"
|
||||
>
|
||||
<a
|
||||
hx-get = "{% url 'ticket-archive' ticket.id %}"
|
||||
hx-swap = "outerHTML"
|
||||
{% if ticket.is_active %}
|
||||
hx-confirm = "Do you want to archive this ticket?"
|
||||
{% else %}
|
||||
hx-confirm = "Do you want to Un-archive this ticket?"
|
||||
{% endif %}
|
||||
hx-on-htmx-after-request="$('.reload-record').click()"
|
||||
>
|
||||
{% if ticket.is_active %}
|
||||
{% trans "Archive" %}
|
||||
{% else %}
|
||||
{% trans 'Un-archive' %}
|
||||
{% endif %}
|
||||
</a>
|
||||
</p>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if perms.helpdesk.delete_ticket %}
|
||||
{% if ticket.status == 'new' %}
|
||||
<li>
|
||||
<p
|
||||
class="w-full text-left px-3 py-1 hover:text-primary-600 font-semibold"
|
||||
>
|
||||
<a
|
||||
href = "{% url 'ticket-delete' ticket.id %}"
|
||||
onsubmit="return confirm('{% trans 'Are you sure you want to delete this Ticket?' %}');"
|
||||
>
|
||||
{% trans 'Delete' %}
|
||||
</a>
|
||||
</p>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -1,10 +1,30 @@
|
||||
{% extends "index.html" %}
|
||||
{% load static i18n %}
|
||||
{% include "generic/horilla_section.html" %}
|
||||
{% block content %}
|
||||
{% include "generic/components.html" %}
|
||||
|
||||
<div
|
||||
class="oh-checkpoint-badge mb-2"
|
||||
id="selectedTickets"
|
||||
data-ids="[]"
|
||||
data-clicked=""
|
||||
style="display: none"
|
||||
></div>
|
||||
{% for path in script_static_paths %}
|
||||
<script src="{% static path %}"></script>
|
||||
{% endfor %}
|
||||
|
||||
<div
|
||||
class="oh-checkpoint-badge mb-2"
|
||||
id="selectedInstances"
|
||||
data-ids="[]"
|
||||
data-clicked=""
|
||||
style="display: none"
|
||||
></div>
|
||||
|
||||
{% if nav_url %}
|
||||
<div hx-get="{{nav_url}}?{{request.GET.urlencode}}" hx-trigger="load">
|
||||
<div class="mt-5 oh-wrapper animated-background" style="height: 80px"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if view_url %}
|
||||
<div class="oh-wrapper" id="pipelineContainer">
|
||||
<div class="mt-4 animated-background" style="height: 600px"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
@@ -77,6 +77,7 @@ urlpatterns = [
|
||||
path("get-ticket-tabs", pipeline.TicketTabView.as_view(), name="get-ticket-tabs"),
|
||||
path("ticket-tab/", pipeline.TicketTabView.as_view(), name="ticket-tab"),
|
||||
path("ticket-tab-list/", pipeline.TicketListView.as_view(), name="ticket-tab-list"),
|
||||
path("ticket-tab-card/", pipeline.TicketCardView.as_view(), name="ticket-tab-card"),
|
||||
# path("ticket-pipeline-view/", pipeline.TicketPipelineTabView.as_view(), name="ticket-pipeline-view"),
|
||||
path(
|
||||
"ticket-create",
|
||||
@@ -246,4 +247,9 @@ urlpatterns = [
|
||||
name="delete-ticket-document",
|
||||
),
|
||||
path("load-faqs/", views.load_faqs, name="load-faqs"),
|
||||
path(
|
||||
"ticket-file-upload/<int:id>/",
|
||||
views.ticket_file_upload,
|
||||
name="ticket-file-upload",
|
||||
),
|
||||
]
|
||||
|
||||
@@ -1863,3 +1863,25 @@ def load_faqs(request):
|
||||
"catagories": category_lookup,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@hx_request_required
|
||||
def ticket_file_upload(request, id):
|
||||
"""
|
||||
This function is used to upload files to the ticket.
|
||||
"""
|
||||
ticket = Ticket.objects.get(id=id)
|
||||
if request.method == "POST":
|
||||
files = request.FILES.getlist("file")
|
||||
|
||||
for file in files:
|
||||
a_form = AttachmentForm({"file": file, "ticket": ticket, "comment": None})
|
||||
a_form.save()
|
||||
messages.success(request, _("File(s) uploaded successfully."))
|
||||
|
||||
return render(
|
||||
request,
|
||||
"helpdesk/ticket/ticket_detail.html",
|
||||
{"ticket": ticket, "attachments": ticket.ticket_attachment.all()},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user