emile 1 year ago
parent 661aef2a0d
commit 657a6641a1

@ -6,6 +6,7 @@ from django.template.loader import get_template
from django.conf import settings from django.conf import settings
import os import os
from weasyprint import HTML, CSS from weasyprint import HTML, CSS
from django.core.files.base import ContentFile
@ -110,7 +111,6 @@ def add_order (request, *args, **kwargs):
def add_invoice_pdf(request, order_id): def add_invoice_pdf(request, order_id):
order = get_object_or_404(Order, id=order_id) order = get_object_or_404(Order, id=order_id)
@ -160,15 +160,10 @@ def add_invoice_pdf(request, order_id):
) )
# Save PDF to a file
pdf_file_path = os.path.join(settings.MEDIA_ROOT, f'invoice_{invoice.id}.pdf')
with open(pdf_file_path, 'wb') as pdf_file:
pdf_file.write(pdf)
# Associate PDF file path with the Invoice object # Associate PDF file path with the Invoice object
invoice.pdf = pdf_file_path pdf_content = ContentFile(pdf)
invoice.save() filename = f'invoice_{invoice.invoice_number}.pdf'
invoice.pdf.save(filename, pdf_content, save=True)
# Return PDF # Return PDF
response = HttpResponse(pdf, content_type='application/pdf') response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="my_pdf.pdf"' response['Content-Disposition'] = 'attachment; filename="my_pdf.pdf"'

@ -0,0 +1,18 @@
# Generated by Django 4.2.5 on 2024-04-24 18:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('billing', '0042_order_due_date'),
]
operations = [
migrations.AlterField(
model_name='invoice',
name='pdf',
field=models.FileField(blank=True, null=True, upload_to='generated_invoices'),
),
]

@ -0,0 +1,18 @@
# Generated by Django 4.2.5 on 2024-04-24 18:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('billing', '0043_alter_invoice_pdf'),
]
operations = [
migrations.AlterField(
model_name='orderitem',
name='active',
field=models.BooleanField(blank=True, null=True),
),
]

@ -58,7 +58,7 @@ class Order(models.Model):
class OrderItem(models.Model): class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE) order = models.ForeignKey(Order, on_delete=models.CASCADE)
item = models.ForeignKey(Item, on_delete=models.CASCADE) item = models.ForeignKey(Item, on_delete=models.CASCADE)
active = models.BooleanField(default=False, null=True) active = models.BooleanField(null=True, blank=True)
purchased_at = models.DateField(null=True, blank=True) purchased_at = models.DateField(null=True, blank=True)
end_at = models.DateField(blank=True, null=True) end_at = models.DateField(blank=True, null=True)
terminated_at = models.DateField(blank=True, null=True) terminated_at = models.DateField(blank=True, null=True)
@ -98,7 +98,7 @@ class Invoice(models.Model):
invoice_number = models.CharField(max_length=100, null=True, blank=True) invoice_number = models.CharField(max_length=100, null=True, blank=True)
order = models.OneToOneField(Order, on_delete=models.SET_NULL, null=True) order = models.OneToOneField(Order, on_delete=models.SET_NULL, null=True)
date_created = models.DateField() date_created = models.DateField()
pdf = models.FileField(upload_to='uploaded_images', null=True, blank=True) pdf = models.FileField(upload_to='generated_invoices', null=True, blank=True)
def __str__(self): def __str__(self):
return self.invoice_number return self.invoice_number
def save(self, *args, **kwargs): def save(self, *args, **kwargs):

@ -135,7 +135,7 @@
<body> <body>
<div class="mainContainer"> <div class="mainContainer">
<div class="logoContainer"> <div class="logoContainer">
<img src="https://newosina.osinode.com/static/images/ositcom_logos/full-logo.png"> <img src="https://osina.ositcom.com/static/images/ositcom_logos/full-logo.png">
</div> </div>

