emile 1 year ago
parent 5d8243243e
commit 066f2e507b

BIN
.DS_Store vendored

Binary file not shown.

BIN
osinaweb/.DS_Store vendored

Binary file not shown.

Binary file not shown.

@ -0,0 +1,9 @@
from django.urls import path
from billing.add import views
urlpatterns = [
path('product', views.add_product, name='addproduct'),
path('service', views.add_service, name='addservice'),
path('order', views.add_order, name='addorder'),
]

@ -0,0 +1,63 @@
from django.shortcuts import render, get_object_or_404, redirect
from osinacore.models import *
from billing.models import *
from django.http import JsonResponse, HttpResponse
from django.template.loader import get_template
from weasyprint import HTML
def add_product (request, *args, **kwargs):
item_types = ProjectType.objects.all().order_by('name')
if request.method == 'POST':
title = request.POST.get('title')
description = request.POST.get('description')
item_type_id = request.POST.get('item_type')
item_type = get_object_or_404(ProjectType, id=item_type_id)
amount = request.POST.get('amount')
recurring = request.POST.get('recurring')
Item.objects.create(
type='Product',
title=title,
description = description,
item_type = item_type,
amount = amount,
recurring = recurring,
)
return redirect('items')
context = {
'item_types' : item_types,
}
return render(request, 'add_templates/add-product.html', context)
def add_service (request, *args, **kwargs):
context = {
}
return render(request, 'add_templates/add-service.html', context)
def add_order (request, *args, **kwargs):
customers = CustomerProfile.objects.all().order_by('-id')
context = {
'customers': customers,
}
return render(request, 'add_templates/add-order.html', context)
def add_invoice_pdf(request):
template = get_template('details_templates/invoice-details.html')
context = {}
html_string = template.render(context)
pdf = HTML(string=html_string).write_pdf()
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="my_pdf.pdf"'
return response

@ -0,0 +1,22 @@
# Generated by Django 4.2.5 on 2024-04-12 17:48
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('billing', '0025_remove_item_project_item_customer'),
]
operations = [
migrations.RenameField(
model_name='item',
old_name='type',
new_name='item_type',
),
migrations.RemoveField(
model_name='order',
name='paid',
),
]

@ -0,0 +1,18 @@
# Generated by Django 4.2.5 on 2024-04-12 17:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('billing', '0026_rename_type_item_item_type_remove_order_paid'),
]
operations = [
migrations.AddField(
model_name='item',
name='type',
field=models.CharField(choices=[('Product', 'Product'), ('Service', 'Service')], max_length=200, null=True),
),
]

@ -17,10 +17,11 @@ class Item(models.Model):
('Product', 'Product'),
('Service', 'Service'),
)
type = models.CharField(max_length=200, choices=TYPE, null=True)
title = models.CharField(max_length=200)
description = models.TextField(blank=True)
customer = models.ForeignKey(CustomerProfile, null=True, blank=True, on_delete=models.CASCADE)
type = models.ForeignKey(ProjectType, on_delete=models.CASCADE, null=True, blank=True)
item_type = models.ForeignKey(ProjectType, on_delete=models.CASCADE, null=True, blank=True)
amount = models.FloatField(null=True)
recurring = models.BooleanField(default=False)
def __str__(self):
@ -38,7 +39,6 @@ class Order(models.Model):
status = models.CharField(max_length=200, choices=STATUS, default='None')
order_id = models.CharField(max_length=100, null=True, blank=True)
due_date = models.DateField(null=True)
paid = models.BooleanField(null=True, default=False)
@property
def get_cart_total(self):
orderitems = self.orderitem_set.all()

Binary file not shown.

@ -8,55 +8,48 @@
Add Product
</h1>
<form method="POST" action="" enctype="multipart/form-data">
<form method="POST" action="{% url 'addproduct' %}" enctype="multipart/form-data">
{% csrf_token %}
<div class="w-full flex flex-col gap-5">
<div class="w-full">
<label class="text-gray-500">Title:</label>
<input name="" type="text"
<input name="title" type="text"
class="w-full h-[50px] py-1 px-3 border border-gray-300 outline-none rounded-md mt-1" required>
</div>
<div class="w-full">
<label class="text-gray-500">Description:</label>
<textarea name="" type="text"
<textarea name="description" type="text"
class="w-full py-1 px-3 border border-gray-300 outline-none rounded-md mt-1 resize-none"
rows="8" required></textarea>
</div>
<div class="w-full">
<label class="text-gray-500">Customer:</label>
<select name="type" id=""
class="w-full h-[50px] py-1 px-3 border border-gray-300 outline-none rounded-md text-gray-500 mt-1">
<option value="">Customer 1</option>
<option value="">Customer 2</option>
</select>
</div>
<div class="w-full">
<label class="text-gray-500">Project Type:</label>
<select name="type" id=""
<label class="text-gray-500">Type:</label>
<select name="item_type" id=""
class="w-full h-[50px] py-1 px-3 border border-gray-300 outline-none rounded-md text-gray-500 mt-1" required>
<option value="">Type 1</option>
<option value="">Type 2</option>
<option value="" disabled selected>Select Type</option>
{% for type in item_types %}
<option value="{{type.id}}">{{type.name}}</option>
{% endfor %}
</select>
</div>
<div class="w-full">
<label class="text-gray-500">Amount:</label>
<input name="" type="decimal"
<input name="amount" type="decimal"
class="w-full h-[50px] py-1 px-3 border border-gray-300 outline-none rounded-md mt-1" required>
</div>
<div class="w-full">
<label class="text-gray-500">Recurring:</label>
<select name="" id=""
<select name="recurring" id=""
class="w-full h-[50px] py-1 px-3 border border-gray-300 outline-none rounded-md text-gray-500 mt-1" required>
<option value="">True</option>
<option value="">False</option>
<option value="True">True</option>
<option value="False">False</option>
</select>
</div>

