This commit is contained in:
Marwan Alwali 2025-02-17 21:46:27 +03:00
parent 3e2af239e4
commit 9b282154b0
16 changed files with 219 additions and 48 deletions

View File

@ -1,7 +1,9 @@
from appointment.models import Appointment
from django.contrib import admin
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
admin.site.register(models.Dealer)
@ -32,12 +34,15 @@ admin.site.register(models.AdditionalServices)
admin.site.register(models.Payment)
admin.site.register(models.VatRate)
admin.site.register(ledger_models.CustomerModel)
admin.site.register(ledger_models.VendorModel)
admin.site.register(ledger_models.ItemModel)
admin.site.register(models.Opportunity)
admin.site.register(models.Notification)
admin.site.register(models.Lead)
admin.site.register(models.Activity)
admin.site.register(models.Schedule)
admin.site.register(models.Notes)
# admin.site.register(appointment_models.Client)
@admin.register(models.Car)
@ -126,4 +131,5 @@ class CarOptionAdmin(admin.ModelAdmin):
@admin.register(ledger_models.ItemTransactionModel)
class ItemTransactionModelAdmin(admin.ModelAdmin):
actions = [export_to_pdf_landscape, export_to_pdf_portrait]
actions = [export_to_pdf_landscape, export_to_pdf_portrait]

View File

@ -0,0 +1,33 @@
# Generated by Django 5.1.5 on 2025-02-17 14:05
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('inventory', '0030_alter_activity_activity_type_delete_carhistory'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='activity',
name='dealer',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='activities', to='inventory.dealer'),
preserve_default=False,
),
migrations.AlterField(
model_name='activity',
name='content_type',
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='contenttypes.contenttype'),
),
migrations.AlterField(
model_name='activity',
name='created_by',
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='activities_created_by', to=settings.AUTH_USER_MODEL),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 5.1.6 on 2025-02-17 17:40
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0031_activity_dealer_alter_activity_content_type_and_more'),
]
operations = [
migrations.AlterField(
model_name='carcolors',
name='car',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='colors', to='inventory.car'),
),
]

View File

@ -644,7 +644,7 @@ class InteriorColors(models.Model, LocalizedNameMixin):
class CarColors(models.Model):
car = models.ForeignKey("Car", on_delete=models.CASCADE, related_name="colors")
car = models.OneToOneField("Car", on_delete=models.CASCADE, related_name="colors")
exterior = models.ForeignKey(
"ExteriorColors", on_delete=models.CASCADE, related_name="colors"
)
@ -1386,7 +1386,8 @@ class Email(models.Model):
class Activity(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="activities")
content_type = models.ForeignKey(ContentType, on_delete=models.DO_NOTHING)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey("content_type", "object_id")
activity_type = models.CharField(
@ -1394,7 +1395,7 @@ class Activity(models.Model):
)
notes = models.TextField(blank=True, null=True, verbose_name=_("Notes"))
created_by = models.ForeignKey(
User, on_delete=models.DO_NOTHING, related_name="activities_created"
User, on_delete=models.DO_NOTHING, related_name="activities_created_by"
)
created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created"))
updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated"))

View File

@ -5,7 +5,7 @@ from . import models
from django_tables2.utils import A
import django_tables2 as tables
from django import forms
from inventory.models import Car, SaleQuotation, SaleQuotationCar
class ImageColumn(tables.Column):
@ -19,3 +19,88 @@ class CustomerTable(tables.Table):
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"))
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)
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"))
class Meta:
model = Car
template_name = "django_tables2/bootstrap.html"
fields = (
"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",
)
attrs = {"class": "table table-striped table-bordered"}
def render_dealer(self, value):
return str(value)
def render_vendor(self, value):
return str(value)
def render_id_car_make(self, value):
return str(value)
def render_id_car_model(self, value):
return str(value)
def render_id_car_serie(self, value):
return str(value)
def render_id_car_trim(self, value):
return str(value)
def render_exterior_color(self, value):
return str(value)
def render_interior_color(self, value):
return str(value)

View File

