emile 1 year ago
parent 9e430f7bdf
commit 81b59f4871

@ -6,5 +6,6 @@ urlpatterns = [
path('product', views.add_product, name='addproduct'),
path('service', views.add_service, name='addservice'),
path('order', views.add_order, name='addorder'),
path('invoice/<int:order_id>/', views.add_invoice_pdf, name='addinvoice'),
]

@ -5,6 +5,7 @@ from django.http import JsonResponse, HttpResponse
from django.template.loader import get_template
from django.conf import settings
import os
from weasyprint import HTML, CSS
@ -81,11 +82,18 @@ def add_order (request, *args, **kwargs):
customer_id = request.POST.get('customer')
customer = get_object_or_404(CustomerProfile, id=customer_id)
business_id = request.POST.get('business')
if business_id:
business = get_object_or_404(Business, id=business_id)
else:
business = None
selected_items = request.POST.getlist('items')
order = Order.objects.create(
customer=customer,
status=status
status=status,
business=business,
)
for item_id in selected_items:
@ -103,9 +111,66 @@ def add_order (request, *args, **kwargs):
def add_invoice_pdf(request, order_id):
order = get_object_or_404(Order, id=order_id)
current_year = str(timezone.now().year)[-2:]
last_invoice = Invoice.objects.filter(invoice_number__startswith=current_year).order_by('-invoice_number').first()
if last_invoice:
last_invoice_number = int(last_invoice.invoice_number.split('-')[1].split('+')[0])
new_invoice_number = f"${current_year}-{last_invoice_number + 1}"
else:
new_invoice_number = f"${current_year}-1425"
invoice = Invoice.objects.create(
invoice_number = new_invoice_number,
order=order,
date_created=datetime.now(),
)
template = get_template('details_templates/invoice-details.html')
context = {'order': order}
html_string = template.render(context)
# Define the CSS string with Poppins font
css_string = '''
@font-face {
font-family: 'Poppins';
src: url('path_to_poppins_font_file.ttf') format('truetype'); /* Update the path to the font file */
}
body {
font-family: 'Poppins', sans-serif; /* Use Poppins font for the entire document */
}
/* Your existing CSS styles */
/* Add or modify styles as needed */
'''
# Generate PDF
pdf = HTML(string=html_string).write_pdf(
stylesheets=[
CSS(string=css_string),
CSS(string='@page { margin: 30px; }')
],
presentational_hints=True
)
# 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
invoice.pdf = pdf_file_path
invoice.save()
# Return PDF
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="my_pdf.pdf"'
return response

@ -0,0 +1,20 @@
# Generated by Django 4.2.5 on 2024-04-17 17:44
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('osinacore', '0065_alter_customerprofile_status'),
('billing', '0031_alter_invoice_invoice_number'),
]
operations = [
migrations.AddField(
model_name='order',
name='business',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='osinacore.business'),
),
]

@ -0,0 +1,18 @@
# Generated by Django 4.2.5 on 2024-04-17 18:47
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('billing', '0032_order_business'),
]
operations = [
migrations.AlterField(
model_name='order',
name='status',
field=models.CharField(choices=[('Completed', 'Completed'), ('Failed', 'Failed'), ('Cancelled', 'Cancelled'), ('None', 'None'), ('Pending', 'Pending')], default='None', max_length=200),
),
]

@ -0,0 +1,18 @@
# Generated by Django 4.2.5 on 2024-04-17 19:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('billing', '0033_alter_order_status'),
]
operations = [
migrations.AlterField(
model_name='invoice',
name='pdf',
field=models.FileField(blank=True, null=True, upload_to='images/invoices/'),
),
]

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

@ -0,0 +1,18 @@
# Generated by Django 4.2.5 on 2024-04-17 19:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('billing', '0035_alter_invoice_pdf'),
]
operations = [
migrations.AlterField(
model_name='invoice',
name='invoice_number',
field=models.CharField(blank=True, max_length=100, null=True),
),
]