@ -77,14 +77,18 @@
<p class="text-slate-800">{{invoice.date_created}}</p> <p class="text-slate-800">{{invoice.date_created}}</p>
</td> </td>
<td class="px-6 py-4"> <td class="px-6 py-4">
<div class="w-full flex justify-center items-center"> <a href="{{invoice.pdf.url}}">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-[18px] text-blue-500"> <div class="w-full flex justify-center items-center">
<path fill-rule="evenodd" d="M5.625 1.5H9a3.75 3.75 0 0 1 3.75 3.75v1.875c0 1.036.84 1.875 1.875 1.875H16.5a3.75 3.75 0 0 1 3.75 3.75v7.875c0 1.035-.84 1.875-1.875 1.875H5.625a1.875 1.875 0 0 1-1.875-1.875V3.375c0-1.036.84-1.875 1.875-1.875Zm5.845 17.03a.75.75 0 0 0 1.06 0l3-3a.75.75 0 1 0-1.06-1.06l-1.72 1.72V12a.75.75 0 0 0-1.5 0v4.19l-1.72-1.72a.75.75 0 0 0-1.06 1.06l3 3Z" clip-rule="evenodd" /> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-[18px] text-blue-500">
<path d="M14.25 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 16.5 7.5h-1.875a.375.375 0 0 1-.375-.375V5.25Z" /> <path fill-rule="evenodd" d="M5.625 1.5H9a3.75 3.75 0 0 1 3.75 3.75v1.875c0 1.036.84 1.875 1.875 1.875H16.5a3.75 3.75 0 0 1 3.75 3.75v7.875c0 1.035-.84 1.875-1.875 1.875H5.625a1.875 1.875 0 0 1-1.875-1.875V3.375c0-1.036.84-1.875 1.875-1.875Zm5.845 17.03a.75.75 0 0 0 1.06 0l3-3a.75.75 0 1 0-1.06-1.06l-1.72 1.72V12a.75.75 0 0 0-1.5 0v4.19l-1.72-1.72a.75.75 0 0 0-1.06 1.06l3 3Z" clip-rule="evenodd" />
</svg> <path d="M14.25 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 16.5 7.5h-1.875a.375.375 0 0 1-.375-.375V5.25Z" />
</div> </svg>
</div>
</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

@ -95,10 +95,12 @@
{% endif %} {% endif %}
{% if order.invoice %} {% if order.invoice %}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-[18px] text-blue-500"> <a href="{{order.invoice.pdf.url}}">
<path fill-rule="evenodd" d="M5.625 1.5H9a3.75 3.75 0 0 1 3.75 3.75v1.875c0 1.036.84 1.875 1.875 1.875H16.5a3.75 3.75 0 0 1 3.75 3.75v7.875c0 1.035-.84 1.875-1.875 1.875H5.625a1.875 1.875 0 0 1-1.875-1.875V3.375c0-1.036.84-1.875 1.875-1.875Zm5.845 17.03a.75.75 0 0 0 1.06 0l3-3a.75.75 0 1 0-1.06-1.06l-1.72 1.72V12a.75.75 0 0 0-1.5 0v4.19l-1.72-1.72a.75.75 0 0 0-1.06 1.06l3 3Z" clip-rule="evenodd" /> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-[18px] text-blue-500">
<path d="M14.25 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 16.5 7.5h-1.875a.375.375 0 0 1-.375-.375V5.25Z" /> <path fill-rule="evenodd" d="M5.625 1.5H9a3.75 3.75 0 0 1 3.75 3.75v1.875c0 1.036.84 1.875 1.875 1.875H16.5a3.75 3.75 0 0 1 3.75 3.75v7.875c0 1.035-.84 1.875-1.875 1.875H5.625a1.875 1.875 0 0 1-1.875-1.875V3.375c0-1.036.84-1.875 1.875-1.875Zm5.845 17.03a.75.75 0 0 0 1.06 0l3-3a.75.75 0 1 0-1.06-1.06l-1.72 1.72V12a.75.75 0 0 0-1.5 0v4.19l-1.72-1.72a.75.75 0 0 0-1.06 1.06l3 3Z" clip-rule="evenodd" />
</svg> <path d="M14.25 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 16.5 7.5h-1.875a.375.375 0 0 1-.375-.375V5.25Z" />
</svg>
</a>
{% endif %} {% endif %}

@ -0,0 +1,59 @@
# Generated by Django 4.2.5 on 2024-04-24 19:30
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('osinacore', '0075_remove_ticketattachment_ticket_and_more'),
('billing', '0044_alter_orderitem_active'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Ticket',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=400)),
('description', models.TextField(blank=True, null=True)),
('regarding', models.CharField(choices=[('General/Account/Billing', 'General/Account/Billing'), ('Project/Product', 'Project/Product')], max_length=50, null=True)),
('opened_date', models.DateTimeField()),
('department', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='osinacore.department')),
('opened_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
('product', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='billing.item')),
('project', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='osinacore.project')),
],
),
migrations.CreateModel(
name='TicketUpdate',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('description', models.TextField(blank=True, null=True)),
('date_added', models.DateTimeField()),
('added_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='customercore.ticket')),
],
),
migrations.CreateModel(
name='TicketReaction',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ticket_update', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='customercore.ticketupdate')),
],
),
migrations.CreateModel(
name='TicketAttachment',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('file', models.FileField(upload_to='')),
('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='customercore.ticket')),
('ticket_update', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='customercore.ticketupdate')),
],
),
]

