haikal/templates/sales/orders/order_details.html
2025-08-31 14:49:32 +03:00

640 lines
36 KiB
HTML

{% extends "base.html" %}
{% load static i18n humanize %}
{% block customCSS %}
<style>
/* Custom CSS for additional styling */
.status-badge {
font-size: 0.8rem;
padding: 0.35rem 0.65rem;
border-radius: 50rem;
}
.timeline {
position: relative;
padding-left: 1.5rem;
}
.timeline:before {
content: '';
position: absolute;
left: 0.5rem;
top: 0;
bottom: 0;
width: 2px;
background-color: #dee2e6;
}
.timeline-item {
position: relative;
padding-bottom: 1.5rem;
}
.timeline-item:last-child {
padding-bottom: 0;
}
.timeline-item:before {
content: '';
position: absolute;
left: -1.5rem;
top: 0.25rem;
width: 1rem;
height: 1rem;
border-radius: 50%;
background-color: #0d6efd;
}
.file-upload {
border: 2px dashed #dee2e6;
border-radius: 0.375rem;
padding: 1.5rem;
text-align: center;
cursor: pointer;
transition: all 0.3s;
}
.file-upload:hover {
border-color: #0d6efd;
background-color: rgba(13, 110, 253, 0.05);
}
.document-thumbnail {
width: 100%;
height: 120px;
object-fit: cover;
border-radius: 0.375rem;
}
</style>
{% endblock customCSS %}
{% block content %}
<div class="container-fluid px-0">
<!-- Header -->
<header class="bg-primary py-3">
<div class="container">
<div class="d-flex justify-content-between align-items-center">
<h1 class="h4 mb-0 text-light">
<i class="fas fa-file-invoice me-2"></i>
{{ _("Sale Order") }} #{{ saleorder.formatted_order_id }}
</h1>
<div>
<button class="btn btn-sm btn-outline-light me-2">
<i class="fas fa-print me-1"></i> {{ _("Print") }}
</button>
<button class="btn btn-sm btn-outline-light">
<i class="fas fa-share-alt me-1"></i> {{ _("Share") }}
</button>
</div>
</div>
</div>
</header>
<!-- Main Content -->
<div class="container py-4">
<div class="row">
<!-- Left Column -->
<div class="col-lg-8 mb-4">
<!-- Order Summary Card -->
<div class="card mb-4 shadow-sm">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0 text-primary">{{ _("Order Summary") }}</h5>
<span class="status-badge {% if saleorder.status == 'approved' %} bg-success text-white {% elif saleorder.status == 'cancelled' %} bg-danger text-white {% elif saleorder.status == 'pending_approval' %} bg-warning text-dark {% elif saleorder.status == 'delivered' %} bg-info text-white {% else %} bg-secondary text-white {% endif %}">{{ saleorder.get_status_display }}</span>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label text-muted small mb-1">{{ _("Order Date") }}</label>
<p class="mb-0 fw-bold">{{ saleorder.order_date|date }}</p>
</div>
<div class="mb-3">
<label class="form-label text-muted small mb-1">{{ _("Customer") }}</label>
<p class="mb-0 fw-bold">{{ saleorder.customer.full_name|capfirst }}</p>
</div>
<div class="mb-3">
<label class="form-label text-muted small mb-1">{{ _("Payment Method") }}</label>
<p class="mb-0 fw-bold">{{ saleorder.get_payment_method_display }}</p>
</div>
<div class="mb-3">
<label class="form-label text-muted small mb-1">{{ _("Created By") }}</label>
<p class="mb-0 fw-bold">{{ saleorder.created_by }}</p>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label text-muted small mb-1">{{ _("Expected Delivery") }}</label>
<p class="mb-0 fw-bold">
{% if saleorder.expected_delivery_date %}
{{ saleorder.expected_delivery_date|date }}
{% else %}
<span class="text-warning">{{ _("Not scheduled") }}</span>
{% endif %}
</p>
</div>
<div class="mb-3">
<label class="form-label text-muted small mb-1">{{ _("Last Updated") }}</label>
<p class="mb-0 fw-bold">
{%blocktrans %} {{ saleorder.updated_at|naturaltime|capfirst }} by {% endblocktrans %}
{{ saleorder.last_modified_by }}
</p>
</div>
{% if saleorder.status == 'cancelled' %}
<div class="mb-3">
<label class="form-label text-muted small mb-1">{{ _("Cancellation Reason") }}</label>
<p class="mb-0 fw-bold text-danger">{{ saleorder.cancellation_reason|default:"Not specified" }}</p>
</div>
{% endif %}
</div>
</div>
{% if saleorder.comments %}
<div class="mt-3">
<label class="form-label text-muted small mb-1">{{ _("Order Comments") }}</label>
<blockquote class="blockquote mb-0">
<p class="mb-0">{{ saleorder.comments }}</p>
</blockquote>
</div>
{% endif %}
</div>
</div>
<!-- Vehicle Details Card -->
<div class="card mb-4 shadow-sm">
<div class="card-header">
<h5 class="mb-0">{{ _("Vehicle Details") }}</h5>
</div>
<div class="card-body">
<div class="row">
{% if data.cars %}
{% for car in data.cars %}
<div class="col-md-4 mb-3">
<img src="{{ car.logo|default:'https://via.placeholder.com/300x200?text=Vehicle+Image' }}"
alt="Vehicle"
class="img-fluid rounded"
width="200"
height="100">
</div>
<div class="col-md-8">
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label text-muted small mb-1">{{ _("Make") }}</label>
<p class="mb-0">{{ car.make }}</p>
</div>
<div class="col-md-6 mb-3">
<label class="form-label text-muted small mb-1">{{ _("Model") }}</label>
<p class="mb-0">{{ car.model }}</p>
</div>
<div class="col-md-6 mb-3">
<label class="form-label text-muted small mb-1">{{ _("Year") }}</label>
<p class="mb-0">{{ car.year }}</p>
</div>
<div class="col-md-6 mb-3">
<label class="form-label text-muted small mb-1">{{ _("VIN") }}</label>
<p class="mb-0">{{ car.vin }}</p>
</div>
<div class="col-md-6 mb-3">
<label class="form-label text-muted small mb-1">{{ _("Mileage") }}</label>
<p class="mb-0">{{ car.mileage|intcomma }} {{ _("km") }}</p>
</div>
</div>
</div>
<hr class="my-4">
{% endfor %}
{% else %}
<div class="col-12 text-center py-4">
<p class="text-muted">{{ _("No vehicle assigned to this order") }}</p>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Financial Details Card -->
<div class="card mb-4 shadow-sm">
<div class="card-header">
<h5 class="mb-0">{{ _("Financial Details") }}</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label text-muted small mb-1">{{ _("Agreed Price") }}</label>
<p class="mb-0 fw-bold">SAR {{ saleorder.agreed_price|intcomma }}</p>
</div>
<div class="mb-3">
<label class="form-label text-muted small mb-1">{{ _("Down Payment") }}</label>
<p class="mb-0">SAR {{ saleorder.down_payment_amount|intcomma }}</p>
</div>
<div class="mb-3">
<label class="form-label text-muted small mb-1">{{ _("Trade-In Value") }}</label>
<p class="mb-0">SAR {{ saleorder.trade_in_value|intcomma }}</p>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label text-muted small mb-1">{{ _("Loan Amount") }}</label>
<p class="mb-0">SAR {{ saleorder.loan_amount|intcomma }}</p>
</div>
<div class="mb-3">
<label class="form-label text-muted small mb-1">{{ _("Total Paid") }}</label>
<p class="mb-0">SAR {{ saleorder.total_paid_amount|intcomma }}</p>
</div>
<div class="mb-3">
<label class="form-label text-muted small mb-1">{{ _("Remaining Balance") }}</label>
<p class="mb-0 fw-bold {% if saleorder.remaining_balance > 0 %} text-danger {% else %} text-success {% endif %}">
SAR {{ saleorder.remaining_balance|intcomma }}
</p>
</div>
</div>
</div>
<div class="progress mt-3" style="height: 10px;">
{% widthratio saleorder.total_paid_amount saleorder.agreed_price 100 as payment_percentage %}
<div class="progress-bar bg-success"
role="progressbar"
style="width: {{ payment_percentage }}%"
aria-valuenow="{{ payment_percentage }}"
aria-valuemin="0"
aria-valuemax="100"></div>
</div>
<div class="d-flex justify-content-between mt-1 small text-muted">
<span>{{ payment_percentage }}% {{ _("Paid") }}</span>
<span>SAR {{ saleorder.agreed_price|intcomma }} {{ _("Total") }}</span>
</div>
</div>
</div>
<!-- Documents Card -->
<div class="card mb-4 shadow-sm">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">{{ _("Documents") }}</h5>
<button class="btn btn-sm btn-primary">
<i class="fas fa-plus me-1"></i> {{ _("Add Document") }}
</button>
</div>
<div class="card-body">
<div class="file-upload mb-3">
<i class="fas fa-cloud-upload-alt fa-3x text-muted mb-2"></i>
<p class="mb-1">{{ _("Drag & drop files here or click to browse") }}</p>
<p class="small text-muted mb-0">PDF, JPG, PNG up to 10MB</p>
</div>
<div class="row">
{% for document in saleorder.documents.all %}
<div class="col-md-3 mb-3">
<div class="card">
{% if document.file.url|lower|slice:'-3:' == 'pdf' %}
<img src="{% static 'images/icons/file.png' %}"
class="document-thumbnail card-img-top"
alt="PDF Document">
{% else %}
<img src="{{ document.file.url }}"
class="document-thumbnail card-img-top"
alt="Document">
{% endif %}
<div class="card-body p-2">
<p class="card-text small mb-1">{{ document.get_filename }}</p>
<p class="card-text small text-muted mb-0">Added: {{ document.created_at|date:"F j, Y" }}</p>
</div>
</div>
</div>
{% empty %}
<div class="col-12 text-center py-3">
<p class="text-muted">{{ _("No documents uploaded yet") }}</p>
</div>
{% endfor %}
</div>
</div>
</div>
<!-- Comments Card -->
<div class="card shadow-sm">
<div class="card-header">
<h5 class="mb-0">{{ _("Comments & Notes") }}</h5>
</div>
<div class="card-body">
{% comment %} <form method="post"
action="{% url 'add_sale_order_comment' saleorder.pk %}"> {% endcomment %}
<form method="post" action="">
{% csrf_token %}
<div class="mb-3">
<textarea class="form-control"
name="comment"
rows="3"
placeholder="Add a comment or note..."
required></textarea>
<div class="d-flex justify-content-end mt-2">
<button type="submit" class="btn btn-primary btn-sm">{{ _("Post Comment") }}</button>
</div>
</div>
</form>
<div class="timeline">
{% for comment in saleorder.comments.all %}
<div class="timeline-item">
<div class="card mb-2">
<div class="card-body p-3">
<div class="d-flex justify-content-between mb-1">
<strong>{{ comment.created_by.get_full_name|default:comment.created_by.username }}</strong>
<small class="text-muted">{{ comment.created_at|date:"F j, Y H:i A" }}</small>
</div>
<p class="mb-0">{{ comment.text }}</p>
</div>
</div>
</div>
{% empty %}
<div class="text-center py-3">
<p class="text-muted">{{ _("No comments yet") }}</p>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
<!-- Right Column -->
<div class="col-lg-4">
<!-- Actions Card -->
<div class="card mb-4 shadow-sm">
<div class="card-header">
<h5 class="mb-0">{{ _("Order Actions") }}</h5>
</div>
<div class="card-body">
<div class="d-grid gap-2">
{% if saleorder.status == 'pending_approval' %}
<button class="btn btn-success" onclick="updateStatus('approved')">
<i class="fas fa-check-circle me-2"></i> {% trans "Approve Order" %}
</button>
{% endif %}
<a href="" class="btn btn-primary">
<i class="fas fa-edit me-2"></i> {{ _("Edit Order") }}
</a>
{% if not saleorder.invoice %}
<a href="" class="btn btn-info">
<i class="fas fa-file-invoice-dollar me-2"></i> {{ _("Create Invoice") }}
</a>
{% endif %}
{% if saleorder.status == 'approved' and not saleorder.actual_delivery_date %}
<button class="btn btn-warning"
data-bs-toggle="modal"
data-bs-target="#deliveryModal">
<i class="fas fa-truck me-2"></i> {{ _("Schedule Delivery") }}
</button>
{% endif %}
{% if saleorder.status != 'cancelled' %}
<button class="btn btn-danger"
data-bs-toggle="modal"
data-bs-target="#cancelModal">
<i class="fas fa-times-circle me-2"></i> {{ _("Cancel Order") }}
</button>
{% endif %}
</div>
</div>
</div>
<!-- Status Timeline Card -->
<div class="card mb-4 shadow-sm">
<div class="card-header">
<h5 class="mb-0">{{ _("Order Status Timeline") }}</h5>
</div>
<div class="card-body">
<div class="timeline">
{% for log in saleorder.status_logs.all %}
<div class="timeline-item">
<div class="d-flex justify-content-between">
<strong>{{ log.get_status_display }}</strong>
<small class="text-muted">{{ log.created_at|date:"F j, Y" }}</small>
</div>
<p class="small mb-0">
{% if log.note %}{{ log.note }}{% endif %}
<br>
<small class="text-muted">{{ _("Changed by") }}: {{ log.changed_by.get_full_name|default:log.changed_by.username }}</small>
</p>
</div>
{% empty %}
<div class="text-center py-3">
<p class="text-muted">{{ _("No status history available") }}</p>
</div>
{% endfor %}
</div>
</div>
</div>
<!-- Related Items Card -->
<div class="card mb-4 shadow-sm">
<div class="card-header">
<h5 class="mb-0">{{ _("Related Items") }}</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label class="form-label text-muted small mb-1">{{ _("Quotation") }}</label>
<a href="{% url 'estimate_detail' saleorder.estimate.pk %}"
target="_blank"
rel="noopener noreferrer">
<p class="mb-0">
<span class="badge bg-success ms-1">{{ saleorder.estimate.estimate_number }} <i class="fas fa-external-link-alt ms-2" style="font-size: 0.8rem;"></i></span>
</p>
</a>
</div>
<div class="mb-3">
<label class="form-label text-muted small mb-1">{{ _("Invoice") }}</label>
<p class="mb-0">
{% if saleorder.invoice %}
<a href="{% url 'invoice_detail' request.dealer.slug request.entity.slug saleorder.invoice.pk %}"
target="_blank"
rel="noopener noreferrer">
<p class="mb-0">
<span class="badge bg-success ms-1">{{ saleorder.invoice.invoice_number }} <i class="fas fa-external-link-alt ms-2" style="font-size: 0.8rem;"></i></span>
</p>
</a>
{% else %}
<span class="text-muted">{{ _("Not created yet") }}</span>
{% endif %}
</p>
</div>
<div class="mb-3">
<label class="form-label text-muted small mb-1">{{ _("Opportunity") }}</label>
<a href="{% url 'opportunity_detail' saleorder.opportunity.slug %}"
target="_blank"
rel="noopener noreferrer">
<p class="mb-0">
<span class="badge bg-success ms-1">{{ saleorder.opportunity }} <i class="fas fa-external-link-alt ms-2" style="font-size: 0.8rem;"></i></span>
</p>
</a>
</div>
<div class="mb-3">
<label class="form-label text-muted small mb-1">{{ _("Customer") }}</label>
<a href="{% url 'customer_detail' saleorder.customer.slug %}"
target="_blank"
rel="noopener noreferrer">
<p class="mb-0">
<span class="badge bg-success ms-1">{{ saleorder.customer.full_name|capfirst }} <i class="fas fa-external-link-alt ms-2" style="font-size: 0.8rem;"></i></span>
</p>
</a>
</div>
</div>
</div>
<!-- Trade-In Vehicle Card -->
{% if saleorder.trade_in_vehicle %}
<div class="card shadow-sm">
<div class="card-header">
<h5 class="mb-0">{{ _("Trade-In Vehicle") }}</h5>
</div>
<div class="card-body">
<div class="text-center mb-3">
<img src="{{ saleorder.trade_in_vehicle.image.url|default:'https://via.placeholder.com/300x200?text=Trade-In' }}"
alt="Trade-In Vehicle"
class="img-fluid rounded mb-2">
<h6 class="mb-1">
{{ saleorder.trade_in_vehicle.year }}
{{ saleorder.trade_in_vehicle.make }}
{{ saleorder.trade_in_vehicle.model }}
</h6>
<p class="small text-muted mb-2">{{ _("VIN") }}: {{ saleorder.trade_in_vehicle.vin }}</p>
<p class="fw-bold">SAR {{ saleorder.trade_in_value|intcomma }}</p>
</div>
<div class="row">
<div class="col-6">
<p class="small mb-1">
<i class="fas fa-tachometer-alt me-1 text-muted"></i>
{{ saleorder.trade_in_vehicle.mileage|intcomma }} {{ _("km") }}
</p>
</div>
<div class="col-6">
<p class="small mb-1">
<i class="fas fa-paint-brush me-1 text-muted"></i>
{{ saleorder.trade_in_vehicle.color }}
</p>
</div>
<div class="col-6">
<p class="small mb-1">
<i class="fas fa-gas-pump me-1 text-muted"></i>
{{ saleorder.trade_in_vehicle.engine }}
</p>
</div>
<div class="col-6">
<p class="small mb-1">
<i class="fas fa-cog me-1 text-muted"></i>
{{ saleorder.trade_in_vehicle.get_transmission_display }}
</p>
</div>
</div>
</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<!-- Cancel Order Modal -->
<div class="modal fade"
id="cancelModal"
tabindex="-1"
aria-labelledby="cancelModalLabel"
aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="cancelModalLabel">{{ _("Cancel Order") }}</h5>
<button type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<form method="post" action="">
{% csrf_token %}
<div class="modal-body">
<div class="mb-3">
<label for="cancellationReason" class="form-label">{{ _("Reason for Cancellation") }}</label>
<textarea class="form-control"
id="cancellationReason"
name="cancellation_reason"
rows="3"
required></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ _("Close") }}</button>
<button type="submit" class="btn btn-danger">{{ _("Confirm Cancellation") }}</button>
</div>
</form>
</div>
</div>
</div>
<!-- Schedule Delivery Modal -->
<div class="modal fade"
id="deliveryModal"
tabindex="-1"
aria-labelledby="deliveryModalLabel"
aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deliveryModalLabel">{{ _("Schedule Delivery") }}</h5>
<button type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
{% comment %} <form method="post" action="{% url 'schedule_delivery' saleorder.pk %}"> {% endcomment %}
<form method="post" action="">
{% csrf_token %}
<div class="modal-body">
<div class="mb-3">
<label for="deliveryDate" class="form-label">{{ _("Delivery Date") }}</label>
<input type="date"
class="form-control"
id="deliveryDate"
name="delivery_date"
required>
</div>
<div class="mb-3">
<label for="deliveryNotes" class="form-label">{{ _("Notes") }}</label>
<textarea class="form-control" id="deliveryNotes" name="notes" rows="3"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ _("Close") }}</button>
<button type="submit" class="btn btn-primary">{{ _("Schedule Delivery") }}</button>
</div>
</form>
</div>
</div>
</div>
{% endblock content %}
{% block customJS %}
<script>
// Status update function
function updateStatus(newStatus) {
fetch("", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': '{{ csrf_token }}'
},
body: JSON.stringify({
status: newStatus
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert('Error: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('An error occurred while updating status');
});
}
// Document upload handling
document.querySelector('.file-upload').addEventListener('click', function() {
// In a real application, this would open a file dialog
alert('File upload dialog would open here');
});
// Initialize tooltips
document.addEventListener('DOMContentLoaded', function() {
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
});
</script>
{% endblock customJS %}