Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12
Binary file modified Customer_Relation/__pycache__/__init__.cpython-312.pyc
Binary file not shown.
Binary file not shown.
Binary file modified Customer_Relation/__pycache__/admin.cpython-312.pyc
Binary file not shown.
Binary file not shown.
Binary file modified Customer_Relation/__pycache__/apps.cpython-312.pyc
Binary file not shown.
Binary file added Customer_Relation/__pycache__/apps.cpython-313.pyc
Binary file not shown.
Binary file modified Customer_Relation/__pycache__/models.cpython-312.pyc
Binary file not shown.
Binary file not shown.
Binary file modified Customer_Relation/__pycache__/urls.cpython-312.pyc
Binary file not shown.
Binary file added Customer_Relation/__pycache__/urls.cpython-313.pyc
Binary file not shown.
16 changes: 12 additions & 4 deletions Customer_Relation/admin.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import os
from django.conf import settings
from django.contrib import admin
from django.utils.html import format_html
from django.urls import reverse
from django.http import HttpResponse
from django.template.loader import render_to_string
from weasyprint import HTML

from django.utils import timezone
from .models import Quotation, QuotationItem
from MasterData.models import ClientMasterData
Expand All @@ -27,7 +29,7 @@ class QuotationAdmin(admin.ModelAdmin):

# Default readonly fields
readonly_fields = (
'code', 'grand_total', 'copy_code_button', 'pdf_button',
'code', 'grand_total', 'copy_code_button', 'pdf_button',
'total_amount', 'vat_amount',
'payment_term', 'client_currency', 'sales_rep'
)
Expand Down Expand Up @@ -149,8 +151,10 @@ def get_urls(self):

# PDF generation
def generate_pdf_view(self, request, quotation_id):
from weasyprint import HTML
quotation = self.get_object(request, quotation_id)
client_master = None
logo_path = os.path.join(settings.BASE_DIR, "static", "images", "logo.png")
if quotation.client:
client_master = ClientMasterData.objects.filter(Client=quotation.client).last()
context = {
Expand All @@ -159,10 +163,14 @@ def generate_pdf_view(self, request, quotation_id):
"generated_by": request.user,
"generated_at": timezone.now(),
"signed_by": "-",
"logo_path": f"file://{logo_path}",
}
html_string = render_to_string("Customer_Relation/quotation_pdf.html", context)
html = HTML(string=html_string)
html = HTML(
string=html_string,
base_url=request.build_absolute_uri("/")
)
pdf_file = html.write_pdf()
response = HttpResponse(pdf_file, content_type='application/pdf')
response['Content-Disposition'] = f'attachment; filename=Quotation-{quotation.code}.pdf'
return response
return response
153 changes: 132 additions & 21 deletions Customer_Relation/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 6.0.2 on 2026-03-06 19:06
# Generated by Django 6.0.3 on 2026-03-12 08:06

import django.db.models.deletion
from django.db import migrations, models
Expand All @@ -9,31 +9,142 @@ class Migration(migrations.Migration):
initial = True

dependencies = [
('MasterData', '0013_file_item_transport'),
("MasterData", "0001_initial"),
]

operations = [
migrations.CreateModel(
name='Quotation',
name="Quotation",
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('commodity_desc', models.CharField(blank=True, max_length=255)),
('fcl', models.CharField(blank=True, max_length=100)),
('vatable', models.BooleanField(default=False)),
('vat_percentage', models.DecimalField(decimal_places=2, default=16, max_digits=5)),
('total_amount', models.DecimalField(decimal_places=2, default=0, max_digits=10)),
('vat_amount', models.DecimalField(decimal_places=2, default=0, max_digits=10)),
('description', models.TextField(blank=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('client', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='MasterData.client')),
('currency', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='MasterData.currency')),
('file', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='MasterData.file')),
('fpod', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='fpod_port', to='MasterData.port')),
('pod', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='pod_port', to='MasterData.port')),
('pol', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='pol_port', to='MasterData.port')),
('supplier', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='MasterData.supplier')),
('transport', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='MasterData.transport')),
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("code", models.CharField(blank=True, max_length=20, unique=True)),
("commodity_desc", models.CharField(blank=True, max_length=255)),
("fcl", models.CharField(blank=True, max_length=100)),
("vatable", models.BooleanField(default=True)),
(
"vat_percentage",
models.DecimalField(decimal_places=2, default=16, max_digits=5),
),
(
"total_amount",
models.DecimalField(decimal_places=2, default=0, max_digits=12),
),
(
"vat_amount",
models.DecimalField(decimal_places=2, default=0, max_digits=12),
),
(
"grand_total",
models.DecimalField(decimal_places=2, default=0, max_digits=12),
),
("consignment", models.TextField(blank=True)),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"client",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="MasterData.client",
),
),
(
"currency",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="MasterData.currency",
),
),
(
"file",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="MasterData.file",
),
),
(
"fpod",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="fpod_port",
to="MasterData.port",
),
),
(
"pod",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="pod_port",
to="MasterData.port",
),
),
(
"pol",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="pol_port",
to="MasterData.port",
),
),
(
"supplier",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="MasterData.supplier",
),
),
(
"transport",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="MasterData.transport",
),
),
],
),
migrations.CreateModel(
name="QuotationItem",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("quantity", models.DecimalField(decimal_places=2, max_digits=10)),
("unit_price", models.DecimalField(decimal_places=2, max_digits=12)),
(
"item",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="MasterData.item",
),
),
(
"quotation",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="items",
to="Customer_Relation.quotation",
),
),
],
),
]
18 changes: 0 additions & 18 deletions Customer_Relation/migrations/0002_quotation_code.py

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Loading