This commit is contained in:
gitea 2024-12-24 13:54:41 +00:00
commit 8a9ccf26c7
9 changed files with 564 additions and 857 deletions

View File

@ -809,4 +809,47 @@ class SalesOrder(models.Model):
) )
def __str__(self): def __str__(self):
return f"Sales Order #{self.id} from Quotation #{self.quotation.id}" return f"Sales Order #{self.id} from Quotation #{self.quotation.id}"
class Payment(models.Model):
METHOD_CHOICES = [
('cash', _('cash')),
('credit', _('credit')),
('transfer', _('transfer')),
('debit', _('debit')),
('SADAD', _('SADAD')),
]
quotation = models.ForeignKey(SaleQuotation, on_delete=models.CASCADE, related_name="payments")
amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name=_("amount"))
payment_method = models.CharField(choices=METHOD_CHOICES, max_length=50, verbose_name=_("method"))
reference_number = models.CharField(max_length=100, null=True, blank=True, verbose_name=_("reference number"))
payment_date = models.DateField(auto_now_add=True, verbose_name=_("date"))
# def save(self, *args, **kwargs):
# super().save(*args, **kwargs)
# self.quotation.remaining_balance -= self.amount
# if self.quotation.remaining_balance <= 0:
# self.quotation.is_paid = True
# self.quotation.save()
class Meta:
verbose_name = _("payment")
verbose_name_plural = _("payments")
def __str__(self):
return f"Payment of {self.amount} on {self.date} for {self.order}"
class Refund(models.Model):
payment = models.OneToOneField(Payment, on_delete=models.CASCADE, related_name="refund")
amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name=_("amount"))
reason = models.TextField(blank=True, verbose_name=_("reason"))
refund_date = models.DateField(auto_now_add=True, verbose_name=_("refund date"))
class Meta:
verbose_name = _("refund")
verbose_name_plural = _("refunds")
def __str__(self):
return f"Refund of {self.amount} on {self.refund_date}"

View File

@ -1,3 +1,4 @@
from nltk.app.wordnet_app import page_from_reference
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
from reportlab.lib import colors from reportlab.lib import colors
from reportlab.lib.pagesizes import A4 from reportlab.lib.pagesizes import A4
@ -62,7 +63,7 @@ def generate_quotation_pdf(response, quotation, services):
# Car Details Table # Car Details Table
elements.append(Paragraph("Car Details", heading_style)) elements.append(Paragraph("Car Details", heading_style))
car_data = [["VIN", "Model", "Year", "Quantity", "Price", "VAT %", "Total"]] car_data = [["رقم الهيكل", "الموديل", "سنة الصنع", "الكمية", "السعر", "الضريبة", "الإجمالي"]]
for item in quotation.quotation_cars.all(): for item in quotation.quotation_cars.all():
car_data.append([ car_data.append([
item.car.vin, item.car.vin,
@ -117,5 +118,6 @@ def generate_quotation_pdf(response, quotation, services):
])) ]))
elements.append(additional_table) elements.append(additional_table)
# Build PDF # Build PDF
doc.build(elements) doc.build(elements)

View File