@ -21,7 +21,7 @@
</div>
<div class="w-full bg-osiblue h-[50px]">
<div class="w-full bg-osiblue h-[50px]" style="background-color: red;">
</div>
</div>

@ -41,10 +41,6 @@
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
Title
</th>
<th scope="col"
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
Customer
</th>
<th scope="col"
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
Type
@ -61,21 +57,18 @@
<!-- TABLE BODY -->
<tbody class="bg-white divide-y divide-gray-200">
{% for product in products %}
<tr>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
<p class="text-slate-800">Item 1</p>
<p class="text-slate-800">{{product.title}}</p>
</td>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
<p class="text-slate-800">Nataly</p>
<p class="text-slate-800">{{product.item_type}}</p>
</td>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
<p class="text-slate-800">Type</p>
</td>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
<p class="text-slate-800">222</p>
<p class="text-slate-800">${{product.amount}}</p>
</td>
@ -97,6 +90,7 @@
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>

@ -1,36 +1,20 @@
from django.contrib import admin
from django.urls import path, include
from django.conf.urls import handler404
from django.conf.urls.static import static
from django.conf import settings
from billing import views
urlpatterns = [
path('add/', include('billing.add.urls')),
# LISTING
path('items', views.items, name='items'),
path('orders', views.orders, name='orders'),
path('invoices', views.invoices, name='invoices'),
# ADD
path('add-product', views.add_product, name='addproduct'),
path('add-service', views.add_service, name='addservice'),
path('add-order', views.add_order, name='addorder'),
path('fetch-customer-items/<int:customer_id>/', views.fetch_customer_items, name='fetch_customer_items'),
path('fetch-invoice-details/<int:invoice_id>/', views.fetch_invoice_details, name='fetchinvoicedetails'),
# DETAILS
path('invoice-details/<int:invoice_id>/', views.invoice_details, name='invoicedetails'),
path('generate-pdf/', views.generate_pdf, name='generate-pdf'),
path('fetch-customer-items/<int:customer_id>/', views.fetch_customer_items, name='fetch_customer_items'),
]

@ -9,7 +9,9 @@ from weasyprint import HTML
# LISTING
def items (request, *args, **kwargs):
products = Item.objects.filter(type='Product').order_by('-id')
context = {
'products': products,
}
return render(request, 'listing_pages/items.html', context)
@ -32,31 +34,17 @@ def invoices (request, *args, **kwargs):
return render(request, 'listing_pages/invoices.html', context)
#DETAILS
def invoice_details (request, invoice_id):
invoice = get_object_or_404(Invoice, id=invoice_id)
# ADD
def add_product (request, *args, **kwargs):
context = {
}
return render(request, 'add_templates/add-product.html', context)
def add_service (request, *args, **kwargs):
context = {
'invoice' : invoice,
}
return render(request, 'add_templates/add-service.html', context)
def add_order (request, *args, **kwargs):
customers = CustomerProfile.objects.all().order_by('-id')
return render(request, 'invoice-details.html', context)
context = {
'customers': customers,
}
return render(request, 'add_templates/add-order.html', context)
@ -74,51 +62,3 @@ def fetch_customer_items(request, customer_id):
}
return JsonResponse(data)
def fetch_invoice_details(request, invoice_id):
invoice = get_object_or_404(Invoice, id=invoice_id)
order = invoice.order
order_items = OrderItem.objects.filter(order=order)
order_total = order.get_cart_total
data = {
'invoice_number': invoice.invoice_number,
'order_id': order.order_id,
'order_total' : order_total,
'date_created': invoice.date_created,
'customer_first_name': order.customer.user.first_name,
'customer_last_name': order.customer.user.last_name,
'customer_email': order.customer.user.email,
'order_items': list(order_items.values()), # Convert QuerySet to list of dictionaries
}
return JsonResponse(data)
def invoice_details (request, invoice_id):
invoice = get_object_or_404(Invoice, id=invoice_id)
context = {
'invoice' : invoice,
}
return render(request, 'invoice-details.html', context)
def generate_pdf(request):
template = get_template('invoice-details.html')
context = {}
html_string = template.render(context)
pdf = HTML(string=html_string).write_pdf()
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="my_pdf.pdf"'
return response

