edit styles

This commit is contained in:
Marwan Alwali 2024-12-12 11:00:42 +03:00
parent 9e0824de6d
commit b227d9ff5b
23 changed files with 917 additions and 510 deletions

2
.gitignore vendored
View File

@ -5,7 +5,7 @@
__pycache__
db.sqlite3
media
./car_inventorysettings.py
# Backup files #
*.bak

View File

@ -9,7 +9,7 @@ https://docs.djangoproject.com/en/5.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.0/ref/settings/
"""
from decimal import Decimal
from pathlib import Path
import os
from django.utils.translation import gettext_lazy as _
@ -26,7 +26,7 @@ SECRET_KEY = 'django-insecure-gc9bh4*3=b6hihdnaom0edjsbxh$5t)aap@e8p&340r7)*)qb8
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['10.10.1.109',"10.10.1.120", 'localhost', '127.0.0.1', '192.168.1.135', '172.20.10.4']
ALLOWED_HOSTS = ['10.10.1.109', 'localhost', '127.0.0.1', '192.168.1.135', '172.20.10.4']
# Application definition
@ -110,9 +110,9 @@ WSGI_APPLICATION = 'car_inventory.wsgi.application'
DATABASES = {
"default": {
"ENGINE": "django_prometheus.db.backends.postgresql",
"NAME": "haikal",
"USER": "haikal",
"PASSWORD": "haikal",
"NAME": "haikal_app",
"USER": "f95166",
"PASSWORD": "Kfsh&rc9788",
"HOST": "localhost",
"PORT": 5432,
}
@ -255,3 +255,7 @@ LOGGING = {
},
},
}
# Global Settings
CURRENCY = _('SAR')
VAT_RATE = Decimal('0.15')

View File

@ -15,6 +15,7 @@ admin.site.register(models.CustomCard)
admin.site.register(models.CarSpecificationValue)
admin.site.register(models.ExteriorColors)
admin.site.register(models.InteriorColors)
admin.site.register(models.CarLocation)
@admin.register(models.CarMake)
class CarMakeAdmin(admin.ModelAdmin):

View File

@ -4,3 +4,6 @@ from django.apps import AppConfig
class InventoryConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'inventory'
def ready(self):
import inventory.signals

View File

@ -13,7 +13,8 @@ from .models import (
CarColors,
ExteriorColors,
InteriorColors,
SaleQuotation
SaleQuotation,
CarLocation
)
from django.forms import ModelMultipleChoiceField
from django.utils.translation import gettext_lazy as _
@ -97,6 +98,15 @@ class CarFinanceForm(AddClassMixin, forms.ModelForm):
exclude = ['car', 'profit_margin', 'vat_amount', 'total', 'vat_rate']
class CarLocationForm(forms.ModelForm):
class Meta:
model = CarLocation
fields = ['showroom', 'description']
widgets = {
'description': forms.Textarea(attrs={'rows': 2, 'class': 'form-control'}),
}
# Custom Card Form
class CustomCardForm(forms.ModelForm):
custom_date = forms.DateTimeField(

View File

@ -1,4 +1,5 @@
from uuid import uuid4
from django.conf import settings
from django.db import models, transaction
from django.contrib.auth.models import User
from django.db.models.signals import pre_save, post_save
@ -21,6 +22,7 @@ from django.core.exceptions import ValidationError
from phonenumber_field.modelfields import PhoneNumberField
from django.contrib.contenttypes.models import ContentType
from django.utils.timezone import now
from .mixins import LocalizedNameMixin
@ -222,10 +224,10 @@ class Car(models.Model):
class CarReservation(models.Model):
car = models.ForeignKey('Car', on_delete=models.CASCADE, related_name='reservations')
reserved_by = models.ForeignKey(User, on_delete=models.CASCADE)
reserved_at = models.DateTimeField(auto_now_add=True)
reserved_until = models.DateTimeField()
car = models.ForeignKey('Car', on_delete=models.CASCADE, related_name='reservations', verbose_name=_("Car"))
reserved_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='reservations', verbose_name=_("Reserved By"))
reserved_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Reserved At"))
reserved_until = models.DateTimeField(verbose_name=_("Reserved Until"))
def is_active(self):
return self.reserved_until > now()
@ -233,11 +235,13 @@ class CarReservation(models.Model):
class Meta:
unique_together = ('car', 'reserved_until')
ordering = ['-reserved_at']
verbose_name = _("Car Reservation")
verbose_name_plural = _("Car Reservations")
# Car Finance Model
class CarFinance(models.Model):
car = models.ForeignKey(Car, on_delete=models.CASCADE, related_name='finances')
car = models.OneToOneField(Car, on_delete=models.CASCADE, related_name='finances')
cost_price = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Cost Price"))
selling_price = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Selling Price"))
profit_margin = models.DecimalField(max_digits=14,
@ -258,35 +262,35 @@ class CarFinance(models.Model):
default=Decimal('0.00'))
custom_card_fee = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Custom Card Fee"),
default=Decimal('0.00'))
vat_rate = models.DecimalField(max_digits=14, decimal_places=2, default=Decimal('0.15'), verbose_name=_("VAT Rate"),)
total = models.DecimalField(max_digits=14, decimal_places=2, default=Decimal('0.00'), null=True, blank=True)
def __str__(self):
return f"{self.selling_price}"
return f"Car: {self.car}, Selling Price: {self.selling_price}"
def save(self, *args, **kwargs):
vat_rate = settings.VAT_RATE
self.full_clean()
try:
services = self.administration_fee + self.transportation_fee + self.custom_card_fee
price_after_discount = self.selling_price - self.discount_amount
total_vat_amount = (price_after_discount + services) * self.vat_rate
self.vat_amount = self.selling_price * self.vat_rate
total_vat_amount = (price_after_discount + services) * vat_rate
self.vat_amount = price_after_discount * vat_rate
self.profit_margin = self.selling_price - self.cost_price - self.discount_amount - self.registration_fee
self.total = price_after_discount + services + total_vat_amount + self.registration_fee
except InvalidOperation as e:
raise ValidationError(_("Invalid decimal operation: %s") % str(e))
super().save(*args, **kwargs)
class Meta:
verbose_name = _("Car Financial Details")
@property
def total_vat_amount(self):
vat_rate = settings.VAT_RATE
services = self.administration_fee + self.transportation_fee + self.custom_card_fee
price_after_discount = self.selling_price - self.discount_amount
return (price_after_discount + services) * self.vat_rate
return (price_after_discount + services) * vat_rate
class Meta:
verbose_name = _("Car Financial Details")
verbose_name_plural = _("Car Financial Details")
class ExteriorColors(models.Model, LocalizedNameMixin):
@ -332,7 +336,7 @@ class CarColors(models.Model):
# Custom Card Model
class CustomCard(models.Model):
car = models.ForeignKey(Car, on_delete=models.CASCADE, related_name='custom_cards', verbose_name=_("Car"))
car = models.OneToOneField(Car, on_delete=models.CASCADE, related_name='custom_cards', verbose_name=_("Car"))
custom_number = models.CharField(max_length=255, verbose_name=_("Custom Number"))
custom_date = models.DateField(verbose_name=_("Custom Date"))
@ -344,6 +348,55 @@ class CustomCard(models.Model):
return f"{self.car} - {self.custom_number}"
class CarLocation(models.Model):
car = models.OneToOneField(
Car,
on_delete=models.CASCADE,
related_name='location',
verbose_name=_("Car")
)
owner = models.ForeignKey(
'Dealer',
on_delete=models.CASCADE,
related_name='owned_cars',
verbose_name=_("Owner"),
help_text=_("Dealer who owns the car.")
)
showroom = models.ForeignKey(
'Dealer',
on_delete=models.CASCADE,
related_name='showroom_cars',
verbose_name=_("Showroom"),
help_text=_("Dealer where the car is displayed (can be the owner).")
)
description = models.TextField(
blank=True,
null=True,
verbose_name=_("Description"),
help_text=_("Optional description about the showroom placement.")
)
created_at = models.DateTimeField(
auto_now_add=True,
verbose_name=_("Created At")
)
updated_at = models.DateTimeField(
auto_now=True,
verbose_name=_("Last Updated")
)
class Meta:
verbose_name = _("Car Location")
verbose_name_plural = _("Car Locations")
def __str__(self):
return f"Car: {self.car}, Showroom: {self.showroom}, Owner: {self.owner}"
def is_owner_showroom(self):
"""
Returns True if the showroom is the same as the owner.
"""
return self.owner == self.showroom
# Car Registration Model
class CarRegistration(models.Model):
car = models.ForeignKey(Car, on_delete=models.CASCADE, related_name='registrations', verbose_name=_("Car"))

View File

@ -2,11 +2,27 @@ from random import randint
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django_ledger.models import EntityModel, VendorModel, CustomerModel, UnitOfMeasureModel
from django_ledger.models import EntityModel, VendorModel, CustomerModel, UnitOfMeasureModel, AccountModel, \
ItemModelAbstract
from django.utils.translation import gettext_lazy as _
from . import models
@receiver(post_save, sender=models.Car)
def create_car_location(sender, instance, created, **kwargs):
"""
Signal to create or update the car's location when a car instance is saved.
"""
if created:
models.CarLocation.objects.create(
car=instance,
owner=instance.dealer,
showroom=instance.dealer,
description=f"Initial location set for car {instance.vin}."
)
print("Car Location created")
@receiver(post_save, sender=models.CarReservation)
def update_car_status_on_reservation(sender, instance, created, **kwargs):
if created:
@ -24,21 +40,21 @@ def update_car_status_on_reservation_delete(sender, instance, **kwargs):
# Create Entity
@receiver(post_save, sender=models.Dealer)
def create_ledger_entity(sender, instance, created, **kwargs):
if created:
entity = EntityModel.objects.create(
name=instance.name,
admin=instance.user,
address_1=instance.address,
fy_start_month=1,
accrual_method=True,
depth=0,
)
default_coa = entity.create_chart_of_accounts(assign_as_default=True,
commit=True,
coa_name=_("Chart of Accounts"))
# @receiver(post_save, sender=models.Dealer)
# def create_ledger_entity(sender, instance, created, **kwargs):
# if created:
# entity = EntityModel.objects.create(
# name=instance.name,
# admin=instance.user,
# address_1=instance.address,
# fy_start_month=1,
# accrual_method=True,
# depth=0,
# )
#
# default_coa = entity.create_chart_of_accounts(assign_as_default=True,
# commit=True,
# coa_name=_("Chart of Accounts"))
# entity.create_account(
# coa_model=coa,
# code=1010,
@ -48,25 +64,56 @@ def create_ledger_entity(sender, instance, created, **kwargs):
# )
# entity.create_account(
# coa_model=coa,
# code=1100,
# role='asset_ca_recv',
# name=_('Accounts Receivable'),
# balance_type="debit",
# )
# entity.create_account(
# coa_model=coa,
# code=1200,
# role='asset_ca_inv',
# name=_('Inventory'),
# balance_type="debit",
# active=True)
#
# entity.create_account(
# coa_model=coa,
# code=2010,
# role='lia_cl_acc_payable',
# name=_('Accounts Payable'),
# balance_type="credit",
# active=True)
#
# entity.create_account(
# coa_model=coa,
# code=4010,
# role='in_operational',
# name=_('Sales Income'),
# balance_type="credit",
# active=True)
#
# entity.create_account(
# coa_model=coa,
# code=5010,
# role='cogs_regular',
# name=_('Cost of Goods Sold'),
# balance_type="debit",
# active=True)
if default_coa:
entity.populate_default_coa(activate_accounts=True, coa_model=default_coa)
uom_name = _("Unit")
unit_abbr = _("U")
entity.create_uom(uom_name, unit_abbr)
print(f"Ledger entity created for Dealer: {instance.name}")
# if default_coa:
# entity.populate_default_coa(activate_accounts=True, coa_model=default_coa)
#
# uom_name = _("Unit")
# unit_abbr = _("U")
#
# entity.create_uom(uom_name, unit_abbr)
#
# print(f"Ledger entity created for Dealer: {instance.name}")
# # Create Vendor
# Create Vendor
@receiver(post_save, sender=models.Vendor)
def create_ledger_vendor(sender, instance, created, **kwargs):
@ -113,55 +160,64 @@ def create_customer(sender, instance, created, **kwargs):
# Create Item
@receiver(post_save, sender=models.Car)
def create_item_model(sender, instance, created, **kwargs):
item_name = f"{instance.year} - {instance.id_car_make} - {instance.id_car_model} - {instance.id_car_trim}"
uom_name = _("Car")
unit_abbr = _("C")
uom, uom_created = UnitOfMeasureModel.objects.get_or_create(
name=uom_name,
unit_abbr=unit_abbr
)
if uom_created:
print(f"UOM created: {uom_name}")
else:
print(f"Using existing UOM: {uom_name}")
entity = EntityModel.objects.filter(name=instance.dealer.name).first()
inventory_account = AccountModel.objects.first()
cogs_account = AccountModel.objects.first()
earnings_account = AccountModel.objects.first()
entity.create_i
item = ItemModel.objects.create(
entity=entity,
uom=uom,
name=item_name,
item_role=ItemModelAbstract.ITEM_ROLE_INVENTORY,
item_type=ItemModelAbstract.ITEM_TYPE_MATERIAL,
item_id=instance.vin,
sold_as_unit=True,
inventory_received=1.00,
inventory_received_value=0.00,
inventory_account=inventory_account,
for_inventory=True,
is_product_or_service=True,
cogs_account=cogs_account,
earnings_account=earnings_account,
is_active=True,
additional_info={
"remarks": instance.remarks,
"status": instance.status,
"stock_type": instance.stock_type,
"mileage": instance.mileage,
},
)
print(f"ItemModel {'created' if created else 'updated'} for Car: {item.name}")
# @receiver(post_save, sender=models.Car)
# def create_item_model(sender, instance, created, **kwargs):
# item_name = f"{instance.year} - {instance.id_car_make} - {instance.id_car_model} - {instance.id_car_trim}"
# uom_name = _("Car")
# unit_abbr = _("C")
#
# uom, uom_created = UnitOfMeasureModel.objects.get_or_create(
# name=uom_name,
# unit_abbr=unit_abbr
# )
#
# if uom_created:
# print(f"UOM created: {uom_name}")
# else:
# print(f"Using existing UOM: {uom_name}")
#
# entity = EntityModel.objects.filter(name=instance.dealer.name).first()
#
# inventory_account = AccountModel.objects.first()
# cogs_account = AccountModel.objects.first()
# earnings_account = AccountModel.objects.first()
#
# entity.create_item_product(
# item_name=item_name,
# item_role=ItemModelAbstract.ITEM_ROLE_PRODUCT,
# item_type=ItemModelAbstract.ITEM_TYPE_MATERIAL,
# item_id=instance.vin,
# sold_as_unit=True,
# inventory_received=1.00,
# inventory_received_value=0.00,
# inventory_account=inventory_account,
# for_inventory=True,)
#
# item = ItemModel.objects.create(
# entity=entity,
# uom=uom,
# name=item_name,
# item_role=ItemModelAbstract.ITEM_ROLE_INVENTORY,
# item_type=ItemModelAbstract.ITEM_TYPE_MATERIAL,
# item_id=instance.vin,
# sold_as_unit=True,
# inventory_received=1.00,
# inventory_received_value=0.00,
# inventory_account=inventory_account,
# for_inventory=True,
# is_product_or_service=True,
# cogs_account=cogs_account,
# earnings_account=earnings_account,
# is_active=True,
# additional_info={
# "remarks": instance.remarks,
# "status": instance.status,
# "stock_type": instance.stock_type,
# "mileage": instance.mileage,
# },
# )
#
# print(f"ItemModel {'created' if created else 'updated'} for Car: {item.name}")
#
#
# # update price - CarFinance

View File

@ -56,6 +56,8 @@ urlpatterns = [
path('cars/add/', views.CarCreateView.as_view(), name='car_add'),
path('ajax/', views.AjaxHandlerView.as_view(), name='ajax_handler'),
path('cars/<int:car_pk>/add-color/', views.CarColorCreate.as_view(), name='add_color'),
path('car/<int:car_pk>/location/add/', views.CarLocationCreateView.as_view(), name='add_car_location'),
path('car/<int:pk>/location/update/', views.CarLocationUpdateView.as_view(), name='transfer'),
# path('cars/<int:car_pk>/colors/<int:pk>/update/',views.CarColorUpdateView.as_view(),name='color_update'),
path('cars/reserve/<int:car_id>/', views.reserve_car_view, name='reserve_car'),

View File

@ -167,7 +167,9 @@ class AjaxHandlerView(LoginRequiredMixin, View):
def get_models(self, request):
make_id = request.GET.get('make_id')
car_models = models.CarModel.objects.filter(id_car_make=make_id).values('id_car_model', 'name', 'arabic_name')
car_models = (models.CarModel.objects.filter(id_car_make=make_id)
.values('id_car_model', 'name', 'arabic_name')
.order_by('name'))
return JsonResponse(list(car_models), safe=False)
def get_series(self, request):
@ -405,6 +407,31 @@ class CarDeleteView(LoginRequiredMixin, DeleteView):
return super().delete(request, *args, **kwargs)
class CarLocationCreateView(CreateView):
model = models.CarLocation
form_class = forms.CarLocationForm
template_name = 'inventory/car_location_form.html'
def get_success_url(self):
return reverse_lazy('car_detail', kwargs={'pk': self.object.car.pk})
def form_valid(self, form):
form.instance.car = get_object_or_404(models.Car, pk=self.kwargs['car_pk'])
form.instance.owner = self.request.user.dealer
form.save()
messages.success(self.request, 'Car saved successfully.')
return super().form_valid(form)
class CarLocationUpdateView(UpdateView):
model = models.CarLocation
form_class = forms.CarLocationForm
template_name = 'inventory/car_location_form.html'
def get_success_url(self):
return reverse_lazy('car_detail', kwargs={'pk': self.object.car.pk})
class CustomCardCreateView(LoginRequiredMixin, CreateView):
model = models.CustomCard
form_class = forms.CustomCardForm

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -149,6 +149,27 @@
</td>
</tr>
{% endif %}
<tr>
<th>{% trans 'Showroom Location' %}</th>
<td>
{% if car.location %}
{% if car.location.is_owner_showroom %}
{% trans 'Our Showroom' %}
{% else %}
{{ car.location.showroom.get_local_name }}
{% endif %}
<a href="{% url 'transfer' car.location.pk %}" class="btn btn-danger btn-sm">{% trans "transfer" %}</a>
{% else %}
{% trans "No location available." %}
<a href="{% url 'add_car_location' car.pk %}"
class="btn btn-success btn-sm mb-3 ms-2">
{% trans "Add" %}
</a>
</td>
{% endif %}
</tr>
</table>
</div>
<div class="col-lg-6 col-xl-6">
@ -304,7 +325,7 @@
<div class="row g-4">
<div class="">
<!-- Actions -->
<a href="#" class="btn btn-danger btn-sm">{% trans "transfer" %}</a>
<a href="{% url 'car_update' car.pk %}" class="btn btn-warning btn-sm">{% trans "Edit" %}</a>

View File

@ -1,12 +1,13 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% block title %}
{% trans 'inventory'|capfirst %}
{% endblock %}
{% block inventory %}<a class="nav-link active fw-bold">{% trans "inventory" %}<span class="visually-hidden">(current)</span></a>{% endblock %}
{% block inventory %}
<a class="nav-link active fw-bold">{% trans "inventory" %}<span class="visually-hidden">(current)</span></a>
{% endblock %}
{% block content %}
<style>
<style>
.color-div {
width: 22px;
height: 22px;
@ -15,115 +16,136 @@
margin: auto;
text-align: center;
}
</style>
</style>
<div class="d-flex flex-column min-vh-100">
<div class="d-flex flex-column flex-sm-grow-1 ms-sm-14 p-1">
<main class="d-grid gap-4 p-1">
<div class="row g-4">
<div class="col-lg-6 col-xl-12">
<div class="container-fluid p-2">
<form method="get">
<div class="input-group input-group-sm">
<button id="inputGroup-sizing-sm"
class="btn btn-sm btn-secondary rounded-start" type="submit">
{% trans 'search'|capfirst %}
</button>
<input type="text"
name="q"
class="form-control form-control-sm rounded-end"
value="{{ request.GET.q }}"
aria-describedby="inputGroup-sizing-sm"/>
<!-- Clear Button -->
{% if request.GET.q %}
<a href="{{request.META.HTTP_REFERER}}"
class="btn btn-sm btn-outline-danger ms-1 rounded">
<i class="bi bi-x-lg"></i>
</a>
{% endif %}
</div>
</form>
</div>
<main class="d-grid gap-4 p-1">
<div class="row g-4">
<div class="col-lg-6 col-xl-12">
<div class="container-fluid p-2">
<form method="get" class="mb-3">
<div class="input-group input-group-sm">
<button id="inputGroup-sizing-sm"
class="btn btn-sm btn-secondary rounded-start" type="submit">
{% trans 'search'|capfirst %}
</button>
<input type="text"
name="q"
class="form-control form-control-sm rounded-end"
value="{{ request.GET.q }}"
aria-describedby="inputGroup-sizing-sm" />
<!-- Clear Button -->
{% if request.GET.q %}
<a href="{% url 'inventory_list' %}"
class="btn btn-sm btn-outline-danger ms-1 rounded">
<i class="bi bi-x-lg"></i>
</a>
{% endif %}
</div>
</form>
</div>
<table class="table table-responsive table-sm align-middle">
<thead>
<tr>
<th></th>
<th>{% trans "VIN" %}</th>
<th>{% trans "Year" %}</th>
<th>{% trans "Make" %}</th>
<th>{% trans "Model" %}</th>
<th>{% trans "Actions" %}</th>
</tr>
</thead>
<tbody>
{% for car in cars %}
<tr class="{% if car.is_reserved %}table-danger{% endif %}">
{% if car.colors.all %}
{% for color in car.colors.all %}
<td><div class="color-div" style="background-color: rgb({{ color.rgb }});"></div></td>
{% endfor %}
{% else %}
<td><div class="color-div"><i class="bi bi-x-lg fs-6"></i></div></td>
{% endif %}
<td>{{ car.vin }}</td>
<td>{{ car.year }}</td>
<td>{{ car.id_car_make.get_local_name }}</td>
<td>{{ car.id_car_model.get_local_name }}</td>
<td>
<a href="{% url 'car_detail' car.pk %}" class="btn btn-sm btn-success"><small>{% trans "view" %}</small></a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="7">{% trans "No cars available." %}</td>
</tr>
{% endfor %}
</tbody>
</table>
<!-- Optional: Pagination -->
{% if is_paginated %}
<nav aria-label="Page navigation">
<ul class="pagination pagination-sm justify-content-center">
{% if page_obj.has_previous %}
<li class="page-item py-0">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
</a>
</li>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<li class="page-item active"><a class="page-link" href="?page={{ num }}">{{ num }}</a></li>
{% else %}
<li class="page-item"><a class="page-link" href="?page={{ num }}">{{ num }}</a></li>
{% endif %}
{% endfor %} {% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
</div>
</main>
<table class="table table-responsive table-sm align-middle">
<thead>
<tr>
<th>{% trans "VIN" %}</th>
<th>{% trans "Year" %}</th>
<th>{% trans 'Exterior Color' %}</th>
<th>{% trans 'Interior Color' %}</th>
<th>{% trans "Showroom Location" %}</th>
<th>{% trans "Actions" %}</th>
</tr>
</thead>
<tbody>
{% for car in cars %}
<tr class="{% if car.is_reserved %}table-danger{% endif %}">
<td>{{ car.vin }}</td>
<td>{{ car.year }}</td>
{% if car.colors.exists %}
<td><span>{{ car.colors.first.exterior.get_local_name }}<div class="color-div" style="background-color: rgb({{ car.colors.first.exterior.rgb }});"></div></span></td>
<td>{{ car.colors.first.interior.get_local_name }}<div class="color-div" style="background-color: rgb({{ car.colors.first.interior.rgb }});"></div></td>
{% else %}
<td><div class="color-div"><i class="bi bi-x-lg fs-6"></i></div></td>
<td><div class="color-div"><i class="bi bi-x-lg fs-6"></i></div></td>
{% endif %}
{% if car.location.is_owner_showroom %}
<td> {% trans 'Our Showroom' %}</td>
{% else %}
<td>{{ car.location.showroom.get_local_name }}</td>
{% endif %}
<td>
<a href="{% url 'car_detail' car.pk %}" class="btn btn-sm btn-success">
<small>{% trans "view" %}</small>
</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="6">{% trans "No cars available." %}</td>
</tr>
{% endfor %}
</tbody>
</table>
<!-- Pagination -->
{% if is_paginated %}
<nav aria-label="Page navigation">
<ul class="pagination pagination-sm justify-content-center">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page=1" aria-label="First">
&laquo;&laquo;
</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous">
&laquo;
</a>
</li>
{% else %}
<li class="page-item disabled">
<span class="page-link">&laquo;&laquo;</span>
</li>
<li class="page-item disabled">
<span class="page-link">&laquo;</span>
</li>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<li class="page-item active">
<span class="page-link">{{ num }}</span>
</li>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<li class="page-item">
<a class="page-link" href="?page={{ num }}">{{ num }}</a>
</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next">
&raquo;
</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}" aria-label="Last">
&raquo;&raquo;
</a>
</li>
{% else %}
<li class="page-item disabled">
<span class="page-link">&raquo;</span>
</li>
<li class="page-item disabled">
<span class="page-link">&raquo;&raquo;</span>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
</div>
</main>
</div>
</div>
{% endblock %}

View File

@ -1,10 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>$Title$</title>
</head>
<body>
$END$
</body>
</html>
{% extends 'base.html' %}
{% load i18n %}
{% load crispy_forms_filters %}
{% block title %}{% trans "Manage Car Location" %}{% endblock %}
{% block content %}
{% if carlocation.exists %}
<p>Transfer</p>
{% else %}
<p>Add</p>
{% endif %}
<div class="container mt-3">
<h3 class="mb-3">{% trans "Manage Car Location" %}</h3>
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<div class="form-group">
<button type="submit" class="btn btn-primary">{% trans "Save" %}</button>
</div>
</form>
</div>
{% endblock %}