edit styles
This commit is contained in:
parent
9e0824de6d
commit
b227d9ff5b
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,7 +5,7 @@
|
||||
__pycache__
|
||||
db.sqlite3
|
||||
media
|
||||
|
||||
./car_inventorysettings.py
|
||||
# Backup files #
|
||||
*.bak
|
||||
|
||||
|
||||
Binary file not shown.
@ -9,7 +9,7 @@ https://docs.djangoproject.com/en/5.0/topics/settings/
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/5.0/ref/settings/
|
||||
"""
|
||||
|
||||
from decimal import Decimal
|
||||
from pathlib import Path
|
||||
import os
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@ -26,7 +26,7 @@ SECRET_KEY = 'django-insecure-gc9bh4*3=b6hihdnaom0edjsbxh$5t)aap@e8p&340r7)*)qb8
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ['10.10.1.109',"10.10.1.120", 'localhost', '127.0.0.1', '192.168.1.135', '172.20.10.4']
|
||||
ALLOWED_HOSTS = ['10.10.1.109', 'localhost', '127.0.0.1', '192.168.1.135', '172.20.10.4']
|
||||
|
||||
# Application definition
|
||||
|
||||
@ -110,9 +110,9 @@ WSGI_APPLICATION = 'car_inventory.wsgi.application'
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django_prometheus.db.backends.postgresql",
|
||||
"NAME": "haikal",
|
||||
"USER": "haikal",
|
||||
"PASSWORD": "haikal",
|
||||
"NAME": "haikal_app",
|
||||
"USER": "f95166",
|
||||
"PASSWORD": "Kfsh&rc9788",
|
||||
"HOST": "localhost",
|
||||
"PORT": 5432,
|
||||
}
|
||||
@ -255,3 +255,7 @@ LOGGING = {
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# Global Settings
|
||||
CURRENCY = _('SAR')
|
||||
VAT_RATE = Decimal('0.15')
|
||||
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.
@ -15,6 +15,7 @@ admin.site.register(models.CustomCard)
|
||||
admin.site.register(models.CarSpecificationValue)
|
||||
admin.site.register(models.ExteriorColors)
|
||||
admin.site.register(models.InteriorColors)
|
||||
admin.site.register(models.CarLocation)
|
||||
|
||||
@admin.register(models.CarMake)
|
||||
class CarMakeAdmin(admin.ModelAdmin):
|
||||
|
||||
@ -4,3 +4,6 @@ from django.apps import AppConfig
|
||||
class InventoryConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'inventory'
|
||||
|
||||
def ready(self):
|
||||
import inventory.signals
|
||||
@ -13,7 +13,8 @@ from .models import (
|
||||
CarColors,
|
||||
ExteriorColors,
|
||||
InteriorColors,
|
||||
SaleQuotation
|
||||
SaleQuotation,
|
||||
CarLocation
|
||||
)
|
||||
from django.forms import ModelMultipleChoiceField
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@ -97,6 +98,15 @@ class CarFinanceForm(AddClassMixin, forms.ModelForm):
|
||||
exclude = ['car', 'profit_margin', 'vat_amount', 'total', 'vat_rate']
|
||||
|
||||
|
||||
class CarLocationForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = CarLocation
|
||||
fields = ['showroom', 'description']
|
||||
widgets = {
|
||||
'description': forms.Textarea(attrs={'rows': 2, 'class': 'form-control'}),
|
||||
}
|
||||
|
||||
|
||||
# Custom Card Form
|
||||
class CustomCardForm(forms.ModelForm):
|
||||
custom_date = forms.DateTimeField(
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from uuid import uuid4
|
||||
from django.conf import settings
|
||||
from django.db import models, transaction
|
||||
from django.contrib.auth.models import User
|
||||
from django.db.models.signals import pre_save, post_save
|
||||
@ -21,6 +22,7 @@ from django.core.exceptions import ValidationError
|
||||
from phonenumber_field.modelfields import PhoneNumberField
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.timezone import now
|
||||
|
||||
from .mixins import LocalizedNameMixin
|
||||
|
||||
|
||||
@ -222,10 +224,10 @@ class Car(models.Model):
|
||||
|
||||
|
||||
class CarReservation(models.Model):
|
||||
car = models.ForeignKey('Car', on_delete=models.CASCADE, related_name='reservations')
|
||||
reserved_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
reserved_at = models.DateTimeField(auto_now_add=True)
|
||||
reserved_until = models.DateTimeField()
|
||||
car = models.ForeignKey('Car', on_delete=models.CASCADE, related_name='reservations', verbose_name=_("Car"))
|
||||
reserved_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='reservations', verbose_name=_("Reserved By"))
|
||||
reserved_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Reserved At"))
|
||||
reserved_until = models.DateTimeField(verbose_name=_("Reserved Until"))
|
||||
|
||||
def is_active(self):
|
||||
return self.reserved_until > now()
|
||||
@ -233,11 +235,13 @@ class CarReservation(models.Model):
|
||||
class Meta:
|
||||
unique_together = ('car', 'reserved_until')
|
||||
ordering = ['-reserved_at']
|
||||
verbose_name = _("Car Reservation")
|
||||
verbose_name_plural = _("Car Reservations")
|
||||
|
||||
|
||||
# Car Finance Model
|
||||
class CarFinance(models.Model):
|
||||
car = models.ForeignKey(Car, on_delete=models.CASCADE, related_name='finances')
|
||||
car = models.OneToOneField(Car, on_delete=models.CASCADE, related_name='finances')
|
||||
cost_price = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Cost Price"))
|
||||
selling_price = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Selling Price"))
|
||||
profit_margin = models.DecimalField(max_digits=14,
|
||||
@ -258,35 +262,35 @@ class CarFinance(models.Model):
|
||||
default=Decimal('0.00'))
|
||||
custom_card_fee = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Custom Card Fee"),
|
||||
default=Decimal('0.00'))
|
||||
vat_rate = models.DecimalField(max_digits=14, decimal_places=2, default=Decimal('0.15'), verbose_name=_("VAT Rate"),)
|
||||
total = models.DecimalField(max_digits=14, decimal_places=2, default=Decimal('0.00'), null=True, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.selling_price}"
|
||||
return f"Car: {self.car}, Selling Price: {self.selling_price}"
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
vat_rate = settings.VAT_RATE
|
||||
self.full_clean()
|
||||
try:
|
||||
services = self.administration_fee + self.transportation_fee + self.custom_card_fee
|
||||
price_after_discount = self.selling_price - self.discount_amount
|
||||
total_vat_amount = (price_after_discount + services) * self.vat_rate
|
||||
self.vat_amount = self.selling_price * self.vat_rate
|
||||
total_vat_amount = (price_after_discount + services) * vat_rate
|
||||
self.vat_amount = price_after_discount * vat_rate
|
||||
self.profit_margin = self.selling_price - self.cost_price - self.discount_amount - self.registration_fee
|
||||
self.total = price_after_discount + services + total_vat_amount + self.registration_fee
|
||||
|
||||
except InvalidOperation as e:
|
||||
raise ValidationError(_("Invalid decimal operation: %s") % str(e))
|
||||
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Car Financial Details")
|
||||
|
||||
@property
|
||||
def total_vat_amount(self):
|
||||
vat_rate = settings.VAT_RATE
|
||||
services = self.administration_fee + self.transportation_fee + self.custom_card_fee
|
||||
price_after_discount = self.selling_price - self.discount_amount
|
||||
return (price_after_discount + services) * self.vat_rate
|
||||
return (price_after_discount + services) * vat_rate
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Car Financial Details")
|
||||
verbose_name_plural = _("Car Financial Details")
|
||||
|
||||
|
||||
class ExteriorColors(models.Model, LocalizedNameMixin):
|
||||
@ -332,7 +336,7 @@ class CarColors(models.Model):
|
||||
|
||||
# Custom Card Model
|
||||
class CustomCard(models.Model):
|
||||
car = models.ForeignKey(Car, on_delete=models.CASCADE, related_name='custom_cards', verbose_name=_("Car"))
|
||||
car = models.OneToOneField(Car, on_delete=models.CASCADE, related_name='custom_cards', verbose_name=_("Car"))
|
||||
custom_number = models.CharField(max_length=255, verbose_name=_("Custom Number"))
|
||||
custom_date = models.DateField(verbose_name=_("Custom Date"))
|
||||
|
||||
@ -344,6 +348,55 @@ class CustomCard(models.Model):
|
||||
return f"{self.car} - {self.custom_number}"
|
||||
|
||||
|
||||
class CarLocation(models.Model):
|
||||
car = models.OneToOneField(
|
||||
Car,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='location',
|
||||
verbose_name=_("Car")
|
||||
)
|
||||
owner = models.ForeignKey(
|
||||
'Dealer',
|
||||
on_delete=models.CASCADE,
|
||||
related_name='owned_cars',
|
||||
verbose_name=_("Owner"),
|
||||
help_text=_("Dealer who owns the car.")
|
||||
)
|
||||
showroom = models.ForeignKey(
|
||||
'Dealer',
|
||||
on_delete=models.CASCADE,
|
||||
related_name='showroom_cars',
|
||||
verbose_name=_("Showroom"),
|
||||
help_text=_("Dealer where the car is displayed (can be the owner).")
|
||||
)
|
||||
description = models.TextField(
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name=_("Description"),
|
||||
help_text=_("Optional description about the showroom placement.")
|
||||
)
|
||||
created_at = models.DateTimeField(
|
||||
auto_now_add=True,
|
||||
verbose_name=_("Created At")
|
||||
)
|
||||
updated_at = models.DateTimeField(
|
||||
auto_now=True,
|
||||
verbose_name=_("Last Updated")
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Car Location")
|
||||
verbose_name_plural = _("Car Locations")
|
||||
|
||||
def __str__(self):
|
||||
return f"Car: {self.car}, Showroom: {self.showroom}, Owner: {self.owner}"
|
||||
|
||||
def is_owner_showroom(self):
|
||||
"""
|
||||
Returns True if the showroom is the same as the owner.
|
||||
"""
|
||||
return self.owner == self.showroom
|
||||
|
||||
# Car Registration Model
|
||||
class CarRegistration(models.Model):
|
||||
car = models.ForeignKey(Car, on_delete=models.CASCADE, related_name='registrations', verbose_name=_("Car"))
|
||||
|
||||
@ -2,11 +2,27 @@ from random import randint
|
||||
|
||||
from django.db.models.signals import post_save, post_delete
|
||||
from django.dispatch import receiver
|
||||
from django_ledger.models import EntityModel, VendorModel, CustomerModel, UnitOfMeasureModel
|
||||
from django_ledger.models import EntityModel, VendorModel, CustomerModel, UnitOfMeasureModel, AccountModel, \
|
||||
ItemModelAbstract
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from . import models
|
||||
|
||||
|
||||
@receiver(post_save, sender=models.Car)
|
||||
def create_car_location(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Signal to create or update the car's location when a car instance is saved.
|
||||
"""
|
||||
if created:
|
||||
models.CarLocation.objects.create(
|
||||
car=instance,
|
||||
owner=instance.dealer,
|
||||
showroom=instance.dealer,
|
||||
description=f"Initial location set for car {instance.vin}."
|
||||
)
|
||||
print("Car Location created")
|
||||
|
||||
|
||||
@receiver(post_save, sender=models.CarReservation)
|
||||
def update_car_status_on_reservation(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
@ -24,21 +40,21 @@ def update_car_status_on_reservation_delete(sender, instance, **kwargs):
|
||||
|
||||
|
||||
# Create Entity
|
||||
@receiver(post_save, sender=models.Dealer)
|
||||
def create_ledger_entity(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
entity = EntityModel.objects.create(
|
||||
name=instance.name,
|
||||
admin=instance.user,
|
||||
address_1=instance.address,
|
||||
fy_start_month=1,
|
||||
accrual_method=True,
|
||||
depth=0,
|
||||
)
|
||||
|
||||
default_coa = entity.create_chart_of_accounts(assign_as_default=True,
|
||||
commit=True,
|
||||
coa_name=_("Chart of Accounts"))
|
||||
# @receiver(post_save, sender=models.Dealer)
|
||||
# def create_ledger_entity(sender, instance, created, **kwargs):
|
||||
# if created:
|
||||
# entity = EntityModel.objects.create(
|
||||
# name=instance.name,
|
||||
# admin=instance.user,
|
||||
# address_1=instance.address,
|
||||
# fy_start_month=1,
|
||||
# accrual_method=True,
|
||||
# depth=0,
|
||||
# )
|
||||
#
|
||||
# default_coa = entity.create_chart_of_accounts(assign_as_default=True,
|
||||
# commit=True,
|
||||
# coa_name=_("Chart of Accounts"))
|
||||
# entity.create_account(
|
||||
# coa_model=coa,
|
||||
# code=1010,
|
||||
@ -48,25 +64,56 @@ def create_ledger_entity(sender, instance, created, **kwargs):
|
||||
# )
|
||||
# entity.create_account(
|
||||
# coa_model=coa,
|
||||
# code=1100,
|
||||
# role='asset_ca_recv',
|
||||
# name=_('Accounts Receivable'),
|
||||
# balance_type="debit",
|
||||
# )
|
||||
# entity.create_account(
|
||||
# coa_model=coa,
|
||||
# code=1200,
|
||||
# role='asset_ca_inv',
|
||||
# name=_('Inventory'),
|
||||
# balance_type="debit",
|
||||
# active=True)
|
||||
#
|
||||
# entity.create_account(
|
||||
# coa_model=coa,
|
||||
# code=2010,
|
||||
# role='lia_cl_acc_payable',
|
||||
# name=_('Accounts Payable'),
|
||||
# balance_type="credit",
|
||||
# active=True)
|
||||
#
|
||||
# entity.create_account(
|
||||
# coa_model=coa,
|
||||
# code=4010,
|
||||
# role='in_operational',
|
||||
# name=_('Sales Income'),
|
||||
# balance_type="credit",
|
||||
# active=True)
|
||||
#
|
||||
# entity.create_account(
|
||||
# coa_model=coa,
|
||||
# code=5010,
|
||||
# role='cogs_regular',
|
||||
# name=_('Cost of Goods Sold'),
|
||||
# balance_type="debit",
|
||||
# active=True)
|
||||
|
||||
|
||||
if default_coa:
|
||||
entity.populate_default_coa(activate_accounts=True, coa_model=default_coa)
|
||||
|
||||
uom_name = _("Unit")
|
||||
unit_abbr = _("U")
|
||||
|
||||
entity.create_uom(uom_name, unit_abbr)
|
||||
|
||||
print(f"Ledger entity created for Dealer: {instance.name}")
|
||||
# if default_coa:
|
||||
# entity.populate_default_coa(activate_accounts=True, coa_model=default_coa)
|
||||
#
|
||||
# uom_name = _("Unit")
|
||||
# unit_abbr = _("U")
|
||||
#
|
||||
# entity.create_uom(uom_name, unit_abbr)
|
||||
#
|
||||
# print(f"Ledger entity created for Dealer: {instance.name}")
|
||||
|
||||
|
||||
# # Create Vendor
|
||||
# Create Vendor
|
||||
@receiver(post_save, sender=models.Vendor)
|
||||
def create_ledger_vendor(sender, instance, created, **kwargs):
|
||||
|
||||
@ -113,55 +160,64 @@ def create_customer(sender, instance, created, **kwargs):
|
||||
|
||||
|
||||
# Create Item
|
||||
@receiver(post_save, sender=models.Car)
|
||||
def create_item_model(sender, instance, created, **kwargs):
|
||||
item_name = f"{instance.year} - {instance.id_car_make} - {instance.id_car_model} - {instance.id_car_trim}"
|
||||
uom_name = _("Car")
|
||||
unit_abbr = _("C")
|
||||
|
||||
uom, uom_created = UnitOfMeasureModel.objects.get_or_create(
|
||||
name=uom_name,
|
||||
unit_abbr=unit_abbr
|
||||
)
|
||||
|
||||
if uom_created:
|
||||
print(f"UOM created: {uom_name}")
|
||||
else:
|
||||
print(f"Using existing UOM: {uom_name}")
|
||||
|
||||
entity = EntityModel.objects.filter(name=instance.dealer.name).first()
|
||||
|
||||
inventory_account = AccountModel.objects.first()
|
||||
cogs_account = AccountModel.objects.first()
|
||||
earnings_account = AccountModel.objects.first()
|
||||
|
||||
entity.create_i
|
||||
|
||||
item = ItemModel.objects.create(
|
||||
entity=entity,
|
||||
uom=uom,
|
||||
name=item_name,
|
||||
item_role=ItemModelAbstract.ITEM_ROLE_INVENTORY,
|
||||
item_type=ItemModelAbstract.ITEM_TYPE_MATERIAL,
|
||||
item_id=instance.vin,
|
||||
sold_as_unit=True,
|
||||
inventory_received=1.00,
|
||||
inventory_received_value=0.00,
|
||||
inventory_account=inventory_account,
|
||||
for_inventory=True,
|
||||
is_product_or_service=True,
|
||||
cogs_account=cogs_account,
|
||||
earnings_account=earnings_account,
|
||||
is_active=True,
|
||||
additional_info={
|
||||
"remarks": instance.remarks,
|
||||
"status": instance.status,
|
||||
"stock_type": instance.stock_type,
|
||||
"mileage": instance.mileage,
|
||||
},
|
||||
)
|
||||
|
||||
print(f"ItemModel {'created' if created else 'updated'} for Car: {item.name}")
|
||||
# @receiver(post_save, sender=models.Car)
|
||||
# def create_item_model(sender, instance, created, **kwargs):
|
||||
# item_name = f"{instance.year} - {instance.id_car_make} - {instance.id_car_model} - {instance.id_car_trim}"
|
||||
# uom_name = _("Car")
|
||||
# unit_abbr = _("C")
|
||||
#
|
||||
# uom, uom_created = UnitOfMeasureModel.objects.get_or_create(
|
||||
# name=uom_name,
|
||||
# unit_abbr=unit_abbr
|
||||
# )
|
||||
#
|
||||
# if uom_created:
|
||||
# print(f"UOM created: {uom_name}")
|
||||
# else:
|
||||
# print(f"Using existing UOM: {uom_name}")
|
||||
#
|
||||
# entity = EntityModel.objects.filter(name=instance.dealer.name).first()
|
||||
#
|
||||
# inventory_account = AccountModel.objects.first()
|
||||
# cogs_account = AccountModel.objects.first()
|
||||
# earnings_account = AccountModel.objects.first()
|
||||
#
|
||||
# entity.create_item_product(
|
||||
# item_name=item_name,
|
||||
# item_role=ItemModelAbstract.ITEM_ROLE_PRODUCT,
|
||||
# item_type=ItemModelAbstract.ITEM_TYPE_MATERIAL,
|
||||
# item_id=instance.vin,
|
||||
# sold_as_unit=True,
|
||||
# inventory_received=1.00,
|
||||
# inventory_received_value=0.00,
|
||||
# inventory_account=inventory_account,
|
||||
# for_inventory=True,)
|
||||
#
|
||||
# item = ItemModel.objects.create(
|
||||
# entity=entity,
|
||||
# uom=uom,
|
||||
# name=item_name,
|
||||
# item_role=ItemModelAbstract.ITEM_ROLE_INVENTORY,
|
||||
# item_type=ItemModelAbstract.ITEM_TYPE_MATERIAL,
|
||||
# item_id=instance.vin,
|
||||
# sold_as_unit=True,
|
||||
# inventory_received=1.00,
|
||||
# inventory_received_value=0.00,
|
||||
# inventory_account=inventory_account,
|
||||
# for_inventory=True,
|
||||
# is_product_or_service=True,
|
||||
# cogs_account=cogs_account,
|
||||
# earnings_account=earnings_account,
|
||||
# is_active=True,
|
||||
# additional_info={
|
||||
# "remarks": instance.remarks,
|
||||
# "status": instance.status,
|
||||
# "stock_type": instance.stock_type,
|
||||
# "mileage": instance.mileage,
|
||||
# },
|
||||
# )
|
||||
#
|
||||
# print(f"ItemModel {'created' if created else 'updated'} for Car: {item.name}")
|
||||
#
|
||||
#
|
||||
# # update price - CarFinance
|
||||
|
||||
@ -56,6 +56,8 @@ urlpatterns = [
|
||||
path('cars/add/', views.CarCreateView.as_view(), name='car_add'),
|
||||
path('ajax/', views.AjaxHandlerView.as_view(), name='ajax_handler'),
|
||||
path('cars/<int:car_pk>/add-color/', views.CarColorCreate.as_view(), name='add_color'),
|
||||
path('car/<int:car_pk>/location/add/', views.CarLocationCreateView.as_view(), name='add_car_location'),
|
||||
path('car/<int:pk>/location/update/', views.CarLocationUpdateView.as_view(), name='transfer'),
|
||||
# path('cars/<int:car_pk>/colors/<int:pk>/update/',views.CarColorUpdateView.as_view(),name='color_update'),
|
||||
|
||||
path('cars/reserve/<int:car_id>/', views.reserve_car_view, name='reserve_car'),
|
||||
|
||||
@ -167,7 +167,9 @@ class AjaxHandlerView(LoginRequiredMixin, View):
|
||||
|
||||
def get_models(self, request):
|
||||
make_id = request.GET.get('make_id')
|
||||
car_models = models.CarModel.objects.filter(id_car_make=make_id).values('id_car_model', 'name', 'arabic_name')
|
||||
car_models = (models.CarModel.objects.filter(id_car_make=make_id)
|
||||
.values('id_car_model', 'name', 'arabic_name')
|
||||
.order_by('name'))
|
||||
return JsonResponse(list(car_models), safe=False)
|
||||
|
||||
def get_series(self, request):
|
||||
@ -405,6 +407,31 @@ class CarDeleteView(LoginRequiredMixin, DeleteView):
|
||||
return super().delete(request, *args, **kwargs)
|
||||
|
||||
|
||||
class CarLocationCreateView(CreateView):
|
||||
model = models.CarLocation
|
||||
form_class = forms.CarLocationForm
|
||||
template_name = 'inventory/car_location_form.html'
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy('car_detail', kwargs={'pk': self.object.car.pk})
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.car = get_object_or_404(models.Car, pk=self.kwargs['car_pk'])
|
||||
form.instance.owner = self.request.user.dealer
|
||||
form.save()
|
||||
messages.success(self.request, 'Car saved successfully.')
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class CarLocationUpdateView(UpdateView):
|
||||
model = models.CarLocation
|
||||
form_class = forms.CarLocationForm
|
||||
template_name = 'inventory/car_location_form.html'
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy('car_detail', kwargs={'pk': self.object.car.pk})
|
||||
|
||||
|
||||
class CustomCardCreateView(LoginRequiredMixin, CreateView):
|
||||
model = models.CustomCard
|
||||
form_class = forms.CustomCardForm
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
static/images/logos/.DS_Store
vendored
BIN
static/images/logos/.DS_Store
vendored
Binary file not shown.
@ -149,6 +149,27 @@
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<th>{% trans 'Showroom Location' %}</th>
|
||||
<td>
|
||||
{% if car.location %}
|
||||
{% if car.location.is_owner_showroom %}
|
||||
{% trans 'Our Showroom' %}
|
||||
{% else %}
|
||||
{{ car.location.showroom.get_local_name }}
|
||||
{% endif %}
|
||||
<a href="{% url 'transfer' car.location.pk %}" class="btn btn-danger btn-sm">{% trans "transfer" %}</a>
|
||||
{% else %}
|
||||
|
||||
{% trans "No location available." %}
|
||||
<a href="{% url 'add_car_location' car.pk %}"
|
||||
class="btn btn-success btn-sm mb-3 ms-2">
|
||||
{% trans "Add" %}
|
||||
</a>
|
||||
</td>
|
||||
|
||||
{% endif %}
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-lg-6 col-xl-6">
|
||||
@ -304,7 +325,7 @@
|
||||
<div class="row g-4">
|
||||
<div class="">
|
||||
<!-- Actions -->
|
||||
<a href="#" class="btn btn-danger btn-sm">{% trans "transfer" %}</a>
|
||||
|
||||
|
||||
<a href="{% url 'car_update' car.pk %}" class="btn btn-warning btn-sm">{% trans "Edit" %}</a>
|
||||
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% block title %}
|
||||
{% trans 'inventory'|capfirst %}
|
||||
{% endblock %}
|
||||
{% block inventory %}<a class="nav-link active fw-bold">{% trans "inventory" %}<span class="visually-hidden">(current)</span></a>{% endblock %}
|
||||
{% block inventory %}
|
||||
<a class="nav-link active fw-bold">{% trans "inventory" %}<span class="visually-hidden">(current)</span></a>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<style>
|
||||
<style>
|
||||
.color-div {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
@ -15,115 +16,136 @@
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
<div class="d-flex flex-column min-vh-100">
|
||||
<div class="d-flex flex-column flex-sm-grow-1 ms-sm-14 p-1">
|
||||
<main class="d-grid gap-4 p-1">
|
||||
<div class="row g-4">
|
||||
<div class="col-lg-6 col-xl-12">
|
||||
|
||||
|
||||
<div class="container-fluid p-2">
|
||||
<form method="get">
|
||||
<div class="input-group input-group-sm">
|
||||
<button id="inputGroup-sizing-sm"
|
||||
class="btn btn-sm btn-secondary rounded-start" type="submit">
|
||||
{% trans 'search'|capfirst %}
|
||||
</button>
|
||||
<input type="text"
|
||||
name="q"
|
||||
class="form-control form-control-sm rounded-end"
|
||||
value="{{ request.GET.q }}"
|
||||
aria-describedby="inputGroup-sizing-sm"/>
|
||||
<!-- Clear Button -->
|
||||
{% if request.GET.q %}
|
||||
<a href="{{request.META.HTTP_REFERER}}"
|
||||
class="btn btn-sm btn-outline-danger ms-1 rounded">
|
||||
<i class="bi bi-x-lg"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<main class="d-grid gap-4 p-1">
|
||||
<div class="row g-4">
|
||||
<div class="col-lg-6 col-xl-12">
|
||||
<div class="container-fluid p-2">
|
||||
<form method="get" class="mb-3">
|
||||
<div class="input-group input-group-sm">
|
||||
<button id="inputGroup-sizing-sm"
|
||||
class="btn btn-sm btn-secondary rounded-start" type="submit">
|
||||
{% trans 'search'|capfirst %}
|
||||
</button>
|
||||
<input type="text"
|
||||
name="q"
|
||||
class="form-control form-control-sm rounded-end"
|
||||
value="{{ request.GET.q }}"
|
||||
aria-describedby="inputGroup-sizing-sm" />
|
||||
<!-- Clear Button -->
|
||||
{% if request.GET.q %}
|
||||
<a href="{% url 'inventory_list' %}"
|
||||
class="btn btn-sm btn-outline-danger ms-1 rounded">
|
||||
<i class="bi bi-x-lg"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<table class="table table-responsive table-sm align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>{% trans "VIN" %}</th>
|
||||
<th>{% trans "Year" %}</th>
|
||||
<th>{% trans "Make" %}</th>
|
||||
<th>{% trans "Model" %}</th>
|
||||
<th>{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for car in cars %}
|
||||
<tr class="{% if car.is_reserved %}table-danger{% endif %}">
|
||||
{% if car.colors.all %}
|
||||
{% for color in car.colors.all %}
|
||||
<td><div class="color-div" style="background-color: rgb({{ color.rgb }});"></div></td>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<td><div class="color-div"><i class="bi bi-x-lg fs-6"></i></div></td>
|
||||
{% endif %}
|
||||
<td>{{ car.vin }}</td>
|
||||
<td>{{ car.year }}</td>
|
||||
<td>{{ car.id_car_make.get_local_name }}</td>
|
||||
<td>{{ car.id_car_model.get_local_name }}</td>
|
||||
<td>
|
||||
<a href="{% url 'car_detail' car.pk %}" class="btn btn-sm btn-success"><small>{% trans "view" %}</small></a>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="7">{% trans "No cars available." %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- Optional: Pagination -->
|
||||
{% if is_paginated %}
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination pagination-sm justify-content-center">
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item py-0">
|
||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% for num in page_obj.paginator.page_range %}
|
||||
{% if page_obj.number == num %}
|
||||
<li class="page-item active"><a class="page-link" href="?page={{ num }}">{{ num }}</a></li>
|
||||
{% else %}
|
||||
<li class="page-item"><a class="page-link" href="?page={{ num }}">{{ num }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %} {% if page_obj.has_next %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<table class="table table-responsive table-sm align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "VIN" %}</th>
|
||||
<th>{% trans "Year" %}</th>
|
||||
<th>{% trans 'Exterior Color' %}</th>
|
||||
<th>{% trans 'Interior Color' %}</th>
|
||||
<th>{% trans "Showroom Location" %}</th>
|
||||
<th>{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for car in cars %}
|
||||
<tr class="{% if car.is_reserved %}table-danger{% endif %}">
|
||||
<td>{{ car.vin }}</td>
|
||||
<td>{{ car.year }}</td>
|
||||
{% if car.colors.exists %}
|
||||
<td><span>{{ car.colors.first.exterior.get_local_name }}<div class="color-div" style="background-color: rgb({{ car.colors.first.exterior.rgb }});"></div></span></td>
|
||||
<td>{{ car.colors.first.interior.get_local_name }}<div class="color-div" style="background-color: rgb({{ car.colors.first.interior.rgb }});"></div></td>
|
||||
{% else %}
|
||||
<td><div class="color-div"><i class="bi bi-x-lg fs-6"></i></div></td>
|
||||
<td><div class="color-div"><i class="bi bi-x-lg fs-6"></i></div></td>
|
||||
{% endif %}
|
||||
{% if car.location.is_owner_showroom %}
|
||||
<td> {% trans 'Our Showroom' %}</td>
|
||||
{% else %}
|
||||
<td>{{ car.location.showroom.get_local_name }}</td>
|
||||
{% endif %}
|
||||
<td>
|
||||
<a href="{% url 'car_detail' car.pk %}" class="btn btn-sm btn-success">
|
||||
<small>{% trans "view" %}</small>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="6">{% trans "No cars available." %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- Pagination -->
|
||||
{% if is_paginated %}
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination pagination-sm justify-content-center">
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page=1" aria-label="First">
|
||||
««
|
||||
</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>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% for num in page_obj.paginator.page_range %}
|
||||
{% if page_obj.number == num %}
|
||||
<li class="page-item active">
|
||||
<span class="page-link">{{ num }}</span>
|
||||
</li>
|
||||
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ num }}">{{ num }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next">
|
||||
»
|
||||
</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 %}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -1,10 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>$Title$</title>
|
||||
</head>
|
||||
<body>
|
||||
$END$
|
||||
</body>
|
||||
</html>
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% load crispy_forms_filters %}
|
||||
{% block title %}{% trans "Manage Car Location" %}{% endblock %}
|
||||
{% block content %}
|
||||
{% if carlocation.exists %}
|
||||
<p>Transfer</p>
|
||||
{% else %}
|
||||
<p>Add</p>
|
||||
{% endif %}
|
||||
<div class="container mt-3">
|
||||
<h3 class="mb-3">{% trans "Manage Car Location" %}</h3>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">{% trans "Save" %}</button>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Loading…
x
Reference in New Issue
Block a user