add qotation-02

This commit is contained in:
Marwan Alwali 2024-12-11 15:55:27 +03:00
parent 88e81fadf1
commit 51fdc0b31f
41 changed files with 569 additions and 261 deletions

View File

@ -1533,7 +1533,7 @@ def decode_vin(vin):
# VR3USHNLWRJ521303
# KNARH81E8P5194005
# Example usage
vin_number = 'LGWCBE196SB652802'
vin_number = 'LGWEE4A53SK607775'
decoded_vin = decode_vin(vin_number)
print(decoded_vin)

View File

@ -46,7 +46,7 @@ class CarModelAdmin(admin.ModelAdmin):
@admin.register(models.CarSerie)
class CarSeriesAdmin(admin.ModelAdmin):
list_display = ('name', 'arabic_name', 'id_car_model')
list_display = ('name', 'arabic_name', 'id_car_model', )
search_fields = ('name', 'id_car_model__name')
list_filter = ('id_car_model__id_car_make__is_sa_import',
'id_car_model__id_car_make__name',)
@ -55,18 +55,18 @@ class CarSeriesAdmin(admin.ModelAdmin):
verbose_name = "Car Series"
# @admin.register(models.CarTrim)
# class CarTrimAdmin(admin.ModelAdmin):
# list_display = ('name',
# 'id_car_serie__name',
# 'id_car_serie__id_car_model__name',
# 'id_car_serie__id_car_model__id_car_make__name')
# search_fields = ('name', 'arabic_name', 'id_car_serie__id_car_model__name')
# list_filter = ('id_car_serie__id_car_model__id_car_make__is_sa_import',
# 'id_car_serie__id_car_model__id_car_make__name')
@admin.register(models.CarTrim)
class CarTrimAdmin(admin.ModelAdmin):
list_display = ('name',
'id_car_serie__name',
'id_car_serie__id_car_model__name',
'id_car_serie__id_car_model__id_car_make__name')
search_fields = ('name', 'arabic_name', 'id_car_serie__id_car_model__name')
list_filter = ('id_car_serie__id_car_model__id_car_make__is_sa_import',
'id_car_serie__id_car_model__id_car_make__name')
# class Meta:
# verbose_name = "Car Trim"
class Meta:
verbose_name = "Car Trim"
@admin.register(models.CarSpecification)

View File

@ -168,6 +168,7 @@ class QuotationForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['cars'].queryset = Car.objects.filter(
finances__isnull=False
).distinct()

Binary file not shown.

View File

@ -0,0 +1,36 @@
from openai import OpenAI
from django.core.management.base import BaseCommand
from inventory.models import CarSerie
from django.conf import settings
class Command(BaseCommand):
help = 'Translates to Arabic and saves them in arabic_name field.'
def handle(self, *args, **kwargs):
client = OpenAI(api_key=settings.OPENAI_API_KEY)
car_serie = CarSerie.objects.filter(id_car_model__car__id_car_make__is_sa_import=True)[:500]
total = car_serie.count()
print(f'Translating {total} names...')
for index, car_serie in enumerate(car_serie, start=1):
try:
completion = client.chat.completions.create(
model="gpt-4",
messages=[
{
"role": "system",
"content": "You are a translation assistant that translates English to Arabic."
},
{
"role": "user",
"content": car_serie.name
}
],
temperature=0.3,
)
translation = completion.choices[0].message.content.strip()
car_serie.arabic_name = translation
car_serie.save()
print(f"[{index}/{total}] Translated '{car_serie.name}' to '{translation}'")
except Exception as e:
print(f"Error translating '{car_serie.name}': {e}")

View File

