This commit is contained in:
Marwan Alwali 2025-02-18 09:57:19 +03:00
parent 9b282154b0
commit 7423fa9878
21 changed files with 185 additions and 105 deletions

View File

@ -4,7 +4,18 @@ from . import models
from django_ledger import models as ledger_models
from django_pdf_actions.actions import export_to_pdf_landscape, export_to_pdf_portrait
from appointment import models as appointment_models
from import_export.admin import ExportMixin
from import_export.resources import ModelResource
# Define resource class
# class CarSerieResource(ModelResource):
# class Meta:
# model = models.CarSerie
#
# # Integrate into Django Admin
# @admin.register(models.CarSerie)
# class CarSeriesAdmin(ExportMixin, admin.ModelAdmin):
# resource_class = CarSerieResource
admin.site.register(models.Dealer)
admin.site.register(models.Staff)
@ -29,7 +40,7 @@ admin.site.register(models.CarLocation)
admin.site.register(models.CarReservation)
admin.site.register(models.Organization)
admin.site.register(models.Representative)
admin.site.register(models.CarTrim)
# admin.site.register(models.CarTrim)
admin.site.register(models.AdditionalServices)
admin.site.register(models.Payment)
admin.site.register(models.VatRate)
@ -82,7 +93,7 @@ class CarModelAdmin(admin.ModelAdmin):
@admin.register(models.CarSerie)
class CarSeriesAdmin(admin.ModelAdmin):
list_display = ('name', 'arabic_name', 'id_car_model', )
search_fields = ('id_car_serie', 'name', 'id_car_model__name', 'id_car_model__id_car_make__name')
search_fields = ('name',)
list_filter = ('id_car_model__id_car_make__is_sa_import',
'id_car_model__id_car_make__name',)
@ -90,18 +101,18 @@ class CarSeriesAdmin(admin.ModelAdmin):
verbose_name = "Car Series"
# @admin.register(models.CarTrim)
# class CarTrimAdmin(admin.ModelAdmin):
# list_display = ('name',
# 'id_car_serie__name',
# 'id_car_serie__id_car_model__name',
# 'id_car_serie__id_car_model__id_car_make__name')
# search_fields = ('name', 'arabic_name', 'id_car_serie__id_car_model__name')
# list_filter = ('id_car_serie__id_car_model__id_car_make__is_sa_import',
# 'id_car_serie__id_car_model__id_car_make__name')
@admin.register(models.CarTrim)
class CarTrimAdmin(admin.ModelAdmin):
list_display = ('name',
'id_car_serie__name',
'id_car_serie__id_car_model__name',
'id_car_serie__id_car_model__id_car_make__name')
search_fields = ('name', 'arabic_name', 'id_car_serie__id_car_model__name')
list_filter = ('id_car_serie__id_car_model__id_car_make__is_sa_import',
'id_car_serie__id_car_model__id_car_make__name')
# class Meta:
# verbose_name = "Car Trim"
class Meta:
verbose_name = "Car Trim"
@admin.register(models.CarSpecification)

View File