@ -1,6 +1,6 @@
from random import randint from random import randint
from django.db.models.signals import post_save, post_delete, pre_delete from django.db.models.signals import post_save, post_delete,pre_delete
from django.dispatch import receiver from django.dispatch import receiver
from django_ledger.views import JournalEntryCreateView from django_ledger.views import JournalEntryCreateView
from django_ledger.models import ( from django_ledger.models import (
@ -19,6 +19,7 @@ from django.utils.translation import gettext_lazy as _
from . import models from . import models
# @receiver(post_save, sender=models.SaleQuotation) # @receiver(post_save, sender=models.SaleQuotation)
# def link_quotation_to_entity(sender, instance, created, **kwargs): # def link_quotation_to_entity(sender, instance, created, **kwargs):
# if created: # if created:
@ -31,72 +32,21 @@ from . import models
# user = instance.user # user = instance.user
# if user: # if user:
# user.delete() # user.delete()
User = get_user_model()
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
dealer = models.Dealer.objects.create(user=instance, name=instance.username)
# dealer.user.set_password("Tenhal@123")
dealer.save()
@receiver(post_save, sender=models.Car)
def create_product_for_car(sender, instance, created, **kwargs):
if created:
entity = EntityModel.objects.get(name=instance.dealer.get_root_dealer.name)
product_model = entity.create_item_product(
name=f"{instance.year} {instance.id_car_make} {instance.id_car_model} {instance.id_car_trim}",
uom_model=entity.get_uom_all().first(),
item_type=ItemModel.ITEM_TYPE_OTHER,
coa_model=entity.get_default_coa(),
)
print(f"Created product: {product_model.name}")
@receiver(post_save, sender=models.CarFinance)
def update_product_default_value(sender, instance, **kwargs):
# Get the associated car
car = instance.car
# Get the entity associated with the dealer
entity = EntityModel.objects.get(name=car.dealer.get_root_dealer.name) # Assuming the dealer's name matches the entity name
# Get the product in Django Ledger associated with the car
items_products = entity.get_items_products()
try:
product_model = items_products.get(
name=f"{car.year} {car.id_car_make} {car.id_car_model} {car.id_car_trim}"
)
except ItemModel.DoesNotExist:
print(f"Product for car {car} does not exist in Django Ledger.")
return
# Update the default value per unit of measure for the product
product_model.default_amount = instance.selling_price
product_model.save()
print(f"Updated product {product_model.name} with default value: {product_model.default_amount}")
@receiver(post_save, sender=models.Car) @receiver(post_save, sender=models.Car)
def create_car_location(sender, instance, created, **kwargs): def create_car_location(sender, instance, created, **kwargs):
""" """
Signal to create or update the car's location when a car instance is saved. Signal to create or update the car's location when a car instance is saved.
""" """
try: try:
if created: if created:
if instance.dealer is None: if instance.dealer is None:
raise ValueError( raise ValueError(f"Cannot create CarLocation for car {instance.vin}: dealer is missing.")
f"Cannot create CarLocation for car {instance.vin}: dealer is missing."
)
models.CarLocation.objects.create( models.CarLocation.objects.create(
car=instance, car=instance,
owner=instance.dealer, owner=instance.dealer,
showroom=instance.dealer, showroom=instance.dealer,
description=f"Initial location set for car {instance.vin}.", description=f"Initial location set for car {instance.vin}."
) )
print("Car Location created") print("Car Location created")
except Exception as e: except Exception as e:
@ -143,65 +93,65 @@ def create_ledger_entity(sender, instance, created, **kwargs):
) )
print(f"Ledger entity created for Dealer: {instance.name}") print(f"Ledger entity created for Dealer: {instance.name}")
entity.create_account( # entity.create_account(
coa_model=default_coa, # coa_model=coa,
code="10100", # code=1010,
role='asset_ca_cash', # role='asset_ca_cash',
name=_('Cash'), # name=_('Cash'),
balance_type="debit", # balance_type="debit",
) # )
entity.create_account( # entity.create_account(
coa_model=default_coa, # coa_model=coa,
code="11000", # code=1100,
role='asset_ca_recv', # role='asset_ca_recv',
name=_('Accounts Receivable'), # name=_('Accounts Receivable'),
balance_type="debit", # balance_type="debit",
) # )
entity.create_account( # entity.create_account(
coa_model=default_coa, # coa_model=coa,
code="12000", # code=1200,
role='asset_ca_inv', # role='asset_ca_inv',
name=_('Inventory'), # name=_('Inventory'),
balance_type="debit", # balance_type="debit",
active=True) # active=True)
entity.create_account(
coa_model=default_coa,
code="20100",
role='lia_cl_acc_payable',
name=_('Accounts Payable'),
balance_type="credit",
active=True)
entity.create_account(
coa_model=default_coa,
code="40100",
role='in_operational',
name=_('Sales Income'),
balance_type="credit",
active=True)
entity.create_account(
coa_model=default_coa,
code="50100",
role='cogs_regular',
name=_('Cost of Goods Sold'),
balance_type="debit",
active=True)
except Exception as e:
print(f"Failed to create Ledger entity for Dealer: {instance.name}. Error: {e}")
# entity = EntityModel.objects.filter(name=instance.dealer.name).first()
# #
# entity.create_account(
# coa_model=coa,
# code=2010,
# role='lia_cl_acc_payable',
# name=_('Accounts Payable'),
# balance_type="credit",
# active=True)
#
# entity.create_account(
# coa_model=coa,
# code=4010,
# role='in_operational',
# name=_('Sales Income'),
# balance_type="credit",
# active=True)
#
# entity.create_account(
# coa_model=coa,
# code=5010,
# role='cogs_regular',
# name=_('Cost of Goods Sold'),
# balance_type="debit",
# active=True)
# uom_name = _("Unit") # uom_name = _("Unit")
# unit_abbr = _("U") # unit_abbr = _("U")
# #
# entity.create_uom(uom_name, unit_abbr) # entity.create_uom(uom_name, unit_abbr)
# Create Vendor # Create Vendor
@receiver(post_save, sender=models.Vendor) @receiver(post_save, sender=models.Vendor)
def create_ledger_vendor(sender, instance, created, **kwargs): def create_ledger_vendor(sender, instance, created, **kwargs):
if created: if created:
entity = EntityModel.objects.filter(name=instance.dealer.name).first() entity = EntityModel.objects.filter(name=instance.dealer.name).first()
@ -216,8 +166,8 @@ def create_ledger_vendor(sender, instance, created, **kwargs):
additional_info={ additional_info={
"arabic_name": instance.arabic_name, "arabic_name": instance.arabic_name,
"contact_person": instance.contact_person, "contact_person": instance.contact_person,
}, })
)
print(f"VendorModel created for Vendor: {instance.name}") print(f"VendorModel created for Vendor: {instance.name}")
@ -225,9 +175,7 @@ def create_ledger_vendor(sender, instance, created, **kwargs):
@receiver(post_save, sender=models.Customer) @receiver(post_save, sender=models.Customer)
def create_customer(sender, instance, created, **kwargs): def create_customer(sender, instance, created, **kwargs):
if created: if created:
entity = EntityModel.objects.filter( entity = EntityModel.objects.filter(name=instance.dealer.get_root_dealer.name).first()
name=instance.dealer.get_root_dealer.name
).first()
name = f"{instance.first_name} {instance.middle_name} {instance.last_name}" name = f"{instance.first_name} {instance.middle_name} {instance.last_name}"
entity.create_customer( entity.create_customer(
@ -239,7 +187,7 @@ def create_customer(sender, instance, created, **kwargs):
"sales_tax_rate": 0.15, "sales_tax_rate": 0.15,
"active": True, "active": True,
"hidden": False, "hidden": False,
"additional_info": {}, "additional_info": {}
} }
) )