@ -1,3 +1,39 @@
from django.db import models from django.db import models
from billing.models import *
# Create your models here. # Create your models here.
class Ticket(models.Model):
REGARDING_CHOICES = (
('General/Account/Billing', 'General/Account/Billing'),
('Project/Product', 'Project/Product'),
)
title = models.CharField(max_length=400)
description = models.TextField(null=True, blank=True)
regarding = models.CharField(max_length=50, choices=REGARDING_CHOICES, null=True)
project = models.ForeignKey(Project, on_delete=models.SET_NULL, blank=True, null=True)
product = models.ForeignKey(Item, on_delete=models.SET_NULL, blank=True, null=True)
department = models.ForeignKey(Department, on_delete=models.SET_NULL,null=True)
opened_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
opened_date = models.DateTimeField()
class TicketUpdate(models.Model):
ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE)
description = models.TextField(null=True, blank=True)
added_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
date_added = models.DateTimeField()
class TicketAttachment(models.Model):
ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE)
ticket_update = models.ForeignKey(TicketUpdate, on_delete=models.CASCADE)
file = models.FileField()
class TicketReaction(models.Model):
REGARDING_CHOICES = (
('Happy', 'Happy'),
('Indifferent', 'Indifferent'),
('Sad', 'Sad'),
)
ticket_update = models.ForeignKey(TicketUpdate, on_delete=models.CASCADE)

@ -6,14 +6,14 @@
<div class="w-full px-5 s:px-9 flex flex-col gap-3"> <div class="w-full px-5 s:px-9 flex flex-col gap-3">
<div class="w-full bg-white rounded-md h-fit shadow-md p-5"> <div class="w-full bg-white rounded-md h-fit shadow-md p-5">
<h1 class="text-3xl text-secondosiblue text-center font-semibold"> <h1 class="text-3xl text-secondosiblue text-center font-semibold">
Open Ticket Create Ticket
</h1> </h1>
<form class="w-full flex flex-col gap-5 justify-center items-center mt-5" method="POST" action=""> <form class="w-full flex flex-col gap-5 justify-center items-center mt-5" method="POST" action="">
{% csrf_token %} {% csrf_token %}
<div class="w-full"> <div class="w-full">
<label class="text-gray-500">Ticket Title:</label> <label class="text-gray-500">Title:</label>
<input required name="title" type="text" <input required name="title" type="text"
class="w-full h-[50px] py-1 px-3 border border-gray-300 outline-none rounded-md mt-1"> class="w-full h-[50px] py-1 px-3 border border-gray-300 outline-none rounded-md mt-1">
</div> </div>
@ -21,12 +21,18 @@
<div class="w-full"> <div class="w-full">
<label class="text-gray-500">What is this regarding?</label> <label class="text-gray-500">What is this regarding?</label>
<select class="w-full h-[50px] py-1 px-3 border border-gray-300 outline-none rounded-md mt-1"> <select class="w-full h-[50px] py-1 px-3 border border-gray-300 outline-none rounded-md mt-1">
<option value="">General Accounting</option> <option value="General/Account/Billing">General/Account/Billing</option>
{% for customer_product in customer_products %}
<option value="">{{customer_product.item.title}}</option>
{% endfor %}
{% for customer_project in customer_projects %}
<option value="">{{customer_project.title}}</option>
{% endfor %}
</select> </select>
</div> </div>
<div class="w-full"> <div class="w-full">
<label class="text-gray-500">Desceription:</label> <label class="text-gray-500">Description:</label>
<textarea required name="description" <textarea required name="description"
class="w-full py-1 px-3 border border-gray-300 outline-none rounded-md mt-1 resize-none" class="w-full py-1 px-3 border border-gray-300 outline-none rounded-md mt-1 resize-none"
rows="8"></textarea> rows="8"></textarea>