@ -0,0 +1,69 @@
from django.core.management.base import BaseCommand
from inventory.models import CarSerie
TRANSLATIONS = {
"Sedan": "سيدان",
"Coupe": "كوبيه",
"SUV 5 doors": "إس يو في - خمسة أبواب",
"Minivan": "ميني فان",
"Hatchback": "هاتشباك",
"Cabriolet": "سطح قابل للطي",
"Hatchback 5-doors": "هاتشباك - خمسة أبواب",
"Hatchback 5 doors": "هاتشباك - خمسة أبواب",
"Hatchback 3-doors": "هاتشباك - ثلاثة أبواب",
"Crossover": "كروس أوفر",
"Wagon": "واغن",
"SUV": "إس يو في",
"Wagon 5 doors": "واغن - خمسة أبواب",
"Roadster": "رودستر",
"SUV 5-doors": "إس يو في - خمسة أبواب",
"Wagon 5-doors": "واغن - خمسة أبواب",
"Sedan 4-doors": "سيدان - أربعة أبواب",
"Hatchback 3 doors": "هاتشباك - ثلاثة أبواب",
"Van": "فان",
"Pickup Double cabin": "بيك أب - غمارتين",
"Compactvan": "كومباكت فان",
"Pickup": "بيك أب",
"Microvan": "ميكروفان",
"Liftback": "ليفت باك",
"SUV 3-doors": "إس يو في - ثلاثة أبواب",
"Coupe 2-doors": "كوبيه - بابين",
"Pickup Single cabin": "بيك أب - غمارة واحدة",
"Crossover 5-doors": "كروس أوفر - خمسة أبواب",
"Coupe-Hardtop": "كوبيه هاردتوب",
"SUV 3 doors": "إس يو في - ثلاثة أبواب",
"Hardtop": "هاردتوب",
"Sedan 2-doors": "سيدان - بابين",
"Minivan 5-doors": "ميني فان - خمسة أبواب",
"Targa": "تارغا",
"SUV opened": "إس يو في مكشوف",
"Pickup One-and-a-half cabin": "بيك أب - غمارة ونصف",
"Sedan 2 doors": "سيدان - بابين",
"AMG Sedan 4-doors": "أي إم جي سيدان - أربعة أبواب",
"Cabriolet 2-doors": "سطح قابل للطي - بابين",
"Fastback": "فاست باك",
"Sedan-Hardtop": "سيدان هاردتوب",
"Regular Cab pickup 2-doors": "بيك أب كابينة عادية - بابين",
"Grand minivan 5-doors": "ميني فان كبير - خمسة أبواب",
"Sedan Long": "سيدان طويل",
"Speedster": "سبيدستر",
}
class Command(BaseCommand):
help = "Translate CarSerie model names into Arabic"
def handle(self, *args, **kwargs):
updated_count = 0
for car_serie in CarSerie.objects.all():
arabic_translation = TRANSLATIONS.get(car_serie.name)
if arabic_translation and car_serie.arabic_name != arabic_translation:
car_serie.arabic_name = arabic_translation
car_serie.save()
updated_count += 1
self.stdout.write(self.style.SUCCESS(f"Updated: {car_serie.name} -> {arabic_translation}"))
if updated_count:
self.stdout.write(self.style.SUCCESS(f"Successfully updated {updated_count} entries."))
else:
self.stdout.write(self.style.WARNING("No updates were made."))

View File

@ -416,7 +416,7 @@ class Car(models.Model):
@property
def ready(self):
try:
return all([self.colors.exists() ,self.finances,])
return all([self.colors ,self.finances,])
except Exception as e:
return False
def get_transfer(self):

View File