@ -0,0 +1,23 @@
# Generated by Django 5.1.4 on 2024-12-10 11:45
from decimal import Decimal
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0004_remove_carfinance_administration_vat_amount_and_more'),
]
operations = [
migrations.AlterModelOptions(
name='carfinance',
options={'verbose_name': 'Car Financial Details'},
),
migrations.AlterField(
model_name='carfinance',
name='total',
field=models.DecimalField(blank=True, decimal_places=2, default=Decimal('0.00'), max_digits=14, null=True),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 5.1.4 on 2024-12-10 14:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0005_alter_carfinance_options_alter_carfinance_total'),
]
operations = [
migrations.AlterField(
model_name='car',
name='status',
field=models.CharField(choices=[('available', 'Available'), ('sold', 'Sold'), ('hold', 'Hold'), ('damaged', 'Damaged'), ('reserved', 'Reserved')], default='available', max_length=10, verbose_name='Status'),
),
]

View File

@ -0,0 +1,43 @@
# Generated by Django 5.1.4 on 2024-12-10 22:52
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0006_alter_car_status'),
]
operations = [
migrations.AddField(
model_name='salequotation',
name='amount',
field=models.DecimalField(decimal_places=2, default=100000, max_digits=10, verbose_name='Amount'),
preserve_default=False,
),
migrations.AddField(
model_name='salequotation',
name='dealer',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='sales', to='inventory.dealer'),
preserve_default=False,
),
migrations.AddField(
model_name='salequotationcar',
name='dealer',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='sale_cars', to='inventory.dealer', verbose_name='Dealer'),
preserve_default=False,
),
migrations.AddField(
model_name='salequotationcar',
name='price',
field=models.DecimalField(decimal_places=2, default=12000.0, editable=False, max_digits=10, verbose_name='Price'),
preserve_default=False,
),
migrations.AddField(
model_name='salequotationcar',
name='quantity',
field=models.PositiveIntegerField(default=1, verbose_name='Quantity'),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 5.1.4 on 2024-12-10 23:02
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0007_salequotation_amount_salequotation_dealer_and_more'),
]
operations = [
migrations.AddField(
model_name='carfinance',
name='vat_amount',
field=models.DecimalField(decimal_places=2, default=2300, editable=False, max_digits=14, verbose_name='Vat Amount'),
preserve_default=False,
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 5.1.4 on 2024-12-11 12:09
from decimal import Decimal
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0008_carfinance_vat_amount'),
]
operations = [
migrations.AlterField(
model_name='salequotation',
name='amount',
field=models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=10, verbose_name='Amount'),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 5.1.4 on 2024-12-11 12:16
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0009_alter_salequotation_amount'),
]
operations = [
migrations.AlterField(
model_name='salequotation',
name='dealer',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sales', to='inventory.dealer'),
),
]

View File

@ -0,0 +1,17 @@
# Generated by Django 5.1.4 on 2024-12-11 12:17
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '0010_alter_salequotation_dealer'),
]
operations = [
migrations.RemoveField(
model_name='salequotationcar',
name='dealer',
),
]

View File

@ -0,0 +1,17 @@
# Generated by Django 5.1.4 on 2024-12-11 12:18
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '0011_remove_salequotationcar_dealer'),
]
operations = [
migrations.RemoveField(
model_name='salequotationcar',
name='price',
),
]

View File

