diff --git a/.DS_Store b/.DS_Store
index 7f3454fd..f80b544f 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
index b04f24a5..0c4d7f23 100644
--- a/.idea/dataSources.xml
+++ b/.idea/dataSources.xml
@@ -1,14 +1,20 @@
-
- postgresql
+
+ sqlite.xerial
true
- true
- $PROJECT_DIR$/car_inventory/settings.py
- org.postgresql.Driver
- jdbc:postgresql://127.0.0.1:5432/murad_haikal
+ org.sqlite.JDBC
+ jdbc:sqlite:$PROJECT_DIR$/db.sqlite3
$ProjectFileDir$
+
+
+ file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/xerial/sqlite-jdbc/3.45.1.0/sqlite-jdbc-3.45.1.0.jar
+
+
+ file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar
+
+
\ No newline at end of file
diff --git a/inventory/__pycache__/admin.cpython-311.pyc b/inventory/__pycache__/admin.cpython-311.pyc
index 2eb5c0b1..155fbae0 100644
Binary files a/inventory/__pycache__/admin.cpython-311.pyc and b/inventory/__pycache__/admin.cpython-311.pyc differ
diff --git a/inventory/__pycache__/services.cpython-311.pyc b/inventory/__pycache__/services.cpython-311.pyc
index f702d2b6..11ea12a4 100644
Binary files a/inventory/__pycache__/services.cpython-311.pyc and b/inventory/__pycache__/services.cpython-311.pyc differ
diff --git a/inventory/__pycache__/views.cpython-311.pyc b/inventory/__pycache__/views.cpython-311.pyc
index 69f26693..f6af4e8c 100644
Binary files a/inventory/__pycache__/views.cpython-311.pyc and b/inventory/__pycache__/views.cpython-311.pyc differ
diff --git a/inventory/admin.py b/inventory/admin.py
index b3dcfaa2..a20b6522 100644
--- a/inventory/admin.py
+++ b/inventory/admin.py
@@ -14,7 +14,7 @@ admin.site.register(models.CarColors)
admin.site.register(models.CarRegistration)
admin.site.register(models.CustomCard)
admin.site.register(models.CarSpecificationValue)
-
+admin.site.register(models.CarEquipment)
admin.site.register(models.CarOptionValue)
admin.site.register(models.ExteriorColors)
admin.site.register(models.InteriorColors)
diff --git a/inventory/services.py b/inventory/services.py
index f4e90bf9..668b35fc 100644
--- a/inventory/services.py
+++ b/inventory/services.py
@@ -36,10 +36,10 @@ def decodevin(vin):
if result:=decode_vin(vin):
return result
- elif result:=decode_vin_haikalna(vin):
- return result
elif result:=elm(vin):
return result
+ elif result:=decode_vin_haikalna(vin):
+ return result
else:
return None
diff --git a/inventory/signals.py b/inventory/signals.py
index 6b9d66e1..7b90d598 100644
--- a/inventory/signals.py
+++ b/inventory/signals.py
@@ -116,7 +116,7 @@ def create_ledger_entity(sender, instance, created, **kwargs):
# Create Cash Account
asset_ca_cash = entity.create_account(
coa_model=coa,
- code="1010",
+ code="1101",
role=roles.ASSET_CA_CASH,
name=_("Cash"),
balance_type="debit",
diff --git a/inventory/views.py b/inventory/views.py
index 9313148e..48492b56 100644
--- a/inventory/views.py
+++ b/inventory/views.py
@@ -244,6 +244,8 @@ class AjaxHandlerView(LoginRequiredMixin, View):
"get_series": self.get_series,
"get_trims": self.get_trims,
"get_specifications": self.get_specifications,
+ "get_equipments": self.get_equipments,
+ "get_options": self.get_options,
}
handler = handlers.get(action)
if handler:
@@ -314,17 +316,18 @@ class AjaxHandlerView(LoginRequiredMixin, View):
# Validate inputs
if not model_id or not year:
- return JsonResponse(
- {"error": "Missing required parameters: model_id or year"}, status=400
- )
-
+ return JsonResponse({"error": "Missing required parameters: model_id or year"}, status=400)
try:
year = int(year)
except ValueError:
return JsonResponse({"error": "Invalid year format"}, status=400)
- series = models.CarSerie.objects.filter(id_car_model=model_id).values(
- "id_car_serie", "name", "arabic_name"
+ series = models.CarSerie.objects.filter(
+ id_car_model=model_id,
+ year_begin__lte=year,
+ year_end__gte=year
+ ).values(
+ "id_car_serie", "name", "arabic_name", "generation_name"
)
return JsonResponse(list(series), safe=False)
@@ -373,6 +376,38 @@ class AjaxHandlerView(LoginRequiredMixin, View):
]
return JsonResponse(serialized_specs, safe=False)
+ def get_equipments(self, request):
+ trim_id = request.GET.get('trim_id')
+ equipments = models.CarEquipment.objects.filter(
+ id_car_trim=trim_id
+ ).values('id_car_equipment', 'name').order_by('name')
+ return JsonResponse(list(equipments), safe=False)
+
+ def get_options(self, request):
+ equipment_id = request.GET.get('equipment_id')
+ car_option_values = models.CarOptionValue.objects.filter(id_car_equipment=equipment_id)
+
+ options_by_parent = {}
+ for value in car_option_values:
+ option = value.id_car_option
+ parent = option.id_parent
+ parent_id = parent.id_car_option if parent else 0
+ parent_name = parent.name if parent else "Root"
+ if parent_id not in options_by_parent:
+ options_by_parent[parent_id] = {'parent_name': parent_name, 'options': []}
+ option_data = {
+ 'option_id': option.id_car_option,
+ 'option_name': option.name,
+ 'is_base': value.is_base,
+ 'equipment_name': value.id_car_equipment.name
+ }
+ options_by_parent[parent_id]['options'].append(option_data)
+ serialized_options = [
+ {'parent_name': v['parent_name'], 'options': v['options']}
+ for v in options_by_parent.values()
+ ]
+ return JsonResponse(serialized_options, safe=False)
+
class CarInventory(LoginRequiredMixin, ListView):
model = models.Car
diff --git a/static/.DS_Store b/static/.DS_Store
index da833c67..62b03f3e 100644
Binary files a/static/.DS_Store and b/static/.DS_Store differ
diff --git a/static/images/.DS_Store b/static/images/.DS_Store
index c641451b..4ee801b4 100644
Binary files a/static/images/.DS_Store and b/static/images/.DS_Store differ
diff --git a/static/images/car_make/Peugeot_S4LPdsy.png b/static/images/car_make/Peugeot_S4LPdsy.png
new file mode 100644
index 00000000..0702e75a
Binary files /dev/null and b/static/images/car_make/Peugeot_S4LPdsy.png differ
diff --git a/static/images/logos/.DS_Store b/static/images/logos/.DS_Store
index 5617c87d..5a705ef9 100644
Binary files a/static/images/logos/.DS_Store and b/static/images/logos/.DS_Store differ
diff --git a/static/images/logos/car_make/Peugeot.png b/static/images/logos/car_make/Peugeot.png
index 39b7e13a..0702e75a 100644
Binary files a/static/images/logos/car_make/Peugeot.png and b/static/images/logos/car_make/Peugeot.png differ
diff --git a/templates/inventory/car_form.html b/templates/inventory/car_form.html
index 0b201939..eb2fe273 100644
--- a/templates/inventory/car_form.html
+++ b/templates/inventory/car_form.html
@@ -82,11 +82,7 @@
{% trans 'make'|capfirst %}:
- {{ form.id_car_make|add_class:"form-select form-select-sm" }} {% if form.id_car_make.errors %}
-
- {{ form.id_car_make.errors|striptags }}
-
- {% endif %}
+ {{ form.id_car_make|add_class:"form-select form-select-sm" }}
@@ -104,11 +100,7 @@
name="{{ form.id_car_model.html_name }}">
- {% if form.id_car_model.errors %}
-
- {{ form.id_car_model.errors|striptags }}
-
- {% endif %}
+
@@ -125,11 +117,7 @@
name="{{ form.id_car_serie.html_name }}">
- {% if form.id_car_serie.errors %}
-
- {{ form.id_car_serie.errors|striptags }}
-
- {% endif %}
+
@@ -146,11 +134,20 @@
name="{{ form.id_car_trim.html_name }}">
- {% if form.id_car_trim.errors %}
-
- {{ form.id_car_trim.errors|striptags }}
-
- {% endif %}
+
+
@@ -174,6 +171,7 @@
+
+
+
@@ -243,21 +243,13 @@
-
-
+
-
@@ -284,6 +276,40 @@
+
+
+
@@ -329,8 +355,12 @@
const yearSelect = document.getElementById("{{ form.year.id_for_label }}");
const serieSelect = document.getElementById("{{ form.id_car_serie.id_for_label }}");
const trimSelect = document.getElementById("{{ form.id_car_trim.id_for_label }}");
+ const equipmentSelect = document.getElementById("equipment_id")
const showSpecificationButton = document.getElementById("specification-btn");
+ const showEquipmentButton = document.getElementById("options-btn")
const specificationsContent = document.getElementById("specificationsContent");
+ const optionsContent = document.getElementById("optionsContent")
+ const generationContainer = document.getElementById("generation-div")
const ajaxUrl = "{% url 'ajax_handler' %}";
@@ -478,9 +508,11 @@
});
const data = await response.json();
data.forEach((serie) => {
+
const option = document.createElement("option");
option.value = serie.id_car_serie;
option.textContent = document.documentElement.lang === "en" ? serie.name : serie.name;
+ generationContainer.innerHTML = serie.generation_name
serieSelect.appendChild(option);
});
}
@@ -492,7 +524,7 @@
headers: {
"X-Requested-With": "XMLHttpRequest",
"X-CSRFToken": csrfToken,
- },
+ }
});
const data = await response.json();
data.forEach((trim) => {
@@ -504,6 +536,24 @@
showSpecificationButton.disabled = !this.value;
}
+ async function loadEquipment(trimId){
+ resetDropdown(equipmentSelect, '{% trans "Select" %}');
+ optionsContent.innerHTML = "";
+ const response = await fetch(`${ajaxUrl}?action=get_equipments&trim_id=${trimId}`, {
+ headers: {
+ 'X-Requested-With': 'XMLHttpRequest',
+ 'X-CSRFToken': csrfToken
+ }
+ });
+ const data = await response.json();
+ data.forEach((equipment) => {
+ const option = document.createElement('option');
+ option.value = equipment.id_car_equipment;
+ option.textContent = equipment.name;
+ equipmentSelect.appendChild(option);
+ });
+ }
+
async function loadSpecifications(trimId) {
specificationsContent.innerHTML = "";
const response = await fetch(`${ajaxUrl}?action=get_specifications&trim_id=${trimId}`, {
@@ -525,6 +575,28 @@
});
}
+ async function loadOptions(equipmentId) {
+ optionsContent.innerHTML = "";
+ const response = await fetch(`${ajaxUrl}?action=get_options&equipment_id=${equipmentId}`, {
+ headers: {
+ "X-Requested-With": "XMLHttpRequest",
+ "X-CSRFToken": csrfToken,
+ },
+ });
+ const data = await response.json();
+ data.forEach((parent) => {
+ const parentDiv = document.createElement("div");
+ parentDiv.innerHTML = `
${parent.parent_name}`;
+ parent.options.forEach((option) => {
+ const optDiv = document.createElement("div");
+ optDiv.innerHTML = `• ${option.option_name}`;
+ parentDiv.appendChild(optDiv);
+ });
+ optionsContent.appendChild(parentDiv);
+ });
+ }
+
+
scanVinBtn.addEventListener("click", () => {
resultDisplay.textContent = "";
startScanner();
@@ -532,29 +604,37 @@
fallbackButton.addEventListener("click", () => {
captureAndOCR();
- });
+ })
serieSelect.addEventListener("change", () => {
const serie_id = serieSelect.value;
const model_id = modelSelect.value;
if (serie_id && model_id) loadTrims(serie_id, model_id);
- });
+ })
trimSelect.addEventListener("change", () => {
- const trimId = trimSelect.value;
- showSpecificationButton.disabled = !trimId;
- if (trimId) loadSpecifications(trimId);
- });
+ const trimId = trimSelect.value
+ showSpecificationButton.disabled = !trimId
+ showEquipmentButton.disabled = !trimId
+ if (trimId) loadSpecifications(trimId)
+ })
+
+ equipmentSelect.addEventListener("change", () => {
+ const equipmentId = equipmentSelect.value
+ if (equipmentId) loadOptions(equipmentId)
+ })
closeButton.addEventListener("click", closeModal);
makeSelect.addEventListener("change", (e) => {
loadModels(e.target.value, modelSelect.value);
- });
+ })
modelSelect.addEventListener("change", (e) => {
loadSeries(e.target.value, yearSelect.value);
- });
+ })
decodeVinBtn.addEventListener("click", decodeVin);
- });
+})
+
+
function showLoading() {
Swal.fire({
title: "{% trans 'Please Wait' %}",
diff --git a/templates/inventory/car_form_qabl alfalsafa.html b/templates/inventory/car_form_qabl alfalsafa.html
new file mode 100644
index 00000000..f481c0fe
--- /dev/null
+++ b/templates/inventory/car_form_qabl alfalsafa.html
@@ -0,0 +1,675 @@
+{% extends "base.html" %} {% load i18n static custom_filters %} {% block content %}
+
+{% include 'partials/form_errors.html' %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ _("scanner") }}
+
+
+
+
+
{{ _("VIN will appear here.") }}
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
diff --git a/templates/inventory/car_inventory.html b/templates/inventory/car_inventory.html
index 41533e8d..ab11d563 100644
--- a/templates/inventory/car_inventory.html
+++ b/templates/inventory/car_inventory.html
@@ -30,9 +30,9 @@
{% if cars.first.id_car_make.logo %}
-

+

{% else %}
-

+

{% endif %}