update
This commit is contained in:
parent
4664029c95
commit
7b3688cb89
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -254,6 +254,7 @@ wmi_manufacturer_mapping = {
|
|||||||
"LND": "JMEV",
|
"LND": "JMEV",
|
||||||
"LNP": "NAC MG",
|
"LNP": "NAC MG",
|
||||||
"LNY": "Yuejin",
|
"LNY": "Yuejin",
|
||||||
|
"LMX": "Dongfeng Forthing",
|
||||||
"LPA": "Changan",
|
"LPA": "Changan",
|
||||||
"LPE": "BYD",
|
"LPE": "BYD",
|
||||||
"LPS": "Polestar",
|
"LPS": "Polestar",
|
||||||
@ -346,9 +347,7 @@ wmi_manufacturer_mapping = {
|
|||||||
"MCG": "Atul",
|
"MCG": "Atul",
|
||||||
"MC1": "Force",
|
"MC1": "Force",
|
||||||
"MC2": "Eicher",
|
"MC2": "Eicher",
|
||||||
"MDE": "Kinetic Engineering Limited",
|
|
||||||
"MDH": "Nissan",
|
"MDH": "Nissan",
|
||||||
"MDT": "Kerala Limited",
|
|
||||||
"MD6": "TVS",
|
"MD6": "TVS",
|
||||||
"MD9": "Shuttles",
|
"MD9": "Shuttles",
|
||||||
"MEC": "Daimler",
|
"MEC": "Daimler",
|
||||||
@ -358,8 +357,6 @@ wmi_manufacturer_mapping = {
|
|||||||
"MET": "Piaggio",
|
"MET": "Piaggio",
|
||||||
"MEX": "Škoda",
|
"MEX": "Škoda",
|
||||||
"ME1": "Yamaha",
|
"ME1": "Yamaha",
|
||||||
"ME3": "Royal Enfield",
|
|
||||||
"MYH": "Ather Energy",
|
|
||||||
"MZB": "Kia",
|
"MZB": "Kia",
|
||||||
"MZZ": "Citroën",
|
"MZZ": "Citroën",
|
||||||
"MZ7": "MG",
|
"MZ7": "MG",
|
||||||
@ -1501,7 +1498,7 @@ def decode_vds(manufacturer, vds):
|
|||||||
return "Unknown Model"
|
return "Unknown Model"
|
||||||
|
|
||||||
|
|
||||||
def decode_vin(vin):
|
def decode_vin_haikalna(vin):
|
||||||
if len(vin) != 17:
|
if len(vin) != 17:
|
||||||
raise ValueError("Invalid VIN length. VIN must be 17 characters.")
|
raise ValueError("Invalid VIN length. VIN must be 17 characters.")
|
||||||
|
|
||||||
@ -1518,21 +1515,22 @@ def decode_vin(vin):
|
|||||||
manufacturer = wmi_manufacturer_mapping.get(wmi, vds)
|
manufacturer = wmi_manufacturer_mapping.get(wmi, vds)
|
||||||
|
|
||||||
year_code = vis[0]
|
year_code = vis[0]
|
||||||
year = vin_years(year_code)
|
year = vin_years(year_code)[0]
|
||||||
model = decode_vds(manufacturer, vds)
|
model = decode_vds(manufacturer, vds)
|
||||||
|
|
||||||
return {
|
data = {
|
||||||
'VIN': vin,
|
'maker': manufacturer,
|
||||||
'Manufacturer': manufacturer,
|
'model': model,
|
||||||
'Year': year,
|
'modelYear': year,
|
||||||
'Model': model
|
|
||||||
}
|
}
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
# JTDKB3FU4G3507653
|
# JTDKB3FU4G3507653
|
||||||
# VR3USHNLWRJ521303
|
# VR3USHNLWRJ521303
|
||||||
# KNARH81E8P5194005
|
# KNARH81E8P5194005
|
||||||
# Example usage
|
# Example usage
|
||||||
vin_number = 'VYFED9HP0SJ519559'
|
# vin_number = 'LMXA14AF7PZ356070'
|
||||||
decoded_vin = decode_vin(vin_number)
|
# decoded_vin = decode_vin_haikalna(vin_number)
|
||||||
print(decoded_vin)
|
# print(decoded_vin)
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 5.1.4 on 2024-12-31 21:00
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0021_opportunitylog'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='customer',
|
|
||||||
name='is_lead',
|
|
||||||
field=models.BooleanField(default=False, verbose_name='Is Lead'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2025-01-01 16:25
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
|
||||||
|
('inventory', '0021_opportunitylog'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='opportunitylog',
|
||||||
|
name='user',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='opportunitylog',
|
||||||
|
name='staff',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='inventory.staff', verbose_name='Staff'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='carfinance',
|
||||||
|
name='additional_services',
|
||||||
|
field=models.ManyToManyField(blank=True, related_name='additional_finances', to='django_ledger.itemmodel'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='customer',
|
||||||
|
name='is_lead',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='Is Lead'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -1,5 +1,6 @@
|
|||||||
# Generated by Django 4.2.17 on 2025-01-01 12:43
|
# Generated by Django 5.1.4 on 2025-01-01 16:40
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
@ -7,7 +8,7 @@ class Migration(migrations.Migration):
|
|||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
|
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
|
||||||
('inventory', '0022_rename_log_oportunitylog'),
|
('inventory', '0022_remove_opportunitylog_user_opportunitylog_staff_and_more'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
@ -17,7 +18,8 @@ class Migration(migrations.Migration):
|
|||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='carfinance',
|
model_name='carfinance',
|
||||||
name='services',
|
name='additional_services',
|
||||||
field=models.ManyToManyField(blank=True, related_name='services', to='django_ledger.itemmodel'),
|
field=models.ForeignKey(blank=True, default=1, on_delete=django.db.models.deletion.CASCADE, related_name='additional_finances', to='django_ledger.itemmodel'),
|
||||||
|
preserve_default=False,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,23 +0,0 @@
|
|||||||
# Generated by Django 5.1.4 on 2025-01-01 01:24
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0022_alter_customer_is_lead'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='opportunitylog',
|
|
||||||
name='user',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='opportunitylog',
|
|
||||||
name='staff',
|
|
||||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='inventory.staff', verbose_name='Staff'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 4.2.17 on 2025-01-01 12:46
|
# Generated by Django 5.1.4 on 2025-01-01 16:51
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ class Migration(migrations.Migration):
|
|||||||
operations = [
|
operations = [
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(
|
||||||
model_name='carfinance',
|
model_name='carfinance',
|
||||||
name='services',
|
name='additional_services',
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='carfinance',
|
model_name='carfinance',
|
||||||
@ -154,7 +154,6 @@ class CarSpecificationValue(models.Model):
|
|||||||
verbose_name = "Specification Value"
|
verbose_name = "Specification Value"
|
||||||
|
|
||||||
|
|
||||||
# Car Model
|
|
||||||
class CarStatusChoices(models.TextChoices):
|
class CarStatusChoices(models.TextChoices):
|
||||||
AVAILABLE = "available", _("Available")
|
AVAILABLE = "available", _("Available")
|
||||||
SOLD = "sold", _("Sold")
|
SOLD = "sold", _("Sold")
|
||||||
@ -184,6 +183,7 @@ class AdditionalServices(models.Model, LocalizedNameMixin):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name + " - " + str(self.price)
|
return self.name + " - " + str(self.price)
|
||||||
|
|
||||||
|
|
||||||
class Car(models.Model):
|
class Car(models.Model):
|
||||||
vin = models.CharField(max_length=17, unique=True, verbose_name=_("VIN"))
|
vin = models.CharField(max_length=17, unique=True, verbose_name=_("VIN"))
|
||||||
dealer = models.ForeignKey(
|
dealer = models.ForeignKey(
|
||||||
@ -308,6 +308,7 @@ class CarReservation(models.Model):
|
|||||||
verbose_name = _("Car Reservation")
|
verbose_name = _("Car Reservation")
|
||||||
verbose_name_plural = _("Car Reservations")
|
verbose_name_plural = _("Car Reservations")
|
||||||
|
|
||||||
|
|
||||||
# Car Finance Model
|
# Car Finance Model
|
||||||
class CarFinance(models.Model):
|
class CarFinance(models.Model):
|
||||||
additional_services = models.ManyToManyField(ItemModel, related_name="additional_finances",blank=True)
|
additional_services = models.ManyToManyField(ItemModel, related_name="additional_finances",blank=True)
|
||||||
@ -389,7 +390,6 @@ class InteriorColors(models.Model, LocalizedNameMixin):
|
|||||||
return f"{self.name} ({self.rgb})"
|
return f"{self.name} ({self.rgb})"
|
||||||
|
|
||||||
|
|
||||||
# Colors Model
|
|
||||||
class CarColors(models.Model):
|
class CarColors(models.Model):
|
||||||
car = models.ForeignKey("Car", on_delete=models.CASCADE, related_name="colors")
|
car = models.ForeignKey("Car", on_delete=models.CASCADE, related_name="colors")
|
||||||
exterior = models.ForeignKey(
|
exterior = models.ForeignKey(
|
||||||
@ -408,7 +408,6 @@ class CarColors(models.Model):
|
|||||||
return f"{self.car} ({self.exterior.name}) ({self.interior.name})"
|
return f"{self.car} ({self.exterior.name}) ({self.interior.name})"
|
||||||
|
|
||||||
|
|
||||||
# Custom Card Model
|
|
||||||
class CustomCard(models.Model):
|
class CustomCard(models.Model):
|
||||||
car = models.OneToOneField(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_number = models.CharField(max_length=255, verbose_name=_("Custom Number"))
|
||||||
@ -471,7 +470,7 @@ class CarLocation(models.Model):
|
|||||||
"""
|
"""
|
||||||
return self.owner == self.showroom
|
return self.owner == self.showroom
|
||||||
|
|
||||||
# Car Registration Model
|
|
||||||
class CarRegistration(models.Model):
|
class CarRegistration(models.Model):
|
||||||
car = models.ForeignKey(
|
car = models.ForeignKey(
|
||||||
Car,
|
Car,
|
||||||
@ -501,7 +500,7 @@ class TimestampedModel(models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
#subscription
|
|
||||||
class Subscription(models.Model):
|
class Subscription(models.Model):
|
||||||
plan = models.CharField(max_length=255) # e.g. "basic", "premium"
|
plan = models.CharField(max_length=255) # e.g. "basic", "premium"
|
||||||
start_date = models.DateField()
|
start_date = models.DateField()
|
||||||
@ -529,7 +528,6 @@ class SubscriptionPlan(models.Model):
|
|||||||
return f"{self.name} - {self.price}"
|
return f"{self.name} - {self.price}"
|
||||||
|
|
||||||
|
|
||||||
# Dealer Model
|
|
||||||
class Dealer(models.Model, LocalizedNameMixin):
|
class Dealer(models.Model, LocalizedNameMixin):
|
||||||
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="dealer")
|
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="dealer")
|
||||||
crn = models.CharField(max_length=10,
|
crn = models.CharField(max_length=10,
|
||||||
@ -608,18 +606,21 @@ class Dealer(models.Model, LocalizedNameMixin):
|
|||||||
# return self.parent_dealer if self.parent_dealer else self
|
# return self.parent_dealer if self.parent_dealer else self
|
||||||
|
|
||||||
|
|
||||||
|
class StaffTypes(models.TextChoices):
|
||||||
class STAFF_TYPES(models.TextChoices):
|
|
||||||
MANAGER = "manager", _("Manager")
|
MANAGER = "manager", _("Manager")
|
||||||
INVENTORY = "inventory", _("Inventory")
|
INVENTORY = "inventory", _("Inventory")
|
||||||
ACCOUNTANT = "accountant", _("Accountant")
|
ACCOUNTANT = "accountant", _("Accountant")
|
||||||
SALES = "sales", _("Sales")
|
SALES = "sales", _("Sales")
|
||||||
|
|
||||||
|
##############################
|
||||||
|
# Additional staff types for later
|
||||||
|
|
||||||
# COORDINATOR = "coordinator", _("Coordinator")
|
# COORDINATOR = "coordinator", _("Coordinator")
|
||||||
# RECEPTIONIST = "receptionist", _("Receptionist")
|
# RECEPTIONIST = "receptionist", _("Receptionist")
|
||||||
# AGENT = "agent", _("Agent")
|
# AGENT = "agent", _("Agent")
|
||||||
# TECHNICIAN = "technician", _("Technician")
|
# TECHNICIAN = "technician", _("Technician")
|
||||||
# DRIVER = "driver", _("Driver")
|
# DRIVER = "driver", _("Driver")
|
||||||
|
##############################
|
||||||
|
|
||||||
|
|
||||||
class Staff(models.Model, LocalizedNameMixin):
|
class Staff(models.Model, LocalizedNameMixin):
|
||||||
@ -628,7 +629,7 @@ class Staff(models.Model, LocalizedNameMixin):
|
|||||||
name = models.CharField(max_length=255, verbose_name=_("Name"))
|
name = models.CharField(max_length=255, verbose_name=_("Name"))
|
||||||
arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
|
arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
|
||||||
phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number"))
|
phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number"))
|
||||||
staff_type = models.CharField(choices=STAFF_TYPES.choices, max_length=255, verbose_name=_("Staff Type"))
|
staff_type = models.CharField(choices=StaffTypes.choices, max_length=255, verbose_name=_("Staff Type"))
|
||||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created At"))
|
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created At"))
|
||||||
updated_at = models.DateTimeField(auto_now=True, verbose_name=_("Updated At"))
|
updated_at = models.DateTimeField(auto_now=True, verbose_name=_("Updated At"))
|
||||||
|
|
||||||
@ -641,7 +642,6 @@ class Staff(models.Model, LocalizedNameMixin):
|
|||||||
return f"{self.name} - {self.get_staff_type_display()}"
|
return f"{self.name} - {self.get_staff_type_display()}"
|
||||||
|
|
||||||
|
|
||||||
# Vendor Model
|
|
||||||
class Vendor(models.Model, LocalizedNameMixin):
|
class Vendor(models.Model, LocalizedNameMixin):
|
||||||
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="vendors")
|
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="vendors")
|
||||||
crn = models.CharField(
|
crn = models.CharField(
|
||||||
@ -671,7 +671,6 @@ class Vendor(models.Model, LocalizedNameMixin):
|
|||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
# Customer Model
|
|
||||||
class Customer(models.Model):
|
class Customer(models.Model):
|
||||||
dealer = models.ForeignKey(Dealer,
|
dealer = models.ForeignKey(Dealer,
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
@ -932,6 +931,7 @@ class SaleQuotation(models.Model):
|
|||||||
last_quotation_number = 0
|
last_quotation_number = 0
|
||||||
return itertools.count(last_quotation_number + 1)
|
return itertools.count(last_quotation_number + 1)
|
||||||
|
|
||||||
|
|
||||||
class SaleQuotationCar(models.Model):
|
class SaleQuotationCar(models.Model):
|
||||||
quotation = models.ForeignKey(
|
quotation = models.ForeignKey(
|
||||||
SaleQuotation,
|
SaleQuotation,
|
||||||
|
|||||||
@ -12,6 +12,7 @@ from pyvin import VIN
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
from .models import Car,CarMake,CarModel
|
from .models import Car,CarMake,CarModel
|
||||||
|
from inventory.haikalna import decode_vin_haikalna
|
||||||
|
|
||||||
|
|
||||||
def get_make(item):
|
def get_make(item):
|
||||||
@ -37,6 +38,8 @@ def decodevin(vin):
|
|||||||
return result
|
return result
|
||||||
elif result:=elm(vin):
|
elif result:=elm(vin):
|
||||||
return result
|
return result
|
||||||
|
elif result:=decode_vin_haikalna(vin):
|
||||||
|
return result
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@ -30,3 +30,4 @@ def attr(field, args):
|
|||||||
else:
|
else:
|
||||||
attrs[definition.strip()] = True
|
attrs[definition.strip()] = True
|
||||||
return field.as_widget(attrs=attrs)
|
return field.as_widget(attrs=attrs)
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ urlpatterns = [
|
|||||||
path('login/code/', allauth_views.RequestLoginCodeView.as_view(template_name='account/request_login_code.html')),
|
path('login/code/', allauth_views.RequestLoginCodeView.as_view(template_name='account/request_login_code.html')),
|
||||||
#Dashboards
|
#Dashboards
|
||||||
path('dashboards/accounting/', views.AccountingDashboard.as_view(), name='accounting'),
|
path('dashboards/accounting/', views.AccountingDashboard.as_view(), name='accounting'),
|
||||||
|
path('test/', views.TestView.as_view(), name='test'),
|
||||||
# Dealer URLs
|
# Dealer URLs
|
||||||
path('dealers/<int:pk>/', views.DealerDetailView.as_view(), name='dealer_detail'),
|
path('dealers/<int:pk>/', views.DealerDetailView.as_view(), name='dealer_detail'),
|
||||||
path('dealers/<int:pk>/update/', views.DealerUpdateView.as_view(), name='dealer_update'),
|
path('dealers/<int:pk>/update/', views.DealerUpdateView.as_view(), name='dealer_update'),
|
||||||
|
|||||||
@ -58,3 +58,11 @@ def send_email(from_, to_, subject, message):
|
|||||||
from_email = from_
|
from_email = from_
|
||||||
recipient_list = [to_]
|
recipient_list = [to_]
|
||||||
send_mail(subject, message, from_email, recipient_list)
|
send_mail(subject, message, from_email, recipient_list)
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_type(request):
|
||||||
|
if hasattr(request.user, 'dealer'):
|
||||||
|
dealer = request.user.dealer
|
||||||
|
elif hasattr(request.user, 'staff'):
|
||||||
|
dealer = request.user.staff.dealer
|
||||||
|
return dealer
|
||||||
@ -66,7 +66,7 @@ from . import models, forms
|
|||||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
from .utils import get_calculations, send_email
|
from .utils import get_calculations, send_email, get_user_type
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from allauth.account import views
|
from allauth.account import views
|
||||||
from django.db.models import Count, F, Value
|
from django.db.models import Count, F, Value
|
||||||
@ -166,6 +166,10 @@ class HomeView(TemplateView):
|
|||||||
template_name = "index.html"
|
template_name = "index.html"
|
||||||
|
|
||||||
|
|
||||||
|
class TestView(TemplateView):
|
||||||
|
template_name = "test.html"
|
||||||
|
|
||||||
|
|
||||||
class AccountingDashboard(LoginRequiredMixin, TemplateView):
|
class AccountingDashboard(LoginRequiredMixin, TemplateView):
|
||||||
template_name = "dashboards/accounting.html"
|
template_name = "dashboards/accounting.html"
|
||||||
|
|
||||||
@ -374,8 +378,9 @@ class CarInventory(LoginRequiredMixin, ListView):
|
|||||||
model_id = self.kwargs["model_id"]
|
model_id = self.kwargs["model_id"]
|
||||||
trim_id = self.kwargs["trim_id"]
|
trim_id = self.kwargs["trim_id"]
|
||||||
|
|
||||||
|
dealer = get_user_type(self.request)
|
||||||
cars = models.Car.objects.filter(
|
cars = models.Car.objects.filter(
|
||||||
dealer=self.request.user.dealer,
|
dealer=dealer,
|
||||||
id_car_make=make_id,
|
id_car_make=make_id,
|
||||||
id_car_model=model_id,
|
id_car_model=model_id,
|
||||||
id_car_trim=trim_id,
|
id_car_trim=trim_id,
|
||||||
@ -415,7 +420,7 @@ class CarColorCreate(LoginRequiredMixin, CreateView):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def inventory_stats_view(request):
|
def inventory_stats_view(request):
|
||||||
dealer = request.user.dealer
|
dealer = get_user_type(request)
|
||||||
|
|
||||||
# Annotate total cars by make, model, and trim
|
# Annotate total cars by make, model, and trim
|
||||||
cars = (
|
cars = (
|
||||||
@ -692,7 +697,6 @@ class DealerUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
|
|||||||
|
|
||||||
class CustomerListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
class CustomerListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
||||||
model = models.Customer
|
model = models.Customer
|
||||||
home_label = _("customers")
|
|
||||||
context_object_name = "customers"
|
context_object_name = "customers"
|
||||||
paginate_by = 10
|
paginate_by = 10
|
||||||
template_name = "customers/customer_list.html"
|
template_name = "customers/customer_list.html"
|
||||||
@ -700,17 +704,15 @@ class CustomerListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
|||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
query = self.request.GET.get("q")
|
query = self.request.GET.get("q")
|
||||||
if self.request.user.is_staff:
|
dealer = get_user_type(self.request)
|
||||||
dealer = self.request.user.staff.dealer
|
|
||||||
customers = models.Customer.objects.filter(
|
customers = models.Customer.objects.filter(dealer=dealer)
|
||||||
dealer=dealer,
|
|
||||||
)
|
|
||||||
|
|
||||||
if query:
|
if query:
|
||||||
customers = customers.filter(
|
customers = customers.filter(
|
||||||
Q(national_id__icontains=query)
|
Q(national_id__icontains=query) |
|
||||||
| Q(first_name__icontains=query)
|
Q(first_name__icontains=query) |
|
||||||
| Q(last_name__icontains=query)
|
Q(last_name__icontains=query)
|
||||||
)
|
)
|
||||||
return customers
|
return customers
|
||||||
|
|
||||||
@ -879,7 +881,7 @@ class QuotationDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailVie
|
|||||||
@login_required
|
@login_required
|
||||||
def generate_invoice(request, pk):
|
def generate_invoice(request, pk):
|
||||||
quotation = get_object_or_404(models.SaleQuotation, pk=pk)
|
quotation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||||
dealer = request.user.dealer
|
dealer = get_user_type(request)
|
||||||
entity = dealer.entity
|
entity = dealer.entity
|
||||||
if not quotation.is_approved:
|
if not quotation.is_approved:
|
||||||
messages.error(
|
messages.error(
|
||||||
@ -1731,7 +1733,8 @@ class EstimateListView(LoginRequiredMixin, ListView):
|
|||||||
# @csrf_exempt
|
# @csrf_exempt
|
||||||
@login_required
|
@login_required
|
||||||
def create_estimate(request):
|
def create_estimate(request):
|
||||||
entity = request.entity
|
dealer = get_user_type(request)
|
||||||
|
entity = dealer.entity
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
try:
|
try:
|
||||||
data = json.loads(request.body)
|
data = json.loads(request.body)
|
||||||
@ -1932,7 +1935,8 @@ class InvoiceListView(LoginRequiredMixin, ListView):
|
|||||||
context_object_name = "invoices"
|
context_object_name = "invoices"
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
entity = self.request.user.dealer.entity
|
dealer = get_user_type(self.request)
|
||||||
|
entity = dealer.entity
|
||||||
return entity.get_invoices()
|
return entity.get_invoices()
|
||||||
|
|
||||||
|
|
||||||
@ -2137,7 +2141,9 @@ def PaymentCreateView(request, pk=None):
|
|||||||
|
|
||||||
|
|
||||||
def PaymentListView(request):
|
def PaymentListView(request):
|
||||||
entity = request.user.dealer.entity
|
dealer = get_user_type(request)
|
||||||
|
|
||||||
|
entity = dealer.entity
|
||||||
journals = JournalEntryModel.objects.filter(ledger__entity=entity).all()
|
journals = JournalEntryModel.objects.filter(ledger__entity=entity).all()
|
||||||
return render(request, "sales/payments/payment_list.html", {"journals": journals})
|
return render(request, "sales/payments/payment_list.html", {"journals": journals})
|
||||||
|
|
||||||
|
|||||||
BIN
static/.DS_Store
vendored
BIN
static/.DS_Store
vendored
Binary file not shown.
@ -0,0 +1,9 @@
|
|||||||
|
.color-div {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
BIN
static/images/.DS_Store
vendored
BIN
static/images/.DS_Store
vendored
Binary file not shown.
BIN
static/images/logos/.DS_Store
vendored
BIN
static/images/logos/.DS_Store
vendored
Binary file not shown.
@ -21,7 +21,7 @@ const getDataTableInit = () => {
|
|||||||
button.classList[disabled ? 'add' : 'remove']('disabled');
|
button.classList[disabled ? 'add' : 'remove']('disabled');
|
||||||
};
|
};
|
||||||
// Selectors
|
// Selectors
|
||||||
const table = document.getElementById('opportunityTable');
|
const table = document.getElementById('inventoryTable');
|
||||||
|
|
||||||
if (table) {
|
if (table) {
|
||||||
const options = {
|
const options = {
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
<link href="{% static 'vendors/simplebar/simplebar.min.css' %}" rel="stylesheet">
|
<link href="{% static 'vendors/simplebar/simplebar.min.css' %}" rel="stylesheet">
|
||||||
<link href="{% static 'css/sweetalert2.min.css' %}" rel="stylesheet">
|
<link href="{% static 'css/sweetalert2.min.css' %}" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="https://unicons.iconscout.com/release/v4.0.8/css/line.css">
|
<link rel="stylesheet" href="https://unicons.iconscout.com/release/v4.0.8/css/line.css">
|
||||||
|
<link href="{% static 'css/custom.css' %}" rel="stylesheet">
|
||||||
{% if LANGUAGE_CODE == 'en' %}
|
{% if LANGUAGE_CODE == 'en' %}
|
||||||
<link href="{% static 'css/theme.min.css' %}" type="text/css" rel="stylesheet" id="style-default">
|
<link href="{% static 'css/theme.min.css' %}" type="text/css" rel="stylesheet" id="style-default">
|
||||||
<link href="{% static 'css/user.min.css' %}" type="text/css" rel="stylesheet" id="user-style-default">
|
<link href="{% static 'css/user.min.css' %}" type="text/css" rel="stylesheet" id="user-style-default">
|
||||||
@ -39,6 +39,7 @@
|
|||||||
<link href="{% static 'css/theme-rtl.min.css' %}" type="text/css" rel="stylesheet" id="style-rtl">
|
<link href="{% static 'css/theme-rtl.min.css' %}" type="text/css" rel="stylesheet" id="style-rtl">
|
||||||
<link href="{% static 'css/user-rtl.min.css' %}" type="text/css" rel="stylesheet" id="user-style-rtl">
|
<link href="{% static 'css/user-rtl.min.css' %}" type="text/css" rel="stylesheet" id="user-style-rtl">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% block extra_css %}{% endblock extra_css %}
|
{% block extra_css %}{% endblock extra_css %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load static %}
|
{% load i18n static custom_filters %}
|
||||||
{% load i18n %}
|
|
||||||
{% load custom_filters %}
|
|
||||||
{% block title %}{{ _("Car Details") }}{% endblock %}
|
{% block title %}{{ _("Car Details") }}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.color-circle {
|
.color-circle {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
@ -13,82 +13,16 @@
|
|||||||
border-color: #fff;
|
border-color: #fff;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="container">
|
|
||||||
<div class="pb-5">
|
|
||||||
<!-- Custom Card Modal -->
|
|
||||||
<div class="modal fade" id="customCardModal" tabindex="-1" aria-labelledby="customCardModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-sm">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-primary">
|
|
||||||
<h5 class="modal-title text-light" id="customCardModalLabel">{% trans 'Custom Card' %}</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<!-- Content will be loaded here via AJAX -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Reservation Modal -->
|
|
||||||
<div class="modal fade" id="reserveModal" tabindex="-1" aria-labelledby="reserveModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-sm">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-primary">
|
|
||||||
<h5 class="modal-title text-light" id="reserveModalLabel">{% trans 'Car Reservation' %}</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% trans 'Are you sure you want to reserve this car?' %}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button"
|
|
||||||
class="btn btn-sm btn-phoenix-danger"
|
|
||||||
data-bs-dismiss="modal">
|
|
||||||
{% trans 'No' %}
|
|
||||||
</button>
|
|
||||||
<form method="POST" action="{% url 'reserve_car' car.id %}" class="d-inline">
|
|
||||||
{% csrf_token %}
|
|
||||||
<button type="submit" class="btn btn-phoenix-success btn-sm">{% trans "Yes" %}</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Specification Modal -->
|
|
||||||
|
|
||||||
<div class="modal fade" id="specificationsModal" tabindex="-1" aria-labelledby="specificationsModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title" id="specificationsModalLabel">{% trans 'specifications'|upper %}</h5>
|
|
||||||
<button class="btn btn-close p-1" type="button" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div id="specificationsContent"></div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button class="btn btn-phoenix-primary" type="button" data-bs-dismiss="modal">{% trans 'Close' %}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Specification Modal -->
|
|
||||||
|
|
||||||
<!-- Main Container -->
|
<!-- Main Container -->
|
||||||
|
<div class="container-fluid">
|
||||||
<div class="row gx-6">
|
<div class="row g-3 justify-content-between">
|
||||||
<div class="col-lg-12 col-xl-6">
|
<div class="col-lg-12 col-xl-6">
|
||||||
<div class="container-small-fluid">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="card rounded shadow d-flex align-content-center">
|
<div class="card rounded shadow d-flex align-content-center">
|
||||||
<p class="card-header rounded-top fw-bold">{% trans 'Car Details' %}</p>
|
<p class="card-header rounded-top fw-bold">{% trans 'Car Details' %}</p>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive scrollbar mb-3">
|
||||||
<table class="table fs-9 mb-0">
|
<table class="table table-sm fs-9 mb-0 overflow-hidden">
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "VIN" %}</th>
|
<th>{% trans "VIN" %}</th>
|
||||||
<td>{{ car.vin }}</td>
|
<td>{{ car.vin }}</td>
|
||||||
@ -142,11 +76,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>{% trans 'specifications'|capfirst %}</th>
|
<th>{% trans 'specifications'|capfirst %}</th>
|
||||||
<td>
|
<td>
|
||||||
<button type="button"
|
<button type="button" class="btn btn-phoenix-primary btn-sm" id="specification-btn" data-bs-toggle="modal" data-bs-target="#specificationsModal">
|
||||||
class="btn btn-phoenix-primary btn-sm"
|
|
||||||
id="specification-btn"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#specificationsModal">
|
|
||||||
{% trans 'view'|capfirst %}
|
{% trans 'view'|capfirst %}
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
@ -164,10 +94,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Custom Card" %}</th>
|
<th>{% trans "Custom Card" %}</th>
|
||||||
<td>
|
<td>
|
||||||
<button type="button"
|
<button type="button" class="btn btn-sm btn-phoenix-success" data-bs-toggle="modal" data-bs-target="#customCardModal">
|
||||||
class="btn btn-sm btn-phoenix-success"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#customCardModal">
|
|
||||||
{% trans 'Add' %}
|
{% trans 'Add' %}
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
@ -176,19 +103,12 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>{% trans 'Location'|capfirst %}</th>
|
<th>{% trans 'Location'|capfirst %}</th>
|
||||||
<td>
|
<td>
|
||||||
{% if car.location %}
|
{% if car.location %} {% if car.location.is_owner_showroom %} {% trans 'Our Showroom' %} {% else %} {{ car.location.showroom.get_local_name }} {% endif %}
|
||||||
{% if car.location.is_owner_showroom %}
|
<a href="{% url 'transfer' car.location.pk %}" class="btn btn-phoenix-danger btn-sm">
|
||||||
{% trans 'Our Showroom' %}
|
|
||||||
{% else %}
|
|
||||||
{{ car.location.showroom.get_local_name }}
|
|
||||||
{% endif %}
|
|
||||||
<a href="{% url 'transfer' car.location.pk %}"
|
|
||||||
class="btn btn-phoenix-danger btn-sm">
|
|
||||||
{% trans "transfer"|capfirst %}
|
{% trans "transfer"|capfirst %}
|
||||||
</a>
|
</a>
|
||||||
{% else %} {% trans "No location available." %}
|
{% else %} {% trans "No location available." %}
|
||||||
<a href="{% url 'add_car_location' car.pk %}"
|
<a href="{% url 'add_car_location' car.pk %}" class="btn btn-phoenix-success btn-sm ms-2">
|
||||||
class="btn btn-phoenix-success btn-sm ms-2">
|
|
||||||
{% trans "Add" %}
|
{% trans "Add" %}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
@ -201,17 +121,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6 col-xl-6">
|
<div class="col-lg-6 col-xl-6">
|
||||||
<div class="card rounded shadow">
|
<div class="card rounded shadow d-flex align-content-center">
|
||||||
<p class="card-header rounded-top fw-bold">{% trans 'Financial Details' %}</p>
|
<p class="card-header rounded-top fw-bold">{% trans 'Financial Details' %}</p>
|
||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|
||||||
|
<div class="table-responsive scrollbar mb-3">
|
||||||
|
<table class="table table-sm fs-9 mb-0 overflow-hidden">
|
||||||
{% if car.finances %}
|
{% if car.finances %}
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table fs-9 mb-0">
|
|
||||||
{% if perms.inventory.view_carfinance %}
|
{% if perms.inventory.view_carfinance %}
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Cost Price"|capfirst %}</th>
|
<th>{% trans "Cost Price"|capfirst %}</th>
|
||||||
@ -249,16 +167,13 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
{% if perms.inventory.change_carfinance %}
|
{% if perms.inventory.change_carfinance %}
|
||||||
<a href="{% url 'car_finance_update' car.finances.pk %}"
|
<a href="{% url 'car_finance_update' car.finances.pk %}" class="btn btn-phoenix-warning btn-sm mb-3">
|
||||||
class="btn btn-phoenix-warning btn-sm mb-3">
|
|
||||||
{% trans "Edit" %}
|
{% trans "Edit" %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>{% trans "No finance details available." %}</p>
|
<p>{% trans "No finance details available." %}</p>
|
||||||
<a href="{% url 'car_finance_create' car.pk %}"
|
<a href="{% url 'car_finance_create' car.pk %}" class="btn btn-phoenix-success btn-sm mb-3">
|
||||||
class="btn btn-phoenix-success btn-sm mb-3">
|
|
||||||
{% trans "Add" %}
|
{% trans "Add" %}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
@ -268,12 +183,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card rounded shadow mt-3">
|
<div class="card rounded shadow d-flex align-content-center mt-3">
|
||||||
<p class="card-header rounded-top fw-bold">{% trans 'Colors Details' %}</p>
|
<p class="card-header rounded-top fw-bold">{% trans 'Colors Details' %}</p>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive scrollbar mb-3">
|
||||||
<table class="table fs-9 mb-0">
|
<table class="table table-sm fs-9 mb-0 overflow-hidden">
|
||||||
<tbody class="align-middle">
|
|
||||||
{% if car.colors.exists %}
|
{% if car.colors.exists %}
|
||||||
{% for color in car.colors.all %}
|
{% for color in car.colors.all %}
|
||||||
<tr>
|
<tr>
|
||||||
@ -282,9 +196,7 @@
|
|||||||
<span>{{ color.exterior.get_local_name }}</span>
|
<span>{{ color.exterior.get_local_name }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle">
|
<td class="align-middle">
|
||||||
<div class="text-end color-circle"
|
<div class="text-end color-circle" style="background-color: rgb({{ color.exterior.rgb }});"></div>
|
||||||
style="background-color: rgb({{ color.exterior.rgb }});">
|
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -293,13 +205,10 @@
|
|||||||
<span>{{ color.interior.get_local_name }}</span>
|
<span>{{ color.interior.get_local_name }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle">
|
<td class="align-middle">
|
||||||
<div class="text-end color-circle"
|
<div class="text-end color-circle" style="background-color: rgb({{ color.interior.rgb }});"></div>
|
||||||
style="background-color: rgb({{ color.interior.rgb }});">
|
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %} {% else %}
|
||||||
{% else %}
|
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
{% trans "No colors available for this car." %}
|
{% trans "No colors available for this car." %}
|
||||||
@ -313,18 +222,16 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tbody>
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card rounded shadow d-flex align-content-center mt-3">
|
||||||
<div class="card rounded shadow mt-3">
|
|
||||||
<p class="card-header rounded-top fw-bold">{% trans 'Reservations Details' %}</p>
|
<p class="card-header rounded-top fw-bold">{% trans 'Reservations Details' %}</p>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive scrollbar mb-3">
|
||||||
|
<table class="table table-sm fs-9 mb-0 overflow-hidden">
|
||||||
{% if car.is_reserved %}
|
{% if car.is_reserved %}
|
||||||
<table class="table fs-9 mb-0">
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Reserved By" %}</th>
|
<th>{% trans "Reserved By" %}</th>
|
||||||
@ -341,50 +248,92 @@
|
|||||||
{% if reservation.is_active %}
|
{% if reservation.is_active %}
|
||||||
<form method="post" action="{% url 'reservations' reservation.id %}">
|
<form method="post" action="{% url 'reservations' reservation.id %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<button type="submit"
|
<button type="submit" name="action" value="renew" class="btn btn-sm btn-phoenix-success">
|
||||||
name="action"
|
|
||||||
value="renew"
|
|
||||||
class="btn btn-sm btn-phoenix-success">
|
|
||||||
{% trans "Renew" %}
|
{% trans "Renew" %}
|
||||||
</button>
|
</button>
|
||||||
<button type="submit"
|
<button type="submit" name="action" value="cancel" class="btn btn-sm btn-phoenix-secondary">
|
||||||
name="action"
|
|
||||||
value="cancel"
|
|
||||||
class="btn btn-sm btn-phoenix-secondary">
|
|
||||||
{% trans "Cancel" %}
|
{% trans "Cancel" %}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="badge bg-danger"
|
<span class="badge bg-danger" style="width: 120px;">
|
||||||
style="width: 120px;">
|
|
||||||
{% trans "Expired" %}
|
{% trans "Expired" %}
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %} {% else %}
|
||||||
{% else %}
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<button type="button"
|
<button type="button" class="btn btn-sm btn-phoenix-success" data-bs-toggle="modal" data-bs-target="#reserveModal">
|
||||||
class="btn btn-sm btn-phoenix-success"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#reserveModal">
|
|
||||||
{% trans 'Reserve' %}
|
{% trans 'Reserve' %}
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
{% endif %}
|
||||||
</table>
|
</table>
|
||||||
<div class="table-responsive">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Custom Card Modal -->
|
||||||
|
<div class="modal fade" id="customCardModal" tabindex="-1" aria-labelledby="customCardModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-sm">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header bg-primary">
|
||||||
|
<h5 class="modal-title text-light" id="customCardModalLabel">{% trans 'Custom Card' %}</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<!-- Content will be loaded here via AJAX -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Reservation Modal -->
|
||||||
|
<div class="modal fade" id="reserveModal" tabindex="-1" aria-labelledby="reserveModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-sm">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header bg-primary">
|
||||||
|
<h5 class="modal-title text-light" id="reserveModalLabel">{% trans 'Car Reservation' %}</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
{% trans 'Are you sure you want to reserve this car?' %}
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-sm btn-phoenix-danger" data-bs-dismiss="modal">
|
||||||
|
{% trans 'No' %}
|
||||||
|
</button>
|
||||||
|
<form method="POST" action="{% url 'reserve_car' car.id %}" class="d-inline">
|
||||||
|
{% csrf_token %}
|
||||||
|
<button type="submit" class="btn btn-phoenix-success btn-sm">{% trans "Yes" %}</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Specification Modal -->
|
||||||
|
<div class="modal fade" id="specificationsModal" tabindex="-1" aria-labelledby="specificationsModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="specificationsModalLabel">{% trans 'specifications'|upper %}</h5>
|
||||||
|
<button class="btn btn-close p-1" type="button" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div id="specificationsContent"></div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn btn-phoenix-primary" type="button" data-bs-dismiss="modal">{% trans 'Close' %}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
@ -403,7 +352,7 @@
|
|||||||
return cookieValue;
|
return cookieValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const csrfToken = getCookie("csrftoken");
|
||||||
const ajaxUrl = "{% url 'ajax_handler' %}";
|
const ajaxUrl = "{% url 'ajax_handler' %}";
|
||||||
|
|
||||||
const modal = document.getElementById("customCardModal");
|
const modal = document.getElementById("customCardModal");
|
||||||
@ -436,7 +385,7 @@
|
|||||||
fetch(`${ajaxUrl}?action=get_specifications&trim_id={{ car.id_car_trim.id_car_trim }}`, {
|
fetch(`${ajaxUrl}?action=get_specifications&trim_id={{ car.id_car_trim.id_car_trim }}`, {
|
||||||
headers: {
|
headers: {
|
||||||
"X-Requested-With": "XMLHttpRequest",
|
"X-Requested-With": "XMLHttpRequest",
|
||||||
"X-CSRFToken": {% csrf_token %},
|
"X-CSRFToken": csrfToken,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
@ -472,7 +421,7 @@
|
|||||||
const response = await fetch(`{% url 'reserve_car' car.pk %}`, {
|
const response = await fetch(`{% url 'reserve_car' car.pk %}`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"X-CSRFToken": {% csrf_token %},
|
"X-CSRFToken": csrfToken,
|
||||||
"X-Requested-With": "XMLHttpRequest",
|
"X-Requested-With": "XMLHttpRequest",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,135 +1,135 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load i18n static %}
|
{% load i18n static %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{% trans 'inventory'|capfirst %}
|
{% trans 'inventory'|capfirst %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block inventory %}
|
{% block inventory %}
|
||||||
<a class="nav-link active fw-bold">{% trans "inventory" %}<span class="visually-hidden">(current)</span></a>
|
<a class="nav-link active fw-bold">{% trans "inventory" %}<span class="visually-hidden">(current)</span></a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<style>
|
|
||||||
.color-div {
|
|
||||||
width: 22px;
|
|
||||||
height: 22px;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
text-align: center;
|
|
||||||
vertical-align: middle;
|
|
||||||
line-height: 22px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row g-3 justify-content-between mb-4">
|
<div class="row g-3 justify-content-between">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<!---->
|
|
||||||
<div class="card border h-100 w-100 overflow-hidden">
|
<div class="card border h-100 w-100 overflow-hidden">
|
||||||
<div class="bg-holder d-block bg-card" style="background-image:url({% static 'images/spot-illustrations/32.png' %});background-position: top right;">
|
<div class="bg-holder d-block bg-card" style="background-image:url({% static 'images/spot-illustrations/32.png' %});background-position: top right;">
|
||||||
</div>
|
</div>
|
||||||
<!--/.bg-holder-->
|
|
||||||
|
|
||||||
<div class="d-dark-none">
|
<div class="d-dark-none">
|
||||||
<div class="bg-holder d-none d-sm-block d-xl-none d-xxl-block bg-card" style="background-image:url({% static 'images/spot-illustrations/dark_21.png' %});background-position: bottom right; background-size: auto;">
|
<div class="bg-holder d-none d-sm-block d-xl-none d-xxl-block bg-card" style="background-image:url({% static 'images/spot-illustrations/dark_21.png' %});background-position: bottom right; background-size: auto;">
|
||||||
</div>
|
</div>
|
||||||
<!--/.bg-holder-->
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="d-light-none">
|
<div class="d-light-none">
|
||||||
<div class="bg-holder d-none d-sm-block d-xl-none d-xxl-block bg-card" style="background-image:url({% static 'images/spot-illustrations/21.png' %});background-position: bottom right; background-size: auto;">
|
<div class="bg-holder d-none d-sm-block d-xl-none d-xxl-block bg-card" style="background-image:url({% static 'images/spot-illustrations/21.png' %});background-position: bottom right; background-size: auto;">
|
||||||
</div>
|
</div>
|
||||||
<!--/.bg-holder-->
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body px-5 position-relative">
|
<div class="card-body px-lg-5 position-relative">
|
||||||
<div class="badge badge-phoenix fs-10 badge-phoenix-warning mb-2">{{ _("Year") }}<span class="ms-1 fw-bold">{{ cars.first.year }}</span></div>
|
<br><br><h3 class="mb-2">{{ cars.first.id_car_make.get_local_name }}<span class="ms-2 text-body-tertiary fw-semibold">{{ cars.first.id_car_model.get_local_name }}</span></h3>
|
||||||
<h3 class="mb-2">{{ cars.first.id_car_make.get_local_name }}<span class="ms-2 text-body-tertiary fw-semibold">{{ cars.first.id_car_model.get_local_name }}</span></h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-footer border-0 py-0 px-5 z-1">
|
|
||||||
<p class="text-body-tertiary fw-semibold">{{ cars.first.id_car_serie.name }}, <span class="fs-10">{{ cars.first.id_car_trim.name }}</span></p>
|
<p class="text-body-tertiary fw-semibold">{{ cars.first.id_car_serie.name }}, <span class="fs-10">{{ cars.first.id_car_trim.name }}</span></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!---->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row g-3 justify-content-between mb-4">
|
<div class="row g-3 justify-content-between mt-4">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="table-responsive scrollbar mx-n1 px-1">
|
<div class="table-list" id="inventoryTable">
|
||||||
<table class="table fs-9 mb-0 leads-table border-top border-translucent">
|
<div class="table-responsive scrollbar mb-3">
|
||||||
<thead>
|
<table class="table table-sm fs-9 mb-0 overflow-hidden">
|
||||||
|
<thead class="text-body">
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "VIN" %}</th>
|
<th class="pe-1 align-middle white-space-nowrap text-center" data-sort="stock">{% trans 'Stock' %}</th>
|
||||||
<th>{% trans "Year" %}</th>
|
<th class="pe-1 align-middle white-space-nowrap text-start" data-sort="vin" style="min-width: 4.5rem;">{% trans "VIN" %}</th>
|
||||||
<th>{% trans 'Exterior Color' %}</th>
|
<th class="pe-1 align-middle white-space-nowrap text-center" data-sort="date">{% trans "Year"|upper %}</th>
|
||||||
<th>{% trans 'Interior Color' %}</th>
|
<th class="pe-1 align-middle white-space-nowrap text-center" data-sort="extColor" style="min-width: 8.5rem">{% trans 'Exterior Color'|upper %}</th>
|
||||||
<th>{% trans "Showroom Location" %}</th>
|
<th class="pe-1 align-middle white-space-nowrap text-center" data-sort="intColor" style="min-width: 8.5rem">{% trans 'Interior Color'|upper %}</th>
|
||||||
<th>{% trans "Actions" %}</th>
|
<th class="pe-1 align-middle white-space-nowrap text-center" data-sort="location" style="min-width: 12.5rem;">{% trans "Showroom Location"|upper %}</th>
|
||||||
|
<th class="pe-1 align-middle white-space-nowrap text-center" data-sort="status">{% trans 'Status'|upper %}</th>
|
||||||
|
<th class="pe-1 align-middle white-space-nowrap text-center" data-sort="age" style="min-width: 7rem">{% trans 'Age'|upper %}</th>
|
||||||
|
<th class="no-sort align-middle white-space-nowrap text-center"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for car in cars %}
|
{% for car in cars %}
|
||||||
<tr class="{% if car.is_reserved %}table-danger{% endif %}">
|
<tr>
|
||||||
<td>{{ car.vin }}</td>
|
<td class="align-middle white-space-nowrap text-center fw-bold text-body-tertiary">
|
||||||
<td>{{ car.year }}</td>
|
{% if car.stock_type == "new" %}
|
||||||
|
<span class="badge badge-phoenix fs-10 badge-phoenix-success"><span class="badge-label">{{_("New")}}</span><span class="ms-1" data-feather="plus" style="height:13px;width:13px;"></span></span>
|
||||||
|
{% elif car.status == "used" %}
|
||||||
|
<span class="badge badge-phoenix fs-10 badge-phoenix-info"><span class="badge-label">{{_("Used")}}</span><span class="ms-1" data-feather="plus" style="height:13px;width:13px;"></span></span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td class="align-middle white-space-nowrap text-start fw-bold">{{ car.vin }}</td>
|
||||||
|
<td class="align-middle white-space-nowrap text-center fw-bold">{{ car.year }}</td>
|
||||||
{% if car.colors.exists %}
|
{% if car.colors.exists %}
|
||||||
<td>
|
<td class="align-middle white-space-nowrap text-body fs-9 text-start">
|
||||||
<div class="d-flex flex-column align-items-center">
|
<div class="d-flex flex-column align-items-center">
|
||||||
<span class="color-div"
|
<span class="color-div" style="background-color: rgb({{ car.colors.first.exterior.rgb }});" title="{{ car.colors.first.exterior.get_local_name }}"></span><span>{{ car.colors.first.exterior.get_local_name }}</span>
|
||||||
style="background-color: rgb({{ car.colors.first.exterior.rgb }});"
|
|
||||||
title="{{ car.colors.first.exterior.get_local_name }}">
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td class="align-middle white-space-nowrap text-body fs-9 text-start">
|
||||||
<div class="d-flex flex-column align-items-center">
|
<div class="d-flex flex-column align-items-center">
|
||||||
<span class="color-div"
|
<span class="color-div" style="background-color: rgb({{ car.colors.first.interior.rgb }});" title="{{ car.colors.first.interior.get_local_name }}"></span><span>{{ car.colors.first.interior.get_local_name }}</span>
|
||||||
style="background-color: rgb({{ car.colors.first.interior.rgb }});"
|
|
||||||
title="{{ car.colors.first.interior.get_local_name }}">
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
{% else %}
|
{% else %}
|
||||||
<td><span class="color-div">{% trans 'No Color' %}</span></td>
|
<td class="align-middle white-space-nowrap text-body fs-9 text-center"><span class="color-div">{% trans 'No Color' %}</span></td>
|
||||||
<td><span class="color-div">{% trans 'No Color' %}</span></td>
|
<td class="align-middle white-space-nowrap text-body fs-9 text-center"><span class="color-div">{% trans 'No Color' %}</span></td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<td class="align-middle white-space-nowrap text-body fs-9 text-center">
|
||||||
{% if car.location.is_owner_showroom %}
|
{% if car.location.is_owner_showroom %}
|
||||||
<td> {% trans 'Our Showroom' %}</td>
|
{% trans 'Our Showroom' %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<td>{{ car.location.showroom.get_local_name }}</td>
|
{{ car.location.showroom.get_local_name }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<td>
|
</td>
|
||||||
<a href="{% url 'car_detail' car.pk %}" class="btn btn-success">
|
<td class="status align-middle white-space-nowrap text-center fw-bold text-body-tertiary">
|
||||||
{% trans "view"|capfirst %}
|
{% if car.status == "available" %}
|
||||||
</a>
|
<span class="badge badge-phoenix fs-10 badge-phoenix-success"><span class="badge-label">{{_("Available")}}</span><span class="ms-1" data-feather="check" style="height:13px;width:13px;"></span></span>
|
||||||
|
{% elif car.status == "sold" %}
|
||||||
|
<span class="badge badge-phoenix fs-10 badge-phoenix-primary"><span class="badge-label">{{_("Sold")}}</span><span class="ms-1" data-feather="package" style="height:13px;width:13px;"></span></span>
|
||||||
|
{% elif car.status == "hold" %}
|
||||||
|
<span class="badge badge-phoenix fs-10 badge-phoenix-warning"><span class="badge-label">{{ _("Hold") }}</span><span class="ms-1" data-feather="alert-octagon" style="height:13px;width:13px;"></span></span>
|
||||||
|
{% elif car.status == "reserved" %}
|
||||||
|
<span class="badge badge-phoenix fs-10 badge-phoenix-danger"><span class="badge-label">{{ _("Reserved") }}</span><span class="ms-1" data-feather="info" style="height:13px;width:13px;"></span></span>
|
||||||
|
{% elif car.status == "damaged" %}
|
||||||
|
<span class="badge badge-phoenix fs-10 badge-phoenix-secondary"><span class="badge-label">{{ _("Damaged") }}</span><span class="ms-1" data-feather="x" style="height:13px;width:13px;"></span></span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td class="date align-middle white-space-nowrap text-body-tertiary fs-9 ps-4 text-start">
|
||||||
|
<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>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="6">{% trans "No cars available." %}</td>
|
<td colspan="7" class="d-flex flex-column align-items-center">
|
||||||
|
<p class="text-muted">{% trans "No cars available." %}</p>
|
||||||
|
<a href="{% url 'add_car' %}" class="btn btn-primary">{% trans "Add a Car" %}</a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- Pagination -->
|
<!-- Pagination -->
|
||||||
{% if is_paginated %}
|
{% if is_paginated %}
|
||||||
<nav aria-label="Page navigation">
|
<nav aria-label="Page navigation">
|
||||||
<ul class="pagination pagination-sm justify-content-center">
|
<ul class="pagination pagination-sm justify-content-center">
|
||||||
{% if page_obj.has_previous %}
|
{% if page_obj.has_previous %}
|
||||||
<li class="page-item">
|
<li class="page-item">
|
||||||
<a class="page-link" href="?page=1" aria-label="First">
|
<a class="page-link" href="?page=1" aria-label="First">««</a>
|
||||||
««
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item">
|
<li class="page-item">
|
||||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous">
|
<a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous">«</a>
|
||||||
«
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% else %}
|
|
||||||
<li class="page-item disabled">
|
|
||||||
<span class="page-link">««</span>
|
|
||||||
</li>
|
|
||||||
<li class="page-item disabled">
|
|
||||||
<span class="page-link">«</span>
|
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% for num in page_obj.paginator.page_range %}
|
{% for num in page_obj.paginator.page_range %}
|
||||||
@ -145,21 +145,10 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if page_obj.has_next %}
|
{% if page_obj.has_next %}
|
||||||
<li class="page-item">
|
<li class="page-item">
|
||||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next">
|
<a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next">»</a>
|
||||||
»
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item">
|
<li class="page-item">
|
||||||
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}" aria-label="Last">
|
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}" aria-label="Last">»»</a>
|
||||||
»»
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% else %}
|
|
||||||
<li class="page-item disabled">
|
|
||||||
<span class="page-link">»</span>
|
|
||||||
</li>
|
|
||||||
<li class="page-item disabled">
|
|
||||||
<span class="page-link">»»</span>
|
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
@ -168,5 +157,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
1
templates/partials/car_card.html
Normal file
1
templates/partials/car_card.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
{% load static %}
|
||||||
137
templates/test.html
Normal file
137
templates/test.html
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Car Inventory</title>
|
||||||
|
<!-- Bootstrap CSS -->
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<!-- Font Awesome for Icons -->
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
|
||||||
|
<!-- Custom CSS -->
|
||||||
|
<style>
|
||||||
|
.color-circle {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.table-hover tbody tr:hover {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
.badge {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
.table-responsive {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
.table thead th {
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.table tbody td {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container my-5">
|
||||||
|
<h1 class="text-center mb-4">Car Inventory</h1>
|
||||||
|
|
||||||
|
<!-- Search and Filter Section -->
|
||||||
|
<div class="row mb-4 g-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
|
<input type="text" class="form-control" placeholder="Search by VIN, Make, or Model">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<select class="form-select">
|
||||||
|
<option>All Years</option>
|
||||||
|
<option>2023</option>
|
||||||
|
<option>2022</option>
|
||||||
|
<option>2021</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<button class="btn btn-primary w-100"><i class="fas fa-filter"></i> Filter</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Car Listing Table -->
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th>Image</th>
|
||||||
|
<th>Make & Model</th>
|
||||||
|
<th>Year</th>
|
||||||
|
<th>VIN</th>
|
||||||
|
<th>Exterior Color</th>
|
||||||
|
<th>Interior Color</th>
|
||||||
|
<th>Location</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<!-- Example Row -->
|
||||||
|
<tr>
|
||||||
|
<td>1</td>
|
||||||
|
<td><img src="https://via.placeholder.com/100" alt="Car Image" class="img-thumbnail" style="width: 100px;"></td>
|
||||||
|
<td>Toyota Camry</td>
|
||||||
|
<td>2023</td>
|
||||||
|
<td>1HGCM82633A123456</td>
|
||||||
|
<td><span class="color-circle" style="background-color: #0000ff;"></span> Blue</td>
|
||||||
|
<td><span class="color-circle" style="background-color: #ffffff;"></span> White</td>
|
||||||
|
<td>Main Showroom</td>
|
||||||
|
<td><span class="badge bg-success">Available</span></td>
|
||||||
|
<td>
|
||||||
|
<a href="#" class="btn btn-sm btn-outline-primary"><i class="fas fa-eye"></i> View</a>
|
||||||
|
<a href="#" class="btn btn-sm btn-outline-warning"><i class="fas fa-edit"></i> Edit</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Add more rows here -->
|
||||||
|
<tr>
|
||||||
|
<td>2</td>
|
||||||
|
<td><img src="https://via.placeholder.com/100" alt="Car Image" class="img-thumbnail" style="width: 100px;"></td>
|
||||||
|
<td>Honda Accord</td>
|
||||||
|
<td>2022</td>
|
||||||
|
<td>1HGCM82633A654321</td>
|
||||||
|
<td><span class="color-circle" style="background-color: #ff0000;"></span> Red</td>
|
||||||
|
<td><span class="color-circle" style="background-color: #000000;"></span> Black</td>
|
||||||
|
<td>Downtown Showroom</td>
|
||||||
|
<td><span class="badge bg-warning">Reserved</span></td>
|
||||||
|
<td>
|
||||||
|
<a href="#" class="btn btn-sm btn-outline-primary"><i class="fas fa-eye"></i> View</a>
|
||||||
|
<a href="#" class="btn btn-sm btn-outline-warning"><i class="fas fa-edit"></i> Edit</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
|
<nav aria-label="Page navigation" class="mt-4">
|
||||||
|
<ul class="pagination justify-content-center">
|
||||||
|
<li class="page-item disabled">
|
||||||
|
<a class="page-link" href="#" tabindex="-1" aria-disabled="true"><i class="fas fa-chevron-left"></i></a>
|
||||||
|
</li>
|
||||||
|
<li class="page-item active"><a class="page-link" href="#">1</a></li>
|
||||||
|
<li class="page-item"><a class="page-link" href="#">2</a></li>
|
||||||
|
<li class="page-item"><a class="page-link" href="#">3</a></li>
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="#"><i class="fas fa-chevron-right"></i></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bootstrap JS -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
x
Reference in New Issue
Block a user