Compare commits
7 Commits
7c9039ce06
...
0988864285
| Author | SHA1 | Date | |
|---|---|---|---|
| 0988864285 | |||
| f5c15feca1 | |||
| 0d24584c81 | |||
| f6958f0cb0 | |||
| c0718cbf20 | |||
| 74993eec94 | |||
| 79df3da4cc |
@ -5,8 +5,4 @@ class InventoryConfig(AppConfig):
|
||||
name = 'inventory'
|
||||
|
||||
def ready(self):
|
||||
pass
|
||||
#from decimal import Decimal
|
||||
#from inventory.models import VatRate
|
||||
#VatRate.objects.get_or_create(rate=Decimal('0.15'), is_active=True)
|
||||
|
||||
import inventory.signals
|
||||
|
||||
@ -550,7 +550,7 @@ class CarColorsForm(forms.ModelForm):
|
||||
model = CarColors
|
||||
fields = ["exterior", "interior"]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.fields["exterior"].queryset = ExteriorColors.objects.all()
|
||||
|
||||
20
inventory/migrations/0009_car_item_model.py
Normal file
20
inventory/migrations/0009_car_item_model.py
Normal file
@ -0,0 +1,20 @@
|
||||
# Generated by Django 5.1.7 on 2025-05-25 11:41
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_ledger', '0021_alter_bankaccountmodel_account_model_and_more'),
|
||||
('inventory', '0008_lead_salary'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='car',
|
||||
name='item_model',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to='django_ledger.itemmodel', verbose_name='Item Model'),
|
||||
),
|
||||
]
|
||||
20
inventory/migrations/0010_alter_car_item_model.py
Normal file
20
inventory/migrations/0010_alter_car_item_model.py
Normal file
@ -0,0 +1,20 @@
|
||||
# Generated by Django 5.1.7 on 2025-05-25 11:43
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_ledger', '0021_alter_bankaccountmodel_account_model_and_more'),
|
||||
('inventory', '0009_car_item_model'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='car',
|
||||
name='item_model',
|
||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to='django_ledger.itemmodel', verbose_name='Item Model'),
|
||||
),
|
||||
]
|
||||
20
inventory/migrations/0011_alter_car_item_model.py
Normal file
20
inventory/migrations/0011_alter_car_item_model.py
Normal file
@ -0,0 +1,20 @@
|
||||
# Generated by Django 5.1.7 on 2025-05-25 11:44
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('django_ledger', '0021_alter_bankaccountmodel_account_model_and_more'),
|
||||
('inventory', '0010_alter_car_item_model'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='car',
|
||||
name='item_model',
|
||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='django_ledger.itemmodel', verbose_name='Item Model'),
|
||||
),
|
||||
]
|
||||
18
inventory/migrations/0012_carfinance_is_sold.py
Normal file
18
inventory/migrations/0012_carfinance_is_sold.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.1.7 on 2025-05-25 14:19
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('inventory', '0011_alter_car_item_model'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='carfinance',
|
||||
name='is_sold',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
||||
@ -458,6 +458,13 @@ class AdditionalServices(models.Model, LocalizedNameMixin):
|
||||
|
||||
|
||||
class Car(Base):
|
||||
item_model = models.OneToOneField(
|
||||
ItemModel,
|
||||
models.DO_NOTHING,
|
||||
verbose_name=_("Item Model"),
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
vin = models.CharField(max_length=17, unique=True, verbose_name=_("VIN"))
|
||||
dealer = models.ForeignKey(
|
||||
"Dealer", models.DO_NOTHING, related_name="cars", verbose_name=_("Dealer")
|
||||
@ -562,7 +569,7 @@ class Car(Base):
|
||||
color = ""
|
||||
try:
|
||||
color = self.colors.exterior.name if self.colors else ""
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
make = self.id_car_make.name if self.id_car_make else ""
|
||||
model = self.id_car_model.name if self.id_car_model else ""
|
||||
@ -572,12 +579,10 @@ class Car(Base):
|
||||
hash_object.update(f"{make}{model}{year}{serie}{trim}{color}".encode('utf-8'))
|
||||
return hash_object.hexdigest()
|
||||
|
||||
def mark_as_sold(self,request):
|
||||
dealer = get_user_type(request)
|
||||
def mark_as_sold(self):
|
||||
self.cancel_reservation()
|
||||
self.status = CarStatusChoices.SOLD
|
||||
self.save()
|
||||
Activity.objects.create(dealer=dealer,content_object=self, notes=_("Car Sold"),created_by=request.user,activity_type=ActionChoices.SALE_CAR)
|
||||
|
||||
def cancel_reservation(self):
|
||||
if self.reservations.exists():
|
||||
@ -607,6 +612,13 @@ class Car(Base):
|
||||
specs = CarSpecificationValue.objects.filter(id_car_trim=self.id_car_trim)
|
||||
return specs
|
||||
|
||||
def get_inventory_account(self):
|
||||
return self.dealer.entity.get_all_accounts().filter(name=f"Inventory:{self.id_car_make.name}").first()
|
||||
def get_revenue_account(self):
|
||||
return self.dealer.entity.get_all_accounts().filter(name=f"Revenue:{self.id_car_make.name}").first()
|
||||
def get_cogs_account(self):
|
||||
return self.dealer.entity.get_all_accounts().filter(name=f"Cogs:{self.id_car_make.name}").first()
|
||||
|
||||
class CarTransfer(models.Model):
|
||||
car = models.ForeignKey(
|
||||
"Car",
|
||||
@ -704,6 +716,8 @@ class CarFinance(models.Model):
|
||||
verbose_name=_("Discount Amount"),
|
||||
default=Decimal("0.00"),
|
||||
)
|
||||
is_sold = models.BooleanField(default=False)
|
||||
|
||||
|
||||
@property
|
||||
def total(self):
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from inventory.tasks import create_coa_accounts
|
||||
from decimal import Decimal
|
||||
from inventory.tasks import create_coa_accounts, create_make_accounts
|
||||
from django.contrib.auth.models import Group
|
||||
from django.db.models.signals import post_save, post_delete
|
||||
from django.dispatch import receiver
|
||||
@ -10,7 +11,8 @@ from django_ledger.models import (
|
||||
ItemModel,
|
||||
JournalEntryModel,
|
||||
TransactionModel,
|
||||
LedgerModel
|
||||
LedgerModel,
|
||||
AccountModel
|
||||
)
|
||||
from . import models
|
||||
from django.utils.timezone import now
|
||||
@ -202,23 +204,30 @@ def create_item_model(sender, instance, created, **kwargs):
|
||||
:return: None
|
||||
"""
|
||||
entity = instance.dealer.entity
|
||||
|
||||
if created:
|
||||
coa = entity.get_default_coa()
|
||||
uom = entity.get_uom_all().get(name="Unit")
|
||||
|
||||
if not entity.get_items_all().filter(name=instance.vin).exists():
|
||||
product = entity.create_item_product(
|
||||
if not instance.item_model:
|
||||
inventory = entity.create_item_product(
|
||||
name=instance.vin,
|
||||
item_type=ItemModel.ITEM_TYPE_MATERIAL,
|
||||
uom_model=uom,
|
||||
coa_model=coa,
|
||||
)
|
||||
product.additional_info = {}
|
||||
product.save()
|
||||
|
||||
product = entity.get_items_all().filter(name=instance.vin).first()
|
||||
product.additional_info.update({'car_info': instance.to_dict()})
|
||||
product.save()
|
||||
# inventory = entity.create_item_inventory(
|
||||
# name=instance.vin,
|
||||
# uom_model=uom,
|
||||
# item_type=ItemModel.ITEM_TYPE_LUMP_SUM
|
||||
# )
|
||||
instance.item_model = inventory
|
||||
inventory.additional_info = {}
|
||||
inventory.additional_info.update({'car_info': instance.to_dict()})
|
||||
inventory.save()
|
||||
else:
|
||||
instance.item_model.additional_info.update({'car_info': instance.to_dict()})
|
||||
instance.item_model.save()
|
||||
|
||||
# # update price - CarFinance
|
||||
@receiver(post_save, sender=models.CarFinance)
|
||||
@ -235,16 +244,49 @@ def update_item_model_cost(sender, instance, created, **kwargs):
|
||||
:param kwargs: Additional keyword arguments passed during the signal invocation.
|
||||
:return: None
|
||||
"""
|
||||
entity = instance.car.dealer.entity
|
||||
if created and not instance.is_sold:
|
||||
entity = instance.car.dealer.entity
|
||||
coa = entity.get_default_coa()
|
||||
inventory_account = entity.get_all_accounts().filter(name=f'Inventory:{instance.car.id_car_make.name}').first()
|
||||
if not inventory_account:
|
||||
inventory_account = create_make_accounts(entity,coa,[instance.car.id_car_make],"Inventory",roles.ASSET_CA_INVENTORY,"debit")
|
||||
|
||||
product = entity.get_items_all().filter(name=instance.car.vin).first()
|
||||
cogs = entity.get_all_accounts().filter(name=f'Cogs:{instance.car.id_car_make.name}').first()
|
||||
if not cogs:
|
||||
cogs = create_make_accounts(entity,coa,[instance.car.id_car_make],"Cogs",roles.COGS,"debit")
|
||||
revenue = entity.get_all_accounts().filter(name=f'Revenue:{instance.car.id_car_make.name}').first()
|
||||
if not revenue:
|
||||
revenue = create_make_accounts(entity,coa,[instance.car.id_car_make],"Revenue",roles.ASSET_CA_RECEIVABLES,"credit")
|
||||
|
||||
product.default_amount = instance.selling_price
|
||||
if not isinstance(product.additional_info, dict):
|
||||
product.additional_info = {}
|
||||
product.additional_info.update({"car_finance":instance.to_dict()})
|
||||
product.additional_info.update({"additional_services": [service.to_dict() for service in instance.additional_services.all()]})
|
||||
product.save()
|
||||
cash_account = entity.get_all_accounts().filter(name="Cash",role=roles.ASSET_CA_CASH).first()
|
||||
|
||||
ledger = LedgerModel.objects.create(entity=entity, name=f"Inventory Purchase - {instance.car}")
|
||||
je = JournalEntryModel.objects.create(
|
||||
ledger=ledger,
|
||||
description=f"Acquired {instance.car} for inventory",
|
||||
)
|
||||
TransactionModel.objects.create(
|
||||
journal_entry=je,
|
||||
account=inventory_account,
|
||||
amount=Decimal(instance.cost_price),
|
||||
tx_type="debit",
|
||||
description="",
|
||||
)
|
||||
|
||||
TransactionModel.objects.create(
|
||||
journal_entry=je,
|
||||
account=cash_account,
|
||||
amount=Decimal(instance.cost_price),
|
||||
tx_type="credit",
|
||||
description="",
|
||||
)
|
||||
|
||||
instance.car.item_model.default_amount = instance.selling_price
|
||||
if not isinstance(instance.car.item_model.additional_info, dict):
|
||||
instance.car.item_model.additional_info = {}
|
||||
instance.car.item_model.additional_info.update({"car_finance":instance.to_dict()})
|
||||
instance.car.item_model.additional_info.update({"additional_services": [service.to_dict() for service in instance.additional_services.all()]})
|
||||
instance.car.item_model.save()
|
||||
print(f"Inventory item updated with CarFinance data for Car: {instance.car}")
|
||||
|
||||
|
||||
@ -695,7 +737,6 @@ def save_journal(car_finance,ledger,vendor):
|
||||
account=vendor_account,
|
||||
amount=car_finance.cost_price,
|
||||
tx_type='credit',
|
||||
|
||||
)
|
||||
|
||||
@receiver(post_save, sender=models.CarFinance)
|
||||
|
||||
@ -560,28 +560,37 @@ def create_accounts_for_make(dealer,makes):
|
||||
entity = dealer.entity
|
||||
coa = entity.get_default_coa()
|
||||
|
||||
name = ["Inventory", "Revenue", "Cogs"]
|
||||
role = [roles.ASSET_CA_INVENTORY,roles.ASSET_CA_RECEIVABLES, roles.COGS]
|
||||
balance_type = ["debit","credit","debit"]
|
||||
|
||||
for name,role,balance_type in zip(name,role,balance_type):
|
||||
create_make_accounts(entity,coa,makes,name,role,balance_type)
|
||||
|
||||
def create_make_accounts(entity,coa,makes,name,role,balance_type):
|
||||
for make in makes:
|
||||
last_account = entity.get_all_accounts().filter(role=roles.ASSET_CA_RECEIVABLES).order_by('-created').first()
|
||||
last_account = entity.get_all_accounts().filter(role=role).order_by('-created').first()
|
||||
if len(last_account.code) == 4:
|
||||
code = f"{int(last_account.code)}{1:03d}"
|
||||
elif len(last_account.code) > 4:
|
||||
code = f"{int(last_account.code)+1}"
|
||||
|
||||
if not entity.get_all_accounts().filter(
|
||||
name=make.name,
|
||||
role=roles.ASSET_CA_RECEIVABLES,
|
||||
acc = entity.get_all_accounts().filter(
|
||||
name=f"{name}:{make.name}",
|
||||
role=role,
|
||||
coa_model=coa,
|
||||
balance_type="credit",
|
||||
balance_type=balance_type,
|
||||
active=True
|
||||
).exists():
|
||||
entity.create_account(
|
||||
name=make.name,
|
||||
).first()
|
||||
if not acc:
|
||||
acc = entity.create_account(
|
||||
name=f"{name}:{make.name}",
|
||||
code=code,
|
||||
role=roles.ASSET_CA_RECEIVABLES,
|
||||
role=role,
|
||||
coa_model=coa,
|
||||
balance_type="credit",
|
||||
balance_type=balance_type,
|
||||
active=True
|
||||
)
|
||||
return acc
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1141,48 +1141,54 @@ def handle_account_process(invoice,amount,finance_data):
|
||||
:return: None
|
||||
"""
|
||||
for i in invoice.get_itemtxs_data()[0]:
|
||||
car = models.Car.objects.get(vin=invoice.get_itemtxs_data()[0].first().item_model.name)
|
||||
# car = models.Car.objects.get(vin=invoice.get_itemtxs_data()[0].first().item_model.name)
|
||||
car = i.item_model.car
|
||||
entity = invoice.ledger.entity
|
||||
coa = entity.get_default_coa()
|
||||
|
||||
make_account = entity.get_all_accounts().filter(name=car.id_car_make.name,role=roles.COGS).first()
|
||||
if not make_account:
|
||||
last_account = entity.get_all_accounts().filter(role=roles.COGS).order_by('-created').first()
|
||||
if len(last_account.code) == 4:
|
||||
code = f"{int(last_account.code)}{1:03d}"
|
||||
elif len(last_account.code) > 4:
|
||||
code = f"{int(last_account.code)+1}"
|
||||
cash_account = entity.get_all_accounts().filter(name="Cash", role=roles.ASSET_CA_CASH).first()
|
||||
inventory_account = car.get_inventory_account()
|
||||
revenue_account = car.get_revenue_account()
|
||||
cogs_account = car.get_cogs_account()
|
||||
|
||||
make_account = entity.create_account(
|
||||
name=car.id_car_make.name,
|
||||
code=code,
|
||||
role=roles.COGS,
|
||||
coa_model=coa,
|
||||
balance_type="debit",
|
||||
active=True
|
||||
)
|
||||
# make_account = entity.get_all_accounts().filter(name=car.id_car_make.name,role=roles.COGS).first()
|
||||
# if not make_account:
|
||||
# last_account = entity.get_all_accounts().filter(role=roles.COGS).order_by('-created').first()
|
||||
# if len(last_account.code) == 4:
|
||||
# code = f"{int(last_account.code)}{1:03d}"
|
||||
# elif len(last_account.code) > 4:
|
||||
# code = f"{int(last_account.code)+1}"
|
||||
|
||||
# get or create additional services account
|
||||
additional_services_account = entity.get_default_coa_accounts().filter(name="Additional Services",role=roles.COGS).first()
|
||||
if not additional_services_account:
|
||||
last_account = entity.get_all_accounts().filter(role=roles.COGS).order_by('-created').first()
|
||||
if len(last_account.code) == 4:
|
||||
code = f"{int(last_account.code)}{1:03d}"
|
||||
elif len(last_account.code) > 4:
|
||||
code = f"{int(last_account.code)+1}"
|
||||
# make_account = entity.create_account(
|
||||
# name=car.id_car_make.name,
|
||||
# code=code,
|
||||
# role=roles.COGS,
|
||||
# coa_model=coa,
|
||||
# balance_type="debit",
|
||||
# active=True
|
||||
# )
|
||||
|
||||
additional_services_account = entity.create_account(
|
||||
name="Additional Services",
|
||||
code=code,
|
||||
role=roles.COGS,
|
||||
coa_model=coa,
|
||||
balance_type="debit",
|
||||
active=True
|
||||
)
|
||||
# # get or create additional services account
|
||||
# additional_services_account = entity.get_default_coa_accounts().filter(name="Additional Services",role=roles.COGS).first()
|
||||
# if not additional_services_account:
|
||||
# last_account = entity.get_all_accounts().filter(role=roles.COGS).order_by('-created').first()
|
||||
# if len(last_account.code) == 4:
|
||||
# code = f"{int(last_account.code)}{1:03d}"
|
||||
# elif len(last_account.code) > 4:
|
||||
# code = f"{int(last_account.code)+1}"
|
||||
|
||||
inventory_account = entity.get_default_coa_accounts().filter(role=roles.ASSET_CA_INVENTORY).first()
|
||||
# additional_services_account = entity.create_account(
|
||||
# name="Additional Services",
|
||||
# code=code,
|
||||
# role=roles.COGS,
|
||||
# coa_model=coa,
|
||||
# balance_type="debit",
|
||||
# active=True
|
||||
# )
|
||||
|
||||
vat_payable_account = entity.get_default_coa_accounts().get(name="VAT Payable", active=True)
|
||||
# inventory_account = entity.get_default_coa_accounts().filter(role=roles.ASSET_CA_INVENTORY).first()
|
||||
|
||||
# vat_payable_account = entity.get_default_coa_accounts().get(name="VAT Payable", active=True)
|
||||
|
||||
|
||||
journal = JournalEntryModel.objects.create(
|
||||
@ -1190,16 +1196,53 @@ def handle_account_process(invoice,amount,finance_data):
|
||||
description=f"Payment for Invoice {invoice.invoice_number}",
|
||||
ledger=invoice.ledger,
|
||||
locked=False,
|
||||
origin="Payment",
|
||||
origin=f"Sale of {car.name}{car.vin}: Invoice {invoice.invoice_number}",
|
||||
)
|
||||
|
||||
TransactionModel.objects.create(
|
||||
journal_entry=journal,
|
||||
account=make_account, # Debit car make Account
|
||||
account=cash_account,
|
||||
amount=Decimal(finance_data.get("grand_total")),
|
||||
tx_type="debit",
|
||||
description="Payment Received",
|
||||
description="",
|
||||
)
|
||||
|
||||
TransactionModel.objects.create(
|
||||
journal_entry=journal,
|
||||
account=revenue_account,
|
||||
amount=Decimal(finance_data.get("grand_total")),
|
||||
tx_type="credit",
|
||||
description="",
|
||||
)
|
||||
|
||||
journal_cogs = JournalEntryModel.objects.create(
|
||||
posted=False,
|
||||
description=f"COGS of {car.name}{car.vin}: Invoice {invoice.invoice_number}",
|
||||
ledger=invoice.ledger,
|
||||
locked=False,
|
||||
origin="Payment",
|
||||
)
|
||||
TransactionModel.objects.create(
|
||||
journal_entry=journal_cogs,
|
||||
account=cogs_account,
|
||||
amount=Decimal(car.finances.cost_price),
|
||||
tx_type="debit",
|
||||
description="",
|
||||
)
|
||||
|
||||
TransactionModel.objects.create(
|
||||
journal_entry=journal_cogs,
|
||||
account=inventory_account,
|
||||
amount=Decimal(car.finances.cost_price),
|
||||
tx_type="credit",
|
||||
description="",
|
||||
)
|
||||
|
||||
car.item_model.for_inventory = False
|
||||
car.finances.is_sold = True
|
||||
car.finances.save()
|
||||
car.item_model.save()
|
||||
|
||||
# TransactionModel.objects.create(
|
||||
# journal_entry=journal,
|
||||
# account=additional_services_account, # Debit Additional Services
|
||||
@ -1208,13 +1251,13 @@ def handle_account_process(invoice,amount,finance_data):
|
||||
# description="Additional Services",
|
||||
# )
|
||||
|
||||
TransactionModel.objects.create(
|
||||
journal_entry=journal,
|
||||
account=inventory_account, # Credit Inventory account
|
||||
amount=Decimal(finance_data.get("grand_total")),
|
||||
tx_type="credit",
|
||||
description="Account Adjustment",
|
||||
)
|
||||
# TransactionModel.objects.create(
|
||||
# journal_entry=journal,
|
||||
# account=inventory_account, # Credit Inventory account
|
||||
# amount=Decimal(finance_data.get("grand_total")),
|
||||
# tx_type="credit",
|
||||
# description="Account Adjustment",
|
||||
# )
|
||||
|
||||
# TransactionModel.objects.create(
|
||||
# journal_entry=journal,
|
||||
|
||||
@ -941,6 +941,37 @@ class CarColorCreate(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
|
||||
context["car"] = get_object_or_404(models.Car, slug=self.kwargs["slug"])
|
||||
return context
|
||||
|
||||
class CarColorsUpdateView( LoginRequiredMixin, PermissionRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||
model = models.CarColors
|
||||
form_class = forms.CarColorsForm
|
||||
template_name = "inventory/add_colors.html"
|
||||
success_message = _("Car finance details updated successfully")
|
||||
permission_required = ["inventory.change_carfinance"]
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse("car_detail", kwargs={"slug": self.object.car.slug})
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs["instance"] = self.get_object()
|
||||
return kwargs
|
||||
|
||||
def get_initial(self):
|
||||
initial = super().get_initial()
|
||||
instance = self.get_object()
|
||||
dealer = get_user_type(self.request)
|
||||
selected_items = instance.additional_services.filter(dealer=dealer)
|
||||
initial["additional_finances"] = selected_items
|
||||
return initial
|
||||
|
||||
def get_form(self, form_class=None):
|
||||
form = super().get_form(form_class)
|
||||
dealer = get_user_type(self.request)
|
||||
form.fields[
|
||||
"additional_finances"
|
||||
].queryset = models.AdditionalServices.objects.filter(dealer=dealer)
|
||||
return form
|
||||
|
||||
|
||||
class CarListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
||||
"""
|
||||
@ -3587,7 +3618,7 @@ def create_estimate(request, pk=None):
|
||||
customer_id = data.get("customer")
|
||||
# terms = data.get("terms")
|
||||
# customer = entity.get_customers().filter(pk=customer_id).first()
|
||||
customer = models.Customer.objects.filter(pk=customer_id).first()
|
||||
customer = models.Customer.objects.filter(pk=int(customer_id)).first()
|
||||
|
||||
items = data.get("item", [])
|
||||
quantities = data.get("quantity", [])
|
||||
@ -3662,27 +3693,39 @@ def create_estimate(request, pk=None):
|
||||
]
|
||||
items_txs = []
|
||||
for item in items_list:
|
||||
car_instance = ItemModel.objects.filter(
|
||||
additional_info__car_info__hash=item.get("item_id")
|
||||
).all()
|
||||
# car_instance = ItemModel.objects.filter(
|
||||
# additional_info__car_info__hash=item.get("item_id")
|
||||
# ).all()
|
||||
# for i in car_instance[: int(quantities[0])]:
|
||||
# items_txs.append(
|
||||
# {
|
||||
# "item_number": i.item_number,
|
||||
# "quantity": 1,
|
||||
# "unit_cost": i.additional_info.get("car_finance").get(
|
||||
# "selling_price"
|
||||
# ),
|
||||
# "unit_revenue": i.additional_info.get("car_finance").get(
|
||||
# "selling_price"
|
||||
# ),
|
||||
# "total_amount": (
|
||||
# i.additional_info.get("car_finance").get("total_vat")
|
||||
# ),
|
||||
# }
|
||||
# )
|
||||
car_instance = models.Car.objects.filter(hash=item.get("item_id"),finances__is_sold=False).all()
|
||||
|
||||
for i in car_instance[: int(quantities[0])]:
|
||||
items_txs.append(
|
||||
{
|
||||
"item_number": i.item_number,
|
||||
"item_number": i.item_model.item_number,
|
||||
"quantity": 1,
|
||||
"unit_cost": i.additional_info.get("car_finance").get(
|
||||
"selling_price"
|
||||
),
|
||||
"unit_revenue": i.additional_info.get("car_finance").get(
|
||||
"selling_price"
|
||||
),
|
||||
"total_amount": (
|
||||
i.additional_info.get("car_finance").get("total_vat")
|
||||
),
|
||||
"unit_cost": round(float(i.finances.selling_price)),
|
||||
"unit_revenue": round(float(i.finances.selling_price)),
|
||||
"total_amount": round(float(i.finances.total_vat)),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
estimate_itemtxs = {
|
||||
item.get("item_number"): {
|
||||
"unit_cost": item.get("unit_cost"),
|
||||
@ -3704,12 +3747,20 @@ def create_estimate(request, pk=None):
|
||||
}
|
||||
}
|
||||
|
||||
estimate.migrate_itemtxs(
|
||||
itemtxs=estimate_itemtxs,
|
||||
commit=True,
|
||||
operation=EstimateModel.ITEMIZE_APPEND,
|
||||
)
|
||||
|
||||
try:
|
||||
estimate.migrate_itemtxs(
|
||||
itemtxs=estimate_itemtxs,
|
||||
commit=True,
|
||||
operation=EstimateModel.ITEMIZE_APPEND,
|
||||
)
|
||||
except Exception as e:
|
||||
estimate.delete()
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "error",
|
||||
"message": e,
|
||||
}
|
||||
)
|
||||
if isinstance(items, list):
|
||||
for item in estimate_itemtxs.keys():
|
||||
item_instance = ItemModel.objects.filter(item_number=item).first()
|
||||
@ -3867,7 +3918,11 @@ def create_sale_order(request, pk):
|
||||
item.item_model.save()
|
||||
except KeyError:
|
||||
pass
|
||||
models.Car.objects.get(vin=item.item_model.name).mark_as_sold(request)
|
||||
dealer = get_user_type(request)
|
||||
|
||||
item.item_model.car.mark_as_sold()
|
||||
# models.Activity.objects.create(dealer=dealer,content_object=item.item_model.car, notes="Car Sold",created_by=request.user,activity_type=models.ActionChoices.SALE_CAR)
|
||||
|
||||
|
||||
messages.success(request, "Sale Order created successfully")
|
||||
return redirect("estimate_detail", pk=estimate.pk)
|
||||
@ -4673,7 +4728,7 @@ class LeadListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
||||
dealer = get_user_type(self.request)
|
||||
qs = models.Lead.objects.filter(dealer=dealer)
|
||||
if query:
|
||||
qs = apply_search_filters(qs, query)
|
||||
qs = apply_search_filters(qs, query)
|
||||
if self.request.is_dealer:
|
||||
return qs
|
||||
staffmember = getattr(self.request.user, "staffmember", None)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
{% extends 'base.html' %}
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n static custom_filters %}
|
||||
{% block title %}{{ _("Car Details") }}{% endblock %}
|
||||
{% block customCSS %}
|
||||
@ -14,7 +14,8 @@
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
</style>
|
||||
{% endblock customCSS %}
|
||||
{% endblock customCSS %}
|
||||
|
||||
{% block content %}
|
||||
{% if not car.ready %}
|
||||
<div class="alert alert-outline-warning d-flex align-items-center"
|
||||
@ -305,8 +306,24 @@
|
||||
style="background-color: rgb({{ car.colors.interior.rgb }})"></div>
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
{% comment %} {% if not car.get_transfer %}
|
||||
<a href="{% url 'car_finance_update' car.finances.pk %}"
|
||||
class="btn btn-phoenix-warning btn-sm mb-3">{% trans "Edit" %}</a>
|
||||
{% else %}
|
||||
<span class="badge bg-danger">{% trans "Cannot Edit, Car in Transfer." %}</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<p>{% trans "No finance details available." %}</p>
|
||||
{% if perms.inventory.add_carfinance %}
|
||||
<a href="{% url 'car_finance_create' car.slug %}"
|
||||
class="btn btn-phoenix-success btn-sm mb-3">{% trans "Add" %}</a>
|
||||
{% endif %} {% endcomment %}
|
||||
</td>
|
||||
</tr>
|
||||
{% comment %} <tr>
|
||||
<td colspan="2">{% trans "No colors available for this car." %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -316,7 +333,7 @@
|
||||
class="btn btn-phoenix-success btn-sm">{% trans "Add" %}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</tr> {% endcomment %}
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
<div class="alert alert-outline-warning d-flex align-items-center"
|
||||
role="alert">
|
||||
<i class="fa-solid fa-circle-info fs-6"></i>
|
||||
<p class="mb-0 flex-1">{{ _("Please Add A Vendor, Before Adding A Car .") }}</p>
|
||||
<p class="mb-0 flex-1">{{ _("Please Add A Vendor, Before Adding A Car .") }} <a href="{% url 'vendor_create' %}" class="ms-3 text-body-primary fs-9" >{{ _("Add Vendor") }}</a> </p>
|
||||
<button class="btn-close"
|
||||
type="button"
|
||||
data-bs-dismiss="alert"
|
||||
|
||||
@ -167,6 +167,7 @@
|
||||
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Color") }}</th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Date Received") }}</th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Status") }}</th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Inventory Ready") }}</th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -216,6 +217,13 @@
|
||||
<span class="badge badge-phoenix fs-11 badge-phoenix-warning">{{ _("Transfer") }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="align-middle product white-space-nowrap">
|
||||
{% if not car.ready %}
|
||||
<span class="text-danger"> {{ _("NO") }} </span>
|
||||
{%else%}
|
||||
<span class="text-success"> {{ _("YES") }} </span>
|
||||
{%endif%}
|
||||
</td>
|
||||
<td class="align-middle text-end white-space-nowrap pe-0 action">
|
||||
<div class="btn-reveal-trigger position-static">
|
||||
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10"
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
<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">
|
||||
@ -56,9 +56,9 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row mt-4">
|
||||
|
||||
|
||||
<div class="table-responsive px-1 scrollbar mt-3">
|
||||
<table class="table align-items-center table-flush">
|
||||
<thead>
|
||||
@ -91,7 +91,9 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="align-middle product white-space-nowrap">
|
||||
{% if tx.description %}
|
||||
{{ tx.description }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="align-middle white-space-nowrap text-start">
|
||||
<div class="btn-reveal-trigger position-static">
|
||||
@ -106,7 +108,7 @@
|
||||
|
||||
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
||||
<td class="align-middle product white-space-nowrap">
|
||||
|
||||
|
||||
</td>
|
||||
<td class="align-middle product white-space-nowrap">
|
||||
<span class="fw-bold fs-8">{{ _("Total") }}</span>
|
||||
@ -118,20 +120,20 @@
|
||||
<span class="fw-bold fs-8 text-danger">{{ total_credits }} <span class="currency">{{ CURRENCY }}</span></span>
|
||||
</td>
|
||||
<td class="align-middle product white-space-nowrap">
|
||||
|
||||
|
||||
</td>
|
||||
<td class="align-middle white-space-nowrap text-start">
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-3 d-flex">
|
||||
<a class="btn btn-sm btn-phoenix-primary me-1" href="{% url 'account_update' account.pk %}">
|
||||
<!-- <i class="bi bi-pencil-square"></i> -->
|
||||
|
||||
@ -275,7 +275,7 @@
|
||||
|
||||
|
||||
// Run the function on page load
|
||||
//window.onload = calculateTotals;
|
||||
//window.onload = calculateTotals;
|
||||
|
||||
function setFormAction(action) {
|
||||
// Get the form element
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user