@ -69,14 +69,17 @@
<td class="px-6 py-4"> <td class="px-6 py-4">
<div class="w-full flex justify-center items-center gap-3"> <div class="w-full flex justify-center items-center gap-3">
<button
class="w-fit px-3 py-2 rounded-md bg-gray-100 border border-gray-100 shadow-md cursor-pointer hover:scale-105 duration-300 transition-transform"> <a href="{{invoice.pdf.url}}">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" <button
stroke-width="1.5" stroke="currentColor" class="w-4 h-4 text-secondosiblue"> class="w-fit px-3 py-2 rounded-md bg-gray-100 border border-gray-100 shadow-md cursor-pointer hover:scale-105 duration-300 transition-transform">
<path stroke-linecap="round" stroke-linejoin="round" <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3" /> stroke-width="1.5" stroke="currentColor" class="w-4 h-4 text-secondosiblue">
</svg> <path stroke-linecap="round" stroke-linejoin="round"
</button> d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3" />
</svg>
</button>
</a>
{% if not invoice.order.status == 'Completed' %} {% if not invoice.order.status == 'Completed' %}

@ -59,12 +59,14 @@
</td> </td>
<td class="px-6 py-4"> <td class="px-6 py-4">
<div class="w-full flex justify-center items-center"> <a href="{{order.invoice.pdf.url}}">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-[25px] text-blue-500"> <div class="w-full flex justify-center items-center">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3" /> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-[25px] text-blue-500">
</svg> <path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3" />
</svg>
</div>
</div>
</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}

@ -18,7 +18,7 @@
<a href="{% url 'customeraddticket' %}"> <a href="{% url 'customeraddticket' %}">
<button class="w-fit px-5 py-2 bg-osiblue border border-osiblue text-white rounded-md cursor-pointer hover:bg-white hover:text-secondosiblue duration-300"> <button class="w-fit px-5 py-2 bg-osiblue border border-osiblue text-white rounded-md cursor-pointer hover:bg-white hover:text-secondosiblue duration-300">
Open Ticket Create Ticket
</button> </button>
</a> </a>
</div> </div>

@ -31,8 +31,12 @@ def redirect_osicard(request):
# ADD # ADD
@customer_login_required @customer_login_required
def customer_add_ticket(request, *args, **kwargs): def customer_add_ticket(request, *args, **kwargs):
customer_products = OrderItem.objects.filter(order__status='Completed', active__in=[True, None], item__type = 'Product', order__customer = request.user.customerprofile)
customer_projects = Project.objects.filter(customer=request.user.customerprofile)
context = { context = {
'customer_products': customer_products,
'customer_projects': customer_projects,
} }
@ -160,6 +164,15 @@ def dedicated_servers_plans(request, *args, **kwargs):
#Products Payment views
@customer_login_required @customer_login_required
def payment(request, item_id): def payment(request, item_id):
item = get_object_or_404(Item, id=item_id) item = get_object_or_404(Item, id=item_id)
@ -305,7 +318,7 @@ def check_order_status(request, merchant_id, order_id):
item.save() item.save()
order_item.save() order_item.save()
add_invoice_pdf(request, order_id=order.id) add_invoice_pdf(request, order_id=order.id)
return redirect('orders') return redirect('customerorders')
error_message = 'Failed to retrieve order details: ' + response.text error_message = 'Failed to retrieve order details: ' + response.text
return JsonResponse({'error': error_message}, status=500) return JsonResponse({'error': error_message}, status=500)
except Exception as e: except Exception as e:
@ -399,6 +412,20 @@ def buy_free_osicard(request):
return redirect('customerorders') return redirect('customerorders')
#Invoice Payment views
@customer_login_required @customer_login_required
def invoice_payment(request, invoice_id): def invoice_payment(request, invoice_id):
invoice = get_object_or_404(Invoice, id = invoice_id) invoice = get_object_or_404(Invoice, id = invoice_id)

Binary file not shown.

@ -31,6 +31,7 @@ class PointAdmin(admin.ModelAdmin):
admin.site.register(Reference) admin.site.register(Reference)
admin.site.register(Business) admin.site.register(Business)
admin.site.register(CustomerProfile) admin.site.register(CustomerProfile)
admin.site.register(Department)
admin.site.register(StaffProfile) admin.site.register(StaffProfile)
admin.site.register(ProjectType) admin.site.register(ProjectType)
admin.site.register(Project, ProjectAdmin) admin.site.register(Project, ProjectAdmin)

@ -0,0 +1,31 @@
# Generated by Django 4.2.5 on 2024-04-24 18:31
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('osinacore', '0069_alter_business_logo_alter_projectfile_file_and_more'),
]
operations = [
migrations.CreateModel(
name='Department',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
],
),
migrations.AlterField(
model_name='staffprofile',
name='staff_position',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='osinacore.staffposition'),
),
migrations.AddField(
model_name='staffposition',
name='department',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='osinacore.department'),
),
]