@ -112,6 +112,7 @@ class CarStatusChoices(models.TextChoices):
SOLD = 'sold', _('Sold')
HOLD = 'hold', _('Hold')
DAMAGED = 'damaged', _('Damaged')
RESERVED = 'reserved', _('Reserved')
class CarStockTypeChoices(models.TextChoices):
@ -171,13 +172,13 @@ class Car(models.Model):
)
status = models.CharField(
max_length=10,
choices=CarStatusChoices.choices,
choices=CarStatusChoices,
default=CarStatusChoices.AVAILABLE,
verbose_name=_("Status")
)
stock_type = models.CharField(
max_length=10,
choices=CarStockTypeChoices.choices,
choices=CarStockTypeChoices,
default=CarStockTypeChoices.NEW,
verbose_name=_("Stock Type")
)
@ -204,6 +205,11 @@ class Car(models.Model):
finance = self.finances.first()
return finance.selling_price if finance else Decimal('0.00')
@property
def discount_amount(self):
finance = self.finances.first()
return finance.discount_amount if finance else Decimal('0.00')
@property
def vat_amount(self):
finance = self.finances.first()
@ -238,6 +244,10 @@ class CarFinance(models.Model):
decimal_places=2,
verbose_name=_("Profit Margin"),
editable=False)
vat_amount = models.DecimalField(max_digits=14,
decimal_places=2,
verbose_name=_("Vat Amount"),
editable=False)
discount_amount = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Discount Amount"),
default=Decimal('0.00'))
registration_fee = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Registration Fee"),
@ -249,17 +259,19 @@ class CarFinance(models.Model):
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)
class Meta:
verbose_name = _("Car Financial Details")
def __str__(self):
return f"{self.selling_price}"
def save(self, *args, **kwargs):
self.full_clean()
try:
self.profit_margin = self.selling_price - self.cost_price - self.discount_amount
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
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:
@ -267,10 +279,14 @@ class CarFinance(models.Model):
super().save(*args, **kwargs)
class Meta:
verbose_name = _("Car Financial Details")
@property
def total_vat_amount(self):
return self.total if self.total else Decimal('0.00')
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
class ExteriorColors(models.Model, LocalizedNameMixin):
@ -413,6 +429,10 @@ class Customer(models.Model):
middle = f" {self.middle_name}" if self.middle_name else ''
return f"{self.first_name}{middle} {self.last_name}"
@property
def get_full_name(self):
return f"{self.first_name} {self.middle_name} {self.last_name}"
class SaleQuotation(models.Model):
STATUS_CHOICES = [
@ -420,8 +440,9 @@ class SaleQuotation(models.Model):
("CONFIRMED", _("Confirmed")),
("CANCELED", _("Canceled")),
]
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name='sales', null=True)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name="quotations", verbose_name=_("Customer"))
amount = models.DecimalField(decimal_places=2, default=Decimal('0.00'), max_digits=10, verbose_name=_("Amount"))
remarks = models.TextField(blank=True, null=True, verbose_name=_("Remarks"))
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default="DRAFT", verbose_name=_("Status"))
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Created At"))
@ -457,6 +478,11 @@ class SaleQuotationCar(models.Model):
on_delete=models.CASCADE,
verbose_name=_("Car")
)
# dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="sale_cars", verbose_name=_("Dealer"))
quantity = models.PositiveIntegerField(default=1, verbose_name=_("Quantity"))
# price = models.DecimalField(decimal_places=2, max_digits=10, verbose_name=_("Price"), editable=False)
def get_financial_details(self):
"""Retrieve financial details dynamically from CarFinance."""
@ -488,128 +514,3 @@ class SalesOrder(models.Model):
return f"Sales Order #{self.id} from Quotation #{self.quotation.id}"
# Create Entity
@receiver(post_save, sender=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"))
if default_coa:
entity.populate_default_coa(activate_accounts=True, coa_model=default_coa)
print(f"Ledger entity created for Dealer: {instance.name}")
# # Create Vendor
@receiver(post_save, sender=Vendor)
def create_ledger_vendor(sender, instance, created, **kwargs):
if created:
entity = EntityModel.objects.filter(name=instance.dealer.name).first()
vendor = VendorModel.objects.update_or_create(
entity_model=entity,
vendor_name=instance.name,
vendor_number=instance.crn,
address_1=instance.address,
phone=instance.phone_number,
tax_id_number=instance.vrn,
active=True,
hidden=False,
additional_info={
"arabic_name": instance.arabic_name,
"contact_person": instance.contact_person,
},
)
print(f"VendorModel created for Vendor: {instance.name}")
@receiver(post_save, sender=Customer)
def create_customer(sender, instance, created, **kwargs):
if created:
entity = EntityModel.objects.filter(name=instance.dealer.name).first()
name = f"{instance.first_name} {instance.middle_name} {instance.last_name}"
customer = CustomerModel.objects.create(
entity_model=entity,
customer_name=name,
customer_number=instance.national_id,
address_1=instance.address,
phone=instance.phone_number,
email=instance.email,
sales_tax_rate=0.15,
)
print(f"Customer created: {name}")
# # Create Item
# @receiver(post_save, sender=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()
#
# 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
# @receiver(post_save, sender=CarFinance)
# def update_item_model_cost(sender, instance, created, **kwargs):
#
# ItemModel.objects.filter(item_id=instance.car.vin).update(
# inventory_received_value=instance.cost_price,
# default_amount=instance.cost_price,
# )
# print(f"Inventory item updated with CarFinance data for Car: {instance.car}")

View File

@ -68,3 +68,11 @@ def calculate_stock_value():
total_value = sum(car.selling_price for car in cars)
return total_value
# from django_ledger.models import EntityModel
#
# def get_purchase_orders():
# entity = EntityModel.objects.get(name='Marwan2')
# items = entity.
# print(items.values())
# return items

View File

@ -1,20 +1,175 @@
# from django.db.models.signals import post_save, post_delete
# from django.dispatch import receiver
# from . import models
#
#
# @receiver(post_save, sender=models.CarReservation)
# def update_car_status_on_reservation(sender, instance, created, **kwargs):
# if created:
# car = instance.car
# car.status = models.CarStatusChoices.RESERVED
# car.save()
#
#
# @receiver(post_delete, sender=models.CarReservation)
# def update_car_status_on_reservation_delete(sender, instance, **kwargs):
# car = instance.car
# if not car.get_current_reservation():
# car.status = models.CarStatusChoices.AVAILABLE
# car.save()
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.utils.translation import gettext_lazy as _
from . import models
@receiver(post_save, sender=models.CarReservation)
def update_car_status_on_reservation(sender, instance, created, **kwargs):
if created:
car = instance.car
car.status = models.CarStatusChoices.RESERVED
car.save()
@receiver(post_delete, sender=models.CarReservation)
def update_car_status_on_reservation_delete(sender, instance, **kwargs):
car = instance.car
if not car.get_current_reservation():
car.status = models.CarStatusChoices.AVAILABLE
car.save()
# 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"))
# entity.create_account(
# coa_model=coa,
# code=1010,
# role='asset_ca_cash',
# name=_('Cash'),
# balance_type="debit",
# )
# entity.create_account(
# coa_model=coa,
# code=1200,
# role='asset_ca_inv',
# name=_('Inventory'),
# 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}")
# # Create Vendor
@receiver(post_save, sender=models.Vendor)
def create_ledger_vendor(sender, instance, created, **kwargs):
if created:
entity = EntityModel.objects.filter(name=instance.dealer.name).first()
entity.create_vendor(
vendor_name=instance.name,
vendor_number=instance.crn,
address_1=instance.address,
phone=instance.phone_number,
tax_id_number=instance.vrn,
active=True,
hidden=False,
additional_info={
"arabic_name": instance.arabic_name,
"contact_person": instance.contact_person,
})
print(f"VendorModel created for Vendor: {instance.name}")
@receiver(post_save, sender=models.Customer)
def create_customer(sender, instance, created, **kwargs):
if created:
entity = EntityModel.objects.filter(name=instance.dealer.name).first()
name = f"{instance.first_name} {instance.middle_name} {instance.last_name}"
entity.create_customer(
customer_name=name,
customer_number=instance.national_id,
address_1=instance.address,
phone=instance.phone_number,
email=instance.email,
sales_tax_rate=0.15,
active=True,
hidden=False,
additional_info={}
)
print(f"Customer created: {name}")
# 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}")
#
#
# # update price - CarFinance
# @receiver(post_save, sender=CarFinance)
# def update_item_model_cost(sender, instance, created, **kwargs):
#
# ItemModel.objects.filter(item_id=instance.car.vin).update(
# inventory_received_value=instance.cost_price,
# default_amount=instance.cost_price,
# )
# print(f"Inventory item updated with CarFinance data for Car: {instance.car}")

View File

@ -153,7 +153,7 @@ class AjaxHandlerView(LoginRequiredMixin, View):
manufacturer_name = vin_info.Make.strip()
model_name = vin_info.Model.strip()
year_model = vin_info.ModelYear
if not manufacturer_name or not year_model:
if not manufacturer_name or not model_name or not year_model:
raise ValueError('PYVIN returned incomplete data.')
elif method_name == 'VIN':
manufacturer_name = vin_info.make.strip()
@ -164,15 +164,11 @@ class AjaxHandlerView(LoginRequiredMixin, View):
elif method_name == 'ELM':
elm_data = vin_info.get('data', {})
manufacturer_name = elm_data.get('maker', '').strip()
print(manufacturer_name)
model_name = elm_data.get('model', '').strip()
print(model_name)
year_model = elm_data.get('modelYear', '').strip()
print(year_model)
if not manufacturer_name or not model_name or not year_model:
raise ValueError('ELM returned incomplete data.')
# model_name = normalize_name(model_name_before)
decoding_method = method_name
print(f"decoded by {method_name}")
break
@ -188,19 +184,27 @@ class AjaxHandlerView(LoginRequiredMixin, View):
f"VIN decoded using {decoding_method}: Make={manufacturer_name}, Model={model_name}, Year={year_model}"
)
regex_make= manufacturer_name.replace(" ", "[- ]?")
car_make = models.CarMake.objects.filter(name__iregex=regex_make).first()
car_make = (models.CarMake.objects
.filter(name__iregex=regex_make, is_sa_import=True)
.first())
if not car_make:
return JsonResponse({'success': False, 'error': 'Manufacturer not found in the database.'}, status=404)
vin_data['make_id'] = car_make.id_car_make
vin_data['name'] = car_make.name
vin_data['arabic_name'] = car_make.arabic_name
# car_model = models.CarModel.objects.filter(id_car_make=car_make.id_car_make, name__contains=model_name).first()
regex_pattern = model_name.replace(" ", "[- ]?")
car_model = models.CarModel.objects.filter(id_car_make=car_make.id_car_make, name__iregex=regex_pattern).first()
car_model = (models.CarModel.objects
.filter(id_car_make=car_make.id_car_make,
name__iregex=regex_pattern)
.first()
)
if not car_model:
return JsonResponse({'success': False, 'error': 'Model not found for the given manufacturer.'}, status=404)
return JsonResponse(
{'success': False,
'error': 'Model not found for the given manufacturer.'}, status=404)
vin_data['model_id'] = car_model.id_car_model
vin_data['year'] = year_model
@ -208,7 +212,11 @@ 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,
id_car_make__is_sa_import=True)
.values('id_car_model', 'name', 'arabic_name')
)
return JsonResponse(list(car_models), safe=False)
def get_series(self, request):
@ -685,6 +693,7 @@ class QuotationCreateView(LoginRequiredMixin, CreateView):
template_name = 'sales/quotation_form.html'
def form_valid(self, form):
form.instance.dealer = self.request.user.dealer
quotation = form.save()
selected_cars = form.cleaned_data.get("cars")
for car in selected_cars:

