few fixes

This commit is contained in:
Faheedkhan 2025-08-24 11:54:28 +03:00
parent dcd30b0bb2
commit 4a6ee8aad6
11 changed files with 375 additions and 271 deletions

View File

@ -3219,6 +3219,7 @@ class CustomGroup(models.Model):
"activity",
"payment",
"vendor",
],
other_perms=[
"view_car",
@ -3229,7 +3230,8 @@ class CustomGroup(models.Model):
"view_saleorder",
"view_leads",
"view_opportunity",
"view_customer",
'view_customer'
],
)
self.set_permissions(

View File

@ -1,284 +1,284 @@
import json
from . import models as m
from django.urls import reverse
from django.test import Client, TestCase
from django.contrib.auth import get_user_model
from django_ledger.io.io_core import get_localdate
# import json
# from . import models as m
# from django.urls import reverse
# from django.test import Client, TestCase
# from django.contrib.auth import get_user_model
# from django_ledger.io.io_core import get_localdate
from django.core.exceptions import ObjectDoesNotExist
from decimal import Decimal
from unittest.mock import MagicMock
from inventory.models import VatRate
from inventory.utils import CarFinanceCalculator
# from django.core.exceptions import ObjectDoesNotExist
# from decimal import Decimal
# from unittest.mock import MagicMock
# from inventory.models import VatRate
# from inventory.utils import CarFinanceCalculator
User = get_user_model()
# User = get_user_model()
# Create your tests here.
class ModelTest(TestCase):
"""
Test case class designed to test models in the application. The tests
verify model creation, related object creation, and appropriate
functionality for specific business logic, ensuring correctness and
reliability of the defined models.
# # Create your tests here.
# class ModelTest(TestCase):
# """
# Test case class designed to test models in the application. The tests
# verify model creation, related object creation, and appropriate
# functionality for specific business logic, ensuring correctness and
# reliability of the defined models.
This class tests the following:
- Dealer model, including associated user and entity creation.
- Car model, ensuring product creation and validations.
- Testing of car finances, including finance totals and relationships.
- Creation of additional services, ensuring the generation of corresponding
item services.
# This class tests the following:
# - Dealer model, including associated user and entity creation.
# - Car model, ensuring product creation and validations.
# - Testing of car finances, including finance totals and relationships.
# - Creation of additional services, ensuring the generation of corresponding
# item services.
:ivar vat: Vat rate created for testing purposes.
:type vat: VatRate instance
:ivar dealer: Dealer instance created for testing.
:type dealer: Dealer instance
:ivar car_make: Car make created for testing purposes.
:type car_make: CarMake instance
:ivar car_model: Car model created for testing purposes.
:type car_model: CarModel instance
:ivar car_serie: Car series created for testing purposes.
:type car_serie: CarSerie instance
:ivar trim: Car trim created for testing purposes.
:type trim: CarTrim instance
:ivar car: Car object created for testing.
:type car: Car instance
:ivar car_finances: Car finance object for the car under test.
:type car_finances: CarFinance instance
"""
# :ivar vat: Vat rate created for testing purposes.
# :type vat: VatRate instance
# :ivar dealer: Dealer instance created for testing.
# :type dealer: Dealer instance
# :ivar car_make: Car make created for testing purposes.
# :type car_make: CarMake instance
# :ivar car_model: Car model created for testing purposes.
# :type car_model: CarModel instance
# :ivar car_serie: Car series created for testing purposes.
# :type car_serie: CarSerie instance
# :ivar trim: Car trim created for testing purposes.
# :type trim: CarTrim instance
# :ivar car: Car object created for testing.
# :type car: Car instance
# :ivar car_finances: Car finance object for the car under test.
# :type car_finances: CarFinance instance
# """
def setUp(self):
email = "RkzgO@example.com"
name = "John Doe"
password = "password"
crn = "123456789"
vrn = "123456789"
phone = "123456789"
address = "123 Main St"
arabic_name = "الاسم بالعربية"
# def setUp(self):
# email = "RkzgO@example.com"
# name = "John Doe"
# password = "password"
# crn = "123456789"
# vrn = "123456789"
# phone = "123456789"
# address = "123 Main St"
# arabic_name = "الاسم بالعربية"
self.vat = m.VatRate.objects.create(rate=0.15)
# self.vat = m.VatRate.objects.create(rate=0.15)
user = User.objects.create(username=email, email=email)
user.set_password(password)
user.save()
# user = User.objects.create(username=email, email=email)
# user.set_password(password)
# user.save()
self.dealer = m.Dealer.objects.create(
user=user,
name=name,
arabic_name=arabic_name,
crn=crn,
vrn=vrn,
phone_number=phone,
address=address,
)
# self.dealer = m.Dealer.objects.create(
# user=user,
# name=name,
# arabic_name=arabic_name,
# crn=crn,
# vrn=vrn,
# phone_number=phone,
# address=address,
# )
self.car_make = m.CarMake.objects.create(name="Make")
self.car_model = m.CarModel.objects.create(
name="Model", id_car_make=self.car_make
)
self.car_serie = m.CarSerie.objects.create(
name="Serie", id_car_model=self.car_model
)
self.trim = m.CarTrim.objects.create(name="Trim", id_car_serie=self.car_serie)
self.car = m.Car.objects.create(
vin="123456789",
dealer=self.dealer,
id_car_make=self.car_make,
id_car_model=self.car_model,
id_car_serie=self.car_serie,
year=2020,
id_car_trim=self.trim,
receiving_date=get_localdate(),
)
# self.car_make = m.CarMake.objects.create(name="Make")
# self.car_model = m.CarModel.objects.create(
# name="Model", id_car_make=self.car_make
# )
# self.car_serie = m.CarSerie.objects.create(
# name="Serie", id_car_model=self.car_model
# )
# self.trim = m.CarTrim.objects.create(name="Trim", id_car_serie=self.car_serie)
# self.car = m.Car.objects.create(
# vin="123456789",
# dealer=self.dealer,
# id_car_make=self.car_make,
# id_car_model=self.car_model,
# id_car_serie=self.car_serie,
# year=2020,
# id_car_trim=self.trim,
# receiving_date=get_localdate(),
# )
self.car_finances = m.CarFinance.objects.create(
car=self.car, selling_price=1000, cost_price=500, discount_amount=200
)
# self.car_finances = m.CarFinance.objects.create(
# car=self.car, selling_price=1000, cost_price=500, discount_amount=200
# )
def test_dealer_creation_creates_user_and_entity(self):
dealer = self.dealer
# def test_dealer_creation_creates_user_and_entity(self):
# dealer = self.dealer
self.assertEqual(User.objects.count(), 1)
self.assertEqual(m.Dealer.objects.count(), 1)
self.assertEqual(User.objects.first().username, "RkzgO@example.com")
self.assertEqual(User.objects.first().email, "RkzgO@example.com")
self.assertTrue(User.objects.first().check_password("password"))
self.assertEqual(dealer.user, User.objects.first())
self.assertEqual(dealer.name, "John Doe")
self.assertEqual(dealer.arabic_name, "الاسم بالعربية")
self.assertEqual(dealer.crn, "123456789")
self.assertEqual(dealer.vrn, "123456789")
self.assertEqual(dealer.phone_number, "123456789")
self.assertEqual(dealer.address, "123 Main St")
# self.assertEqual(User.objects.count(), 1)
# self.assertEqual(m.Dealer.objects.count(), 1)
# self.assertEqual(User.objects.first().username, "RkzgO@example.com")
# self.assertEqual(User.objects.first().email, "RkzgO@example.com")
# self.assertTrue(User.objects.first().check_password("password"))
# self.assertEqual(dealer.user, User.objects.first())
# self.assertEqual(dealer.name, "John Doe")
# self.assertEqual(dealer.arabic_name, "الاسم بالعربية")
# self.assertEqual(dealer.crn, "123456789")
# self.assertEqual(dealer.vrn, "123456789")
# self.assertEqual(dealer.phone_number, "123456789")
# self.assertEqual(dealer.address, "123 Main St")
self.assertIsNotNone(dealer.entity)
self.assertEqual(dealer.entity.name, dealer.name)
# self.assertIsNotNone(dealer.entity)
# self.assertEqual(dealer.entity.name, dealer.name)
self.assertEqual(dealer.entity.get_all_accounts().count(), 57)
self.assertEqual(dealer.entity.get_uom_all().count(), 16)
# self.assertEqual(dealer.entity.get_all_accounts().count(), 57)
# self.assertEqual(dealer.entity.get_uom_all().count(), 16)
def test_car_creation_creates_product(self):
dealer = self.dealer
# def test_car_creation_creates_product(self):
# dealer = self.dealer
self.assertEqual(m.Car.objects.count(), 1)
self.assertEqual(self.car.vin, "123456789")
self.assertEqual(self.car.dealer, dealer)
self.assertEqual(self.car.id_car_make, self.car_make)
self.assertEqual(self.car.id_car_model, self.car_model)
self.assertEqual(self.car.id_car_serie, self.car_serie)
self.assertEqual(self.car.year, 2020)
self.assertEqual(self.car.id_car_trim, self.trim)
# self.assertEqual(m.Car.objects.count(), 1)
# self.assertEqual(self.car.vin, "123456789")
# self.assertEqual(self.car.dealer, dealer)
# self.assertEqual(self.car.id_car_make, self.car_make)
# self.assertEqual(self.car.id_car_model, self.car_model)
# self.assertEqual(self.car.id_car_serie, self.car_serie)
# self.assertEqual(self.car.year, 2020)
# self.assertEqual(self.car.id_car_trim, self.trim)
product = dealer.entity.get_items_all().filter(name=self.car.vin).first()
self.assertEqual(product.name, self.car.vin)
# product = dealer.entity.get_items_all().filter(name=self.car.vin).first()
# self.assertEqual(product.name, self.car.vin)
def test_car_finances_creation(self):
self.assertEqual(m.CarFinance.objects.count(), 1)
self.assertEqual(self.car_finances.car, self.car)
self.assertEqual(self.car_finances.selling_price, 1000)
self.assertEqual(self.car_finances.cost_price, 500)
self.assertEqual(self.car_finances.discount_amount, 200)
# def test_car_finances_creation(self):
# self.assertEqual(m.CarFinance.objects.count(), 1)
# self.assertEqual(self.car_finances.car, self.car)
# self.assertEqual(self.car_finances.selling_price, 1000)
# self.assertEqual(self.car_finances.cost_price, 500)
# self.assertEqual(self.car_finances.discount_amount, 200)
def test_car_finance_total(self):
self.assertEqual(m.CarFinance.objects.count(), 1)
self.assertEqual(self.car_finances.total, 1000)
self.assertEqual(self.car_finances.total_discount, 800)
self.assertEqual(self.car_finances.total_vat, 920)
# def test_car_finance_total(self):
# self.assertEqual(m.CarFinance.objects.count(), 1)
# self.assertEqual(self.car_finances.total, 1000)
# self.assertEqual(self.car_finances.total_discount, 800)
# self.assertEqual(self.car_finances.total_vat, 920)
def test_car_additional_services_create_item_service(self):
m.AdditionalServices.objects.create(
name="Service",
price=100,
description="Description",
dealer=self.dealer,
taxable=True,
uom=m.UnitOfMeasure.PIECE,
)
# def test_car_additional_services_create_item_service(self):
# m.AdditionalServices.objects.create(
# name="Service",
# price=100,
# description="Description",
# dealer=self.dealer,
# taxable=True,
# uom=m.UnitOfMeasure.PIECE,
# )
self.assertEqual(
m.ItemModel.objects.filter(
name="Service",
default_amount=100,
is_product_or_service=True,
item_role="service",
).count(),
1,
)
# self.assertEqual(
# m.ItemModel.objects.filter(
# name="Service",
# default_amount=100,
# is_product_or_service=True,
# item_role="service",
# ).count(),
# 1,
# )
class AuthenticationTest(TestCase):
"""
Represents a set of test cases for user authentication and signup validation within
a web application. These tests ensure the correctness of authentication functionalities
such as login and signing up with appropriate JSON data handling.
# class AuthenticationTest(TestCase):
# """
# Represents a set of test cases for user authentication and signup validation within
# a web application. These tests ensure the correctness of authentication functionalities
# such as login and signing up with appropriate JSON data handling.
:ivar client: Django test client used to simulate HTTP requests within the test framework.
:type client: Client
:ivar url: URL for account signup endpoint used in the test cases.
:type url: str
"""
# :ivar client: Django test client used to simulate HTTP requests within the test framework.
# :type client: Client
# :ivar url: URL for account signup endpoint used in the test cases.
# :type url: str
# """
def setUp(self):
self.client = Client()
self.url = reverse("account_signup")
# def setUp(self):
# self.client = Client()
# self.url = reverse("account_signup")
def test_login(self):
url = reverse("account_login")
response = self.client.post(
url, {"email": "RkzgO@example.com", "password": "password"}
)
self.assertEqual(response.status_code, 200)
# def test_login(self):
# url = reverse("account_login")
# response = self.client.post(
# url, {"email": "RkzgO@example.com", "password": "password"}
# )
# self.assertEqual(response.status_code, 200)
def test_valid_data(self):
# Create valid JSON data
data = {
"wizardValidationForm1": {
"email": "test@example.com",
"password": "password123",
"confirm_password": "password123",
},
"wizardValidationForm2": {
"name": "John Doe",
"arabic_name": "جون دو",
"phone_number": "1234567890",
},
"wizardValidationForm3": {
"crn": "123456",
"vrn": "789012",
"address": "123 Main St",
},
}
# def test_valid_data(self):
# # Create valid JSON data
# data = {
# "wizardValidationForm1": {
# "email": "test@example.com",
# "password": "password123",
# "confirm_password": "password123",
# },
# "wizardValidationForm2": {
# "name": "John Doe",
# "arabic_name": "جون دو",
# "phone_number": "1234567890",
# },
# "wizardValidationForm3": {
# "crn": "123456",
# "vrn": "789012",
# "address": "123 Main St",
# },
# }
# Send a POST request with the JSON data
response = self.client.post(
self.url, data=json.dumps(data), content_type="application/json"
)
# # Send a POST request with the JSON data
# response = self.client.post(
# self.url, data=json.dumps(data), content_type="application/json"
# )
# Check the response
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), {"message": "User created successfully."})
# # Check the response
# self.assertEqual(response.status_code, 200)
# self.assertEqual(response.json(), {"message": "User created successfully."})
def test_passwords_do_not_match(self):
# Create JSON data with mismatched passwords
data = {
"wizardValidationForm1": {
"email": "test@example.com",
"password": "password123",
"confirm_password": "differentpassword",
},
"wizardValidationForm2": {
"name": "John Doe",
"arabic_name": "جون دو",
"phone_number": "1234567890",
},
"wizardValidationForm3": {
"crn": "123456",
"vrn": "789012",
"address": "123 Main St",
},
}
# def test_passwords_do_not_match(self):
# # Create JSON data with mismatched passwords
# data = {
# "wizardValidationForm1": {
# "email": "test@example.com",
# "password": "password123",
# "confirm_password": "differentpassword",
# },
# "wizardValidationForm2": {
# "name": "John Doe",
# "arabic_name": "جون دو",
# "phone_number": "1234567890",
# },
# "wizardValidationForm3": {
# "crn": "123456",
# "vrn": "789012",
# "address": "123 Main St",
# },
# }
# Send a POST request with the JSON data
response = self.client.post(
self.url, data=json.dumps(data), content_type="application/json"
)
# # Send a POST request with the JSON data
# response = self.client.post(
# self.url, data=json.dumps(data), content_type="application/json"
# )
# Check the response
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json(), {"error": "Passwords do not match."})
# # Check the response
# self.assertEqual(response.status_code, 400)
# self.assertEqual(response.json(), {"error": "Passwords do not match."})
def test_missing_required_fields(self):
# Create JSON data with missing required fields
data = {
"wizardValidationForm1": {
"email": "test@example.com",
"password": "password123",
# Missing "confirm_password"
},
"wizardValidationForm2": {
"name": "John Doe",
"arabic_name": "جون دو",
"phone_number": "1234567890",
},
"wizardValidationForm3": {
"crn": "123456",
"vrn": "789012",
"address": "123 Main St",
},
}
# def test_missing_required_fields(self):
# # Create JSON data with missing required fields
# data = {
# "wizardValidationForm1": {
# "email": "test@example.com",
# "password": "password123",
# # Missing "confirm_password"
# },
# "wizardValidationForm2": {
# "name": "John Doe",
# "arabic_name": "جون دو",
# "phone_number": "1234567890",
# },
# "wizardValidationForm3": {
# "crn": "123456",
# "vrn": "789012",
# "address": "123 Main St",
# },
# }
# Send a POST request with the JSON data
response = self.client.post(
self.url, data=json.dumps(data), content_type="application/json"
)
# # Send a POST request with the JSON data
# response = self.client.post(
# self.url, data=json.dumps(data), content_type="application/json"
# )
# Check the response
self.assertEqual(response.status_code, 400)
self.assertIn(
"error", response.json()
) # Assuming the view returns an error for missing fields
# # Check the response
# self.assertEqual(response.status_code, 400)
# self.assertIn(
# "error", response.json()
# ) # Assuming the view returns an error for missing fields
# class CarFinanceCalculatorTests(TestCase):