@ -1,10 +1,15 @@
from django.utils.html import format_html
from django.conf import settings
from django.utils.timesince import timesince
from . import models
from django_tables2.utils import A
import django_tables2 as tables
from django import forms
import django_tables2 as tables
from django.utils.translation import gettext_lazy as _
from .models import Car, CarFinance, ExteriorColors, InteriorColors, CarColors
from .utils import get_local_name
@ -13,88 +18,50 @@ class ImageColumn(tables.Column):
return format_html('<img src="{}{}" width="100" height="50" />', settings.MEDIA_URL, value)
class CustomerTable(tables.Table):
class Meta:
model = models.Customer
first_name = tables.Column()
import django_tables2 as tables
from django.utils.translation import gettext_lazy as _
from .models import Car, CarFinance, ExteriorColors, InteriorColors, CarColors
class CarTable(tables.Table):
# Car fields
vin = tables.Column(verbose_name=_("VIN"))
dealer = tables.Column(verbose_name=_("Dealer"))
vendor = tables.Column(verbose_name=_("Vendor"))
stock_type = tables.Column(verbose_name=_("Stock Type"))
vin = tables.LinkColumn("car_detail", args=[tables.A("pk")], verbose_name=_("VIN"), attrs={"td": {"class": "fw-bold"}, "span": {"class": "fas fa-bars"}})
id_car_make = tables.Column(verbose_name=_("Make"))
id_car_model = tables.Column(verbose_name=_("Model"))
year = tables.Column(verbose_name=_("Year"))
id_car_serie = tables.Column(verbose_name=_("Series"))
id_car_trim = tables.Column(verbose_name=_("Trim"))
status = tables.Column(verbose_name=_("Status"))
stock_type = tables.Column(verbose_name=_("Stock Type"))
remarks = tables.Column(verbose_name=_("Remarks"))
mileage = tables.Column(verbose_name=_("Mileage"))
receiving_date = tables.Column(verbose_name=_("Receiving Date"))
hash = tables.Column(verbose_name=_("Hash"))
# CarFinance fields
cost_price = tables.Column(accessor="finances.cost_price", verbose_name=_("Cost Price"))
selling_price = tables.Column(accessor="finances.selling_price", verbose_name=_("Selling Price"))
discount_amount = tables.Column(accessor="finances.discount_amount", verbose_name=_("Discount Amount"))
# ExteriorColors fields (accessed through CarColors)
selling_price = tables.Column(accessor="finances.selling_price", verbose_name=_("Price"))
exterior_color = tables.Column(accessor="colors.exterior.name", verbose_name=_("Exterior Color"))
exterior_color_rgb = tables.Column(accessor="colors.exterior.rgb", verbose_name=_("Exterior Color RGB"))
# InteriorColors fields (accessed through CarColors)
interior_color = tables.Column(accessor="colors.interior.name", verbose_name=_("Interior Color"))
interior_color_rgb = tables.Column(accessor="colors.interior.rgb", verbose_name=_("Interior Color RGB"))
receiving_date = tables.Column(verbose_name=_("Age"))
status = tables.Column(verbose_name=_("Status"))
class Meta:
model = Car
template_name = "django_tables2/bootstrap.html"
template_name = settings.DJANGO_TABLES2_TEMPLATE
export_formats = ["xlsx", ]
fields = (
"stock_type",
"vin",
"dealer",
"vendor",
"id_car_make",
"id_car_model",
"year",
"id_car_serie",
"id_car_trim",
"status",
"stock_type",
"remarks",
"mileage",
"receiving_date",
"hash",
"cost_price",
"selling_price",
"discount_amount",
"exterior_color",
"exterior_color_rgb",
"interior_color",
"interior_color_rgb",
"receiving_date",
"status",
)
attrs = {"class": "table table-striped table-bordered"}
def render_dealer(self, value):
return str(value)
def render_vendor(self, value):
return str(value)
attrs = {"class": "table table-hover fs-9 mb-0"}
def render_id_car_make(self, value):
return str(value)
return get_local_name(value)
def render_id_car_model(self, value):
return str(value)
return get_local_name(value)
def render_id_car_serie(self, value):
return str(value)
return get_local_name(value)
def render_id_car_trim(self, value):
return str(value)
@ -103,4 +70,7 @@ class CarTable(tables.Table):
return str(value)
def render_interior_color(self, value):
return str(value)
return str(value)
def render_receiving_date(self, value):
return timesince(value) if value else "-"

View File

