299 lines
16 KiB
HTML
299 lines
16 KiB
HTML
{% extends 'base.html' %}
|
|
{% load i18n %}
|
|
|
|
{% block title %}{% trans "Quotation" %} #{{ quotation.quotation_number|default:quotation.id }} | {{ site_settings.business_name }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container py-4">
|
|
<!-- Action Bar -->
|
|
<div class="d-flex justify-content-between align-items-center mb-4 d-print-none">
|
|
<a href="{% url 'quotations' %}" class="btn btn-light rounded-3">
|
|
<i class="bi bi-arrow-left me-2"></i>{% trans "Back to Quotations" %} / العودة لعروض الأسعار
|
|
</a>
|
|
<div class="d-flex gap-2">
|
|
{% if quotation.status != 'converted' %}
|
|
<button type="button" class="btn btn-outline-success rounded-3 px-4" data-bs-toggle="modal" data-bs-target="#convertModal">
|
|
<i class="bi bi-arrow-right-circle me-2"></i>{% trans "Convert to Invoice" %} / تحويل إلى فاتورة
|
|
</button>
|
|
{% endif %}
|
|
<button onclick="downloadPDF()" class="btn btn-outline-primary rounded-3 px-4">
|
|
<i class="bi bi-file-earmark-pdf me-2"></i>{% trans "Download PDF" %} / تحميل PDF
|
|
</button>
|
|
<button onclick="window.print()" class="btn btn-primary rounded-3 px-4 shadow-sm">
|
|
<i class="bi bi-printer me-2"></i>{% trans "Print Quotation" %} / طباعة عرض السعر
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Convert Modal -->
|
|
<div class="modal fade d-print-none" id="convertModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content border-0 shadow rounded-4">
|
|
<div class="modal-body p-4 text-center">
|
|
<div class="text-primary mb-3">
|
|
<i class="bi bi-question-circle" style="font-size: 3rem;"></i>
|
|
</div>
|
|
<h4 class="fw-bold">{% trans "Convert to Invoice?" %}</h4>
|
|
<p class="text-muted">{% trans "This will create a sales invoice and deduct items from stock. This action will change the quotation status to Converted." %}</p>
|
|
<div class="d-grid gap-2">
|
|
<a href="{% url 'convert_quotation_to_invoice' quotation.id %}" class="btn btn-primary rounded-3 py-2">{% trans "Yes, Convert to Invoice" %}</a>
|
|
<button type="button" class="btn btn-light rounded-3 py-2" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quotation Content -->
|
|
<div id="quotation-card" class="card border-0 shadow-sm rounded-4 overflow-hidden mx-auto print-container" style="max-width: 800px;">
|
|
<div class="card-body p-0">
|
|
<!-- Header Section -->
|
|
<div class="p-5 bg-white print-section">
|
|
<div class="row mb-5 print-mb-2">
|
|
<div class="col-sm-6">
|
|
{% if settings.logo %}
|
|
<img src="{{ settings.logo.url }}" alt="Logo" style="max-height: 80px;" class="mb-4 print-mb-2 print-logo">
|
|
{% else %}
|
|
<h3 class="fw-bold text-primary mb-4 print-mb-2 print-h3">{{ settings.business_name }}</h3>
|
|
{% endif %}
|
|
<div class="text-muted small print-small">
|
|
<p class="mb-1"><i class="bi bi-geo-alt me-2"></i>{{ settings.address }}</p>
|
|
<p class="mb-1"><i class="bi bi-telephone me-2"></i>{{ settings.phone }}</p>
|
|
<p class="mb-1"><i class="bi bi-envelope me-2"></i>{{ settings.email }}</p>
|
|
{% if settings.vat_number %}
|
|
<p class="mb-0"><i class="bi bi-receipt me-2"></i>{% trans "VAT" %} / الضريبة: {{ settings.vat_number }}</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-sm-6 text-sm-end">
|
|
<h1 class="fw-bold text-uppercase text-muted opacity-50 mb-4 print-mb-2 print-h1">{% trans "Quotation" %} / عرض سعر</h1>
|
|
<div class="mb-4 print-mb-2">
|
|
<div class="fw-bold text-dark text-uppercase small">{% trans "Quotation Number" %} / رقم العرض</div>
|
|
<div class="h5 print-h5">{{ quotation.quotation_number|default:quotation.id }}</div>
|
|
</div>
|
|
<div class="row g-3">
|
|
<div class="col-6">
|
|
<div class="small text-muted fw-bold text-uppercase">{% trans "Date" %} / التاريخ</div>
|
|
<div>{{ quotation.created_at|date:"Y-m-d" }}</div>
|
|
</div>
|
|
<div class="col-6">
|
|
<div class="small text-muted fw-bold text-uppercase">{% trans "Valid Until" %} / صالح لغاية</div>
|
|
<div>{{ quotation.valid_until|date:"Y-m-d"|default:"-" }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mb-5 print-mb-2">
|
|
<div class="col-sm-6">
|
|
<div class="small text-muted fw-bold mb-3 text-uppercase tracking-wider print-mb-1">{% trans "Quote For" %} / عرض مقدم إلى</div>
|
|
<div class="h5 fw-bold mb-1 print-h5">{{ quotation.customer.name|default:_("Guest Customer") }}</div>
|
|
{% if quotation.customer.phone %}
|
|
<div class="text-muted small"><i class="bi bi-telephone me-2"></i>{{ quotation.customer.phone }}</div>
|
|
{% endif %}
|
|
{% if quotation.customer.address %}
|
|
<div class="text-muted small"><i class="bi bi-geo-alt me-2"></i>{{ quotation.customer.address }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-sm-6 text-sm-end">
|
|
<div class="small text-muted fw-bold mb-3 text-uppercase tracking-wider print-mb-1">{% trans "Status" %} / الحالة</div>
|
|
<div>
|
|
{% if quotation.status == 'converted' %}
|
|
<span class="h5 badge bg-primary text-white rounded-pill px-4 print-badge">{% trans "Converted" %} / محول</span>
|
|
{% elif quotation.status == 'accepted' %}
|
|
<span class="h5 badge bg-success text-white rounded-pill px-4 print-badge">{% trans "Accepted" %} / مقبول</span>
|
|
{% elif quotation.status == 'rejected' %}
|
|
<span class="h5 badge bg-danger text-white rounded-pill px-4 print-badge">{% trans "Rejected" %} / مرفوض</span>
|
|
{% else %}
|
|
<span class="h5 badge bg-info text-white rounded-pill px-4 print-badge">{% trans "Open" %} / مفتوح</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Table Section -->
|
|
<div class="table-responsive mb-5 print-mb-2">
|
|
<table class="table table-hover align-middle table-sm-print">
|
|
<thead class="bg-light print-bg-none">
|
|
<tr>
|
|
<th class="py-3 ps-4 border-0 print-py-1">
|
|
<div class="small text-muted">{% trans "Item Description" %}</div>
|
|
<div class="small">وصف العنصر</div>
|
|
</th>
|
|
<th class="py-3 text-center border-0 print-py-1">
|
|
<div class="small text-muted">{% trans "Unit Price" %}</div>
|
|
<div class="small">سعر الوحدة</div>
|
|
</th>
|
|
<th class="py-3 text-center border-0 print-py-1">
|
|
<div class="small text-muted">{% trans "Quantity" %}</div>
|
|
<div class="small">الكمية</div>
|
|
</th>
|
|
<th class="py-3 text-end pe-4 border-0 print-py-1">
|
|
<div class="small text-muted">{% trans "Total" %}</div>
|
|
<div class="small">المجموع</div>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for item in quotation.items.all %}
|
|
<tr>
|
|
<td class="py-3 ps-4 print-py-1">
|
|
<div class="fw-bold" dir="rtl">{{ item.product.name_ar }}</div>
|
|
<div class="text-muted small">{{ item.product.name_en }}</div>
|
|
</td>
|
|
<td class="py-3 text-center print-py-1">{{ settings.currency_symbol }}{{ item.unit_price|floatformat:3 }}</td>
|
|
<td class="py-3 text-center print-py-1">{{ item.quantity|floatformat:2 }}</td>
|
|
<td class="py-3 text-end pe-4 fw-bold text-primary print-py-1">{{ settings.currency_symbol }}{{ item.line_total|floatformat:3 }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
<tfoot>
|
|
<tr>
|
|
<td colspan="2" class="border-0"></td>
|
|
<td class="text-center py-3 fw-bold border-top print-py-1">
|
|
<div>{% trans "Subtotal" %}</div>
|
|
<div class="small fw-normal">المجموع الفرعي</div>
|
|
</td>
|
|
<td class="text-end pe-4 py-3 fw-bold border-top print-py-1">{{ settings.currency_symbol }}{{ quotation.total_amount|add:quotation.discount|floatformat:3 }}</td>
|
|
</tr>
|
|
{% if quotation.discount > 0 %}
|
|
<tr class="text-muted">
|
|
<td colspan="2" class="border-0"></td>
|
|
<td class="text-center py-2 fw-bold print-py-1">
|
|
<div>{% trans "Discount" %}</div>
|
|
<div class="small fw-normal">الخصم</div>
|
|
</td>
|
|
<td class="text-end pe-4 py-2 fw-bold print-py-1">-{{ settings.currency_symbol }}{{ quotation.discount|floatformat:3 }}</td>
|
|
</tr>
|
|
{% endif %}
|
|
<tr>
|
|
<td colspan="2" class="border-0"></td>
|
|
<td class="text-center py-3 fw-bold border-top print-py-1">
|
|
<div>{% trans "Grand Total" %}</div>
|
|
<div class="small fw-normal">المجموع الكلي</div>
|
|
</td>
|
|
<td class="text-end pe-4 py-3 h5 fw-bold text-primary border-top print-py-1 print-h5">{{ settings.currency_symbol }}{{ quotation.total_amount|floatformat:3 }}</td>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Amount in Words -->
|
|
<div class="mb-5 px-5 print-mb-2 print-px-0">
|
|
<div class="p-3 bg-light rounded-3 print-bg-none print-p-0">
|
|
<div class="small text-muted fw-bold text-uppercase mb-1">{% trans "Amount in Words" %} / المبلغ بالحروف</div>
|
|
<div class="fw-bold text-dark">{{ amount_in_words }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Terms & Conditions -->
|
|
<div class="mb-5 print-mb-2">
|
|
<h6 class="fw-bold small text-uppercase mb-3 text-muted border-bottom pb-2 print-mb-1">{% trans "Terms and Conditions" %} / الشروط والأحكام</h6>
|
|
<div class="small text-muted print-small" style="white-space: pre-line;">
|
|
{{ quotation.terms_and_conditions|default:_("No specific terms provided.") }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Notes -->
|
|
{% if quotation.notes %}
|
|
<div class="bg-light p-4 rounded-3 mb-5 mx-5 print-bg-none print-mb-2 print-mx-0 print-p-0">
|
|
<h6 class="fw-bold small text-uppercase mb-2 text-muted">{% trans "Internal Notes" %} / ملاحظات داخلية</h6>
|
|
<p class="mb-0 small">{{ quotation.notes }}</p>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="text-center text-muted small mt-5 border-top pt-4 print-mt-2 print-pt-2">
|
|
<p class="mb-1">{% trans "This is a computer generated quotation." %} / هذا عرض سعر تم إنشاؤه بواسطة الكمبيوتر.</p>
|
|
<p class="mb-0">{% trans "Software by Meezan" %} / برمجة ميزان</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
|
|
<script>
|
|
function downloadPDF() {
|
|
const element = document.getElementById('quotation-card');
|
|
const opt = {
|
|
margin: 0,
|
|
filename: 'Quotation_{{ quotation.quotation_number|default:quotation.id }}.pdf',
|
|
image: { type: 'jpeg', quality: 0.98 },
|
|
html2canvas: { scale: 2, useCORS: true, letterRendering: true },
|
|
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }
|
|
};
|
|
html2pdf().set(opt).from(element).save();
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
@media print {
|
|
@page {
|
|
size: A4 portrait;
|
|
margin: 10mm;
|
|
}
|
|
body {
|
|
background-color: white !important;
|
|
margin: 0 !important;
|
|
padding: 0 !important;
|
|
font-size: 12px;
|
|
}
|
|
.container {
|
|
width: 100% !important;
|
|
max-width: 100% !important;
|
|
margin: 0 !important;
|
|
padding: 0 !important;
|
|
}
|
|
.d-print-none { display: none !important; }
|
|
|
|
/* Layout Overrides */
|
|
#quotation-card {
|
|
width: 100% !important;
|
|
max-width: none !important;
|
|
margin: 0 !important;
|
|
border: none !important;
|
|
box-shadow: none !important;
|
|
border-radius: 0 !important;
|
|
}
|
|
|
|
.print-section {
|
|
padding: 0 !important;
|
|
}
|
|
|
|
/* Spacing Reductions */
|
|
.print-mb-2 { margin-bottom: 0.5rem !important; }
|
|
.print-mb-1 { margin-bottom: 0.25rem !important; }
|
|
.print-mt-2 { margin-top: 1rem !important; }
|
|
.print-pt-2 { padding-top: 0.5rem !important; }
|
|
.print-pb-0 { padding-bottom: 0 !important; }
|
|
.print-px-0 { padding-left: 0 !important; padding-right: 0 !important; }
|
|
.print-mx-0 { margin-left: 0 !important; margin-right: 0 !important; }
|
|
.print-p-0 { padding: 0 !important; }
|
|
|
|
/* Font Size Reductions */
|
|
.print-h1 { font-size: 18px !important; margin-bottom: 0.5rem !important; }
|
|
.print-h3 { font-size: 16px !important; }
|
|
.print-h5 { font-size: 14px !important; }
|
|
.print-small { font-size: 10px !important; }
|
|
|
|
/* Table Compactness */
|
|
.table th, .table td {
|
|
padding: 4px 8px !important;
|
|
font-size: 11px !important;
|
|
}
|
|
.print-py-1 { padding-top: 4px !important; padding-bottom: 4px !important; }
|
|
|
|
/* Hide Backgrounds */
|
|
.print-bg-none { background-color: transparent !important; }
|
|
.badge {
|
|
border: 1px solid #000;
|
|
color: #000 !important;
|
|
background: transparent !important;
|
|
padding: 2px 8px !important;
|
|
}
|
|
|
|
/* Logo sizing */
|
|
.print-logo { max-height: 50px !important; }
|
|
}
|
|
</style>
|
|
{% endblock %} |