@ -0,0 +1,33 @@
# Generated by Django 4.2.5 on 2024-04-24 18:36
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('osinacore', '0070_department_alter_staffprofile_staff_position_and_more'),
]
operations = [
migrations.AddField(
model_name='projecttype',
name='department',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='osinacore.department'),
),
migrations.CreateModel(
name='Ticket',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=400)),
('description', models.TextField(blank=True, null=True)),
('regarding', models.CharField(choices=[('General/Account/Billing', 'General/Account/Billing'), ('Service/Product', 'Service/Product')], max_length=50, null=True)),
('opened_date', models.DateTimeField()),
('department', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='osinacore.department')),
('opened_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
],
),
]

@ -0,0 +1,42 @@
# Generated by Django 4.2.5 on 2024-04-24 18:41
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('osinacore', '0071_projecttype_department_ticket'),
]
operations = [
migrations.CreateModel(
name='TicketUpdate',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('description', models.TextField(blank=True, null=True)),
('dare_added', models.DateTimeField()),
('added_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='osinacore.ticket')),
],
),
migrations.CreateModel(
name='TicketReaction',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ticket_update', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='osinacore.ticketupdate')),
],
),
migrations.CreateModel(
name='TicketAttachment',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('file', models.FileField(upload_to='')),
('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='osinacore.ticket')),
('ticket_update', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='osinacore.ticketupdate')),
],
),
]

@ -0,0 +1,18 @@
# Generated by Django 4.2.5 on 2024-04-24 19:06
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('osinacore', '0072_ticketupdate_ticketreaction_ticketattachment'),
]
operations = [
migrations.AlterField(
model_name='ticket',
name='regarding',
field=models.CharField(choices=[('General/Account/Billing', 'General/Account/Billing'), ('Project/Product', 'Project/Product')], max_length=50, null=True),
),
]

@ -0,0 +1,18 @@
# Generated by Django 4.2.5 on 2024-04-24 19:14
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('osinacore', '0073_alter_ticket_regarding'),
]
operations = [
migrations.RenameField(
model_name='ticketupdate',
old_name='dare_added',
new_name='date_added',
),
]

@ -0,0 +1,45 @@
# Generated by Django 4.2.5 on 2024-04-24 19:29
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('osinacore', '0074_rename_dare_added_ticketupdate_date_added'),
]
operations = [
migrations.RemoveField(
model_name='ticketattachment',
name='ticket',
),
migrations.RemoveField(
model_name='ticketattachment',
name='ticket_update',
),
migrations.RemoveField(
model_name='ticketreaction',
name='ticket_update',
),
migrations.RemoveField(
model_name='ticketupdate',
name='added_by',
),
migrations.RemoveField(
model_name='ticketupdate',
name='ticket',
),
migrations.DeleteModel(
name='Ticket',
),
migrations.DeleteModel(
name='TicketAttachment',
),
migrations.DeleteModel(
name='TicketReaction',
),
migrations.DeleteModel(
name='TicketUpdate',
),
]

@ -8,6 +8,8 @@ from django.db.models import Sum, F
from datetime import timedelta from datetime import timedelta
# Create your models here. # Create your models here.
class Reference(models.Model): class Reference(models.Model):
@ -93,9 +95,15 @@ class Business(models.Model):
class Department(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class StaffPosition(models.Model): class StaffPosition(models.Model):
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True)
def __str__(self): def __str__(self):
return self.name return self.name
@ -106,7 +114,7 @@ class StaffProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE) user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(upload_to='uploaded_images', null=True, blank=True) image = models.ImageField(upload_to='uploaded_images', null=True, blank=True)
mobile_number = models.CharField(max_length=50) mobile_number = models.CharField(max_length=50)
staff_position = models.ForeignKey(StaffPosition, on_delete=models.CASCADE, null=True, blank=True) staff_position = models.ForeignKey(StaffPosition, on_delete=models.SET_NULL, null=True, blank=True)
intern = models.BooleanField(default=False) intern = models.BooleanField(default=False)
active = models.BooleanField(default=True) active = models.BooleanField(default=True)
staff_id = models.CharField(max_length=20, null=True, blank=True) # Allow null and blank for initial creation staff_id = models.CharField(max_length=20, null=True, blank=True) # Allow null and blank for initial creation
@ -126,6 +134,7 @@ class StaffProfile(models.Model):
class ProjectType(models.Model): class ProjectType(models.Model):
name = models.CharField(max_length=50) name = models.CharField(max_length=50)
department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True)
def __str__(self): def __str__(self):
return self.name return self.name
@ -310,10 +319,6 @@ class PointActivity(models.Model):
return 0, 0, 0 return 0, 0, 0
class Status(models.Model): class Status(models.Model):
text = models.TextField(blank=True) text = models.TextField(blank=True)
date = models.CharField(max_length=40) date = models.CharField(max_length=40)
@ -346,4 +351,6 @@ class Connection(models.Model):
) )
status = models.CharField(max_length=200, choices=STATUS_CHOICES, null=True) status = models.CharField(max_length=200, choices=STATUS_CHOICES, null=True)
date = models.DateTimeField(null=True) date = models.DateTimeField(null=True)
user = models.ForeignKey(User, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE)