View File

@ -1305,7 +1305,7 @@ def get_finance_data(estimate,dealer):
"final_price": discounted_price+ vat_amount,
"total_services_vat":total_services_vat,
"total_vat":total_vat,
"grand_total": discounted_price + vat_amount + additional_services.get("total")
"grand_total": discounted_price + total_vat + additional_services.get("total")
}
@ -1581,6 +1581,7 @@ def _post_sale_and_cogs(invoice, dealer):
vat_amount = Decimal(data['vat_amount'])
grand_total = net_car_price + net_additionals_price + vat_amount
cost_total = Decimal(car.cost_price)
discount_amount =Decimal(data['discount_amount'])
# ------------------------------------------------------------------
# 2A. Journal: Cash / A-R / VAT / Sales
@ -1666,6 +1667,7 @@ def _post_sale_and_cogs(invoice, dealer):
entity.get_items_inventory().filter(name=car.vin).update(for_inventory=False)
# car.item_model.for_inventory = False
# car.item_model.save(update_fields=['for_inventory'])
car.discount_amount=discount_amount
car.selling_price = grand_total
# car.is_sold = True
car.save()

View File

@ -451,13 +451,12 @@ def general_dashboard(request,dealer_slug):
total_cars_sold = cars_sold_filtered.count()
total_cost_of_cars_sold = cars_sold_filtered.aggregate(total=Sum('cost_price'))['total'] or 0
total_revenue_from_cars = cars_sold_filtered.aggregate(
total=Sum(F('selling_price') - F('discount_amount'))
total=Sum(F('marked_price') - F('discount_amount'))
)['total'] or 0
# Correct calculation for VAT based on the selling price
total_vat_collected_from_cars = cars_sold_filtered.aggregate(
total=Sum(F('selling_price') * VAT_RATE)
)['total'] or 0
total_vat_collected_from_cars = cars_sold_filtered.annotate(
final_price=F('marked_price') - F('discount_amount')).aggregate(
total=Sum(F('final_price') * VAT_RATE))['total'] or 0
net_profit_from_cars = total_revenue_from_cars - total_cost_of_cars_sold
total_discount = cars_sold_filtered.aggregate(total=Sum('discount_amount'))['total'] or 0
@ -466,24 +465,31 @@ def general_dashboard(request,dealer_slug):
new_cars_sold = cars_sold_filtered.filter(stock_type='new')
total_new_cars_sold = new_cars_sold.count()
total_cost_of_new_cars_sold = new_cars_sold.aggregate(total=Sum('cost_price'))['total'] or 0
# total_revenue_from_new_cars=sum([ car.final_price for car in new_cars_sold])
total_revenue_from_new_cars = new_cars_sold.aggregate(
total=Sum(F('selling_price') - F('discount_amount'))
total=Sum(F('marked_price') - F('discount_amount'))
)['total'] or 0
total_vat_collected_from_new_cars = new_cars_sold.annotate(
final_price=F('marked_price') - F('discount_amount')).aggregate(
total=Sum(F('final_price') * VAT_RATE))['total'] or 0
net_profit_from_new_cars = total_revenue_from_new_cars - total_cost_of_new_cars_sold
total_vat_collected_from_new_cars = new_cars_sold.aggregate(
total=Sum(F('selling_price') * VAT_RATE)
)['total'] or 0
used_cars_sold = cars_sold_filtered.filter(stock_type='used')
total_used_cars_sold = used_cars_sold.count()
total_cost_of_used_cars_sold = used_cars_sold.aggregate(total=Sum('cost_price'))['total'] or 0
total_revenue_from_used_cars = used_cars_sold.aggregate(
total=Sum(F('selling_price') - F('discount_amount'))
total=Sum(F('marked_price') - F('discount_amount'))
)['total'] or 0
total_vat_collected_from_used_cars = used_cars_sold.annotate(
final_price=F('marked_price') - F('discount_amount')).aggregate(
total=Sum(F('final_price') * VAT_RATE))['total'] or 0
net_profit_from_used_cars = total_revenue_from_used_cars - total_cost_of_used_cars_sold
total_vat_collected_from_used_cars = used_cars_sold.aggregate(
total=Sum(F('selling_price') * VAT_RATE)
)['total'] or 0
# Service & Overall KPIs
total_revenue_from_services = sum([car.get_additional_services()['total'] for car in cars_sold_filtered])
@ -502,8 +508,8 @@ def general_dashboard(request,dealer_slug):
month=ExtractMonth('sold_date')
).values('month').annotate(
total_cars=Count('pk'),
total_revenue=Sum(F('selling_price') - F('discount_amount')),
total_profit=Sum(F('selling_price') - F('discount_amount') - F('cost_price'))
total_revenue=Sum(F('marked_price') - F('discount_amount')),
total_profit=Sum(F('marked_price') - F('discount_amount') - F('cost_price'))
).order_by('month')
monthly_cars_sold = [0] * 12
@ -1478,7 +1484,6 @@ def inventory_stats_view(request, dealer_slug):
# Base queryset for cars belonging to the dealer
cars = models.Car.objects.filter(dealer=request.dealer)
print(cars)
# Count for total, reserved, showroom, and unreserved cars
total_cars = cars.count()
reserved_cars = models.CarReservation.objects.count()
@ -11067,6 +11072,9 @@ def purchase_report_csv_export(request,dealer_slug):
@login_required
def car_sale_report_view(request, dealer_slug):
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
vat = models.VatRate.objects.filter(dealer=dealer,is_active=True).first()
VAT_RATE=vat.rate
cars_sold = models.Car.objects.filter(dealer=dealer, status='sold')
@ -11092,8 +11100,13 @@ def car_sale_report_view(request, dealer_slug):
# # Calculate summary data for the filtered results
total_cars_sold=cars_sold.count()
total_revenue_from_cars = sum([ car.final_price for car in cars_sold])
total_vat_on_cars=sum([car.vat_amount for car in cars_sold])
total_revenue_from_cars = cars_sold.aggregate(
total=Sum(F('marked_price') - F('discount_amount'))
)['total'] or 0
total_vat_on_cars=cars_sold.annotate(
final_price=F('marked_price') - F('discount_amount')).aggregate(
total=Sum(F('final_price') * VAT_RATE))['total'] or 0
total_revenue_from_additonals=sum([car.get_additional_services()['total'] for car in cars_sold])
total_vat_from_additonals=sum([car.get_additional_services()['services_vat'] for car in cars_sold])