Binary file not shown.

@ -27,6 +27,7 @@ urlpatterns = [
path('businesstype/', views.add_businesstype_modal, name='addbusinesstypemodal'),
path('reference/', views.add_reference_modal, name='addreferencemodal'),
path('tag/', views.add_tag_modal, name='addtagmodal'),
path('reaction/<int:status_id>/<str:emoji>/', views.add_reaction, name='add_reaction'),

@ -616,7 +616,7 @@ def add_reference_modal(request, *args, **kwargs):
@staff_login_required
def add_tag_modal(request, *args, **kwargs):
if request.method == 'POST':
name = request.POST.get('name')
@ -633,6 +633,20 @@ def add_tag_modal(request, *args, **kwargs):
@staff_login_required
def add_reaction(request, status_id, emoji):
status = get_object_or_404(Status, pk=status_id)
user = request.user
existing_reaction = Reaction.objects.filter(status=status, user=user).first()
if existing_reaction:
# If the user has already reacted, update the reaction
existing_reaction.emoji = emoji
existing_reaction.save()
return JsonResponse({'message': 'Reaction updated successfully.'})
else:
# If the user hasn't reacted yet, create a new reaction
new_reaction = Reaction.objects.create(status=status, emoji=emoji, user=user)
return JsonResponse({'message': 'Reaction added successfully.'})

@ -21,12 +21,17 @@ class Reference(models.Model):
return f"{parts[2]}-{parts[1]}-{parts[0]}"
class Tag(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class BusinessType(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Business(models.Model):
@ -39,7 +44,9 @@ class Business(models.Model):
website = models.URLField(null=True)
type = models.ForeignKey(BusinessType, on_delete=models.CASCADE, null=True, blank=True)
logo = models.ImageField()
business_id = models.CharField(max_length=20, null=True, blank=True) # Allow null and blank for initial creation
business_id = models.CharField(max_length=20, null=True, blank=True)
def __str__(self):
return self.name
class Meta:
verbose_name_plural = u'Businesses'
def __str__(self):
@ -102,7 +109,6 @@ class StaffProfile(models.Model):
intern = models.BooleanField(default=False)
active = models.BooleanField(default=True)
staff_id = models.CharField(max_length=20, null=True, blank=True) # Allow null and blank for initial creation
def __str__(self):
return self.user.username
def save(self, *args, **kwargs):
@ -119,6 +125,8 @@ class StaffProfile(models.Model):
class ProjectType(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
@ -138,7 +146,9 @@ class Project(models.Model):
status = models.CharField(max_length=200, choices=STATUS_CHOICES)
start_date = models.CharField(max_length=200)
end_date = models.CharField(max_length=200)
project_id = models.CharField(max_length=20, null=True, blank=True) # Allow null and blank for initial creation
project_id = models.CharField(max_length=20, null=True, blank=True)
def __str__(self):
return self.name
def save(self, *args, **kwargs):
if not self.project_id:
# Get the last two digits of the current year
@ -156,6 +166,8 @@ class Milestone(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True)
start_date = models.DateField()
end_date = models.DateField()
def __str__(self):
return self.title
class Epic(models.Model):
@ -169,6 +181,8 @@ class Epic(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True)
start_date = models.CharField(max_length=200)
end_date = models.CharField(max_length=200)
def __str__(self):
return self.title
class ProjectRequirement(models.Model):
@ -176,6 +190,8 @@ class ProjectRequirement(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True)
date = models.DateField(null=True, auto_now=True)
added_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.content
class ProjectFile(models.Model):
@ -302,6 +318,8 @@ class Status(models.Model):
date = models.CharField(max_length=40)
time = models.CharField(max_length=40)
staff = models.ForeignKey(StaffProfile, on_delete=models.CASCADE, null=True,blank=True, related_name='staff')
def __str__(self):
return self.text
class Reaction(models.Model):

@ -10,10 +10,9 @@ from django.http import JsonResponse
from .models import Task, Epic
from django.template.loader import render_to_string
from .custom_context import calculate_time_ago
from django.core.validators import validate_email
from django.core.exceptions import ValidationError
from django.template.loader import get_template
from .decorators import *
from django.contrib import messages
def login_with_email(request, email, key):
@ -27,7 +26,7 @@ def login_with_email(request, email, key):
else:
pass
from django.contrib import messages
# Pages views
def signin(request):
if request.user.is_authenticated:

Loading…
Cancel
Save