This commit is contained in:
gitea 2025-02-10 14:26:54 +00:00
commit dff5148028
30 changed files with 127249 additions and 68 deletions

BIN
.DS_Store vendored

Binary file not shown.

Binary file not shown.

View File

@ -6,7 +6,7 @@ class InventoryConfig(AppConfig):
def ready(self):
import inventory.signals
from decimal import Decimal
from inventory.models import VatRate
VatRate.objects.get_or_create(rate=Decimal('0.15'), is_active=True)
# from decimal import Decimal
# from inventory.models import VatRate
# VatRate.objects.get_or_create(rate=Decimal('0.15'), is_active=True)

View File

@ -0,0 +1,104 @@
import os
import json
import pymysql
import pandas as pd
from django.core.management.base import BaseCommand
from sqlalchemy import create_engine
from tqdm import tqdm # Progress bar support
from django.conf import settings
# Database connection details
db_config = {
'host': 'localhost',
'user': 'root',
'password': settings.PASSWORD,
'database': 'car2db01022025'
}
EXCLUDED_TABLES = {"car_serie", "car_generation"} # Tables to exclude from direct dump
class Command(BaseCommand):
help = "Merge car_serie with car_generation, include in final JSON dump with a progress bar."
def handle(self, *args, **kwargs):
try:
self.stdout.write(self.style.SUCCESS("Connecting to database..."))
# Create SQLAlchemy engine
engine = create_engine(f"mysql+pymysql://{db_config['user']}:{db_config['password']}@{db_config['host']}/{db_config['database']}")
# Load car_generation table
self.stdout.write(self.style.SUCCESS("Loading car_generation data..."))
car_generation_query = "SELECT * FROM car_generation;"
car_generation_df = pd.read_sql(car_generation_query, engine)
# Load car_serie table
self.stdout.write(self.style.SUCCESS("Loading car_serie data..."))
car_serie_query = "SELECT * FROM car_serie;"
car_serie_df = pd.read_sql(car_serie_query, engine)
# Perform a LEFT JOIN to keep all car series and merge with car generations
self.stdout.write(self.style.SUCCESS("Merging car_serie with car_generation..."))
merged_df = pd.merge(car_serie_df, car_generation_df, on="id_car_generation", how="left")
# Select and rename the relevant columns
final_df = merged_df.rename(columns={
"id_car_serie": "id_car_serie",
"id_car_model_x": "id_car_model",
"name_y": "generation_name",
"name_x": "serie_name",
"year_begin": "year_begin",
"year_end": "year_end"
})[["id_car_serie", "id_car_model", "generation_name", "serie_name", "year_begin", "year_end"]]
# Convert merged data to a JSON-ready format
self.stdout.write(self.style.SUCCESS("Processing merged data..."))
car_serie_json = list(tqdm(final_df.to_dict(orient="records"), desc="Processing car_serie"))
# Export the full database including merged car_serie
self.export_database_to_json(car_serie_json)
except Exception as e:
self.stdout.write(self.style.ERROR(f"Error: {e}"))
def export_database_to_json(self, car_serie_data):
""" Export the entire MariaDB database to JSON, replacing car_serie with merged data """
try:
self.stdout.write(self.style.SUCCESS("Exporting database to JSON..."))
# Connect to the database using pymysql
connection = pymysql.connect(**db_config)
cursor = connection.cursor()
# Fetch all table names
cursor.execute("SHOW TABLES")
tables = cursor.fetchall()
# Function to fetch data from a table and convert it to JSON
def table_to_json(table_name):
table_cursor = connection.cursor(pymysql.cursors.DictCursor)
table_cursor.execute(f"SELECT * FROM {table_name}")
rows = table_cursor.fetchall()
return rows
# Export each table to JSON, excluding `car_serie` and `car_generation`
database_json = {}
self.stdout.write(self.style.SUCCESS("Processing database tables..."))
for table in tqdm(tables, desc="Exporting tables"):
table_name = table[0]
if table_name not in EXCLUDED_TABLES:
database_json[table_name] = table_to_json(table_name)
# Add the merged car_serie data to the final export
database_json["car_serie"] = car_serie_data
# Save the JSON to a file
self.stdout.write(self.style.SUCCESS("Saving database_export.json..."))
with open('database_export.json', 'w', encoding='utf-8') as json_file:
json.dump(database_json, json_file, indent=4, ensure_ascii=False)
self.stdout.write(self.style.SUCCESS("✅ Database exported to JSON successfully! (Including merged car_serie)"))
except Exception as e:
self.stdout.write(self.style.ERROR(f"Error exporting database: {e}"))
finally:
if connection:
connection.close()