@ -1,7 +1,9 @@
from django.urls import path
from django_tables2.export.export import TableExport
from . import views
from allauth.account import views as allauth_views
from django_tables2.export.views import TableExport
urlpatterns = [
@ -46,8 +48,8 @@ urlpatterns = [
"dashboards/accounting/", views.AccountingDashboard.as_view(), name="accounting"
),
path("test/", views.TestView.as_view(), name="test"),
path('cars/inventory/table/', views.car_list, name="car_table"),
path('export/<str:format>/', TableExport, name='export'),
path('cars/inventory/table/', views.CarListViewTable.as_view(), name="car_table"),
path("export/format/", TableExport, name="export"),
# Dealer URLs
path("dealers/<int:pk>/", views.DealerDetailView.as_view(), name="dealer_detail"),
path(

View File

@ -25,6 +25,7 @@ from django_ledger.models import (
ItemTransactionModel
)
from decimal import Decimal
from django.utils.translation import get_language
@ -838,4 +839,13 @@ def get_item_transactions(txs):
if bool(data):
transactions.append(data)
print(data)
return transactions
return transactions
def get_local_name(self):
"""
Returns the localized name based on the current language.
"""
if get_language() == 'ar':
return getattr(self, 'arabic_name', None)
return getattr(self, 'name', None)

View File

@ -3,7 +3,8 @@ from appointment.models import Appointment,AppointmentRequest,Service,StaffMembe
from datetime import timedelta
from calendar import month_name
from random import randint
from django_tables2 import RequestConfig
from django_tables2 import SingleTableView
from django_tables2.export.views import ExportMixin
from django_pdf_actions.actions import export_to_pdf_landscape
from reportlab.lib.pagesizes import landscape, A4
from rich import print
@ -4387,11 +4388,14 @@ def apply_search_filters(queryset, query):
return queryset.filter(search_filters).distinct()
def car_list(request):
dealer = get_user_type(request)
queryset = models.Car.objects.select_related(
"finances", "colors__exterior", "colors__interior"
).filter(dealer=dealer)
table = tables.CarTable(queryset)
RequestConfig(request).configure(table)
return render(request, 'inventory/car_list_table.html', {'table': table})
class CarListViewTable(ExportMixin, LoginRequiredMixin, SingleTableView):
model = models.Car
table_class = tables.CarTable
template_name = "inventory/car_list_table.html"
def get_queryset(self):
dealer = get_user_type(self.request)
return models.Car.objects.select_related(
"finances", "colors__exterior", "colors__interior"
).filter(dealer=dealer)

View File

@ -35,6 +35,7 @@ Cython==3.1.0a1
decorator==5.1.1
defusedxml==0.7.1
desert==2020.11.18
diff-match-patch==20241021
dill==0.3.9
distro==1.9.0
dj-rest-auth==7.0.1
@ -52,6 +53,7 @@ django-debug-toolbar==5.0.1
django-extensions==3.2.3
django-filter==25.1
django-formtools==2.5.1
django-import-export==4.3.5
django-ledger==0.7.4.1
django-model-utils==5.0.0
django-money==3.5.3
@ -133,7 +135,7 @@ networkx==3.4.2
newrelic==10.6.0
nltk==3.9.1
num2words==0.5.14
libquadmath==2.2.3
numpy==2.2.3
oauthlib==3.2.2
ofxtools==0.9.5
openai==1.63.1
@ -176,6 +178,7 @@ pyobjc-framework-Cocoa==11.0
pyobjc-framework-Quartz==11.0
pyparsing==3.2.1
pypdf==5.3.0
PyPDF2==3.0.1
pyperclip==1.9.0
pyphen==0.17.2
pypng==0.20220715.0
@ -208,8 +211,8 @@ rich==13.9.4
rubicon-objc==0.5.0
sacremoses==0.1.1
scikit-image==0.25.1
libomp runtime library==1.6.1
libquadmath==1.15.2
scikit-learn==1.6.1
scipy==1.15.2
selenium==4.28.1
sentencepiece==0.2.0
shapely==2.0.7

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

BIN
static/images/icons/pdf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@ -244,27 +244,27 @@
<div class="card-body">
<div class="table-responsive scrollbar mb-3">
<table class="table table-sm fs-9 mb-0 overflow-hidden">
{% if car.colors.exists %}
{% for color in car.colors.all %}
{% if car.colors %}
<tr>
<th>{% trans 'Exterior' %}</th>
<td>
<span>{{ color.exterior.get_local_name }}</span>
<span>{{ car.colors.exterior.get_local_name }}</span>
</td>
<td class="align-middle">
<div class="text-end color-div" style="background-color: rgb({{ color.exterior.rgb }});"></div>
<div class="text-end color-div" style="background-color: rgb({{ car.colors.exterior.rgb }});"></div>
</td>
</tr>
<tr>
<th>{% trans 'Interior' %}</th>
<td>
<span>{{ color.interior.get_local_name }}</span>
<span>{{ car.colors.interior.get_local_name }}</span>
</td>
<td class="align-middle">
<div class="text-end color-div" style="background-color: rgb({{ color.interior.rgb }});"></div>
<div class="text-end color-div" style="background-color: rgb({{ car.colors.interior.rgb }});"></div>
</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="2">

View File

@ -72,15 +72,15 @@
</td>
<td class="align-middle white-space-nowrap text-start"><a class="fs-9 fw-bold" href="{% url 'car_detail' car.pk %}">{{ car.vin }}</a></td>
<td class="align-middle white-space-nowrap text-center fw-bold">{{ car.year }}</td>
{% if car.colors.exists %}
{% if car.colors %}
<td class="align-middle white-space-nowrap text-body fs-9 text-start">
<div class="d-flex flex-column align-items-center">
<span class="color-div" style="background: linear-gradient(90deg, rgba({{ car.colors.first.exterior.rgb }},1) 10%, rgba({{ car.colors.first.exterior.rgb }},0.10) 100%);" title="{{ car.colors.first.exterior.get_local_name }}"></span><span>{{ car.colors.first.exterior.get_local_name }}</span>
<span class="color-div" style="background: linear-gradient(90deg, rgba({{ car.colors.exterior.rgb }},1) 10%, rgba({{ car.colors.exterior.rgb }},0.10) 100%);" title="{{ car.colors.exterior.get_local_name }}"></span><span>{{ car.colors.exterior.get_local_name }}</span>
</div>
</td>
<td class="align-middle white-space-nowrap text-body fs-9 text-start">
<div class="d-flex flex-column align-items-center">
<span class="color-div" style="background: linear-gradient(90deg, rgba({{ car.colors.first.interior.rgb }},1) 10%, rgba({{ car.colors.first.interior.rgb }},0.10) 100%);" title="{{ car.colors.first.interior.get_local_name }}"></span><span>{{ car.colors.first.interior.get_local_name }}</span>
<span class="color-div" style="background: linear-gradient(90deg, rgba({{ car.colors.interior.rgb }},1) 10%, rgba({{ car.colors.interior.rgb }},0.10) 100%);" title="{{ car.colors.interior.get_local_name }}"></span><span>{{ car.colors.interior.get_local_name }}</span>
</div>
</td>
{% else %}

View File

@ -1,15 +1,26 @@
{% extends 'base.html' %}
{% load static i18n django_tables2%}
{% load static i18n django_tables2 %}
{% load export_url from django_tables2 %}
{% block content %}
<div class="container-fluid p-4 my-3">
<div class="row">
<div class="col-md-12 p-2 d-flex justify-content-end gap-3">
<a href="{% export_url 'xlsx' %}" class="btn btn-sm btn-phoenix-success">
<span class="fas fa-arrow-{% if LANGUAGE_CODE == 'ar' %}left{% else %}right{% endif %} me-1"></span>
<span class="fas fa-file-excel fs-8"></span></a>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="table-responsive scrollbar mx-n1 px-1 align-center">
{% render_table table %}
</div>
</div>
</div>
</div>
{% load export_url from django_tables2 %}
<!-- Render the table -->
{% render_table table %}
<!-- Add export buttons -->
<a href="{% export_url 'xlsx' %}" class="btn btn-primary">Export to Excel</a>
<a href="{% export_url 'pdf' %}" class="btn btn-primary">Export to PDF</a>
{% endblock %}

View File

@ -4,11 +4,11 @@
<div class="col-auto d-flex">
{% if page_obj.has_previous %}
<button class="page-link" data-list-pagination="prev" onclick="window.location.href='?page={{ page_obj.previous_page_number }}'">
<span class="fas {% if LANGUAGE_CODE == 'ar' %}fa-chevron-right{% else %}fa-chevron-left{% endif %}"></span>
<span class="fas fa-chevron-{% if LANGUAGE_CODE == 'ar' %}right{% else %}left{% endif %}"></span>
</button>
{% else %}
<button class="page-link" disabled>
<span class="fas {% if LANGUAGE_CODE == 'ar' %}fa-chevron-right{% else %}fa-chevron-left{% endif %}"></span>
<span class="fas fa-chevron-{% if LANGUAGE_CODE == 'ar' %}right{% else %}left{% endif %}"></span>
</button>
{% endif %}
@ -28,11 +28,11 @@
{% if page_obj.has_next %}
<button class="page-link pe-0" data-list-pagination="next" onclick="window.location.href='?page={{ page_obj.next_page_number }}'">
<span class="fas {% if LANGUAGE_CODE == 'ar' %}fa-chevron-left{% else %}fa-chevron-right{% endif %}"></span>
<span class="fas fa-chevron-{% if LANGUAGE_CODE == 'ar' %}left{% else %}right{% endif %}"></span>
</button>
{% else %}
<button class="page-link pe-0" disabled>
<span class="fas {% if LANGUAGE_CODE == 'ar' %}fa-chevron-left{% else %}fa-chevron-right{% endif %}"></span>
<span class="fas fa-chevron-{% if LANGUAGE_CODE == 'ar' %}left{% else %}right{% endif %}"></span>
</button>
{% endif %}
</div>