Merge branch 'main' of http://10.10.1.136:3000/ismail/haikal into frontend
This commit is contained in:
commit
e18f1da115
@ -56,6 +56,7 @@ from .models import (
|
||||
DealerSettings,
|
||||
Tasks,
|
||||
Recall,
|
||||
Ticket
|
||||
)
|
||||
from django_ledger import models as ledger_models
|
||||
from django.forms import (
|
||||
@ -1304,15 +1305,15 @@ class OpportunityStageForm(forms.ModelForm):
|
||||
:type Meta.fields: list
|
||||
"""
|
||||
|
||||
|
||||
|
||||
class Meta:
|
||||
model = Opportunity
|
||||
fields = [
|
||||
"stage",
|
||||
|
||||
|
||||
]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class InvoiceModelCreateForm(InvoiceModelCreateFormBase):
|
||||
@ -2202,3 +2203,31 @@ class RecallCreateForm(forms.ModelForm):
|
||||
'year_to': forms.NumberInput(attrs={'class': 'form-control'}),
|
||||
}
|
||||
|
||||
|
||||
class TicketForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Ticket
|
||||
fields = ['subject', 'description', 'priority']
|
||||
widgets = {
|
||||
'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 10}),
|
||||
}
|
||||
|
||||
|
||||
class TicketResolutionForm(forms.ModelForm):
|
||||
resolution_notes = forms.CharField(
|
||||
widget=forms.Textarea(attrs={'rows': 3}),
|
||||
required=False,
|
||||
help_text="Optional notes about how the issue was resolved."
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Ticket
|
||||
fields = ['status']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# Limit status choices to resolution options
|
||||
self.fields['status'].choices = [
|
||||
('resolved', 'Resolved'),
|
||||
('closed', 'Closed')
|
||||
]
|
||||
@ -155,9 +155,12 @@ class DealerSlugMiddleware:
|
||||
"/ar/signup/", "/en/signup/", "/ar/login/", "/en/login/",
|
||||
"/ar/logout/", "/en/logout/", "/en/ledger/", "/ar/ledger/",
|
||||
"/en/notifications/", "/ar/notifications/", "/en/appointment/",
|
||||
"/ar/appointment/", "/en/feature/recall/","ar/feature/recall/"
|
||||
"/ar/appointment/", "/en/feature/recall/","/ar/feature/recall/",
|
||||
"/ar/help_center/", "/en/help_center/",
|
||||
]
|
||||
if any(request.path_info.startswith(path) for path in paths):
|
||||
print("------------------------------------")
|
||||
print(request.path in paths)
|
||||
if request.path in paths:
|
||||
return None
|
||||
|
||||
if not request.user.is_authenticated:
|
||||
|
||||
@ -3506,4 +3506,64 @@ class RecallNotification(models.Model):
|
||||
verbose_name_plural = _("Recall Notifications")
|
||||
|
||||
def __str__(self):
|
||||
return f"Notification for {self.dealer} about {self.recall}"
|
||||
return f"Notification for {self.dealer} about {self.recall}"
|
||||
|
||||
class Ticket(models.Model):
|
||||
STATUS_CHOICES = [
|
||||
('open', 'Open'),
|
||||
('in_progress', 'In Progress'),
|
||||
('resolved', 'Resolved'),
|
||||
('closed', 'Closed'),
|
||||
]
|
||||
|
||||
PRIORITY_CHOICES = [
|
||||
('low', 'Low'),
|
||||
('medium', 'Medium'),
|
||||
('high', 'High'),
|
||||
('critical', 'Critical'),
|
||||
]
|
||||
|
||||
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name='tickets')
|
||||
subject = models.CharField(max_length=200)
|
||||
description = models.TextField()
|
||||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='open')
|
||||
priority = models.CharField(max_length=20, choices=PRIORITY_CHOICES, default='medium')
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
@property
|
||||
def time_to_resolution(self):
|
||||
"""
|
||||
Calculate the time taken to resolve the ticket.
|
||||
Returns None if ticket isn't resolved/closed.
|
||||
Returns timedelta if resolved/closed.
|
||||
"""
|
||||
if self.status in ['resolved', 'closed'] and self.created_at:
|
||||
return self.updated_at - self.created_at
|
||||
return None
|
||||
|
||||
@property
|
||||
def time_to_resolution_display(self):
|
||||
"""
|
||||
Returns a human-readable version of time_to_resolution
|
||||
"""
|
||||
resolution_time = self.time_to_resolution
|
||||
if not resolution_time:
|
||||
return "Not resolved yet"
|
||||
|
||||
days = resolution_time.days
|
||||
hours, remainder = divmod(resolution_time.seconds, 3600)
|
||||
minutes, _ = divmod(remainder, 60)
|
||||
|
||||
parts = []
|
||||
if days > 0:
|
||||
parts.append(f"{days} day{'s' if days != 1 else ''}")
|
||||
if hours > 0:
|
||||
parts.append(f"{hours} hour{'s' if hours != 1 else ''}")
|
||||
if minutes > 0 or not parts:
|
||||
parts.append(f"{minutes} minute{'s' if minutes != 1 else ''}")
|
||||
|
||||
return ", ".join(parts)
|
||||
|
||||
def __str__(self):
|
||||
return f"#{self.id} - {self.subject} ({self.status})"
|
||||
@ -27,7 +27,8 @@ from django.db import transaction
|
||||
from django_q.tasks import async_task
|
||||
from plans.models import UserPlan
|
||||
from plans.signals import order_completed, activate_user_plan
|
||||
|
||||
from inventory.tasks import send_email
|
||||
from django.conf import settings
|
||||
# logging
|
||||
import logging
|
||||
|
||||
@ -1215,4 +1216,29 @@ def bill_model_in_approve_notification(sender, instance, created, **kwargs):
|
||||
# kwargs={"dealer_slug": dealer.slug, "entity_slug": dealer.entity.slug, "bill_pk": instance.pk},
|
||||
# ),
|
||||
# ),
|
||||
# )
|
||||
# )
|
||||
|
||||
|
||||
|
||||
@receiver(post_save, sender=models.Ticket)
|
||||
def send_ticket_notification(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
subject = f"New Support Ticket: {instance.subject}"
|
||||
message = f"""
|
||||
A new support ticket has been created:
|
||||
|
||||
Ticket ID: #{instance.id}
|
||||
Subject: {instance.subject}
|
||||
Priority: {instance.get_priority_display()}
|
||||
Description:
|
||||
{instance.description}
|
||||
|
||||
Please log in to the admin panel to respond.
|
||||
"""
|
||||
|
||||
send_email(
|
||||
settings.DEFAULT_FROM_EMAIL,
|
||||
[settings.SUPPORT_EMAIL],
|
||||
subject,
|
||||
message,
|
||||
)
|
||||
@ -69,7 +69,7 @@ def create_coa_accounts(instance):
|
||||
"role": roles.ASSET_CA_CASH,
|
||||
"balance_type": roles.DEBIT,
|
||||
"locked": False,
|
||||
"default": False,
|
||||
"default": False,
|
||||
},
|
||||
{
|
||||
"code": "1030",
|
||||
|
||||
@ -933,7 +933,7 @@ urlpatterns = [
|
||||
views.ItemServiceUpdateView.as_view(),
|
||||
name="item_service_update",
|
||||
),
|
||||
|
||||
|
||||
# Expanese
|
||||
path(
|
||||
"<slug:dealer_slug>/items/expeneses/",
|
||||
@ -1292,7 +1292,13 @@ urlpatterns = [
|
||||
|
||||
# staff profile
|
||||
path('<slug:dealer_slug>/staff/<slug:slug>detail/', views.StaffDetailView.as_view(), name='staff_detail'),
|
||||
|
||||
# tickets
|
||||
path('help_center/view/', views.help_center, name='help_center'),
|
||||
path('help_center/tickets/', views.ticket_list, name='ticket_list'),
|
||||
path('help_center/tickets/create/', views.create_ticket, name='create_ticket'),
|
||||
path('help_center/tickets/<int:ticket_id>/', views.ticket_detail, name='ticket_detail'),
|
||||
path('help_center/tickets/<int:ticket_id>/update/', views.ticket_update, name='ticket_update'),
|
||||
# path('help_center/tickets/<int:ticket_id>/ticket_mark_resolved/', views.ticket_mark_resolved, name='ticket_mark_resolved'),
|
||||
|
||||
]
|
||||
|
||||
|
||||
@ -2466,7 +2466,9 @@ class CustomerCreateView(
|
||||
success_message = _("Customer created successfully")
|
||||
|
||||
def form_valid(self, form):
|
||||
dealer = self.request.kwargs.get("dealer_slug")
|
||||
if customer := models.Customer.objects.filter(
|
||||
dealer=dealer,
|
||||
email=form.instance.email
|
||||
).first():
|
||||
if not customer.active:
|
||||
@ -2688,7 +2690,8 @@ class VendorCreateView(
|
||||
permission_required = ["inventory.add_vendor"]
|
||||
|
||||
def form_valid(self, form):
|
||||
if vendor := models.Vendor.objects.filter(email=form.instance.email).first():
|
||||
dealer = self.request.kwargs["dealer_slug"]
|
||||
if vendor := models.Vendor.objects.filter(dealer=dealer,email=form.instance.email).first():
|
||||
if not vendor.active:
|
||||
messages.error(
|
||||
self.request,
|
||||
@ -3451,7 +3454,7 @@ class UserCreateView(
|
||||
return self.form_invalid(form)
|
||||
|
||||
email = form.cleaned_data["email"]
|
||||
if models.Staff.objects.filter(dealer=dealer, user__email=email).exists():
|
||||
if models.Staff.objects.filter(user__email=email).exists():
|
||||
messages.error(
|
||||
self.request,
|
||||
_(
|
||||
@ -11142,4 +11145,72 @@ def schedule_calendar(request,dealer_slug):
|
||||
'schedules': user_schedules,
|
||||
'upcoming_schedules':upcoming_schedules
|
||||
}
|
||||
return render(request, 'schedule_calendar.html', context)
|
||||
return render(request, 'schedule_calendar.html', context)
|
||||
|
||||
|
||||
# Support
|
||||
@login_required
|
||||
def help_center(request):
|
||||
return render(request, 'support/help_center.html')
|
||||
|
||||
@login_required
|
||||
def create_ticket(request):
|
||||
if not request.is_dealer:
|
||||
return redirect('home')
|
||||
|
||||
if request.method == 'POST':
|
||||
form = forms.TicketForm(request.POST)
|
||||
if form.is_valid():
|
||||
instance = form.save(commit=False)
|
||||
instance.dealer = request.dealer
|
||||
instance.save()
|
||||
messages.success(request, 'Your support ticket has been submitted successfully!')
|
||||
return redirect('ticket_list')
|
||||
else:
|
||||
form = forms.TicketForm()
|
||||
|
||||
return render(request, 'support/create_ticket.html', {'form': form})
|
||||
|
||||
@login_required
|
||||
def ticket_list(request):
|
||||
tickets = models.Ticket.objects.all().order_by('-created_at')
|
||||
if request.is_dealer:
|
||||
tickets = tickets = tickets.filter(dealer=request.dealer)
|
||||
return render(request, 'support/ticket_list.html', {'tickets': tickets})
|
||||
|
||||
@login_required
|
||||
def ticket_detail(request, ticket_id):
|
||||
ticket = models.Ticket.objects.get(id=ticket_id)
|
||||
return render(request, 'support/ticket_detail.html', {'ticket': ticket})
|
||||
@login_required
|
||||
def ticket_mark_resolved(request, ticket_id):
|
||||
ticket = models.Ticket.objects.get(id=ticket_id)
|
||||
ticket.status = 'resolved'
|
||||
ticket.save()
|
||||
messages.success(request, 'Ticket marked as resolved successfully!')
|
||||
subject = 'Ticket Resolved'
|
||||
message = f"Your support ticket has been resolved. Please check the details below:\n\nTicket ID: {ticket.id}\nSubject: {ticket.subject}\nDescription: {ticket.description}"
|
||||
send_email(
|
||||
settings.SUPPORT_EMAIL,
|
||||
ticket.dealer.user.email,
|
||||
subject,
|
||||
message
|
||||
)
|
||||
return render(request, 'support/ticket_detail.html', {'ticket': ticket})
|
||||
|
||||
def ticket_update(request, ticket_id):
|
||||
ticket = models.Ticket.objects.get(id=ticket_id)
|
||||
|
||||
if request.method == 'POST':
|
||||
form = forms.TicketResolutionForm(request.POST, instance=ticket)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(request, f'Ticket has been marked as {ticket.get_status_display()}.')
|
||||
return redirect('ticket_detail', ticket_id=ticket.id)
|
||||
else:
|
||||
form = forms.TicketResolutionForm(instance=ticket)
|
||||
|
||||
return render(request, 'support/ticket_update.html', {
|
||||
'ticket': ticket,
|
||||
'form': form
|
||||
})
|
||||
@ -498,39 +498,34 @@
|
||||
</div>
|
||||
<div class="overflow-auto scrollbar" style="height: 10rem;">
|
||||
<ul class="nav d-flex flex-column mb-2 pb-1">
|
||||
{% if request.is_dealer %}
|
||||
{% if not request.dealer %}
|
||||
<li class="nav-item">
|
||||
<a hx-boost="false" class="nav-link px-3 d-block" href="{% url 'staff_detail' request.dealer.slug request.staff.slug %}"> <span class="me-2 text-body align-bottom" data-feather="user"></span><span>{% translate 'profile'|capfirst %}</span></a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link px-3 d-block" href="{% url 'dealer_detail' request.dealer.slug %}"> <span class="me-2 text-body align-bottom" data-feather="user"></span><span>{% translate 'profile'|capfirst %}</span></a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="nav-item">
|
||||
<a hx-boost="false" class="nav-link px-3 d-block" href="{% url 'staff_detail' request.dealer.slug request.staff.slug %}"> <span class="me-2 text-body align-bottom" data-feather="user"></span><span>{% translate 'profile'|capfirst %}</span></a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if request.is_dealer %}
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link px-3 d-block" href="{% url 'user_list' request.dealer.slug %}"><span class="me-2 text-body align-bottom" data-feather="users"></span>{{ _("Staff & Groups") }}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link px-3 d-block" href="{% url 'dealer_activity' request.dealer.slug %}"> <span class="me-2 text-body align-bottom" data-feather="lock"></span>{{ _("Activities") }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="nav-item">
|
||||
{% if request.is_dealer %}
|
||||
<a class="nav-link px-3 d-block" href="{% url 'dealer_settings' request.dealer.slug %}"> <span class="me-2 text-body align-bottom" data-feather="settings"></span>{{ _("Settings") }}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
{% if request.is_dealer %}
|
||||
<a class="nav-link px-3 d-block" href="{% url 'management' request.dealer.slug %}"> <span class="me-2 text-body align-bottom" data-feather="shield"></span>{{ _("Admin Managemnet") }}</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link px-3 d-block" href="#"> <span class="me-2 text-body align-bottom" data-feather="help-circle"></span>{{ _("Help Center") }}</a>
|
||||
<a class="nav-link px-3 d-block" href="{% url 'help_center' %}"> <span class="me-2 text-body align-bottom" data-feather="help-circle"></span>{{ _("Help Center") }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if request.is_staff %}
|
||||
<li class="nav-item">
|
||||
<a hx-boost="false" class="nav-link px-3 d-block" href="{% url 'schedule_calendar' request.dealer.slug%}"> <span class="me-2 text-body align-bottom" data-feather="calendar"></span>{{ _("My Calendar") }}</a>
|
||||
<a hx-boost="false" class="nav-link px-3 d-block" href="{% url 'schedule_calendar' request.dealer.slug %}"> <span class="me-2 text-body align-bottom" data-feather="calendar"></span>{{ _("My Calendar") }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<!--<li class="nav-item"><a class="nav-link px-3 d-block" href=""> Language</a></li>-->
|
||||
|
||||
21
templates/support/create_ticket.html
Normal file
21
templates/support/create_ticket.html
Normal file
@ -0,0 +1,21 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h2 class="h4 mb-0">Create Support Ticket</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{form|crispy}}
|
||||
|
||||
<button type="submit" class="btn btn-primary">Submit Ticket</button>
|
||||
<a href="{% url 'ticket_list' %}" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
13
templates/support/help_center.html
Normal file
13
templates/support/help_center.html
Normal file
@ -0,0 +1,13 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container mt-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Need help?</h5>
|
||||
<p class="card-text">Raise a ticket and we will get back to you as soon as possible.</p>
|
||||
<a href="{% url 'create_ticket' %}" class="btn btn-phoenix-primary">Raise a Ticket</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
59
templates/support/ticket_detail.html
Normal file
59
templates/support/ticket_detail.html
Normal file
@ -0,0 +1,59 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h2 class="h4 mb-0">Ticket #{{ ticket.id }}: {{ ticket.subject }}</h2>
|
||||
<div>
|
||||
{% if ticket.status != 'resolved' %}
|
||||
<a href="{% url 'ticket_update' ticket.id %}" class="btn btn-sm btn-outline-success">
|
||||
Update Ticket Status
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="{% url 'ticket_list' %}" class="btn btn-sm btn-outline-secondary">
|
||||
Back to List
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<p><strong>Status:</strong>
|
||||
<span class="badge
|
||||
{% if ticket.status == 'open' %}bg-primary
|
||||
{% elif ticket.status == 'in_progress' %}bg-info
|
||||
{% elif ticket.status == 'resolved' %}bg-success
|
||||
{% else %}bg-secondary{% endif %}">
|
||||
{{ ticket.get_status_display }}
|
||||
</span>
|
||||
</p>
|
||||
<p><strong>Priority:</strong>
|
||||
<span class="badge
|
||||
{% if ticket.priority == 'low' %}bg-success
|
||||
{% elif ticket.priority == 'medium' %}bg-warning
|
||||
{% elif ticket.priority == 'high' %}bg-danger
|
||||
{% else %}bg-dark{% endif %}">
|
||||
{{ ticket.get_priority_display }}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p><strong>Created:</strong> {{ ticket.created_at|date:"M d, Y H:i" }}</p>
|
||||
<p><strong>Last Updated:</strong> {{ ticket.updated_at|date:"M d, Y H:i" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<h3 class="h5">Description</h3>
|
||||
<div class="p-3 bg-light rounded">
|
||||
{{ ticket.description|linebreaks }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- You can add comments/replies section here later -->
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
80
templates/support/ticket_list.html
Normal file
80
templates/support/ticket_list.html
Normal file
@ -0,0 +1,80 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 class="h3 mb-0">My Support Tickets</h1>
|
||||
<a href="{% url 'create_ticket' %}" class="btn btn-primary">
|
||||
<i class="bi bi-plus-circle"></i> New Ticket
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
|
||||
{{ message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Subject</th>
|
||||
<th>Status</th>
|
||||
<th>Priority</th>
|
||||
<th>Created</th>
|
||||
<th>Resolved At</th>
|
||||
<th>Time To Resolution</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for ticket in tickets %}
|
||||
<tr>
|
||||
<td>#{{ ticket.id }}</td>
|
||||
<td>{{ ticket.subject }}</td>
|
||||
<td>
|
||||
<span class="badge
|
||||
{% if ticket.status == 'open' %}bg-primary
|
||||
{% elif ticket.status == 'in_progress' %}bg-info
|
||||
{% elif ticket.status == 'resolved' %}bg-success
|
||||
{% else %}bg-secondary{% endif %}">
|
||||
{{ ticket.get_status_display }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge
|
||||
{% if ticket.priority == 'low' %}bg-success
|
||||
{% elif ticket.priority == 'medium' %}bg-warning
|
||||
{% elif ticket.priority == 'high' %}bg-danger
|
||||
{% else %}bg-dark{% endif %}">
|
||||
{{ ticket.get_priority_display }}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ ticket.created_at|date:"M d, Y H:i" }}</td>
|
||||
<td>{{ ticket.updated_at|date:"M d, Y H:i" }}</td>
|
||||
<td>
|
||||
<p>
|
||||
<i class="fa fa-clock"></i>
|
||||
{{ ticket.time_to_resolution_display }}
|
||||
</p>
|
||||
<td>
|
||||
<a href="{% url 'ticket_detail' ticket.id %}" class="btn btn-sm btn-outline-primary">
|
||||
View
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="6" class="text-center">No tickets found.</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
20
templates/support/ticket_update.html
Normal file
20
templates/support/ticket_update.html
Normal file
@ -0,0 +1,20 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h2 class="h4 mb-0">Update Ticket</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{form|crispy}}
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
<a href="{% url 'ticket_list' %}" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Loading…
x
Reference in New Issue
Block a user