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})
|
||||||
|
|
||||||
@ -2314,10 +2320,10 @@ def fetch_notifications(request):
|
|||||||
|
|
||||||
|
|
||||||
class ItemServiceCreateView(CreateView):
|
class ItemServiceCreateView(CreateView):
|
||||||
model = ItemModel
|
model = ItemModel
|
||||||
form_class = ServiceCreateForm
|
form_class = ServiceCreateForm
|
||||||
template_name = "items/service/service_create.html"
|
template_name = "items/service/service_create.html"
|
||||||
success_url = reverse_lazy("item_service_list")
|
success_url = reverse_lazy("item_service_list")
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
kwargs = super().get_form_kwargs()
|
kwargs = super().get_form_kwargs()
|
||||||
|
|||||||
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,94 +1,28 @@
|
|||||||
{% 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;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
border-radius: 50px;
|
border-radius: 50px;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
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 -->
|
<!-- Main Container -->
|
||||||
<div class="modal fade" id="reserveModal" tabindex="-1" aria-labelledby="reserveModalLabel" aria-hidden="true">
|
<div class="container-fluid">
|
||||||
<div class="modal-dialog modal-sm">
|
<div class="row g-3 justify-content-between">
|
||||||
<div class="modal-content">
|
<div class="col-lg-12 col-xl-6">
|
||||||
<div class="modal-header bg-primary">
|
<div class="card rounded shadow d-flex align-content-center">
|
||||||
<h5 class="modal-title text-light" id="reserveModalLabel">{% trans 'Car Reservation' %}</h5>
|
<p class="card-header rounded-top fw-bold">{% trans 'Car Details' %}</p>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<div class="card-body">
|
||||||
</div>
|
<div class="table-responsive scrollbar mb-3">
|
||||||
<div class="modal-body">
|
<table class="table table-sm fs-9 mb-0 overflow-hidden">
|
||||||
{% 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 -->
|
|
||||||
|
|
||||||
<div class="row gx-6">
|
|
||||||
<div class="col-lg-12 col-xl-6">
|
|
||||||
<div class="container-small-fluid">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="card rounded shadow d-flex align-content-center">
|
|
||||||
<p class="card-header rounded-top fw-bold">{% trans 'Car Details' %}</p>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table fs-9 mb-0">
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "VIN" %}</th>
|
<th>{% trans "VIN" %}</th>
|
||||||
<td>{{ car.vin }}</td>
|
<td>{{ car.vin }}</td>
|
||||||
@ -129,7 +63,7 @@
|
|||||||
<th>{% trans "Receiving Date"|capfirst %}</th>
|
<th>{% trans "Receiving Date"|capfirst %}</th>
|
||||||
<td>{{ car.receiving_date|timesince }}</td>
|
<td>{{ car.receiving_date|timesince }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% if car.vendor %}
|
{% if car.vendor %}
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Vendor"|capfirst %}</th>
|
<th>{% trans "Vendor"|capfirst %}</th>
|
||||||
<td>{{ car.vendor.get_local_name }}</td>
|
<td>{{ car.vendor.get_local_name }}</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,42 +103,33 @@
|
|||||||
<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' %}
|
{% trans "transfer"|capfirst %}
|
||||||
{% 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 %}
|
|
||||||
</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>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<a href="{% url 'car_update' car.pk %}" class="btn btn-phoenix-warning btn-sm mt-1">{% trans "Edit" %}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div>
|
||||||
|
<a href="{% url 'car_update' car.pk %}" class="btn btn-phoenix-warning btn-sm mt-1">{% trans "Edit" %}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6 col-xl-6">
|
</div>
|
||||||
<div class="card rounded shadow">
|
</div>
|
||||||
<p class="card-header rounded-top fw-bold">{% trans 'Financial Details' %}</p>
|
</div>
|
||||||
|
<div class="col-lg-6 col-xl-6">
|
||||||
<div class="card-body">
|
<div class="card rounded shadow d-flex align-content-center">
|
||||||
|
<p class="card-header rounded-top fw-bold">{% trans 'Financial Details' %}</p>
|
||||||
|
<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>
|
||||||
@ -231,12 +149,12 @@
|
|||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% if car.finances.additional_services.first.pk %}
|
{% if car.finances.additional_services.first.pk %}
|
||||||
{% for service in car.finances.additional_services.all %}
|
{% for service in car.finances.additional_services.all %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{service.name}}</td>
|
<td>{{service.name}}</td>
|
||||||
<td>{{ service.default_amount }}</td>
|
<td>{{ service.default_amount }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "VAT Amount"|capfirst %}</th>
|
<th>{% trans "VAT Amount"|capfirst %}</th>
|
||||||
@ -246,85 +164,74 @@
|
|||||||
<th>{% trans "Total"|capfirst %}</th>
|
<th>{% trans "Total"|capfirst %}</th>
|
||||||
<td>{{ car.finances.total }}</td>
|
<td>{{ car.finances.total }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<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>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card rounded shadow d-flex align-content-center mt-3">
|
||||||
|
<p class="card-header rounded-top fw-bold">{% trans 'Colors Details' %}</p>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive scrollbar mb-3">
|
||||||
|
<table class="table table-sm fs-9 mb-0 overflow-hidden">
|
||||||
|
{% if car.colors.exists %}
|
||||||
|
{% for color in car.colors.all %}
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Exterior' %}</th>
|
||||||
|
<td>
|
||||||
|
<span>{{ color.exterior.get_local_name }}</span>
|
||||||
|
</td>
|
||||||
|
<td class="align-middle">
|
||||||
|
<div class="text-end color-circle" style="background-color: rgb({{ color.exterior.rgb }});"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Interior' %}</th>
|
||||||
|
<td>
|
||||||
|
<span>{{ color.interior.get_local_name }}</span>
|
||||||
|
</td>
|
||||||
|
<td class="align-middle">
|
||||||
|
<div class="text-end color-circle" style="background-color: rgb({{ color.interior.rgb }});"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %} {% else %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
{% trans "No colors available for this car." %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<a href="{% url 'add_color' car.pk %}" class="btn btn-phoenix-success btn-sm">
|
||||||
|
{% trans "Add" %}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card rounded shadow mt-3">
|
</div>
|
||||||
<p class="card-header rounded-top fw-bold">{% trans 'Colors Details' %}</p>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card rounded shadow d-flex align-content-center mt-3">
|
||||||
<div class="table-responsive">
|
<p class="card-header rounded-top fw-bold">{% trans 'Reservations Details' %}</p>
|
||||||
<table class="table fs-9 mb-0">
|
<div class="card-body">
|
||||||
<tbody class="align-middle">
|
<div class="table-responsive scrollbar mb-3">
|
||||||
{% if car.colors.exists %}
|
<table class="table table-sm fs-9 mb-0 overflow-hidden">
|
||||||
{% for color in car.colors.all %}
|
|
||||||
<tr>
|
|
||||||
<th>{% trans 'Exterior' %}</th>
|
|
||||||
<td>
|
|
||||||
<span>{{ color.exterior.get_local_name }}</span>
|
|
||||||
</td>
|
|
||||||
<td class="align-middle">
|
|
||||||
<div class="text-end color-circle"
|
|
||||||
style="background-color: rgb({{ color.exterior.rgb }});">
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>{% trans 'Interior' %}</th>
|
|
||||||
<td>
|
|
||||||
<span>{{ color.interior.get_local_name }}</span>
|
|
||||||
</td>
|
|
||||||
<td class="align-middle">
|
|
||||||
<div class="text-end color-circle"
|
|
||||||
style="background-color: rgb({{ color.interior.rgb }});">
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
<tr>
|
|
||||||
<td colspan="2">
|
|
||||||
{% trans "No colors available for this car." %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td colspan="2">
|
|
||||||
<a href="{% url 'add_color' car.pk %}" class="btn btn-phoenix-success btn-sm">
|
|
||||||
{% trans "Add" %}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card rounded shadow mt-3">
|
|
||||||
<p class="card-header rounded-top fw-bold">{% trans 'Reservations Details' %}</p>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="table-responsive">
|
|
||||||
{% 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" class="btn btn-sm btn-phoenix-success" data-bs-toggle="modal" data-bs-target="#reserveModal">
|
||||||
<button type="button"
|
{% trans 'Reserve' %}
|
||||||
class="btn btn-sm btn-phoenix-success"
|
</button>
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#reserveModal">
|
</td>
|
||||||
{% trans 'Reserve' %}
|
</tr>
|
||||||
</button>
|
</tbody>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
</table>
|
||||||
<div class="table-responsive">
|
|
||||||
</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>
|
</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,172 +1,160 @@
|
|||||||
{% 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>
|
<div class="container">
|
||||||
.color-div {
|
<div class="row g-3 justify-content-between">
|
||||||
width: 22px;
|
<div class="col-sm-12">
|
||||||
height: 22px;
|
<div class="card border h-100 w-100 overflow-hidden">
|
||||||
border-radius: 50%;
|
<div class="bg-holder d-block bg-card" style="background-image:url({% static 'images/spot-illustrations/32.png' %});background-position: top right;">
|
||||||
border: 1px solid #ccc;
|
</div>
|
||||||
text-align: center;
|
<div class="d-dark-none">
|
||||||
vertical-align: middle;
|
<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;">
|
||||||
line-height: 22px;
|
</div>
|
||||||
}
|
</div>
|
||||||
</style>
|
<div class="d-light-none">
|
||||||
<div class="container">
|
<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="row g-3 justify-content-between mb-4">
|
</div>
|
||||||
<div class="col-sm-12">
|
</div>
|
||||||
<!---->
|
<div class="card-body px-lg-5 position-relative">
|
||||||
<div class="card border h-100 w-100 overflow-hidden">
|
<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>
|
||||||
<div class="bg-holder d-block bg-card" style="background-image:url({% static 'images/spot-illustrations/32.png' %});background-position: top right;">
|
<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>
|
||||||
<!--/.bg-holder-->
|
</div>
|
||||||
|
</div>
|
||||||
<div class="d-dark-none">
|
<div class="row g-3 justify-content-between mt-4">
|
||||||
<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="col-sm-12">
|
||||||
</div>
|
<div class="table-list" id="inventoryTable">
|
||||||
<!--/.bg-holder-->
|
<div class="table-responsive scrollbar mb-3">
|
||||||
|
<table class="table table-sm fs-9 mb-0 overflow-hidden">
|
||||||
</div>
|
<thead class="text-body">
|
||||||
<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>
|
|
||||||
<!--/.bg-holder-->
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="card-body px-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>
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!---->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row g-3 justify-content-between mb-4">
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<div class="table-responsive scrollbar mx-n1 px-1">
|
|
||||||
<table class="table fs-9 mb-0 leads-table border-top border-translucent">
|
|
||||||
<thead>
|
|
||||||
<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 }});"
|
</div>
|
||||||
title="{{ car.colors.first.exterior.get_local_name }}">
|
</td>
|
||||||
</span>
|
<td class="align-middle white-space-nowrap text-body fs-9 text-start">
|
||||||
</div>
|
<div class="d-flex flex-column align-items-center">
|
||||||
</td>
|
<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>
|
||||||
<td>
|
</div>
|
||||||
<div class="d-flex flex-column align-items-center">
|
</td>
|
||||||
<span class="color-div"
|
|
||||||
style="background-color: rgb({{ car.colors.first.interior.rgb }});"
|
|
||||||
title="{{ car.colors.first.interior.get_local_name }}">
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</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 %}
|
||||||
{% if car.location.is_owner_showroom %}
|
<td class="align-middle white-space-nowrap text-body fs-9 text-center">
|
||||||
<td> {% trans 'Our Showroom' %}</td>
|
{% if car.location.is_owner_showroom %}
|
||||||
|
{% 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">
|
||||||
</tr>
|
<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>
|
||||||
{% 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>
|
||||||
««
|
</li>
|
||||||
</a>
|
<li class="page-item">
|
||||||
</li>
|
<a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous">«</a>
|
||||||
<li class="page-item">
|
</li>
|
||||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous">
|
{% endif %}
|
||||||
«
|
{% for num in page_obj.paginator.page_range %}
|
||||||
</a>
|
{% if page_obj.number == num %}
|
||||||
</li>
|
<li class="page-item active">
|
||||||
{% else %}
|
<span class="page-link">{{ num }}</span>
|
||||||
<li class="page-item disabled">
|
</li>
|
||||||
<span class="page-link">««</span>
|
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
||||||
</li>
|
<li class="page-item">
|
||||||
<li class="page-item disabled">
|
<a class="page-link" href="?page={{ num }}">{{ num }}</a>
|
||||||
<span class="page-link">«</span>
|
</li>
|
||||||
</li>
|
{% endif %}
|
||||||
{% endif %}
|
{% endfor %}
|
||||||
{% for num in page_obj.paginator.page_range %}
|
{% if page_obj.has_next %}
|
||||||
{% if page_obj.number == num %}
|
<li class="page-item">
|
||||||
<li class="page-item active">
|
<a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next">»</a>
|
||||||
<span class="page-link">{{ num }}</span>
|
</li>
|
||||||
</li>
|
<li class="page-item">
|
||||||
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}" aria-label="Last">»»</a>
|
||||||
<li class="page-item">
|
</li>
|
||||||
<a class="page-link" href="?page={{ num }}">{{ num }}</a>
|
{% endif %}
|
||||||
</li>
|
</ul>
|
||||||
{% endif %}
|
</nav>
|
||||||
{% endfor %}
|
|
||||||
{% if page_obj.has_next %}
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next">
|
|
||||||
»
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}" aria-label="Last">
|
|
||||||
»»
|
|
||||||
</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>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</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