View File

@ -1,6 +1,6 @@
from django import forms
from django.utils.translation import get_language
from django.urls import reverse, reverse_lazy
class AddClassMixin:
"""
@ -40,4 +40,27 @@ class LocalizedNameMixin:
# form.save()
# return super().form_valid(form)
# else:
# return form.errors
# return form.errors
class BaseDateNavigationUrlMixIn:
BASE_DATE_URL_KWARGS = (
'entity_slug',
'unit_slug',
'ledger_pk',
'account_pk',
'coa_slug'
)
def get_context_data(self, **kwargs):
context = super(BaseDateNavigationUrlMixIn, self).get_context_data(**kwargs)
self.get_base_date_nav_url(context)
return context
def get_base_date_nav_url(self, context, **kwargs):
view_name = context['view'].request.resolver_match.url_name
view_name_base = '-'.join(view_name.split('-')[:2])
context['date_navigation_url'] = reverse(
view_name_base,
kwargs={
k: v for k, v in self.kwargs.items() if
k in self.BASE_DATE_URL_KWARGS
})

View File

@ -325,4 +325,25 @@ def number_to_words_arabic(number):
# if language == 'ar':
# return number_to_words_arabic(number)
# else:
# return number_to_words_english(number)
# return number_to_words_english(number)
@register.inclusion_tag('components/date_picker.html', takes_context=True)
def date_picker(context, nav_url=None, date_picker_id=None):
try:
entity_slug = context['view'].kwargs.get('entity_slug')
except KeyError:
entity_slug = context['entity_slug']
if not date_picker_id:
date_picker_id = f'djl-datepicker-{randint(10000, 99999)}'
if 'date_picker_ids' not in context:
context['date_picker_ids'] = list()
context['date_picker_ids'].append(date_picker_id)
date_navigation_url = nav_url if nav_url else context.get('date_navigation_url')
return {
'entity_slug': entity_slug,
'date_picker_id': date_picker_id,
'date_navigation_url': date_navigation_url
}

View File

@ -439,20 +439,23 @@ class AjaxHandlerView(LoginRequiredMixin, View):
model_id = request.GET.get("model_id")
year = request.GET.get("year")
# Validate inputs
if not model_id or not year:
return JsonResponse(
{"error": "Missing required parameters: model_id or year"}, status=400
)
model_id = int(model_id)
year = int(year)
query = Q(id_car_model=model_id) & (
Q(year_begin__lte=year, year_end__gte=year) |
Q(year_end__isnull=True) |
Q(year_begin__isnull=True)
)
try:
year = int(year)
except ValueError:
return JsonResponse({"error": "Invalid year format"}, status=400)
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")
series = models.CarSerie.objects.filter(query).values(
"id_car_serie",
"name",
"arabic_name",
"generation_name"
)
except Exception as e:
return JsonResponse({"error": "Server error occurred"}, status=500)
return JsonResponse(list(series), safe=False)
def get_trims(self, request):

View File

@ -1,23 +1,31 @@
import os
import django
import json
from tqdm import tqdm
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "car_inventory.settings")
django.setup()
from inventory.models import (
CarMake, CarModel, CarSerie, CarTrim, CarEquipment,
CarSpecification, CarSpecificationValue, CarOption, CarOptionValue
)
def run():
with open("final_car_data.json", "r") as file:
data = json.load(file)
def run():
with open("database_export.json", "r") as file:
data = json.load(file)
print("Starting data loading...")
# Step 1: Insert CarMake
for item in tqdm(data["car_make"], desc="Inserting CarMake"):
CarMake.objects.update_or_create(
id_car_make=item["id_car_make"],
defaults={
"name": item["name"],
"arabic_name": item.get("arabic_name", ""),
"logo": item.get("Logo", ""),
"is_sa_import": item.get("is_sa_import", False),
# "arabic_name": item.get("arabic_name", ""),
# "logo": item.get("Logo", ""),
# "is_sa_import": item.get("is_sa_import", False),
}
)
@ -29,7 +37,7 @@ def run():
defaults={
"id_car_make_id": item["id_car_make"],
"name": item["name"],
"arabic_name": item.get("arabic_name", ""),
# "arabic_name": item.get("arabic_name", ""),
}
)
@ -40,8 +48,8 @@ def run():
id_car_serie=item["id_car_serie"],
defaults={
"id_car_model_id": item["id_car_model"],
"name": item["name"],
"arabic_name": item.get("arabic_name", ""),
"name": item["serie_name"],
# "arabic_name": item.get("arabic_name", ""),
"year_begin": item.get("year_begin"),
"year_end": item.get("year_end"),
"generation_name": item.get("generation_name", ""),
@ -56,7 +64,7 @@ def run():
defaults={
"id_car_serie_id": item["id_car_serie"],
"name": item["name"],
"arabic_name": item.get("arabic_name", ""),
# "arabic_name": item.get("arabic_name", ""),
"start_production_year": item["start_production_year"],
"end_production_year": item["end_production_year"],
}
@ -83,7 +91,7 @@ def run():
id_car_specification=item["id_car_specification"],
defaults={
"name": item["name"],
"arabic_name": item.get("arabic_name", ""),
# "arabic_name": item.get("arabic_name", ""),
"id_parent_id": None
}
)
@ -94,7 +102,7 @@ def run():
id_car_specification=item["id_car_specification"],
defaults={
"name": item["name"],
"arabic_name": item.get("arabic_name", ""),
# "arabic_name": item.get("arabic_name", ""),
"id_parent_id": item["id_parent"]
}
)
@ -122,7 +130,7 @@ def run():
id_car_option=item["id_car_option"],
defaults={
"name": item["name"],
"arabic_name": item.get("arabic_name", ""),
# "arabic_name": item.get("arabic_name", ""),
"id_parent_id": None
}
)
@ -133,7 +141,7 @@ def run():
id_car_option=item["id_car_option"],
defaults={
"name": item["name"],
"arabic_name": item.get("arabic_name", ""),
# "arabic_name": item.get("arabic_name", ""),
"id_parent_id": item["id_parent"]
}
)
@ -151,4 +159,7 @@ def run():
}
)
print("Data population completed successfully.")
print("Data population completed successfully.")
if __name__ == "__main__":
run()

Binary file not shown.

View File

@ -7470,27 +7470,18 @@ msgid "Not set."
msgstr "غير محدد"
#: venv/lib/python3.11/site-packages/appointment/utils/date_time.py:84
#, fuzzy, python-format
#| msgid "%(count)d day"
#| msgid_plural "%(count)d days"
msgid "%(count)d day"
msgid_plural "%(count)d days"
msgstr[0] "%(num)d يوم"
msgstr[1] "%(num)d أيام"
#: venv/lib/python3.11/site-packages/appointment/utils/date_time.py:88
#, fuzzy, python-format
#| msgid "%(count)d hour"
#| msgid_plural "%(count)d hours"
msgid "%(count)d hour"
msgid_plural "%(count)d hours"
msgstr[0] "%(num)d ساعة"
msgstr[1] "%(num)d ساعات"
#: venv/lib/python3.11/site-packages/appointment/utils/date_time.py:92
#, fuzzy, python-format
#| msgid "%(count)d minute"
#| msgid_plural "%(count)d minutes"
msgid "%(count)d minute"
msgid_plural "%(count)d minutes"
msgstr[0] "%(num)d دقيقة"
@ -8921,62 +8912,62 @@ msgstr "ديسمبر"
#: venv/lib/python3.11/site-packages/django/utils/dates.py:53
msgctxt "abbrev. month"
msgid "Jan."
msgstr "يناير."
msgstr "يناير"
#: venv/lib/python3.11/site-packages/django/utils/dates.py:54
msgctxt "abbrev. month"
msgid "Feb."
msgstr "فبراير."
msgstr "فبراير"
#: venv/lib/python3.11/site-packages/django/utils/dates.py:55
msgctxt "abbrev. month"
msgid "March"
msgstr "مارس."
msgstr "مارس"
#: venv/lib/python3.11/site-packages/django/utils/dates.py:56
msgctxt "abbrev. month"
msgid "April"
msgstr "أبريل."
msgstr "أبريل"
#: venv/lib/python3.11/site-packages/django/utils/dates.py:57
msgctxt "abbrev. month"
msgid "May"
msgstr "مايو."
msgstr "مايو"
#: venv/lib/python3.11/site-packages/django/utils/dates.py:58
msgctxt "abbrev. month"
msgid "June"
msgstr "يونيو."
msgstr "يونيو"
#: venv/lib/python3.11/site-packages/django/utils/dates.py:59
msgctxt "abbrev. month"
msgid "July"
msgstr "يوليو."
msgstr "يوليو"
#: venv/lib/python3.11/site-packages/django/utils/dates.py:60
msgctxt "abbrev. month"
msgid "Aug."
msgstr "أغسطس."
msgstr "أغسطس"
#: venv/lib/python3.11/site-packages/django/utils/dates.py:61
msgctxt "abbrev. month"
msgid "Sept."
msgstr "سبتمبر."
msgstr "سبتمبر"
#: venv/lib/python3.11/site-packages/django/utils/dates.py:62
msgctxt "abbrev. month"
msgid "Oct."
msgstr "أكتوبر."
msgstr "أكتوبر"
#: venv/lib/python3.11/site-packages/django/utils/dates.py:63
msgctxt "abbrev. month"
msgid "Nov."
msgstr "نوفمبر."
msgstr "نوفمبر"
#: venv/lib/python3.11/site-packages/django/utils/dates.py:64
msgctxt "abbrev. month"
msgid "Dec."
msgstr "ديسمبر."
msgstr "ديسمبر"
#: venv/lib/python3.11/site-packages/django/utils/dates.py:67
msgctxt "alt. month"

35
merge_db.py Normal file
View File

@ -0,0 +1,35 @@
import pymysql
from sqlalchemy import create_engine
import pandas as pd
# Database connection
engine = create_engine("mysql+pymysql://root:Kfsh&rc9788@localhost/car2db01022025")
try:
# Load car_generation table
car_generation_query = "SELECT * FROM car_generation;"
car_generation_df = pd.read_sql(car_generation_query, engine)
# Load car_serie table
car_serie_query = "SELECT * FROM car_serie;"
car_serie_df = pd.read_sql(car_serie_query, engine)
# Perform a LEFT JOIN to keep all car series and merge with car generations
merged_df = pd.merge(car_serie_df, car_generation_df, on="id_car_generation", how="left")
# Select and rename the relevant columns
final_df = merged_df.rename(columns={
"id_car_serie": "id_car_serie",
"id_car_model_x": "id_car_model", # Ensure correct column selection
"name_y": "generation_name", # Car generation name
"name_x": "serie_name", # Car series name
"year_begin": "year_begin",
"year_end": "year_end"
})[["id_car_serie", "id_car_model", "generation_name", "serie_name", "year_begin", "year_end"]]
# Save the filtered data to a JSON file
final_df.to_json("merged_car_data.json", orient="records", indent=4)
print("Filtered merged data saved to 'merged_car_data.json'.")
except Exception as e:
print("Error:", e)

126970
merged_car_data.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -96,6 +96,7 @@ hstspreload==2025.1.1
httpcore==1.0.7
httpx==0.28.1
hyperframe==6.1.0
icalendar==6.1.1
idna==3.10
imageio==2.37.0
imagesize==1.4.1

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

@ -106,7 +106,7 @@ function notify(tag,msg){
</main>
{% block customJS %}
<script src="{% static 'django_ledger/bundle/djetler.bundle.js' %}"></script>
<script src="{% static 'js/djetler.bundle.js' %}"></script>
<script src="{% static 'js/js-utils.js' %}"></script>
<script src="{% static 'js/modal/show_modal.js' %}"></script>

View File

@ -390,6 +390,7 @@
if (vinData.model_id) {
modelSelect.value = vinData.model_id;
document.getElementById("model-check").innerHTML = "&#10003;";
await loadSeries(vinData.model_id, vinData.year);
}
if (vinData.year) {
@ -461,6 +462,7 @@
resetDropdown(serieSelect, '{% trans "Select" %}');
resetDropdown(trimSelect, '{% trans "Select" %}');
specificationsContent.innerHTML = "";
const response = await fetch(`${ajaxUrl}?action=get_series&model_id=${modelId}&year=${year}`, {
headers: {
"X-Requested-With": "XMLHttpRequest",
@ -468,6 +470,7 @@
},
});
const data = await response.json();
console.log(data)
data.forEach((serie) => {
const option = document.createElement("option");

View File

@ -111,12 +111,7 @@
<span class="fw-light">{{ car.receiving_date|timesince }}</span>
</td>
<td class="align-middle white-space-nowrap text-end pe-0 ps-4">
<div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
<div class="dropdown-menu dropdown-menu-end py-2"><a class="dropdown-item" href="{% url 'car_detail' car.pk %}">{% trans "view"|capfirst %}</a>
<div class="dropdown-divider"></div><a class="dropdown-item text-danger" href="#!">Remove</a>
</div>
</div>
<a class="btn btn-sm btn-phoenix-success" href="{% url 'car_detail' car.pk %}">{% trans "view"|capfirst %}</a>
</td>
</tr>
{% empty %}

View File

@ -0,0 +1,7 @@
{% load i18n %}
{% if date_navigation_url %}
<button id="{{ date_picker_id }}" data-baseurl="{{ date_navigation_url }}"
class="button is-small is-rounded is-dark is-outlined">{% trans 'Select Date' %}</button>
{% endif %}

View File

@ -1,4 +1,5 @@
{% load django_ledger %}
{% load i18n %}
<div class="card shadow-sm">
@ -17,15 +18,15 @@
<div class="text-center mb-3">
<p class="mb-1">
<span class="fw-bold">Year: </span>
<span class="fw-bold">{{ _("Year") }}: </span>
<a href="{{ previous_year_url }}" class="text-decoration-none me-2">
<span class="fas fa-chevron-left"> </span>
<span class="fas fa-chevron-left"> </span>
<span class="fas fa-chevron-right"> </span>
<span class="fas fa-chevron-right"> </span>
{{ previous_year }}</a>
<a href="{{ current_year_url }}" class="text-decoration-none me-2 fw-bolder">{{ year }}</a>
<a href="{{ next_year_url }}" class="text-decoration-none">{{ next_year }}
<span class="fas fa-chevron-right"> </span>
<span class="fas fa-chevron-right"> </span>
<span class="fas fa-chevron-left"> </span>
<span class="fas fa-chevron-left"> </span>
</a>
</p>
</div>

View File

@ -32,7 +32,7 @@
<h2 class="display-4 font-weight-light">
{% if quarter %}{{ year }} | Q{{ quarter }}
{% elif month %}{{ start_date | date:'F, Y' }}
{% else %}Fiscal Year {{ year }}
{% else %}{{ _("Fiscal Year")}} {{ year }}
{% endif %}</h2>
<h3 class="h4 font-italic font-weight-light">
{{ from_date | date:'m/d/Y' }} - {{ to_date | date:'m/d/Y' }}

16
the env file.txt Normal file
View File

@ -0,0 +1,16 @@
PASSWORD = 'Kfsh&rc9788'
SECRET_KEY = 'django-insecure-gc9bh4*3=b6hihdnaom0edjsbxh$5t)aap@e8p&340r7)*)qb8'
EMAIL_HOST_USER = 'haikal@tenhal.sa'
EMAIL_HOST_PASSWORD = 'insp avme nsrz pvin'
DEFAULT_FROM_EMAIL = 'haikal@tenhal.sa'
OPENAI_API_KEY = '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'
ELM_APP_ID = 'c2729afb'
ELM_APP_KEY = '6d397471920412d672af1b8a02ca52ea'
ELM_CLIENT_ID = '94142c27-2536-47e9-8e28-9ca7728b9442'
ELM_APP_ID_OPTIONS = '367974ed'
ELM_APP_KEY_OPTIONS = '046b0412c1b4d3f8c39ec6375d6f3030'
TWILIO_ACCOUNT_SID = 'AC988fcc2cce8ae4f36ffc58bf897bcb1d'
TWILIO_AUTH_TOKEN = '8e5a85e1fe8d48d73b8247bdee3ec65a'