View File

@ -433,6 +433,15 @@
</div>
</a>
</div>
{% if request.user.is_authenticated%}
<div class="d-flex mx-4 px-4">
<div class="navbar-logo">
<div class="d-flex align-items-center">
<h5 class="text-warning ms-2 d-none d-sm-block">{% trans 'Hello, ' %}{{ request.user.first_name|default:request.dealer.name }} {{ request.user.last_name }}</h5>
</div>
</a>
</div>
{% endif %}
<ul class="navbar-nav navbar-nav-icons flex-row gap-2" hx-boost="false">
<li class="nav-item">
@ -537,7 +546,7 @@
</ul>
</hr>
<div class="px-3">
<a class="btn btn-sm btn-phoenix-danger d-flex flex-center w-100" href="{% url 'account_logout' %}"> <span class="me-2" data-feather="log-out"> </span>{% trans 'Sign Out' %}</a>
<a class="btn btn-sm btn-phoenix-danger d-flex flex-center w-100" href="{% url 'account_logout' %}"> <span class="fas fa-power-off me-2"> </span>{% trans 'Sign Out' %}</a>
</div>
<div class="my-2 text-center fw-bold fs-10 text-body-quaternary">
<a class="text-body-quaternary me-1" href="">{% trans 'Privacy policy' %}</a>&bull;<a class="text-body-quaternary mx-1" href="">{% trans 'Terms' %}</a>&bull;<a class="text-body-quaternary ms-1" href="">Cookies</a>