@ -34,8 +34,10 @@ class Order(models.Model):
('Failed', 'Failed'),
('Cancelled', 'Cancelled'),
('None', 'None'),
('Pending', 'Pending'),
)
customer = models.ForeignKey(CustomerProfile, on_delete=models.CASCADE)
business = models.ForeignKey(Business, on_delete=models.SET_NULL, null=True, blank=True)
status = models.CharField(max_length=200, choices=STATUS, default='None')
order_id = models.CharField(max_length=100, null=True, blank=True)
@property
@ -87,12 +89,24 @@ class OrderItem(models.Model):
class Invoice(models.Model):
invoice_number = models.CharField(max_length=100, null=True)
invoice_number = models.CharField(max_length=100, null=True, blank=True)
order = models.OneToOneField(Order, on_delete=models.SET_NULL, null=True)
date_created = models.DateField()
pdf = models.FileField(null=True, blank=True)
def __str__(self):
return self.invoice_number
def save(self, *args, **kwargs):
if not self.invoice_number:
current_year = str(timezone.now().year)[-2:]
last_invoice = Invoice.objects.filter(invoice_number__startswith=current_year).order_by('-invoice_number').first()
if last_invoice:
last_invoice_number = int(last_invoice.invoice_number.split('-')[1].split('+')[0])
new_invoice_number = f"${current_year}-{last_invoice_number + 1}"
else:
new_invoice_number = f"${current_year}-1425"
self.invoice_number = new_invoice_number
super().save(*args, **kwargs)
class PaymentType(models.Model):

@ -32,20 +32,20 @@
</div>
<div class="w-full">
<label class="text-gray-500">Items:</label>
<select name="items" id="itemsSelectTag"
class="border border-gray-300 p-3 rounded-md outline-none w-full text-gray-500 mt-1" multiple
<label class="text-gray-500">Business:</label>
<select name="business" id="businessSelectTag"
class="w-full h-[50px] py-1 px-3 border border-gray-300 outline-none rounded-md text-gray-500 mt-1"
required>
<option selected disabled>Select Customer First</option>
</select>
</div>
<div class="w-full">
<label class="text-gray-500">Business:</label>
<select name="business" id="businessSelectTag"
class="w-full h-[50px] py-1 px-3 border border-gray-300 outline-none rounded-md text-gray-500 mt-1"
<label class="text-gray-500">Items:</label>
<select name="items" id="itemsSelectTag"
class="border border-gray-300 p-3 rounded-md outline-none w-full text-gray-500 mt-1" multiple
required>
<option selected disabled>Business</option>
<option selected disabled>Select Customer First</option>
</select>
</div>
@ -55,6 +55,7 @@
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="Completed">Completed</option>
<option value="Pending">Pending</option>
<option value="Failed">Failed</option>
<option value="Cancelled">Cancelled</option>
<option value="None">None</option>

