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",
|
||||
"LNP": "NAC MG",
|
||||
"LNY": "Yuejin",
|
||||
"LMX": "Dongfeng Forthing",
|
||||
"LPA": "Changan",
|
||||
"LPE": "BYD",
|
||||
"LPS": "Polestar",
|
||||
@ -346,9 +347,7 @@ wmi_manufacturer_mapping = {
|
||||
"MCG": "Atul",
|
||||
"MC1": "Force",
|
||||
"MC2": "Eicher",
|
||||
"MDE": "Kinetic Engineering Limited",
|
||||
"MDH": "Nissan",
|
||||
"MDT": "Kerala Limited",
|
||||
"MD6": "TVS",
|
||||
"MD9": "Shuttles",
|
||||
"MEC": "Daimler",
|
||||
@ -358,8 +357,6 @@ wmi_manufacturer_mapping = {
|
||||
"MET": "Piaggio",
|
||||
"MEX": "Škoda",
|
||||
"ME1": "Yamaha",
|
||||
"ME3": "Royal Enfield",
|
||||
"MYH": "Ather Energy",
|
||||
"MZB": "Kia",
|
||||
"MZZ": "Citroën",
|
||||
"MZ7": "MG",
|
||||
@ -1501,7 +1498,7 @@ def decode_vds(manufacturer, vds):
|
||||
return "Unknown Model"
|
||||
|
||||
|
||||
def decode_vin(vin):
|
||||
def decode_vin_haikalna(vin):
|
||||
if len(vin) != 17:
|
||||
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)
|
||||
|
||||
year_code = vis[0]
|
||||
year = vin_years(year_code)
|
||||
year = vin_years(year_code)[0]
|
||||
model = decode_vds(manufacturer, vds)
|
||||
|
||||
return {
|
||||
'VIN': vin,
|
||||
'Manufacturer': manufacturer,
|
||||
'Year': year,
|
||||
'Model': model
|
||||
data = {
|
||||
'maker': manufacturer,
|
||||
'model': model,
|
||||
'modelYear': year,
|
||||
|
||||
}
|
||||
return data
|
||||
|
||||
|
||||
# JTDKB3FU4G3507653
|
||||
# VR3USHNLWRJ521303
|
||||
# KNARH81E8P5194005
|
||||
# Example usage
|
||||
vin_number = 'VYFED9HP0SJ519559'
|
||||
decoded_vin = decode_vin(vin_number)
|
||||
print(decoded_vin)
|
||||
# vin_number = 'LMXA14AF7PZ356070'
|
||||
# decoded_vin = decode_vin_haikalna(vin_number)
|
||||
# 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
|
||||
|
||||
|
||||
@ -7,7 +8,7 @@ class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
|
||||
('inventory', '0022_rename_log_oportunitylog'),
|
||||
('inventory', '0022_remove_opportunitylog_user_opportunitylog_staff_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
@ -17,7 +18,8 @@ class Migration(migrations.Migration):
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='carfinance',
|
||||
name='services',
|
||||
field=models.ManyToManyField(blank=True, related_name='services', to='django_ledger.itemmodel'),
|
||||
name='additional_services',
|
||||
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
|
||||
|
||||
@ -13,7 +13,7 @@ class Migration(migrations.Migration):
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='carfinance',
|
||||
name='services',
|
||||
name='additional_services',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='carfinance',
|
||||
@ -154,7 +154,6 @@ class CarSpecificationValue(models.Model):
|
||||
verbose_name = "Specification Value"
|
||||
|
||||
|
||||
# Car Model
|
||||
class CarStatusChoices(models.TextChoices):
|
||||
AVAILABLE = "available", _("Available")
|
||||
SOLD = "sold", _("Sold")
|
||||
@ -184,6 +183,7 @@ class AdditionalServices(models.Model, LocalizedNameMixin):
|
||||
def __str__(self):
|
||||
return self.name + " - " + str(self.price)
|
||||
|
||||
|
||||
class Car(models.Model):
|
||||
vin = models.CharField(max_length=17, unique=True, verbose_name=_("VIN"))
|
||||
dealer = models.ForeignKey(
|
||||
@ -308,6 +308,7 @@ class CarReservation(models.Model):
|
||||
verbose_name = _("Car Reservation")
|
||||
verbose_name_plural = _("Car Reservations")
|
||||
|
||||
|
||||
# Car Finance Model
|
||||
class CarFinance(models.Model):
|
||||
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})"
|
||||
|
||||
|
||||
# Colors Model
|
||||
class CarColors(models.Model):
|
||||
car = models.ForeignKey("Car", on_delete=models.CASCADE, related_name="colors")
|
||||
exterior = models.ForeignKey(
|
||||
@ -408,7 +408,6 @@ class CarColors(models.Model):
|
||||
return f"{self.car} ({self.exterior.name}) ({self.interior.name})"
|
||||
|
||||
|
||||
# Custom Card Model
|
||||
class CustomCard(models.Model):
|
||||
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"))
|
||||
@ -471,7 +470,7 @@ class CarLocation(models.Model):
|
||||
"""
|
||||
return self.owner == self.showroom
|
||||
|
||||
# Car Registration Model
|
||||
|
||||
class CarRegistration(models.Model):
|
||||
car = models.ForeignKey(
|
||||
Car,
|
||||
@ -501,7 +500,7 @@ class TimestampedModel(models.Model):
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
#subscription
|
||||
|
||||
class Subscription(models.Model):
|
||||
plan = models.CharField(max_length=255) # e.g. "basic", "premium"
|
||||
start_date = models.DateField()
|
||||
@ -529,7 +528,6 @@ class SubscriptionPlan(models.Model):
|
||||
return f"{self.name} - {self.price}"
|
||||
|
||||
|
||||
# Dealer Model
|
||||
class Dealer(models.Model, LocalizedNameMixin):
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="dealer")
|
||||
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
|
||||
|
||||
|
||||
|
||||
class STAFF_TYPES(models.TextChoices):
|
||||
class StaffTypes(models.TextChoices):
|
||||
MANAGER = "manager", _("Manager")
|
||||
INVENTORY = "inventory", _("Inventory")
|
||||
ACCOUNTANT = "accountant", _("Accountant")
|
||||
SALES = "sales", _("Sales")
|
||||
|
||||
##############################
|
||||
# Additional staff types for later
|
||||
|
||||
# COORDINATOR = "coordinator", _("Coordinator")
|
||||
# RECEPTIONIST = "receptionist", _("Receptionist")
|
||||
# AGENT = "agent", _("Agent")
|
||||
# TECHNICIAN = "technician", _("Technician")
|
||||
# DRIVER = "driver", _("Driver")
|
||||
##############################
|
||||
|
||||
|
||||
class Staff(models.Model, LocalizedNameMixin):
|
||||
@ -628,7 +629,7 @@ class Staff(models.Model, LocalizedNameMixin):
|
||||
name = models.CharField(max_length=255, verbose_name=_("Name"))
|
||||
arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
|
||||
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"))
|
||||
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()}"
|
||||
|
||||
|
||||
# Vendor Model
|
||||
class Vendor(models.Model, LocalizedNameMixin):
|
||||
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="vendors")
|
||||
crn = models.CharField(
|
||||
@ -671,7 +671,6 @@ class Vendor(models.Model, LocalizedNameMixin):
|
||||
return self.name
|
||||
|
||||
|
||||
# Customer Model
|
||||
class Customer(models.Model):
|
||||
dealer = models.ForeignKey(Dealer,
|
||||
on_delete=models.CASCADE,
|
||||
@ -932,6 +931,7 @@ class SaleQuotation(models.Model):
|
||||
last_quotation_number = 0
|
||||
return itertools.count(last_quotation_number + 1)
|
||||
|
||||
|
||||
class SaleQuotationCar(models.Model):
|
||||
quotation = models.ForeignKey(
|
||||
SaleQuotation,
|
||||
|
||||
@ -12,6 +12,7 @@ from pyvin import VIN
|
||||
from django.conf import settings
|
||||
from openai import OpenAI
|
||||
from .models import Car,CarMake,CarModel
|
||||
from inventory.haikalna import decode_vin_haikalna
|
||||
|
||||
|
||||
def get_make(item):
|
||||
@ -37,6 +38,8 @@ def decodevin(vin):
|
||||
return result
|
||||
elif result:=elm(vin):
|
||||
return result
|
||||
elif result:=decode_vin_haikalna(vin):
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
Binary file not shown.
@ -30,3 +30,4 @@ def attr(field, args):
|
||||
else:
|
||||
attrs[definition.strip()] = True
|
||||
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')),
|
||||
#Dashboards
|
||||
path('dashboards/accounting/', views.AccountingDashboard.as_view(), name='accounting'),
|
||||
|
||||
path('test/', views.TestView.as_view(), name='test'),
|
||||
# Dealer URLs
|
||||
path('dealers/<int:pk>/', views.DealerDetailView.as_view(), name='dealer_detail'),
|
||||
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_
|
||||
recipient_list = [to_]
|
||||
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.messages.views import SuccessMessageMixin
|
||||
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 allauth.account import views
|
||||
from django.db.models import Count, F, Value
|
||||
@ -166,6 +166,10 @@ class HomeView(TemplateView):
|
||||
template_name = "index.html"
|
||||
|
||||
|
||||
class TestView(TemplateView):
|
||||
template_name = "test.html"
|
||||
|
||||
|
||||
class AccountingDashboard(LoginRequiredMixin, TemplateView):
|
||||
template_name = "dashboards/accounting.html"
|
||||
|
||||
@ -374,8 +378,9 @@ class CarInventory(LoginRequiredMixin, ListView):
|
||||
model_id = self.kwargs["model_id"]
|
||||
trim_id = self.kwargs["trim_id"]
|
||||
|
||||
dealer = get_user_type(self.request)
|
||||
cars = models.Car.objects.filter(
|
||||
dealer=self.request.user.dealer,
|
||||
dealer=dealer,
|
||||
id_car_make=make_id,
|
||||
id_car_model=model_id,
|
||||
id_car_trim=trim_id,
|
||||
@ -415,7 +420,7 @@ class CarColorCreate(LoginRequiredMixin, CreateView):
|
||||
|
||||
@login_required
|
||||
def inventory_stats_view(request):
|
||||
dealer = request.user.dealer
|
||||
dealer = get_user_type(request)
|
||||
|
||||
# Annotate total cars by make, model, and trim
|
||||
cars = (
|
||||
@ -692,7 +697,6 @@ class DealerUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||
|
||||
class CustomerListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
||||
model = models.Customer
|
||||
home_label = _("customers")
|
||||
context_object_name = "customers"
|
||||
paginate_by = 10
|
||||
template_name = "customers/customer_list.html"
|
||||
@ -700,17 +704,15 @@ class CustomerListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
||||
|
||||
def get_queryset(self):
|
||||
query = self.request.GET.get("q")
|
||||
if self.request.user.is_staff:
|
||||
dealer = self.request.user.staff.dealer
|
||||
customers = models.Customer.objects.filter(
|
||||
dealer=dealer,
|
||||
)
|
||||
dealer = get_user_type(self.request)
|
||||
|
||||
customers = models.Customer.objects.filter(dealer=dealer)
|
||||
|
||||
if query:
|
||||
customers = customers.filter(
|
||||
Q(national_id__icontains=query)
|
||||
| Q(first_name__icontains=query)
|
||||
| Q(last_name__icontains=query)
|
||||
Q(national_id__icontains=query) |
|
||||
Q(first_name__icontains=query) |
|
||||
Q(last_name__icontains=query)
|
||||
)
|
||||
return customers
|
||||
|
||||
@ -879,7 +881,7 @@ class QuotationDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailVie
|
||||
@login_required
|
||||
def generate_invoice(request, pk):
|
||||
quotation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||
dealer = request.user.dealer
|
||||
dealer = get_user_type(request)
|
||||
entity = dealer.entity
|
||||
if not quotation.is_approved:
|
||||
messages.error(
|
||||
@ -1731,7 +1733,8 @@ class EstimateListView(LoginRequiredMixin, ListView):
|
||||
# @csrf_exempt
|
||||
@login_required
|
||||
def create_estimate(request):
|
||||
entity = request.entity
|
||||
dealer = get_user_type(request)
|
||||
entity = dealer.entity
|
||||
if request.method == "POST":
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
@ -1932,7 +1935,8 @@ class InvoiceListView(LoginRequiredMixin, ListView):
|
||||
context_object_name = "invoices"
|
||||
|
||||
def get_queryset(self):
|
||||
entity = self.request.user.dealer.entity
|
||||
dealer = get_user_type(self.request)
|
||||
entity = dealer.entity
|
||||
return entity.get_invoices()
|
||||
|
||||
|
||||
@ -2137,7 +2141,9 @@ def PaymentCreateView(request, pk=None):
|
||||
|
||||
|
||||
def PaymentListView(request):
|
||||
entity = request.user.dealer.entity
|
||||
dealer = get_user_type(request)
|
||||
|
||||
entity = dealer.entity
|
||||
journals = JournalEntryModel.objects.filter(ledger__entity=entity).all()
|
||||
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');
|
||||
};
|
||||
// Selectors
|
||||
const table = document.getElementById('opportunityTable');
|
||||
const table = document.getElementById('inventoryTable');
|
||||
|
||||
if (table) {
|
||||
const options = {
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
<link href="{% static 'vendors/simplebar/simplebar.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 href="{% static 'css/custom.css' %}" rel="stylesheet">
|
||||
{% if LANGUAGE_CODE == 'en' %}
|
||||
<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">
|
||||
@ -39,6 +39,7 @@
|
||||
<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">
|
||||
{% endif %}
|
||||
|
||||
{% block extra_css %}{% endblock extra_css %}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load custom_filters %}
|
||||
{% load i18n static custom_filters %}
|
||||
{% block title %}{{ _("Car Details") }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<style>
|
||||
.color-circle {
|
||||
width: 32px;
|
||||
@ -13,82 +13,16 @@
|
||||
border-color: #fff;
|
||||
}
|
||||
</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 -->
|
||||
|
||||
<div class="row gx-6">
|
||||
<div class="container-fluid">
|
||||
<div class="row g-3 justify-content-between">
|
||||
<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">
|
||||
<div class="table-responsive scrollbar mb-3">
|
||||
<table class="table table-sm fs-9 mb-0 overflow-hidden">
|
||||
<tr>
|
||||
<th>{% trans "VIN" %}</th>
|
||||
<td>{{ car.vin }}</td>
|
||||
@ -142,11 +76,7 @@
|
||||
<tr>
|
||||
<th>{% trans 'specifications'|capfirst %}</th>
|
||||
<td>
|
||||
<button type="button"
|
||||
class="btn btn-phoenix-primary btn-sm"
|
||||
id="specification-btn"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#specificationsModal">
|
||||
<button type="button" class="btn btn-phoenix-primary btn-sm" id="specification-btn" data-bs-toggle="modal" data-bs-target="#specificationsModal">
|
||||
{% trans 'view'|capfirst %}
|
||||
</button>
|
||||
</td>
|
||||
@ -164,10 +94,7 @@
|
||||
<tr>
|
||||
<th>{% trans "Custom Card" %}</th>
|
||||
<td>
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-phoenix-success"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#customCardModal">
|
||||
<button type="button" class="btn btn-sm btn-phoenix-success" data-bs-toggle="modal" data-bs-target="#customCardModal">
|
||||
{% trans 'Add' %}
|
||||
</button>
|
||||
</td>
|
||||
@ -176,19 +103,12 @@
|
||||
<tr>
|
||||
<th>{% trans 'Location'|capfirst %}</th>
|
||||
<td>
|
||||
{% if car.location %}
|
||||
{% if car.location.is_owner_showroom %}
|
||||
{% trans 'Our Showroom' %}
|
||||
{% else %}
|
||||
{{ car.location.showroom.get_local_name }}
|
||||
{% endif %}
|
||||
<a href="{% url 'transfer' car.location.pk %}"
|
||||
class="btn btn-phoenix-danger btn-sm">
|
||||
{% if car.location %} {% if car.location.is_owner_showroom %} {% trans 'Our Showroom' %} {% else %} {{ car.location.showroom.get_local_name }} {% endif %}
|
||||
<a href="{% url 'transfer' car.location.pk %}" class="btn btn-phoenix-danger btn-sm">
|
||||
{% trans "transfer"|capfirst %}
|
||||
</a>
|
||||
{% else %} {% trans "No location available." %}
|
||||
<a href="{% url 'add_car_location' car.pk %}"
|
||||
class="btn btn-phoenix-success btn-sm ms-2">
|
||||
<a href="{% url 'add_car_location' car.pk %}" class="btn btn-phoenix-success btn-sm ms-2">
|
||||
{% trans "Add" %}
|
||||
</a>
|
||||
</td>
|
||||
@ -201,17 +121,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
|
||||
<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 %}
|
||||
<div class="table-responsive">
|
||||
<table class="table fs-9 mb-0">
|
||||
{% if perms.inventory.view_carfinance %}
|
||||
<tr>
|
||||
<th>{% trans "Cost Price"|capfirst %}</th>
|
||||
@ -249,16 +167,13 @@
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
{% if perms.inventory.change_carfinance %}
|
||||
<a href="{% url 'car_finance_update' car.finances.pk %}"
|
||||
class="btn btn-phoenix-warning btn-sm mb-3">
|
||||
<a href="{% url 'car_finance_update' car.finances.pk %}" class="btn btn-phoenix-warning btn-sm mb-3">
|
||||
{% trans "Edit" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
<p>{% trans "No finance details available." %}</p>
|
||||
<a href="{% url 'car_finance_create' car.pk %}"
|
||||
class="btn btn-phoenix-success btn-sm mb-3">
|
||||
<a href="{% url 'car_finance_create' car.pk %}" class="btn btn-phoenix-success btn-sm mb-3">
|
||||
{% trans "Add" %}
|
||||
</a>
|
||||
</td>
|
||||
@ -268,12 +183,11 @@
|
||||
</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>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table fs-9 mb-0">
|
||||
<tbody class="align-middle">
|
||||
<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>
|
||||
@ -282,9 +196,7 @@
|
||||
<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>
|
||||
<div class="text-end color-circle" style="background-color: rgb({{ color.exterior.rgb }});"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -293,13 +205,10 @@
|
||||
<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>
|
||||
<div class="text-end color-circle" style="background-color: rgb({{ color.interior.rgb }});"></div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% endfor %} {% else %}
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
{% trans "No colors available for this car." %}
|
||||
@ -313,18 +222,16 @@
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</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 'Reservations Details' %}</p>
|
||||
<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 %}
|
||||
<table class="table fs-9 mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "Reserved By" %}</th>
|
||||
@ -341,50 +248,92 @@
|
||||
{% if reservation.is_active %}
|
||||
<form method="post" action="{% url 'reservations' reservation.id %}">
|
||||
{% csrf_token %}
|
||||
<button type="submit"
|
||||
name="action"
|
||||
value="renew"
|
||||
class="btn btn-sm btn-phoenix-success">
|
||||
<button type="submit" name="action" value="renew" class="btn btn-sm btn-phoenix-success">
|
||||
{% trans "Renew" %}
|
||||
</button>
|
||||
<button type="submit"
|
||||
name="action"
|
||||
value="cancel"
|
||||
class="btn btn-sm btn-phoenix-secondary">
|
||||
<button type="submit" name="action" value="cancel" class="btn btn-sm btn-phoenix-secondary">
|
||||
{% trans "Cancel" %}
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<span class="badge bg-danger"
|
||||
style="width: 120px;">
|
||||
<span class="badge bg-danger" style="width: 120px;">
|
||||
{% trans "Expired" %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% endfor %} {% else %}
|
||||
<tr>
|
||||
<td>
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-phoenix-success"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#reserveModal">
|
||||
<button type="button" class="btn btn-sm btn-phoenix-success" data-bs-toggle="modal" data-bs-target="#reserveModal">
|
||||
{% trans 'Reserve' %}
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
{% endif %}
|
||||
</table>
|
||||
<div class="table-responsive">
|
||||
</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>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
@ -403,7 +352,7 @@
|
||||
return cookieValue;
|
||||
}
|
||||
|
||||
|
||||
const csrfToken = getCookie("csrftoken");
|
||||
const ajaxUrl = "{% url 'ajax_handler' %}";
|
||||
|
||||
const modal = document.getElementById("customCardModal");
|
||||
@ -436,7 +385,7 @@
|
||||
fetch(`${ajaxUrl}?action=get_specifications&trim_id={{ car.id_car_trim.id_car_trim }}`, {
|
||||
headers: {
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
"X-CSRFToken": {% csrf_token %},
|
||||
"X-CSRFToken": csrfToken,
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
@ -472,7 +421,7 @@
|
||||
const response = await fetch(`{% url 'reserve_car' car.pk %}`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"X-CSRFToken": {% csrf_token %},
|
||||
"X-CSRFToken": csrfToken,
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,135 +1,135 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n static %}
|
||||
|
||||
{% block title %}
|
||||
{% trans 'inventory'|capfirst %}
|
||||
{% endblock %}
|
||||
|
||||
{% block inventory %}
|
||||
<a class="nav-link active fw-bold">{% trans "inventory" %}<span class="visually-hidden">(current)</span></a>
|
||||
{% endblock %}
|
||||
|
||||
{% block 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="row g-3 justify-content-between mb-4">
|
||||
<div class="row g-3 justify-content-between">
|
||||
<div class="col-sm-12">
|
||||
<!---->
|
||||
<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>
|
||||
<!--/.bg-holder-->
|
||||
|
||||
<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>
|
||||
<!--/.bg-holder-->
|
||||
|
||||
</div>
|
||||
<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">
|
||||
<div class="card-body px-lg-5 position-relative">
|
||||
<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>
|
||||
<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="row g-3 justify-content-between mt-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>
|
||||
<div class="table-list" id="inventoryTable">
|
||||
<div class="table-responsive scrollbar mb-3">
|
||||
<table class="table table-sm fs-9 mb-0 overflow-hidden">
|
||||
<thead class="text-body">
|
||||
<tr>
|
||||
<th>{% trans "VIN" %}</th>
|
||||
<th>{% trans "Year" %}</th>
|
||||
<th>{% trans 'Exterior Color' %}</th>
|
||||
<th>{% trans 'Interior Color' %}</th>
|
||||
<th>{% trans "Showroom Location" %}</th>
|
||||
<th>{% trans "Actions" %}</th>
|
||||
<th class="pe-1 align-middle white-space-nowrap text-center" data-sort="stock">{% trans 'Stock' %}</th>
|
||||
<th class="pe-1 align-middle white-space-nowrap text-start" data-sort="vin" style="min-width: 4.5rem;">{% trans "VIN" %}</th>
|
||||
<th class="pe-1 align-middle white-space-nowrap text-center" data-sort="date">{% trans "Year"|upper %}</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 class="pe-1 align-middle white-space-nowrap text-center" data-sort="intColor" style="min-width: 8.5rem">{% trans 'Interior Color'|upper %}</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>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for car in cars %}
|
||||
<tr class="{% if car.is_reserved %}table-danger{% endif %}">
|
||||
<td>{{ car.vin }}</td>
|
||||
<td>{{ car.year }}</td>
|
||||
<tr>
|
||||
<td class="align-middle white-space-nowrap text-center fw-bold text-body-tertiary">
|
||||
{% 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 %}
|
||||
<td>
|
||||
<td class="align-middle white-space-nowrap text-body fs-9 text-start">
|
||||
<div class="d-flex flex-column align-items-center">
|
||||
<span class="color-div"
|
||||
style="background-color: rgb({{ car.colors.first.exterior.rgb }});"
|
||||
title="{{ car.colors.first.exterior.get_local_name }}">
|
||||
</span>
|
||||
<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>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<td class="align-middle white-space-nowrap text-body fs-9 text-start">
|
||||
<div class="d-flex flex-column align-items-center">
|
||||
<span class="color-div"
|
||||
style="background-color: rgb({{ car.colors.first.interior.rgb }});"
|
||||
title="{{ car.colors.first.interior.get_local_name }}">
|
||||
</span>
|
||||
<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>
|
||||
</div>
|
||||
</td>
|
||||
{% else %}
|
||||
<td><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>
|
||||
<td class="align-middle white-space-nowrap text-body fs-9 text-center"><span class="color-div">{% trans 'No Color' %}</span></td>
|
||||
{% endif %}
|
||||
<td class="align-middle white-space-nowrap text-body fs-9 text-center">
|
||||
{% if car.location.is_owner_showroom %}
|
||||
<td> {% trans 'Our Showroom' %}</td>
|
||||
{% trans 'Our Showroom' %}
|
||||
{% else %}
|
||||
<td>{{ car.location.showroom.get_local_name }}</td>
|
||||
{{ car.location.showroom.get_local_name }}
|
||||
{% endif %}
|
||||
<td>
|
||||
<a href="{% url 'car_detail' car.pk %}" class="btn btn-success">
|
||||
{% trans "view"|capfirst %}
|
||||
</a>
|
||||
</td>
|
||||
<td class="status align-middle white-space-nowrap text-center fw-bold text-body-tertiary">
|
||||
{% if car.status == "available" %}
|
||||
<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>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<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>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- Pagination -->
|
||||
{% if is_paginated %}
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination pagination-sm justify-content-center">
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page=1" aria-label="First">
|
||||
««
|
||||
</a>
|
||||
<a class="page-link" href="?page=1" aria-label="First">««</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous">
|
||||
«
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled">
|
||||
<span class="page-link">««</span>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<span class="page-link">«</span>
|
||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous">«</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% for num in page_obj.paginator.page_range %}
|
||||
@ -145,21 +145,10 @@
|
||||
{% 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>
|
||||
<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>
|
||||
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}" aria-label="Last">»»</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
@ -168,5 +157,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% 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