@ -1,6 +1,7 @@
from django.urls import path
from . import views
from allauth.account import views as allauth_views
from django_tables2.export.views import TableExport
urlpatterns = [
@ -45,6 +46,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'),
# Dealer URLs
path("dealers/<int:pk>/", views.DealerDetailView.as_view(), name="dealer_detail"),
path(

View File

@ -3,7 +3,7 @@ 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_pdf_actions.actions import export_to_pdf_landscape
from reportlab.lib.pagesizes import landscape, A4
from rich import print
@ -90,7 +90,7 @@ from .services import (
get_make,
get_model,
)
from . import models, forms
from . import models, forms, tables
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.contrib.auth.models import Group
@ -145,6 +145,7 @@ from django_ledger.views.mixins import (
from django_pdf_actions import actions
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
@ -4386,3 +4387,11 @@ 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})

View File

@ -1,24 +1,24 @@
aiohappyeyeballs==2.4.4
aiohttp==3.11.11
aiohappyeyeballs==2.4.6
aiohttp==3.11.12
aiohttp-retry==2.9.1
aiosignal==1.3.2
alabaster==1.0.0
albucore==0.0.23
albumentations==2.0.2
albumentations==2.0.4
annotated-types==0.7.0
anyio==4.8.0
arabic-reshaper==3.0.0
asgiref==3.8.1
astor==0.8.1
astroid==3.3.8
attrs==23.2.0
attrs==25.1.0
autopep8==2.3.2
Babel==2.15.0
beautifulsoup4==4.12.3
beautifulsoup4==4.13.3
bleach==6.2.0
blinker==1.9.0
Brotli==1.1.0
certifi==2024.12.14
certifi==2025.1.31
cffi==1.17.1
chardet==5.2.0
charset-normalizer==3.4.1
@ -27,7 +27,7 @@ colorama==0.4.6
commonmark==0.9.1
contourpy==1.3.1
crispy-bootstrap5==2024.10
cryptography==44.0.0
cryptography==44.0.1
cssselect2==0.7.0
ctranslate2==4.5.0
cycler==0.12.1
@ -39,18 +39,18 @@ dill==0.3.9
distro==1.9.0
dj-rest-auth==7.0.1
dj-shop-cart==8.0.0a2
Django==5.1.5
django-allauth==65.3.1
Django==5.1.6
django-allauth==65.4.1
django-appointment==3.8.0
django-autoslug==1.9.9
django-bootstrap5==24.3
django-classy-tags==4.1.0
django-cors-headers==4.6.0
django-cors-headers==4.7.0
django-countries==7.6.1
django-crispy-forms==2.3
django-debug-toolbar==5.0.1
django-extensions==3.2.3
django-filter==24.3
django-filter==25.1
django-formtools==2.5.1
django-ledger==0.7.4.1
django-model-utils==5.0.0
@ -59,7 +59,7 @@ django-next-url-mixin==0.4.0
django-nine==0.2.7
django-nonefield==0.4
django-ordered-model==3.7.4
django-pdf-actions==0.1.38
django-pdf-actions==0.1.39
django-phonenumber-field==8.0.0
django-picklefield==3.2
django-plans==1.2.0
@ -82,19 +82,19 @@ docutils==0.21.2
easy-thumbnails==2.10
emoji==2.14.1
et_xmlfile==2.0.0
Faker==35.0.0
Faker==36.1.1
filelock==3.17.0
fire==0.7.0
Flask==3.1.0
fonttools==4.55.7
fonttools==4.56.0
fpdf2==2.8.2
frozenlist==1.5.0
fsspec==2024.12.0
fsspec==2025.2.0
gprof2dot==2024.6.6
graphqlclient==0.2.4
greenlet==3.1.1
h11==0.14.0
h2==4.1.0
h2==4.2.0
hpack==4.1.0
hstspreload==2025.1.1
httpcore==1.0.7
@ -117,11 +117,11 @@ lazy_loader==0.4
ledger==1.0.1
libretranslatepy==2.1.4
lmdb==1.6.2
lxml==5.3.0
lxml==5.3.1
Markdown==3.7
markdown-it-py==3.0.0
MarkupSafe==3.0.2
marshmallow==3.26.0
marshmallow==3.26.1
matplotlib==3.10.0
mccabe==0.7.0
mdurl==0.1.2
@ -130,13 +130,13 @@ mpmath==1.3.0
multidict==6.1.0
mypy-extensions==1.0.0
networkx==3.4.2
newrelic==10.4.0
newrelic==10.6.0
nltk==3.9.1
num2words==0.5.14
numpy==2.2.2
libquadmath==2.2.3
oauthlib==3.2.2
ofxtools==0.9.5
openai==1.60.2
openai==1.63.1
opencv-contrib-python==4.11.0.86
opencv-python==4.11.0.86
opencv-python-headless==4.11.0.86
@ -147,8 +147,8 @@ packaging==24.2
pandas==2.2.3
pango==0.0.1
pdfkit==1.0.0
phonenumbers==8.13.42
pillow==10.4.0
phonenumbers==8.13.55
pillow==11.1.0
platformdirs==4.3.6
prometheus_client==0.21.1
propcache==0.2.1
@ -162,7 +162,7 @@ pyclipper==1.3.0.post6
pycodestyle==2.12.1
pycparser==2.22
pydantic==2.10.6
pydantic_core==2.27.2
pydantic_core==2.29.0
pydotplus==2.0.2
pydyf==0.11.0
PyGetWindow==0.0.9
@ -190,41 +190,41 @@ python-openid==2.2.5
python-stdnum==1.20
python3-saml==1.16.0
pytweening==1.2.0
pytz==2024.2
pytz==2025.1
pyvin==0.0.2
pywa==2.7.0
pywhat==5.1.0
pywhatkit==5.4
PyYAML==6.0.2
pyzbar==0.1.9
qrcode==7.4.2
RapidFuzz==3.11.0
qrcode==8.0
RapidFuzz==3.12.1
regex==2024.11.6
reportlab==4.2.5
reportlab==4.3.1
requests==2.32.3
requests-oauthlib==2.0.0
rfc3986==2.0.0
rich==10.16.2
rich==13.9.4
rubicon-objc==0.5.0
sacremoses==0.1.1
scikit-image==0.25.1
scikit-learn==1.6.1
scipy==1.15.1
libomp runtime library==1.6.1
libquadmath==1.15.2
selenium==4.28.1
sentencepiece==0.2.0
shapely==2.0.6
shapely==2.0.7
simsimd==6.2.1
six==1.17.0
sniffio==1.3.1
snowballstemmer==2.2.0
sortedcontainers==2.4.0
soupsieve==2.6
SQLAlchemy==2.0.37
SQLAlchemy==2.0.38
sqlparse==0.5.3
stanza==1.10.1
stringzilla==3.11.3
suds==1.2.0
swapper==1.3.0
swapper==1.4.0
sympy==1.13.1
tablib==3.8.0
termcolor==2.5.0
@ -234,11 +234,11 @@ tinycss2==1.4.0
tinyhtml5==2.0.0
tomli==2.2.1
tomlkit==0.13.2
torch==2.5.1
torch==2.6.0
tqdm==4.67.1
trio==0.28.0
trio-websocket==0.11.1
twilio==9.4.4
trio==0.29.0
trio-websocket==0.12.0
twilio==9.4.5
typing-inspect==0.9.0
typing_extensions==4.12.2
tzdata==2025.1
@ -249,7 +249,7 @@ vin==0.6.2
vininfo==1.8.0
vishap==0.1.5
vpic-api==0.7.4
weasyprint==63.1
weasyprint==64.0
webencodings==0.5.1
websocket-client==1.8.0
Werkzeug==3.1.3

View File

@ -0,0 +1,15 @@
{% extends 'base.html' %}
{% load static i18n django_tables2%}
{% block content %}
{% 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

@ -115,8 +115,8 @@
</div>
</div>
</td>
<td class="email align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent">{{ org.additional_info.organization_info.crn }}</td>
<td class="phone align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent">{{ org.additional_info.organization_info.vrn }}</td>
<td class="email align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent">{{ org.additional_info.info.crn }}</td>
<td class="phone align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent">{{ org.additional_info.info.vrn }}</td>
<td class="phone align-middle white-space-nowrap ps-4 border-end border-translucent fw-semibold text-body-highlight"><a class="text-body-highlight" href="tel:{{ org.phone }}">{{ org.phone }}</a></td>
<td class="company align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 border-end border-translucent fw-semibold text-body-highlight">
{{ org.address_1 }}</td>