View File

@ -1,4 +1,4 @@
from django_ledger.models import EntityModel, InvoiceModel,EntityUnitModel,LedgerModel from django_ledger.models import EntityModel, InvoiceModel
import logging import logging
import json import json
import datetime import datetime
@ -302,7 +302,7 @@ class CarInventory(LoginRequiredMixin, ListView):
make_id = self.kwargs['make_id'] make_id = self.kwargs['make_id']
model_id = self.kwargs['model_id'] model_id = self.kwargs['model_id']
trim_id = self.kwargs['trim_id'] trim_id = self.kwargs['trim_id']
cars = models.Car.objects.filter( cars = models.Car.objects.filter(
dealer=self.request.user.dealer.get_root_dealer, dealer=self.request.user.dealer.get_root_dealer,
id_car_make=make_id, id_car_make=make_id,
@ -786,6 +786,8 @@ class QuotationListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
def get_queryset(self): def get_queryset(self):
status = self.request.GET.get("status") status = self.request.GET.get("status")
# queryset = models.SaleQuotation.objects.all()
print(self.request.user.dealer.get_root_dealer.sales.all())
queryset = self.request.user.dealer.get_root_dealer.sales.all() queryset = self.request.user.dealer.get_root_dealer.sales.all()
if status: if status:
queryset = queryset.filter(status=status) queryset = queryset.filter(status=status)
@ -810,7 +812,7 @@ class QuotationDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailVie
@login_required @login_required
def generate_invoice(request, pk): def generate_invoice(request, pk):
quotation = get_object_or_404(models.SaleQuotation, pk=pk) quotation = get_object_or_404(models.SaleQuotation, pk=pk)
if not quotation.is_approved: if not quotation.is_approved:
messages.error( messages.error(
request, "Quotation must be approved before converting to an invoice." request, "Quotation must be approved before converting to an invoice."
@ -1069,6 +1071,7 @@ def mark_quotation(request, pk):
# messages.success(request, _("Quotation Paid")) # messages.success(request, _("Quotation Paid"))
return redirect("quotation_detail", pk=pk) return redirect("quotation_detail", pk=pk)
@login_required @login_required
def confirm_quotation(request, pk): def confirm_quotation(request, pk):
quotation = get_object_or_404(models.SaleQuotation, pk=pk) quotation = get_object_or_404(models.SaleQuotation, pk=pk)

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -74,7 +74,7 @@
<th>{% trans "Year" %}</th> <th>{% trans "Year" %}</th>
<th>{% trans "Quantity" %}</th> <th>{% trans "Quantity" %}</th>
<th>{% trans "Price" %}</th> <th>{% trans "Price" %}</th>
<th>{% trans "VAT %" %}</th> <th>{% trans "VAT" %}</th>
<th>{% trans "Total" %}</th> <th>{% trans "Total" %}</th>
</tr> </tr>
</thead> </thead>