haikal/templates/inventory/car_list.html
2025-07-15 17:27:03 +03:00

609 lines
33 KiB
HTML

{% extends "base.html" %}
{% load i18n %}
{% load custom_filters %}
{% block content %}
<div class="row-fluid p-2">
<!-- Display Validation Errors -->
{% if errors %}
<div class="alert alert-danger">
<ul>
{% for error in errors %}<li>{{ error }}</li>{% endfor %}
</ul>
</div>
{% endif %}
<!-- Option Modal -->
<div class="modal fade"
id="optionsModal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="optionsModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-scrollable">
<div class="modal-content glossy-modal">
<div class="modal-header bg-primary-subtle">
<h5 class="modal-title" id="optionsModalLabel">{% trans 'options'|capfirst %}</h5>
<button type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="optionsContent"></div>
</div>
</div>
</div>
</div>
<!-- Specification Modal -->
<div class="modal fade"
id="specificationsModal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="specificationsModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-scrollable">
<div class="modal-content glossy-modal">
<div class="modal-header bg-primary-subtle">
<h5 class="modal-title" id="specificationsModalLabel">{% trans 'specifications'|capfirst %}</h5>
<button type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="specificationsContent"></div>
</div>
</div>
</div>
</div>
<!-- CAR FORM -->
<form method="post" id="carForm" class="form">
{% csrf_token %}
<div class="d-flex flex-column min-vh-100">
<div class="d-flex flex-column flex-sm-grow-1 ms-sm-14 p-4">
<main class="d-grid gap-4 p-1">
<div class="row g-4">
<!-- VIN -->
<div class="col-lg-4 col-xl-3">
<div class="card h-100">
<div class="card-body bg-primary-subtle">
<label class="label" for="vin">{% trans 'VIN'|capfirst %}:</label>
<div class="input-group">
<input id="vin"
name="vin"
type="text"
class="form-control form-control-sm"
placeholder="{% trans 'VIN'|capfirst %}"
maxlength="17">
<button type="button"
class="btn btn-sm btn-phoenix-primary"
id="decodeVinBtn">{% trans 'search'|capfirst %}</button>
</div>
</div>
</div>
</div>
<!-- Makes Card -->
<div class="col-lg-4 col-xl-3">
<div class="card h-100">
<div class="card-body bg-danger-subtle" id="make-row">
<label class="label" for="make">{% trans 'make'|capfirst %}:</label>
<select class="form-select form-select-sm" id="make" name="make">
<option value="">{% trans 'select'|capfirst %}</option>
{% for make in car_makes %}
{% if LANGUAGE_CODE == 'ar' %}
<option value="{{ make.id_car_make }}">{{ make.arabic_name }}</option>
{% else %}
<option value="{{ make.id_car_make }}">{{ make.name }}</option>
{% endif %}
{% endfor %}
</select>
</div>
</div>
</div>
<!-- Models Card -->
<div class="col-lg-4 col-xl-3">
<div class="card h-100">
<div class="card-body bg-danger-subtle" id="model-row">
<label class="label" for="model">{% trans 'model'|capfirst %}:</label>
<select class="form-select form-select-sm" id="model" name="model">
<option value="">{% trans 'select'|capfirst %}</option>
</select>
</div>
</div>
</div>
<!-- Generation Card -->
<div class="col-lg-4 col-xl-3">
<div class="card h-100">
<div class="card-body bg-danger-subtle" id="generation-row">
<label class="label" for="generation">{% trans 'generation'|capfirst %}:</label>
<select class="form-select form-select-sm" id="generation" name="generation">
<option value="">{% trans 'select'|capfirst %}</option>
</select>
</div>
</div>
</div>
<!-- Year Card -->
<div class="col-lg-4 col-xl-3">
<div class="card h-100">
<div class="card-body bg-danger-subtle" id="year-row">
<label class="label" for="year">{% trans 'year'|capfirst %}:</label>
<select class="form-select form-select-sm" id="year" name="year">
<option value="">{% trans 'select'|capfirst %}</option>
</select>
</div>
</div>
</div>
<!-- Series Card -->
<div class="col-lg-4 col-xl-3">
<div class="card h-100">
<div class="card-body bg-danger-subtle" id="serie-row">
<label class="label" for="serie">{% trans 'series'|capfirst %}:</label>
<select class="form-select form-select-sm" id="serie" name="serie">
<option value="">{% trans 'select'|capfirst %}</option>
</select>
</div>
</div>
</div>
<!-- Trims Card -->
<div class="col-lg-4 col-xl-3">
<div class="card h-100">
<div class="card-body bg-danger-subtle" id="trim-row">
<label class="label" for="trim">{% trans 'trim'|capfirst %}:</label>
<select class="form-select form-select-sm" id="trim" name="trim">
<option value="">{% trans 'select'|capfirst %}</option>
</select>
</div>
</div>
</div>
<!-- Equipments Card -->
<div class="col-lg-4 col-xl-3">
<div class="card h-100">
<div class="card-body bg-danger-subtle" id="equipment-row">
<label class="label" for="equipment">{% trans 'equipment'|capfirst %}:</label>
<select class="form-select form-select-sm" id="equipment" name="equipment">
<option value="">{% trans 'select'|capfirst %}</option>
</select>
</div>
</div>
</div>
<!-- Status Card -->
<div class="col-lg-4 col-xl-3">
<div class="card h-100">
<div class="card-body bg-info-subtle">
<label class="label" for="status">{% trans 'Status'|capfirst %}:</label>
<select class="form-select form-select-sm" id="status" name="status">
<option value="">{% trans 'select'|capfirst %}</option>
{% for value, display in status_choices %}<option value="{{ value }}">{{ display }}</option>{% endfor %}
</select>
</div>
</div>
</div>
<!-- Stock Type Card -->
<div class="col-lg-4 col-xl-3">
<div class="card h-100">
<div class="card-body bg-info-subtle">
<label class="label" for="stock_type">{% trans 'Stock Type'|capfirst %}:</label>
<select class="form-select form-select-sm" id="stock_type" name="stock_type">
<option value="">{% trans 'select'|capfirst %}</option>
{% for value, display in stock_type_choices %}<option value="{{ value }}">{{ display }}</option>{% endfor %}
</select>
</div>
</div>
</div>
<!-- Mileage Card -->
<div class="col-lg-4 col-xl-3">
<div class="card h-100">
<div class="card-body bg-info-subtle">
<label class="label" for="mileage">{% trans 'Mileage'|capfirst %}:</label>
<input id="mileage"
name="mileage"
type="number"
min="0"
class="form-control form-control-sm"
placeholder="{% trans 'Mileage'|capfirst %}">
</div>
</div>
</div>
<!-- Remarks Card -->
<div class="col-lg-4 col-xl-3">
<div class="card h-100">
<div class="card-body bg-info-subtle">
<label class="label" for="remarks">{% trans 'Remarks'|capfirst %}:</label>
<textarea id="remarks"
name="remarks"
class="form-control form-control-sm"
rows="3"
placeholder="{% trans 'Enter remarks'|capfirst %}"></textarea>
</div>
</div>
</div>
<!-- Options and Specifications Buttons -->
<div class="col-lg-4 col-xl-3">
<div class="card h-100">
<div class="card-body" id="option-row">
<button type="button"
class="btn btn-sm btn-phoenix-danger mt-1"
id="option-btn"
data-bs-toggle="modal"
data-bs-target="#optionsModal"
disabled>{% trans 'options'|capfirst %}</button>
<button type="button"
class="btn btn-sm btn-phoenix-anger mt-1"
id="specification-btn"
data-bs-toggle="modal"
data-bs-target="#specificationsModal"
disabled>{% trans 'specifications'|capfirst %}</button>
<button type="submit"
class="btn btn-sm btn-phoenix-primary mt-1"
id="saveCarBtn">{% trans 'save'|capfirst %}</button>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</form>
</div>
<!-- JavaScript Section -->
<script>
document.addEventListener("DOMContentLoaded", function() {
const vinInput = document.getElementById('vin');
const statusSelect = document.getElementById('status');
const stockTypeSelect = document.getElementById('stock_type');
const mileageInput = document.getElementById('mileage');
const remarksInput = document.getElementById('remarks');
const decodeVinBtn = document.getElementById('decodeVinBtn');
const makeSelect = document.getElementById('make');
const modelSelect = document.getElementById('model');
const generationSelect = document.getElementById('generation');
const yearSelect = document.getElementById('year');
const serieSelect = document.getElementById('serie');
const trimSelect = document.getElementById('trim');
const equipmentSelect = document.getElementById('equipment');
const showOptionsButton = document.getElementById('option-btn');
const optionsContent = document.getElementById('optionsContent');
const showSpecificationButton = document.getElementById('specification-btn');
const specificationsContent = document.getElementById('specificationsContent');
const makeBg = document.getElementById('make-row');
const modelBg = document.getElementById('model-row');
const generationBg = document.getElementById('generation-row');
const yearBg = document.getElementById('year-row');
const serieBg = document.getElementById('serie-row');
const trimBg = document.getElementById('trim-row');
const equipmentBg = document.getElementById('equipment-row');
const saveCarBtn = document.getElementById('saveCarBtn');
function resetDropdown(dropdown, placeholder) {
dropdown.innerHTML = `<option value="">${placeholder}</option>`;
}
function resetAllAfterMake() {
resetDropdown(modelSelect, '{% trans "select"|capfirst %}');
resetDropdown(generationSelect, '{% trans "select"|capfirst %}');
resetDropdown(yearSelect, '{% trans "select"|capfirst %}');
resetDropdown(serieSelect, '{% trans "select"|capfirst %}');
resetDropdown(trimSelect, '{% trans "select"|capfirst %}');
resetDropdown(equipmentSelect, '{% trans "select"|capfirst %}');
specificationsContent.innerHTML = '';
optionsContent.innerHTML = '';
makeBg.classList.remove('bg-success-subtle');
makeBg.classList.add('bg-danger-subtle');
modelBg.classList.remove('bg-success-subtle');
modelBg.classList.add('bg-danger-subtle');
generationBg.classList.remove('bg-success-subtle');
generationBg.classList.add('bg-danger-subtle');
yearBg.classList.remove('bg-success-subtle');
yearBg.classList.add('bg-danger-subtle');
serieBg.classList.remove('bg-success-subtle');
serieBg.classList.add('bg-danger-subtle');
trimBg.classList.remove('bg-success-subtle');
trimBg.classList.add('bg-danger-subtle');
equipmentBg.classList.remove('bg-success-subtle');
equipmentBg.classList.add('bg-danger-subtle');
showOptionsButton.disabled = true;
showOptionsButton.classList.add('btn-phoenix-danger');
showOptionsButton.classList.remove('btn-phoenix-success');
showSpecificationButton.disabled = true;
showSpecificationButton.classList.add('btn-phoenix-danger');
showSpecificationButton.classList.remove('btn-phoenix-success');
}
function checkFormCompletion() {
const isFormComplete = vinInput.value.length === 17 &&
makeSelect.value &&
modelSelect.value &&
trimSelect.value &&
statusSelect.value &&
stockTypeSelect.value;
saveCarBtn.disabled = !isFormComplete;
}
statusSelect.addEventListener('change', checkFormCompletion);
stockTypeSelect.addEventListener('change', checkFormCompletion);
mileageInput.addEventListener('input', checkFormCompletion);
remarksInput.addEventListener('input', checkFormCompletion);
decodeVinBtn.addEventListener('click', decodeVin);
/*vinInput.addEventListener('input', function() {
if (this.value.length === 17) {
decodeVin();
}
checkFormCompletion();
});*/
function decodeVin() {
const vinNo = vinInput.value.trim();
if (vinNo.length === 17) {
fetch(`/cars/?action=decode_vin&vin_no=${vinNo}`, {
headers: {'X-Requested-With': 'XMLHttpRequest'}
})
.then(response => response.json())
.then(data => {
if (data.success) {
const vinData = data.data;
if (vinData.make_id) {
makeSelect.value = vinData.make_id;
makeSelect.dispatchEvent(new Event('change'));
makeBg.classList.remove('bg-danger-subtle');
makeBg.classList.add('bg-success-subtle');
} else {
alert('{% trans "Make not found for the decoded VIN." %}');
}
} else {
console.error('Error decoding VIN:', data.error);
}
})
.catch(error => console.error('Error:', error));
} else {
alert('{% trans "Please enter a valid 17-character VIN number." %}');
}
}
makeSelect.addEventListener('change', function() {
const makeId = this.value;
resetAllAfterMake();
checkFormCompletion();
if (makeId) {
modelBg.classList.remove('bg-danger-subtle');
modelBg.classList.add('bg-success-subtle');
fetch(`/cars/?action=get_models&make_id=${makeId}`, {headers: {'X-Requested-With': 'XMLHttpRequest'}})
.then(response => response.json())
.then(data => {
data.forEach(function(model) {
const option = document.createElement('option');
option.value = model.id_car_model;
option.textContent = model.name;
modelSelect.appendChild(option);
});
});
}
});
modelSelect.addEventListener('change', function() {
resetDropdown(generationSelect, '{% trans "select"|capfirst %}');
resetDropdown(yearSelect, '{% trans "select"|capfirst %}');
resetDropdown(serieSelect, '{% trans "select"|capfirst %}');
resetDropdown(trimSelect, '{% trans "select"|capfirst %}');
resetDropdown(equipmentSelect, '{% trans "select"|capfirst %}');
specificationsContent.innerHTML = '';
optionsContent.innerHTML = '';
checkFormCompletion();
const modelId = this.value;
if (modelId) {
generationBg.classList.remove('bg-danger-subtle');
generationBg.classList.add('bg-success-subtle');
fetch(`/cars/?action=get_generation&model_id=${modelId}`, {headers: {'X-Requested-With': 'XMLHttpRequest'}})
.then(response => response.json())
.then(data => {
data.forEach(function(generation) {
const option = document.createElement('option');
option.value = generation.id_car_generation;
option.textContent = generation.name;
generationSelect.appendChild(option);
});
});
}
});
generationSelect.addEventListener('change', function() {
resetDropdown(yearSelect, '{% trans "select"|capfirst %}');
resetDropdown(serieSelect, '{% trans "select"|capfirst %}');
resetDropdown(trimSelect, '{% trans "select"|capfirst %}');
resetDropdown(equipmentSelect, '{% trans "select"|capfirst %}');
specificationsContent.innerHTML = '';
optionsContent.innerHTML = '';
const makeId = makeSelect.value;
const modelId = modelSelect.value;
const generationId = this.value;
if (generationId) {
yearBg.classList.remove('bg-danger-subtle');
yearBg.classList.add('bg-success-subtle');
fetch(`/cars/?action=get_year&make_id=${makeId}&model_id=${modelId}&generation_id=${generationId}`,
{headers: {'X-Requested-With': 'XMLHttpRequest'}})
.then(response => response.json())
.then(data => {
data.forEach(function(year) {
const option = document.createElement('option');
option.value = year.id;
option.textContent = year.year;
yearSelect.appendChild(option);
});
});
}
});
yearSelect.addEventListener('change', function() {
resetDropdown(serieSelect, '{% trans "select"|capfirst %}');
resetDropdown(trimSelect, '{% trans "select"|capfirst %}');
resetDropdown(equipmentSelect, '{% trans "select"|capfirst %}');
specificationsContent.innerHTML = '';
optionsContent.innerHTML = '';
const modelId = modelSelect.value;
const generationId = generationSelect.value;
const yearId = this.value;
if (yearId) {
serieBg.classList.remove('bg-danger-subtle');
serieBg.classList.add('bg-success-subtle');
fetch(`/cars/?action=get_series&model_id=${modelId}&generation_id=${generationId}`, {headers: {'X-Requested-With': 'XMLHttpRequest'}})
.then(response => response.json())
.then(data => {
data.forEach(function(serie) {
const option = document.createElement('option');
option.value = serie.id_car_serie;
option.textContent = serie.name;
serieSelect.appendChild(option);
});
});
}
});
serieSelect.addEventListener('change', function() {
resetDropdown(trimSelect, '{% trans "select"|capfirst %}');
resetDropdown(equipmentSelect, '{% trans "select"|capfirst %}');
specificationsContent.innerHTML = '';
optionsContent.innerHTML = '';
const modelId = modelSelect.value;
const serieId = this.value;
if (serieId) {
trimBg.classList.remove('bg-danger-subtle');
trimBg.classList.add('bg-success-subtle');
fetch(`/cars/?action=get_trims&serie_id=${serieId}&model_id=${modelId}`, {headers: {'X-Requested-With': 'XMLHttpRequest'}})
.then(response => response.json())
.then(data => {
data.forEach(function(trim) {
const option = document.createElement('option');
option.value = trim.id_car_trim;
option.textContent = trim.name;
trimSelect.appendChild(option);
});
});
}
});
trimSelect.addEventListener('change', function() {
resetDropdown(equipmentSelect, '{% trans "select"|capfirst %}');
optionsContent.innerHTML = '';
showSpecificationButton.disabled = !this.value;
if (this.value) {
showSpecificationButton.classList.remove('btn-phoenix-danger');
showSpecificationButton.classList.add('btn-phoenix-success');
} else {
showSpecificationButton.classList.add('btn-phoenix-danger');
showSpecificationButton.classList.remove('btn-phoenix-success');
}
checkFormCompletion();
const trimId = this.value;
if (trimId) {
equipmentBg.classList.remove('bg-danger-subtle');
equipmentBg.classList.add('bg-success-subtle');
fetch(`/cars/?action=get_equipments&trim_id=${trimId}`, {headers: {'X-Requested-With': 'XMLHttpRequest'}})
.then(response => response.json())
.then(data => {
data.forEach(function(equipment) {
const option = document.createElement('option');
option.value = equipment.id_car_equipment;
option.textContent = equipment.name;
equipmentSelect.appendChild(option);
});
});
}
});
showSpecificationButton.addEventListener('click', function() {
const trimId = trimSelect.value;
specificationsContent.innerHTML = '';
if (trimId){
fetch(`/cars/?action=get_specifications&trim_id=${trimId}`, {headers: {'X-Requested-With': 'XMLHttpRequest'}})
.then(response => response.json())
.then(data => {
if (data.length > 0) {
data.forEach(function(parent) {
const parentSpec = document.createElement('div');
parentSpec.classList.add('mb-3');
parentSpec.innerHTML = `<strong>${parent.parent_name}</strong>`;
parent.specifications.forEach(function(specification) {
const specificationDiv = document.createElement('div');
specificationDiv.classList.add('ms-3'); // Add margin for indentation
specificationDiv.innerHTML = `&#183; ${specification.s_name}: ${specification.s_value} ${specification.s_unit}`;
parentSpec.appendChild(specificationDiv);
});
specificationsContent.appendChild(parentSpec);
});
} else {
specificationsContent.innerHTML = '<p>{% trans "No specifications available." %}</p>';
}
})
.catch(error => {
specificationsContent.innerHTML = '<p>{% trans "Error loading specifications." %}</p>';
console.error('Error fetching specifications:', error);
});
}
});
equipmentSelect.addEventListener('change', function() {
showOptionsButton.disabled = !this.value;
if (this.value) {
showOptionsButton.classList.remove('btn-phoenix-danger');
showOptionsButton.classList.add('btn-phoenix-success');
} else {
showOptionsButton.classList.add('btn-phoenix-danger');
showOptionsButton.classList.remove('btn-phoenix-success');
}
});
showOptionsButton.addEventListener('click', function() {
const equipmentId = equipmentSelect.value;
optionsContent.innerHTML = '';
if (equipmentId) {
fetch(`/cars/?action=get_options&equipment_id=${equipmentId}`, {headers: {'X-Requested-With': 'XMLHttpRequest'}})
.then(response => response.json())
.then(data => {
if (data.length > 0) {
data.forEach(function(parent) {
const parentrow = document.createElement('div');
parentrow.classList.add('mb-3');
parentrow.innerHTML = `<strong>${parent.parent_name}</strong>`;
parent.options.forEach(function(option) {
const optionDiv = document.createElement('div');
optionDiv.classList.add('ms-3'); // Add margin for indentation
optionDiv.innerHTML = `&#10003; ${option.option_name}`;
parentrow.appendChild(optionDiv);
});
optionsContent.appendChild(parentrow);
});
} else {
optionsContent.innerHTML = '<p>{% trans "No options available." %}</p>';
}
})
.catch(error => {
optionsContent.innerHTML = '<p>{% trans "Error loading options." %}</p>';
console.error('Error fetching options:', error);
});
}
});
});
</script>
{% endblock %}