Compare commits

..

No commits in common. "9add48dd056894b6f3291c20ecaee2605a7daa08" and "38f4731a9a171f842270d2dc7b0dfce974490251" have entirely different histories.

9 changed files with 271 additions and 362 deletions

View File

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

View File

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

View File

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

View File

@ -451,45 +451,39 @@ def general_dashboard(request,dealer_slug):
total_cars_sold = cars_sold_filtered.count() total_cars_sold = cars_sold_filtered.count()
total_cost_of_cars_sold = cars_sold_filtered.aggregate(total=Sum('cost_price'))['total'] or 0 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_revenue_from_cars = cars_sold_filtered.aggregate(
total=Sum(F('marked_price') - F('discount_amount')) total=Sum(F('selling_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'] 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 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 total_discount = cars_sold_filtered.aggregate(total=Sum('discount_amount'))['total'] or 0
# Sales breakdown by type # Sales breakdown by type
new_cars_sold = cars_sold_filtered.filter(stock_type='new') new_cars_sold = cars_sold_filtered.filter(stock_type='new')
total_new_cars_sold = new_cars_sold.count() 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_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_revenue_from_new_cars = new_cars_sold.aggregate(
total=Sum(F('marked_price') - F('discount_amount')) total=Sum(F('selling_price') - F('discount_amount'))
)['total'] or 0 )['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 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') used_cars_sold = cars_sold_filtered.filter(stock_type='used')
total_used_cars_sold = used_cars_sold.count() 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_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_revenue_from_used_cars = used_cars_sold.aggregate(
total=Sum(F('marked_price') - F('discount_amount')) total=Sum(F('selling_price') - F('discount_amount'))
)['total'] or 0 )['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 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 # Service & Overall KPIs
total_revenue_from_services = sum([car.get_additional_services()['total'] for car in cars_sold_filtered]) total_revenue_from_services = sum([car.get_additional_services()['total'] for car in cars_sold_filtered])
@ -508,8 +502,8 @@ def general_dashboard(request,dealer_slug):
month=ExtractMonth('sold_date') month=ExtractMonth('sold_date')
).values('month').annotate( ).values('month').annotate(
total_cars=Count('pk'), total_cars=Count('pk'),
total_revenue=Sum(F('marked_price') - F('discount_amount')), total_revenue=Sum(F('selling_price') - F('discount_amount')),
total_profit=Sum(F('marked_price') - F('discount_amount') - F('cost_price')) total_profit=Sum(F('selling_price') - F('discount_amount') - F('cost_price'))
).order_by('month') ).order_by('month')
monthly_cars_sold = [0] * 12 monthly_cars_sold = [0] * 12
@ -1483,7 +1477,8 @@ def inventory_stats_view(request, dealer_slug):
""" """
# Base queryset for cars belonging to the dealer # Base queryset for cars belonging to the dealer
cars = models.Car.objects.filter(dealer=request.dealer) cars = models.Car.objects.filter(dealer=request.dealer)
print(cars)
# Count for total, reserved, showroom, and unreserved cars # Count for total, reserved, showroom, and unreserved cars
total_cars = cars.count() total_cars = cars.count()
reserved_cars = models.CarReservation.objects.count() reserved_cars = models.CarReservation.objects.count()
@ -11072,9 +11067,6 @@ def purchase_report_csv_export(request,dealer_slug):
@login_required @login_required
def car_sale_report_view(request, dealer_slug): def car_sale_report_view(request, dealer_slug):
dealer = get_object_or_404(models.Dealer, slug=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') cars_sold = models.Car.objects.filter(dealer=dealer, status='sold')
@ -11100,13 +11092,8 @@ def car_sale_report_view(request, dealer_slug):
# # Calculate summary data for the filtered results # # Calculate summary data for the filtered results
total_cars_sold=cars_sold.count() total_cars_sold=cars_sold.count()
total_revenue_from_cars = cars_sold.aggregate( total_revenue_from_cars = sum([ car.final_price for car in cars_sold])
total=Sum(F('marked_price') - F('discount_amount')) total_vat_on_cars=sum([car.vat_amount for car in cars_sold])
)['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_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]) total_vat_from_additonals=sum([car.get_additional_services()['services_vat'] for car in cars_sold])

View File

@ -433,15 +433,6 @@
</div> </div>
</a> </a>
</div> </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"> <ul class="navbar-nav navbar-nav-icons flex-row gap-2" hx-boost="false">
<li class="nav-item"> <li class="nav-item">
@ -546,7 +537,7 @@
</ul> </ul>
</hr> </hr>
<div class="px-3"> <div class="px-3">
<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> <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>
</div> </div>
<div class="my-2 text-center fw-bold fs-10 text-body-quaternary"> <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> <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"> <td class="align-middle white-space-nowrap text-center fw-bold text-body-tertiary">
{% if car.stock_type == "new" %} {% if car.stock_type == "new" %}
<span class="badge badge-phoenix badge-phoenix-success"><span class="badge-label">{{ _("New") }}</span></span> <span class="badge badge-phoenix badge-phoenix-success"><span class="badge-label">{{ _("New") }}</span></span>
{% elif car.stock_type == "used" %} {% elif car.status == "used" %}
<span class="badge badge-phoenix badge-phoenix-info"><span class="badge-label">{{ _("Used") }}</span></span> <span class="badge badge-phoenix badge-phoenix-info"><span class="badge-label">{{ _("Used") }}</span></span>
{% endif %} {% endif %}
</td> </td>

View File

@ -5,50 +5,10 @@
{% endblock %} {% endblock %}
{% block content %} {% 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 %} {% if inventory.total_cars > 0 %}
<div class="row justify-content-between"> <div class="row justify-content-between">
<div class="col-sm-12 "> <div class="col-sm-12 ">
<div class="card border h-100 w-100 p-lg-10"> <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" <div class="bg-holder bg-card"
style="background-image:url({% static 'images/spot-illustrations/32.png' %}); style="background-image:url({% static 'images/spot-illustrations/32.png' %});
background-position: top right"></div> background-position: top right"></div>
@ -140,29 +100,3 @@
{% include "empty-illustration-page.html" with value="car" url=create_car_url %} {% include "empty-illustration-page.html" with value="car" url=create_car_url %}
{% endif %} {% endif %}
{% endblock %} {% 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 %} {% for item in items %}
<div class="option" data-value="{{ item.hash }}" data-image="{{item.logo}}"> <div class="option" data-value="{{ item.hash }}" data-image="{{item.logo}}">
<img src="{{item.logo}}" alt="{{item.model}}"> <img src="{{item.logo}}" alt="{{item.model}}">
<span>{{item.vin}} {{item.make}} {{item.model}} {{item.serie}} {{item.trim}} {{item.color_name}}</span> <span>{{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.exterior_color }});"></div>
<div class="color-box" style="background-color: rgb({{ item.interior_color }});"></div> <div class="color-box" style="background-color: rgb({{ item.interior_color }});"></div>
<span style="color:gray;">({{item.hash_count}} in stock)</span> <span style="color:gray;">({{item.hash_count}} in stock)</span>

View File

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