@ -22,8 +22,8 @@
<label class="text-gray-500">Client:</label> <label class="text-gray-500">Client:</label>
<select required name="customer" <select required name="customer"
class="w-full h-[50px] py-1 px-3 border border-gray-300 outline-none rounded-md text-gray-500 mt-1"> class="w-full h-[50px] py-1 px-3 border border-gray-300 outline-none rounded-md text-gray-500 mt-1">
{% for customer in customers %}
<option value="" selected disabled>Select Client</option> <option value="" selected disabled>Select Client</option>
{% for customer in customers %}
<option value="{{customer.id}}">{{customer.user.first_name}} {{customer.user.last_name}} <option value="{{customer.id}}">{{customer.user.first_name}} {{customer.user.last_name}}
</option> </option>
{% endfor %} {% endfor %}

@ -59,7 +59,7 @@
<!-- TICKETS --> <!-- TICKETS -->
<div class="w-full h-fit bg-white rounded-md shadow-md p-5"> <div class="w-full h-fit bg-white rounded-md shadow-md p-5">
<h1 class="text-secondosiblue text-[25px]">Tickets</h1> <h1 class="text-secondosiblue text-[25px]">Tickets</h1>
<div class="overflow-x-auto border border-gray-300 rounded-md"> <div class="overflow-x-auto border border-gray-300 rounded-md mt-3">
<table class="min-w-full divide-y"> <table class="min-w-full divide-y">
<!-- TABLE HEADER --> <!-- TABLE HEADER -->
<thead class="bg-gray-50"> <thead class="bg-gray-50">

@ -86,14 +86,14 @@
<div class="w-full"> <div class="w-full">
<label class="text-gray-500">Description:</label> <label class="text-gray-500">Description:</label>
<textarea required name="details" type="text" rows="5" cols="5" <textarea required name="details" type="text" rows="5" cols="5"
class="w-full py-3 px-3 border border-gray-300 outline-none rounded-md resize-none mt-1">Lorem ipsum dolor sit amet consectetur adipisicing elit. Illum magnam ea temporibus commodi aspernatur culpa totam similique voluptate veritatis? Odit, excepturi? Itaque suscipit libero iure corrupti consequatur soluta expedita quod? class="w-full py-3 px-3 border border-gray-300 outline-none rounded-md resize-none mt-1">{{project.description}}
</textarea> </textarea>
</div> </div>
<div class="w-full"> <div class="w-full">
<label class="text-gray-500">Start Date:</label> <label class="text-gray-500">Start Date:</label>
<input required name="start_date" type="date" id="date" name="date" <input required name="start_date" type="date" id="date" name="date"
value="2023-09-22" value='{{project.start_date|date:"Y-m-d"}}'
class="w-full p-3 border border-gray-300 rounded-md bg-transparent outline-none mt-1"> class="w-full p-3 border border-gray-300 rounded-md bg-transparent outline-none mt-1">
</div> </div>
@ -101,7 +101,7 @@
<div class="w-full"> <div class="w-full">
<label class="text-gray-500">End Date:</label> <label class="text-gray-500">End Date:</label>
<input required name="end_date" type="date" id="date" name="date" <input required name="end_date" type="date" id="date" name="date"
value="2023-10-22" value='{{project.end_date|date:"Y-m-d"}}'
class="w-full p-3 border border-gray-300 rounded-md bg-transparent outline-none mt-2"> class="w-full p-3 border border-gray-300 rounded-md bg-transparent outline-none mt-2">
</div> </div>

Loading…
Cancel
Save