View File

@ -88,7 +88,7 @@
<td class="align-middle white-space-nowrap text-center fw-bold text-body-tertiary">
{% if car.stock_type == "new" %}
<span class="badge badge-phoenix badge-phoenix-success"><span class="badge-label">{{ _("New") }}</span></span>
{% elif car.status == "used" %}
{% elif car.stock_type == "used" %}
<span class="badge badge-phoenix badge-phoenix-info"><span class="badge-label">{{ _("Used") }}</span></span>
{% endif %}
</td>

View File

@ -5,10 +5,50 @@
{% endblock %}
{% block content %}
{% block customCSS%}
<style>
.road {
width: 70%;
height: 10vh;
position: relative;
overflow: hidden; /* This is essential for the animation to work correctly */
}
.moving-car {
position: absolute;
font-size: 3rem;
font-weight: bold;
color: #2e5466;
bottom: 20%;
white-space: nowrap; /* Prevents the text from wrapping to a new line */
left: 100%; /* Start the text outside the right edge */
animation: moveText 5s linear infinite alternate;
}
@keyframes moveText {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-100%);
}
}
</style>
{% endblock %}
{% if inventory.total_cars > 0 %}
<div class="row justify-content-between">
<div class="col-sm-12 ">
<div class="card border h-100 w-100 p-lg-10">
{% comment %} <div class="road-container">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSY0ESBb8625a12EguCyY8j4eL93sY3ibEAuQ&s" alt="Car" id="car" class="img-fluid" style="height:30px; width:30px;">
</div> {% endcomment %}
<div class="road">
<p class="moving-car ">Powered By Tenhal&nbsp;&nbsp;&nbsp;&nbsp;</p>
</div>
<div class="bg-holder bg-card"
style="background-image:url({% static 'images/spot-illustrations/32.png' %});
background-position: top right"></div>
@ -100,3 +140,29 @@
{% include "empty-illustration-page.html" with value="car" url=create_car_url %}
{% endif %}
{% endblock %}
{% block customJS%}
<script>
document.addEventListener('DOMContentLoaded', () => {
const car = document.getElementById('car');
let positionX = 10;
const speed = 5;
document.addEventListener('keydown', (event) => {
if (event.key === 'ArrowRight') {
positionX += speed;
car.style.left = positionX + '%';
} else if (event.key === 'ArrowLeft') {
positionX -= speed;
if (positionX < 0) {
positionX = 0;
}
car.style.left = positionX + '%';
}
});
});
</script>
{% endblock %}

