haikal/templates/sales/estimates/estimate_detail.html
2025-09-07 13:52:05 +03:00

431 lines
22 KiB
HTML

{% extends "base.html" %}
{% load i18n custom_filters %}
{% load crispy_forms_filters %}
{% block title %}
{{ _("View Quotation") }}
{% endblock title %}
{% block content %}
<!-- Cancel Modal -->
<div class="modal fade"
id="CancelModal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="CancelModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
<h4 class="mb-0 me-2 text-danger">
{{ _("Delete") }}<i class="fas fa-exclamation-circle text-danger ms-2"></i>
</h4>
<button class="btn p-0 text-body-quaternary fs-6"
data-bs-dismiss="modal"
aria-label="Close">
<span class="fas fa-times"></span>
</button>
</div>
<div class="modal-body p-4">
<p>{% trans "Are you sure you want to Cancel this Estimate?" %}</p>
</div>
<div class="modal-footer flex justify-content-center border-top-0">
<a type="button"
class="btn btn-sm btn-phoenix-danger w-100"
href="{% url 'estimate_mark_as' request.dealer.slug estimate.pk %}?mark=canceled">
<i class="fa-solid fa-circle-check"></i> {% trans "Yes" %}
</a>
</div>
</div>
</div>
</div>
<!-- Confirm Modal -->
<div class="modal fade"
id="confirmModal"
tabindex="-1"
aria-labelledby="confirmModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content ">
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
<h5 class="mmb-0 me-2 text-warning-dark" id="confirmModalLabel">
<i class="fas fa-exclamation-circle text-warning-dark ms-2"></i>
{% trans 'Confirm' %}
</h5>
<button class="btn p-0 text-body-quaternary fs-6"
data-bs-dismiss="modal"
aria-label="Close">
<span class="fas fa-times"></span>
</button>
</div>
<div class="modal-body">
{% trans 'Are you sure ?' %}
<div class="modal-footer flex justify-content-center border-top-0">
<form id="confirmForm"
method="POST"
action="{% url 'estimate_mark_as' request.dealer.slug estimate.pk %}?mark=approved"
class="form">
{% csrf_token %}
<div class="container-fluid m-0 p-0">
<button type="button"
class="btn btn-phoenix-danger btn-sm"
data-bs-dismiss="modal">
<i class="fa-solid fa-ban"></i> {% trans 'No' %}
</button>
<button type="submit" class="btn btn-phoenix-success btn-sm">
<i class="fa-solid fa-circle-check"></i> {% trans "Yes" %}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<!-- ============================================-->
<!-- <section> begin ============================-->
<section class="pt-5 pb-9 bg-body-emphasis dark__bg-gray-1200 border-top">
<div class="row-small mt-3">
<div class="d-flex justify-content-between align-items-end mb-4 mx-3">
<div class="d-flex flex-row align-items-center gap-2">
<h2 class="mb-0">
<i class="fa-regular fa-file-lines"></i> {% trans 'Quotation' %}
</h2>
<div class="fs-9 text-body-secondary fw-semibold mb-0">
{% if estimate.status == 'draft' %}
<span class="badge text-bg-warning">{% trans "Draft" %}</span>
{% elif estimate.status == 'in_review' %}
<span class="badge text-bg-info">{% trans "In Review" %}</span>
{% elif estimate.status == 'approved' %}
<span class="badge text-bg-success">{% trans "Approved" %}</span>
{% elif estimate.status == 'completed' %}
<span class="badge text-bg-success">{% trans "Completed" %}</span>
{% elif estimate.status == 'canceled' %}
<span class="badge text-bg-danger">{% trans "Canceled" %}</span>
{% endif %}
</div>
</div>
<div class="d-flex align-items-center gap-2">
{% if estimate.status == 'draft' %}
{% if perms.django_ledger.change_estimatemodel %}
<button id="mark_as_sent_estimate"
class="btn btn-phoenix-secondary"
onclick="setFormAction('review')"
data-bs-toggle="modal"
data-bs-target="#confirmModal">
<span class="d-none d-sm-inline-block"><i class="fa-solid fa-check-double"></i> {% trans 'Mark As Review' %}</span>
</button>
{% endif %}
{% elif estimate.status == 'in_review' %}
{% if perms.django_ledger.can_approve_estimatemodel %}
<button id="accept_estimate"
onclick="setFormAction('approved')"
class="btn btn-phoenix-secondary"
data-bs-toggle="modal"
data-bs-target="#confirmModal">
<span class="d-none d-sm-inline-block"><i class="fa-solid fa-check-double"></i> {% trans 'Mark As Approved' %}</span>
</button>
{% endif %}
{% if estimate.can_approve and not request.is_manager %}
<button class="btn btn-phoenix-warning" disabled>
<i class="fas fa-hourglass-start me-2"></i><span class="text-warning">{% trans 'Waiting for Manager Approval' %}</span>
</button>
{% endif %}
{% elif estimate.status == 'approved' %}
{% if perms.django_ledger.change_estimatemodel %}
<a href="{% url 'send_email' request.dealer.slug estimate.pk %}"
class="btn btn-phoenix-primary me-2"><span class="fa-regular fa-paper-plane me-sm-2"></span><span class="d-none d-sm-inline-block">{% trans 'Send Quotation' %}</span></a>
<a href="{% url 'estimate_print' request.dealer.slug estimate.pk %}"
class="btn btn-phoenix-secondary"
target="_blank">
<span class="d-none d-sm-inline-block"><i class="fas fa-print me-2"></i>{% trans 'Print' %}</span>
</a>
{% endif %}
{% if estimate.sale_orders.first %}
<!--if sale order exist-->
{% if perms.django_ledger.add_invoicemodel %}
<a href="{% url 'invoice_create' request.dealer.slug estimate.pk %}"
class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-receipt"></i> {% trans 'Create Invoice' %}</span></a>
{% endif %}
{% if perms.inventory.view_saleorder %}
<a href="{% url 'order_detail' request.dealer.slug estimate.sale_orders.first.pk %}"
class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{{ _("Preview Sale Order") }}</span></a>
{% endif %}
{% else %}
{% if perms.inventory.add_saleorder %}
<a href="{% url 'create_sale_order' request.dealer.slug estimate.pk %}"
class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-file-import"></i> {% trans 'Create Sale Order' %}</span></a>
{% endif %}
{% endif %}
{% elif estimate.status == 'completed' %}
{% if perms.inventory.view_saleorder %}
<a href="{% url 'order_detail' request.dealer.slug estimate.sale_orders.first.pk %}"
class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{{ _("Preview Sale Order") }}</span></a>
{% endif %}
{% if perms.django_ledger.view_invoicemodel %}
<a href="{% url 'invoice_detail' request.dealer.slug request.entity.slug estimate.invoicemodel_set.first.pk %}"
class="btn btn-phoenix-primary btn-sm"
type="button"><i class="fa-solid fa-receipt"></i>
{{ _("View Invoice") }}</a>
{% endif %}
{% endif %}
{% if estimate.can_cancel %}
{% if perms.django_ledger.change_estimatemodel %}
<button class="btn btn-phoenix-danger"
data-bs-toggle="modal"
data-bs-target="#CancelModal">
<i class="fa-solid fa-ban"></i> {% trans "Cancel" %}
</button>
{% endif %}
{% endif %}
</div>
</div>
<div class="container bg-body dark__bg-gray-1100 p-4 mb-4 rounded-2">
<div class="row">
<div class="col mb-2">
<h6>
<i class="fa-solid fa-hashtag"></i> {% trans 'Quotation Number' %}:
</h6>
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{ estimate.estimate_number }}</p>
</div>
<div class="col mb-2">
<h6>
<i class="fa-solid fa-calendar-days"></i> {% trans 'Quotation Date' %}:
</h6>
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{ estimate.created }}</p>
</div>
<div class="col mb-2">
<h6>
<i class="fa-solid fa-user"></i> {% trans 'Customer' %}:
</h6>
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{ estimate.customer.customer_name }}</p>
</div>
<div class="col mb-2">
<h6>
<i class="fa-solid fa-envelope"></i> {% trans 'Email' %}:
</h6>
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{ estimate.customer.email }}</p>
</div>
<div class="col">
<h6>
<i class="fa-solid fa-list"></i> {% trans "Quotation Status" %}:
</h6>
<div class="fs-9 text-body-secondary fw-semibold mb-0">
{% if estimate.status == 'draft' %}
<span class="badge text-bg-warning">{% trans "Draft" %}</span>
{% elif estimate.status == 'in_review' %}
<span class="badge text-bg-info">{% trans "In Review" %}</span>
{% elif estimate.status == 'approved' %}
<span class="badge text-bg-success">{% trans "Approved" %}</span>
{% elif estimate.status == 'completed' %}
<span class="badge text-bg-success">{% trans "Completed" %}</span>
{% elif estimate.status == 'canceled' %}
<span class="badge text-bg-danger">{% trans "Canceled" %}</span>
{% endif %}
</div>
</div>
</div>
</div>
<div class="px-0">
<div class="table-responsive scrollbar">
<table id="estimate-table" class="table fs-9 text-body mb-0">
<thead class="bg-body-secondary">
<tr>
<th scope="col" style="width: 24px;">
<i class="fa-solid fa-hashtag"></i>
</th>
<th scope="col" style="min-width: 100px;">{% trans "Make" %}</th>
<th scope="col" style="min-width: 100px;">{% trans "Model" %}</th>
<th scope="col" style="min-width: 100px;">{% trans "Year" %}</th>
<th scope="col" style="min-width: 100px;">{% trans "VIN" %}</th>
<th scope="col" style="min-width: 100px;">{% trans "Quantity" %}</th>
<th scope="col" style="min-width: 100px;">{% trans "Unit Price" %}</th>
<th scope="col" style="min-width: 100px;">{% trans "Total" %}</th>
</tr>
</thead>
<tr>
<td class="align-middle">
<img src="{{ data.car.logo }}" width="40" height="40" class="ps-2">
</img>
</td>
<td class="align-middle">{{ data.car.id_car_make }}</td>
<td class="align-middle">{{ data.car.id_car_model }}</td>
<td class="align-middle">{{ data.car.year }}</td>
<td class="align-middle">{{ data.car.vin }}</td>
<td class="align-middle">1</td>
<td class="align-middle ps-5">{{ data.car.marked_price }}</td>
<td class="align-middle text-body-tertiary fw-semibold">{{ data.car.marked_price }}</td>
</tr>
<tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="7">{% trans "Discount Amount" %}</td>
<td class="align-middle text-start text-danger fw-semibold">
{% if estimate.is_draft %}
<form action="{% url 'update_estimate_discount' request.dealer.slug estimate.pk %}"
method="post">
{% csrf_token %}
<div class="input-group input-group-sm">
<input type="number"
class="form-control"
name="discount_amount"
value="{{ data.discount_amount }}"
step="0.01"
style="width: 1px">
<span class="input-group-text"><span class="icon-saudi_riyal"></span></span>
<button type="submit" class="btn btn-sm btn-phoenix-primary ms-n2">{% trans "Update" %}</button>
</div>
</form>
{% else %}
{{ data.discount_amount }} <span class="icon-saudi_riyal"></span>
{% endif %}
</td>
</tr>
<tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="7">{% trans "Vat" %} ({{ data.vat_rate }})</td>
<td class="align-middle text-start fw-semibold">
<span id="">+ {{ data.vat_amount|floatformat:2 }}<span class="icon-saudi_riyal"></span></span>
</td>
</tr>
<tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="7">{% trans "Additional Services" %}</td>
<td class="align-middle text-start fw-semibold">
{% for service in data.additional_services.services %}
<small><span class="fw-semibold">+ {{ service.0.name }} - {{ service.0.price_|floatformat }}<span class="icon-saudi_riyal"></span></span></small>
<br>
{% endfor %}
{% if estimate.is_draft %}
<button class="btn btn-phoenix-primary btn-xs ms-auto"
type="button"
data-bs-toggle="modal"
data-bs-target="#additionalModal">
<span class="fas fa-plus me-1"></span>{{ _("Add") }}
</button>
{% endif %}
</td>
</tr>
<tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-bolder text-body-highlight" colspan="7">{% trans "Grand Total" %}</td>
<td class="align-middle text-start fw-bolder">
<span id="grand-total">{{ data.grand_total|floatformat }}<span class="icon-saudi_riyal"></span></span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- end of .row-->
</section>
<!-- <section> close ============================-->
<!-- ============================================-->
<!-- add update Modal -->
<div class="modal fade"
id="additionalModal"
tabindex="-1"
aria-labelledby="additionalModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-md">
<div class="modal-content">
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
<h4 class="modal-title" id="additionalModalLabel">{% trans 'Additional Services' %}</h4>
<button class="btn p-0 text-body-quaternary fs-6"
data-bs-dismiss="modal"
aria-label="Close">
<span class="fas fa-times"></span>
</button>
</div>
<div class="modal-body">
<form action="{% url 'update_estimate_additionals' request.dealer.slug estimate.pk %}"
method="post">
{% csrf_token %}
{{ additionals_form|crispy }}
<button type="submit" class="btn btn-phoenix-primary">{% trans 'Update' %}</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
{% block customJS %}
<script>
// Initialize when page loads and after HTMX swaps
document.addEventListener('DOMContentLoaded', initEstimateFunctions);
document.addEventListener('htmx:afterSwap', initEstimateFunctions);
function initEstimateFunctions() {
// Initialize calculateTotals if estimate table exists
// Initialize form action setter if form exists
const confirmForm = document.getElementById('confirmForm');
if (confirmForm) {
// Remove old event listeners if any
document.querySelectorAll('[data-set-form-action]').forEach(button => {
button.removeEventListener('click', setFormActionHandler);
button.addEventListener('click', setFormActionHandler);
});
}
htmx.process(confirmForm)
}
function calculateTotals() {
const table = document.getElementById('estimate-table');
if (!table) return;
try {
const tbody = table.getElementsByTagName('tbody')[0];
if (!tbody) return;
const rows = tbody.rows;
let grandTotal = 0;
for (let row of rows) {
// Skip rows that don't have enough cells
if (row.cells.length < 5) continue;
// Get quantity and unit price
const quantityText = row.cells[2]?.textContent?.trim() || '0';
const unitPriceText = row.cells[3]?.textContent?.trim() || '0';
// Parse values, handling any formatting
const quantity = parseFloat(quantityText.replace(/[^0-9.-]/g, ''));
const unitPrice = parseFloat(unitPriceText.replace(/[^0-9.-]/g, ''));
if (!isNaN(quantity) && !isNaN(unitPrice)) {
const total = quantity * unitPrice;
if (row.cells[4]) {
row.cells[4].textContent = total.toFixed(2);
}
grandTotal += total;
}
}
// Update grand total display
const grandTotalElement = document.getElementById('grand-total');
if (grandTotalElement) {
grandTotalElement.textContent = grandTotal.toFixed(2);
}
} catch (error) {
console.error('Error calculating totals:', error);
}
}
function setFormActionHandler(event) {
const action = event.currentTarget.getAttribute('data-set-form-action');
if (action) {
setFormAction(action);
}
}
function setFormAction(action) {
const form = document.getElementById('confirmForm');
htmx.process(form)
if (!form) return;
const baseUrl = "{% url 'estimate_mark_as' request.dealer.slug estimate.pk %}";
form.action = `${baseUrl}?mark=${encodeURIComponent(action)}`;
// Optional: Submit form immediately after setting action
// form.submit();
}
</script>
{% endblock %}