@ -15,6 +15,18 @@
box-sizing: border-box;
}
h1 {
color: #20336b;
font-size: 16px;
margin-bottom: 10px;
}
p {
color: #374a7a;
margin-bottom: 5px;
font-size: 13px;
}
.mainContainer {
width: 100%;
display: block;
@ -26,89 +38,95 @@
}
.logoContainer img {
width: 200px;
width: 150px;
}
.invoiceDetails {
.invoiceNumberBar {
width: 100%;
display: table;
background-color: #374a7a;
padding: 10px 20px;
color: white;
font-weight: 600;
text-align: end;
font-size: 18px;
margin: 30px 0px;
}
.customerDetails {
width: 50%;
float: left;
.invoiceNumberBar p {
color: white;
font-size: 15px;
}
.companyDetails {
width: 50%;
float: left;
}
.customerDetails h1 {
color: rgb(166, 166, 166);
font-size: 20px;
margin-bottom: 10px;
.invoiceDetails {
width: 100%;
display: table;
}
.customerDetails p {
color: #374a7a;
margin-bottom: 5px;
.customerDetails, .companyDetails {
width: 50%;
float: left;
}
.companyDetails {
text-align: end;
}
.companyDetails h1 {
color: #20336b;
font-size: 20px;
margin-bottom: 10px;
}
.companyDetails p {
color: #374a7a;
margin-bottom: 5px;
}
.invoiceNumberBar {
.invoiceItemsBar {
width: 100%;
background-color: #374a7a;
padding: 10px 20px;
color: white;
font-weight: 600;
text-align: end;
text-align: start;
font-size: 18px;
margin-bottom: 50px;
margin: 30px 0px;
}
.invoiceItemsBar {
width: 100%;
background-color: #374a7a;
padding: 10px 20px;
.invoiceItemsBar p {
color: white;
font-weight: 600;
text-align: start;
font-size: 18px;
margin: 50px 0px;
font-size: 15px;
}
.invoiceItemsContainer ul {
padding: 0px 20px;
list-style:circle;
color: #20336b;
font-size: 13px;
}
.totalContainer {
width: 100%;
text-align: end;
margin-top: 20px;
margin-top: 30px;
color: #20336b;
font-weight: 600;
}
.totalContainer p {
font-size: 16px;
}
.footer {
width: 100%;
bottom: 0;
position: absolute;
}
.footer div {
margin-top: 20px;
}
.footer p {
color: rgb(151, 151, 151);
margin-bottom: 5px;
}
.footer span {
font-weight: 600;
color: #20336b;
font-size: 13px;
}
</style>
</head>
@ -122,7 +140,7 @@
<div class="invoiceNumberBar">
<p>Invoice $024-1298</p>
<p>Invoice {{order.invoice.invoice_number}}</p>
</div>
@ -130,23 +148,24 @@
<div class="customerDetails">
<h1>Bill To:</h1>
<p>{{order.customer}}</p>
<p>Lb</p>
<p>+96103556600</p>
<p>info@winabig.com</p>
{% if not order.business %}
<p>{{order.customer.user.first_name}} {{order.customer.user.last_name}}</p>
<p>{{order.customer.mobile_number}}</p>
<p>{{order.customer.user.email}}</p>
{% else %}
<p>{{order.business.name}}</p>
<p>{{order.business.phone_number}}</p>
<p>{{order.business.email}}</p>
{% endif %}
</div>
<div class="companyDetails">
<h1>Due Date: 2024-03-03</h1>
<h1>Date: 2024-03-03</h1>
<p>OSITCOM ltd</p>
<p>OSITCOM LTD</p>
<p>CR. 2014057</p>
<p>Registration Number: 1808707</p>
<p>Jounieh, Lebanon </p>
<p> Facing Fouad Chehab Stadium,</p>
<p>Jounieh Highway,</p>
<p> 7th Floor, Doueihy Building</p>
<p>PO Box: 90-1246</p>
<p>Tel/Fax: +961 (9) 918718/9</p>
<p>Mobile: +961 (70) 918 718</p>
@ -162,19 +181,31 @@
<div class="invoiceItemsContainer">
<ul>
<li>USSD App integration via API</li>
<li>Promotion 1 for users when registering during a specific period of time</li>
<li>Promotion 2 for campaign tickets during a specific period of time</li>
{% for item in order.orderitem_set.all %}
<li>{{item.item.title}}</li>
{% endfor %}
</ul>
<div class="totalContainer">
<p>Total Cost: <span>$1200.00</span></p>
<p>Total:<span> ${{order.get_cart_total}}</span></p>
</div>
</div>
</div>
<div class="footer">
<div class="footer">
<p>Thank you for choosing us, we hope to satisfy all your IT Requirements.</p>
<p>OSITCOM ltd</p>
<p>Optimal Solutions for IT and Communication Lebanon Jounieh Highway, Doueihy Building, 7th Floor </p>
<p>Phone: +961 (9) 918 718 - Fax: +961 (9) 918 718 - Mobile: +961 (70) 918 718</p>
<p>Box: 90-1246</p>
<p>Email: billing@ositcom.net</p>
<div >
<p>If you have any questions, please feel free to contact us at billing@ositcom.net.</p>
<span>You can now pay your invoice online through <a>https://osina.ositcom.com</a></span>
</div>
</div>
</body>

@ -79,7 +79,7 @@
<td class="px-6 py-4">
<div class="w-full flex justify-center items-center">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-[18px] text-osiblue">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-[18px] text-blue-500">
<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" />
<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>

@ -71,7 +71,7 @@
<p class="text-slate-800">${{order.get_cart_total}}</p>
</td>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300 {% if order.status == 'Completed' %} bg-green-700 {% else %} bg-gray-400 {% endif %}">
<td class="px-6 py-4 text-center text-sm border-r border-gray-300 {% if order.status == 'Completed' %} bg-green-700 {% elif order.status == 'Pending' %} bg-yellow-500 {% else %} bg-gray-400 {% endif %}">
<p class="text-white">{{order.status}}</p>
</td>
@ -85,8 +85,8 @@
</a>
{% if order.status == 'Completed' and not order.invoice %}
<a >
{% if order.status == 'Pending' and not order.invoice %}
<a href="{% url 'addinvoice' order.id %}">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-[18px] text-blue-500">
<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.875ZM12.75 12a.75.75 0 0 0-1.5 0v2.25H9a.75.75 0 0 0 0 1.5h2.25V18a.75.75 0 0 0 1.5 0v-2.25H15a.75.75 0 0 0 0-1.5h-2.25V12Z" clip-rule="evenodd" />
<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" />

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save