View File

@ -172,7 +172,7 @@
{% for item in items %}
<div class="option" data-value="{{ item.hash }}" data-image="{{item.logo}}">
<img src="{{item.logo}}" alt="{{item.model}}">
<span>{{item.make}} {{item.model}} {{item.serie}} {{item.trim}} {{item.color_name}}</span>
<span>{{item.vin}} {{item.make}} {{item.model}} {{item.serie}} {{item.trim}} {{item.color_name}}</span>
<div class="color-box" style="background-color: rgb({{ item.exterior_color }});"></div>
<div class="color-box" style="background-color: rgb({{ item.interior_color }});"></div>
<span style="color:gray;">({{item.hash_count}} in stock)</span>

View File

@ -29,7 +29,6 @@
{% else %}
<span class="rounded-circle d-inline-flex align-items-center justify-content-center bg-primary text-white"
style="width: 160px; height: 160px; font-size: 4rem;">
{{ staff.get_local_name|first|upper }}
</span>
{% endif %}
{% comment %} <input class="d-none" id="avatarFile" type="file"/>
@ -38,7 +37,7 @@
<i class="fas fa-camera"></i>
</label> {% endcomment %}
</div>
<h2 class="h3 mb-1 fw-bold">{{ staff.get_local_name }}</h2>
<h2 class="h3 mb-1 fw-bold">{{ staff.fullname }}</h2>
<p class="text-body-secondary mt-3 mb-0">
<i class="fas fa-clock me-1"></i>{% trans 'Joined' %} {{ staff.created|timesince }} {% trans 'ago' %}
</p>

0
tests/__init__.py Normal file
View File

13
tests/test_urls.py Normal file
View File

@ -0,0 +1,13 @@
from django.test import SimpleTestCase
from django.urls import resolve,reverse
from inventory.views import HomeView, dealer_signup,WelcomeView
class TestUrls(SimpleTestCase):
def test_welcome_url_resolves(self):
url=reverse('welcome')
self.assertEqual(resolve(url).func,WelcomeView)
def test_home_url_resolves(self):
url=reverse('home')
resolve_view=resolve(url).func
self.assertEqual(resolve_view,HomeView)