3
ledger_testing.py Normal file
View File

@ -0,0 +1,3 @@

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -55,9 +55,9 @@ small, .small {
<script type="text/javascript" src="{% static 'js/main.js' %}"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
$('.form-select').select2({
/* $('.form-select').select2({
theme: 'bootstrap4',
});
});*/
'use strict';
// Fetch all the forms with the "needs-validation" class

View File

@ -21,12 +21,12 @@
</div>
<div class="btn-group">
<button type="button"
class="btn btn-secondary"
class="btn btn-sm btn-secondary"
data-bs-dismiss="modal">
{% trans 'No' %}
</button>
<a type="button"
class="btn btn-danger"
class="btn btn-sm btn-danger"
href="{% url 'customer_delete' customer.id %}">
{% trans 'Yes' %}
</a>
@ -56,17 +56,17 @@
</div>
</div>
<div class="card-footer d-flex ">
<a class="btn btn-primary me-1" href="{% url 'customer_update' customer.id %}">
<a class="btn btn-sm btn-primary me-1" href="{% url 'customer_update' customer.id %}">
<!--<i class="bi bi-pencil-square"></i> -->
{{ _("Edit") }}
</a>
<a class="btn btn-danger me-1"
<a class="btn btn-sm btn-danger me-1"
data-bs-toggle="modal"
data-bs-target="#deleteModal">
<!--<i class="bi bi-trash-fill"></i>-->
{{ _("Delete") }}
</a>
<a class="btn btn-secondary"
<a class="btn btn-sm btn-secondary"
href="{% url 'customer_list' %}">
<!--<i class="bi bi-arrow-left-square-fill"></i>-->
{% trans "Back to List" %}

BIN
templates/partials/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -12,7 +12,7 @@
<h5>{% trans "Customer Details" %}</h5>
<p>
<strong>{% trans "Name" %}:</strong>
{{ quotation.customer.first_name }} {{ quotation.customer.last_name_name }}</p>
{{ quotation.customer.get_full_name }}</p>
<p><strong>{% trans "Address" %}:</strong> {{ quotation.customer.address }}</p>
<p><strong>{% trans "VAT No" %}:</strong> {{ quotation.customer.vat_number }}</p>
</div>
@ -32,7 +32,6 @@
<th>Model</th>
<th>Selling Price</th>
<th>VAT</th>
<th>Total Before VAT</th>
<th>Total</th>
</tr>
</thead>
@ -42,18 +41,17 @@
<td>{{ item.car.vin }}</td>
<td>{{ item.car.id_car_model.get_local_name }}</td>
<td>{{ item.car.selling_price }}</td>
<td>{{ item.car.total_vat_amount }}</td>
<td>{{ item.car.total_before_vat }}</td>
<td>{{ item.car.vat_amount }}</td>
<td>{{ item.car.total }}</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<th colspan="3">Totals</th>
<th>{{ item.car.total_vat_amount }}</th>
<th>{{ item.car.total_before_vat }}</th>
<th>{{ item.car.total }}</th>
<th colspan="2">Totals</th>
<th>{{ item.car.finances.total_vat_amount }}</th>
<th>{{ item.car.finances.total_before_vat }}</th>
<th>{{ item.car.finances.total }}</th>
</tr>
</tfoot>
</table>

View File

@ -24,7 +24,7 @@
<td>{{ forloop.counter }}</td>
<td>{{ quotation.customer.get_full_name }}</td>
<td>{{ quotation.quotation_cars.count }}</td>
<td>{{ quotation.total }}</td>
<td>{{ quotation.quotation_cars.get_financial_details.total_amount }}</td>
<td>{{ quotation.created_at|date:"d/m/Y H:i" }}</td>
<td>
<a href="{% url 'quotation_detail' quotation.id %}" class="btn btn-sm btn-info">

View File

@ -6,7 +6,7 @@
{% block content %}
<div class="container-fluid p-3">
<div class="card shadow-sm">
<div class="card shadow rounded">
<div class="card-header d-flex justify-content-between align-items-center">
<h6 class="mb-0">{{ _("Vendors")|capfirst }}</h6>
<form method="get" class="d-inline-block">

View File

@ -1,56 +1,74 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "View Vendor" %}{% endblock title %}
{% block content %}
<!-- Delete Modal -->
<div class="modal fade" id="deleteModal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="deleteModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-sm ">
<div class="modal-content rounded">
<div class="modal-body d-flex justify-content-center">
<h1 class="text-danger me-2"><i class="bi bi-exclamation-diamond-fill"></i></h1>
<span class="text-danger">
{% trans "Are you sure you want to delete this vendor?" %}
</span>
</div>
<div class="btn-group">
<button type="button"
class="btn btn-secondary"
data-bs-dismiss="modal">
{% trans 'No' %}
</button>
<a type="button"
class="btn btn-danger"
href="{% url 'vendor_delete' vendor.id %}">
{% trans 'Yes' %}
</a>
</div>
<!-- Delete Modal -->
<div class="modal fade" id="deleteModal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="deleteModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header bg-danger text-white">
<h5 class="modal-title" id="deleteModalLabel">
<i class="bi bi-exclamation-diamond-fill"></i>
{% trans "Delete Vendor" %}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-center">
<p class="mb-0 text-danger fw-bold">
{% trans "Are you sure you want to delete this vendor?" %}
</p>
</div>
<div class="modal-footer justify-content-center">
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">
{% trans "No" %}
</button>
<a type="button" class="btn btn-danger btn-sm" href="{% url 'vendor_delete' vendor.id %}">
{% trans "Yes" %}
</a>
</div>
</div>
</div>
<div class="container">
<h1>{% trans "Vendor Details" %}</h1>
<ul>
<li><strong>{% trans "Name" %}:</strong>
{{ vendor.get_local_name }}
</li>
<li><strong>{% trans "Contact Person" %}:</strong> {{ vendor.contact_person }}</li>
<li><strong>{% trans "Phone Number" %}:</strong> {{ vendor.phone_number }}</li>
<li><strong>{% trans "Email" %}:</strong> {{ vendor.email }}</li>
<li><strong>{% trans "Address" %}:</strong> {{ vendor.address }}</li>
</ul>
<a class="btn btn-sm btn-primary" href="{% url 'vendor_update' vendor.id %}">{% trans "Edit" %}</a>
<a class="btn btn-sm btn-danger me-1"
data-bs-toggle="modal"
data-bs-target="#deleteModal">
<!--<i class="bi bi-trash-fill"></i>-->
{{ _("Delete") }}
</div>
<!-- Vendor Details -->
<div class="container mt-4">
<div class="card shadow rounded">
<div class="card-header bg-primary text-white">
<h4 class="mb-0">{% trans "Vendor Details" %}</h4>
</div>
<div class="card-body">
<ul class="list-group list-group-flush">
<li class="list-group-item">
<strong>{% trans "Name" %}:</strong> {{ vendor.get_local_name }}
</li>
<li class="list-group-item">
<strong>{% trans "Contact Person" %}:</strong> {{ vendor.contact_person }}
</li>
<li class="list-group-item">
<strong>{% trans "Phone Number" %}:</strong> {{ vendor.phone_number }}
</li>
<li class="list-group-item">
<strong>{% trans "Email" %}:</strong> {{ vendor.email }}
</li>
<li class="list-group-item">
<strong>{% trans "Address" %}:</strong> {{ vendor.address }}
</li>
</ul>
</div>
<div class="card-footer d-flex justify-content-between">
<a class="btn btn-sm btn-primary" href="{% url 'vendor_update' vendor.id %}">
{% trans "Edit" %}
</a>
<button class="btn btn-sm btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">
{% trans "Delete" %}
</button>
</div>
</div>
</div>
{% endblock %}

View File

@ -1,20 +1,8 @@
# from vin import VIN
from vin import VIN
import requests
import json
#
# vin_no = 'VR7ED9HP6SJ522156'
#
# details = {
# # 'Description': VIN(vin_no).description,
# 'make': VIN(vin_no).make,
# 'year': VIN(vin_no).model_year,
# 'model': VIN(vin_no).model,
# 'trim': VIN(vin_no).trim,
# 'Series': VIN(vin_no).series,
# 'body_class': VIN(vin_no).body_class,
# 'Type': VIN(vin_no).vehicle_type,
# 'Electrification level': VIN(vin_no).electrification_level,
# }
#
# print(details)
@ -62,7 +50,7 @@ import json
#
# from pyvin import VIN
#
# number_vin = 'VR7ED9HP6SJ522156'
# number_vin = '5LMCJ2D93NUL03460'
#
# vehicle = VIN(number_vin)
# if vehicle:
@ -84,9 +72,25 @@ import json
# print(e)
# else:
# print("No vehicle found")
# vin_info_py(number_vin)
vin_no = '5LMCJ2D93NUL03460'
details = {
# 'Description': VIN(vin_no).description,
'make': VIN(vin_no).make,
'year': VIN(vin_no).model_year,
'model': VIN(vin_no).model,
'trim': VIN(vin_no).trim,
'Series': VIN(vin_no).series,
'body_class': VIN(vin_no).body_class,
'Type': VIN(vin_no).vehicle_type,
'Electrification level': VIN(vin_no).electrification_level,
}
print(details)
# from vpic import Client
#
# c = Client()
@ -120,11 +124,11 @@ import json
#
# except Exception as e:
# print(e)
vin_no = "LS5A3DKR0SA966230"
url = "https://vin17.com/Search/query?vin=+"+vin_no
response = requests.request("GET", url)
car_info = json.loads(response.text)
print(car_info)
# vin_no = "LS5A3DKR0SA966230"
#
#
# url = "https://vin17.com/Search/query?vin=+"+vin_no
#
# response = requests.request("GET", url)
# car_info = json.loads(response.text)
# print(car_info)