diff --git a/app/core/forms/ticket_categories.py b/app/core/forms/ticket_categories.py new file mode 100644 index 00000000..613bcd11 --- /dev/null +++ b/app/core/forms/ticket_categories.py @@ -0,0 +1,120 @@ +from django import forms +from django.forms import ValidationError +from django.urls import reverse + +from app import settings + +from core.forms.common import CommonModelForm +from core.models.ticket.ticket_category import TicketCategory + + + +class TicketCategoryForm(CommonModelForm): + + + class Meta: + + fields = '__all__' + + model = TicketCategory + + prefix = 'ticket_category' + + def __init__(self, *args, **kwargs): + + super().__init__(*args, **kwargs) + + self.fields['parent'].queryset = self.fields['parent'].queryset.exclude( + id=self.instance.pk + ) + + + def clean(self): + + cleaned_data = super().clean() + + pk = self.instance.id + + parent = cleaned_data.get("parent") + + if pk: + + if parent == pk: + + raise ValidationError("Category can't have itself as its parent category") + + return cleaned_data + + + +class DetailForm(TicketCategoryForm): + + + tabs: dict = { + "details": { + "name": "Details", + "slug": "details", + "sections": [ + { + "layout": "double", + "left": [ + 'parent', + 'name', + 'runbook', + 'organization', + 'c_created', + 'c_modified' + ], + "right": [ + 'model_notes', + ] + }, + { + "layout": "double", + "name": "Ticket Types", + "left": [ + 'change', + 'problem' + 'request' + ], + "right": [ + 'incident', + 'project_task' + ] + }, + ] + }, + "notes": { + "name": "Notes", + "slug": "notes", + "sections": [] + } + } + + + def __init__(self, *args, **kwargs): + + super().__init__(*args, **kwargs) + + + self.fields['c_created'] = forms.DateTimeField( + label = 'Created', + input_formats=settings.DATETIME_FORMAT, + disabled = True, + initial = self.instance.created, + ) + + self.fields['c_modified'] = forms.DateTimeField( + label = 'Modified', + input_formats=settings.DATETIME_FORMAT, + disabled = True, + initial = self.instance.modified, + ) + + + self.tabs['details'].update({ + "edit_url": reverse('Settings:_ticket_category_change', kwargs={'pk': self.instance.pk}) + }) + + self.url_index_view = reverse('Settings:_ticket_categories') + diff --git a/app/core/migrations/0006_ticketcategory.py b/app/core/migrations/0006_ticketcategory.py new file mode 100644 index 00000000..3dfe26ac --- /dev/null +++ b/app/core/migrations/0006_ticketcategory.py @@ -0,0 +1,43 @@ +# Generated by Django 5.0.8 on 2024-09-13 01:10 + +import access.fields +import access.models +import django.db.models.deletion +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('access', '0001_initial'), + ('assistance', '0001_initial'), + ('core', '0005_ticket_relatedtickets_ticketcomment'), + ] + + operations = [ + migrations.CreateModel( + name='TicketCategory', + fields=[ + ('is_global', models.BooleanField(default=False)), + ('model_notes', models.TextField(blank=True, default=None, null=True, verbose_name='Notes')), + ('id', models.AutoField(help_text='Category ID Number', primary_key=True, serialize=False, unique=True, verbose_name='Number')), + ('created', access.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False)), + ('modified', access.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False)), + ('name', models.CharField(help_text='Category Name', max_length=50, verbose_name='Name')), + ('change', models.BooleanField(default=True, help_text='Use category for change tickets', verbose_name='Change Tickets')), + ('incident', models.BooleanField(default=True, help_text='Use category for incident tickets', verbose_name='Incident Tickets')), + ('problem', models.BooleanField(default=True, help_text='Use category for problem tickets', verbose_name='Problem Tickets')), + ('project_task', models.BooleanField(default=True, help_text='Use category for Project tasks', verbose_name='Project Tasks')), + ('request', models.BooleanField(default=True, help_text='Use category for request tickets', verbose_name='Request Tickets')), + ('organization', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='access.organization', validators=[access.models.TenancyObject.validatate_organization_exists])), + ('parent', models.ForeignKey(blank=True, help_text='The Parent Category', null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.ticketcategory', verbose_name='Parent Category')), + ('runbook', models.ForeignKey(blank=True, help_text='The runbook for this category', null=True, on_delete=django.db.models.deletion.SET_NULL, to='assistance.knowledgebase', verbose_name='Runbook')), + ], + options={ + 'verbose_name': 'Ticket Category', + 'verbose_name_plural': 'Ticket Categories', + 'ordering': ['name'], + }, + ), + ] diff --git a/app/core/models/ticket/ticket_category.py b/app/core/models/ticket/ticket_category.py new file mode 100644 index 00000000..73e128f4 --- /dev/null +++ b/app/core/models/ticket/ticket_category.py @@ -0,0 +1,111 @@ +from django.db import models + +from access.fields import AutoCreatedField, AutoLastModifiedField +from access.models import TenancyObject, Team + +from assistance.models.knowledge_base import KnowledgeBase + + + +class TicketCategoryCommonFields(TenancyObject): + + class Meta: + abstract = True + + id = models.AutoField( + blank=False, + help_text = 'Category ID Number', + primary_key=True, + unique=True, + verbose_name = 'Number', + ) + + created = AutoCreatedField() + + modified = AutoLastModifiedField() + + + +class TicketCategory(TicketCategoryCommonFields): + + + class Meta: + + ordering = [ + 'name' + ] + + verbose_name = "Ticket Category" + + verbose_name_plural = "Ticket Categories" + + + parent = models.ForeignKey( + 'self', + blank= True, + help_text = 'The Parent Category', + null = True, + on_delete = models.SET_NULL, + verbose_name = 'Parent Category', + ) + + name = models.CharField( + blank = False, + help_text = "Category Name", + max_length = 50, + verbose_name = 'Name', + ) + + runbook = models.ForeignKey( + KnowledgeBase, + blank= True, + help_text = 'The runbook for this category', + null = True, + on_delete = models.SET_NULL, + verbose_name = 'Runbook', + ) + + change = models.BooleanField( + blank = False, + default = True, + help_text = 'Use category for change tickets', + null = False, + verbose_name = 'Change Tickets', + ) + + incident = models.BooleanField( + blank = False, + default = True, + help_text = 'Use category for incident tickets', + null = False, + verbose_name = 'Incident Tickets', + ) + + problem = models.BooleanField( + blank = False, + default = True, + help_text = 'Use category for problem tickets', + null = False, + verbose_name = 'Problem Tickets', + ) + + project_task = models.BooleanField( + blank = False, + default = True, + help_text = 'Use category for Project tasks', + null = False, + verbose_name = 'Project Tasks', + ) + + request = models.BooleanField( + blank = False, + default = True, + help_text = 'Use category for request tickets', + null = False, + verbose_name = 'Request Tickets', + ) + + + def __str__(self): + + return self.name diff --git a/app/core/templates/core/index_ticket_categories.html.j2 b/app/core/templates/core/index_ticket_categories.html.j2 new file mode 100644 index 00000000..47099704 --- /dev/null +++ b/app/core/templates/core/index_ticket_categories.html.j2 @@ -0,0 +1,29 @@ +{% extends 'base.html.j2' %} + +{% block content %} + + +
Name | +Organization | +created | +modified | ++ + {% if items %} + {% for category in items %} + |
---|---|---|---|---|
{{ category.name }} | +{{ category.organization }} | +{{ category.created }} | +{{ category.modified }} | ++ |
Nothing Found |