472 lines
15 KiB
Python
472 lines
15 KiB
Python
import json
|
|
import datetime
|
|
from django.shortcuts import redirect
|
|
from django.contrib import messages
|
|
from django.utils import timezone
|
|
from django_ledger.models.entity import UnitOfMeasureModel
|
|
from django_ledger.models.journal_entry import JournalEntryModel
|
|
from django_ledger.models.ledger import LedgerModel
|
|
from django_ledger.models.transactions import TransactionModel
|
|
import requests
|
|
from inventory import models
|
|
from django.conf import settings
|
|
from django.core.mail import send_mail
|
|
from django.utils.translation import gettext_lazy as _
|
|
from inventory.utilities.financials import get_financial_value
|
|
from django_ledger.models.items import ItemModel
|
|
from django_ledger.models import InvoiceModel, EstimateModel,BillModel
|
|
from decimal import Decimal
|
|
|
|
|
|
def get_jwt_token():
|
|
url = "https://carapi.app/api/auth/login"
|
|
headers = {
|
|
"accept": "text/plain",
|
|
"Content-Type": "application/json",
|
|
}
|
|
data = {
|
|
"api_token": "f5204a00-6f31-4de2-96d8-ed998e0d230c",
|
|
"api_secret": "8c11320781a5b8f4f327b6937e6f8241",
|
|
}
|
|
try:
|
|
response = requests.post(url, headers=headers, json=data)
|
|
response.raise_for_status()
|
|
return response.text
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"Error obtaining JWT token: {e}")
|
|
return None
|
|
|
|
|
|
def localize_some_words():
|
|
success = _("success")
|
|
error = _("error")
|
|
forget = _("Forgot Password?")
|
|
|
|
return None
|
|
|
|
|
|
def get_calculations(quotation):
|
|
context = {}
|
|
qc_len = quotation.quotation_cars.count()
|
|
cars = [x.car for x in quotation.quotation_cars.all()]
|
|
finances = models.CarFinance.objects.filter(car__in=cars)
|
|
|
|
services = ItemModel.objects.filter(additional_finances__in=finances).all()
|
|
data = [
|
|
{
|
|
"name": x.name,
|
|
"price": x.default_amount,
|
|
"total_price": x.default_amount * qc_len,
|
|
"vated": float(x.default_amount) * 0.15 * float(qc_len),
|
|
"total_price_vat": float(x.default_amount)
|
|
+ (float(x.default_amount) * 0.15 * float(qc_len)),
|
|
}
|
|
for x in services
|
|
]
|
|
context["services"] = data
|
|
context["total_cost"] = 0
|
|
context["total_vat"] = 0
|
|
context["total_cost_vat"] = 0
|
|
for k in context["services"]:
|
|
context["total_cost"] += k["total_price"]
|
|
context["total_vat"] += k["vated"]
|
|
context["total_cost_vat"] = float(context["total_cost"]) + float(
|
|
context["total_vat"]
|
|
)
|
|
return context
|
|
|
|
|
|
def send_email(from_, to_, subject, message):
|
|
subject = subject
|
|
message = message
|
|
from_email = from_
|
|
recipient_list = [to_]
|
|
send_mail(subject, message, from_email, recipient_list)
|
|
|
|
|
|
def get_user_type(request):
|
|
dealer = ""
|
|
if hasattr(request.user, "dealer"):
|
|
dealer = request.user.dealer
|
|
elif hasattr(request.user, "staff"):
|
|
dealer = request.user.staff.dealer
|
|
return dealer
|
|
|
|
|
|
def get_dealer_from_instance(instance):
|
|
if instance.dealer.staff:
|
|
return instance.dealer
|
|
else:
|
|
return instance.dealer
|
|
|
|
|
|
def reserve_car(car, request):
|
|
try:
|
|
reserved_until = timezone.now() + timezone.timedelta(hours=24)
|
|
models.CarReservation.objects.create(
|
|
car=car, reserved_by=request.user, reserved_until=reserved_until
|
|
)
|
|
car.status = models.CarStatusChoices.RESERVED
|
|
car.save()
|
|
messages.success(request, _("Car reserved successfully."))
|
|
except Exception as e:
|
|
messages.error(request, f"Error reserving car: {e}")
|
|
|
|
return redirect("car_detail", pk=car.pk)
|
|
|
|
|
|
def calculate_vat_amount(amount):
|
|
vat = models.VatRate.objects.filter(is_active=True).first()
|
|
if vat:
|
|
return ((amount * Decimal(vat.rate)).quantize(Decimal("0.01")), vat.rate)
|
|
return amount
|
|
|
|
|
|
def get_financial_values(model):
|
|
vat = models.VatRate.objects.filter(is_active=True).first()
|
|
|
|
if not model.get_itemtxs_data()[0].exists():
|
|
return {
|
|
"vat_amount": 0,
|
|
"total": 0,
|
|
"grand_total": 0,
|
|
"discount_amount": 0,
|
|
"vat": 0,
|
|
"car_and_item_info": [],
|
|
"additional_services": [],
|
|
}
|
|
|
|
data = model.get_itemtxs_data()[0].all()
|
|
|
|
if isinstance(model, InvoiceModel):
|
|
data = model.ce_model.get_itemtxs_data()[0].all()
|
|
|
|
car_and_item_info = [
|
|
{
|
|
"car": models.Car.objects.get(vin=x.item_model.name),
|
|
"total": models.Car.objects.get(
|
|
vin=x.item_model.name
|
|
).finances.selling_price
|
|
* Decimal(x.ce_quantity),
|
|
"itemmodel": x,
|
|
}
|
|
for x in data
|
|
]
|
|
total = sum(
|
|
Decimal(models.Car.objects.get(vin=x.item_model.name).finances.total)
|
|
* Decimal(x.ce_quantity)
|
|
for x in data
|
|
)
|
|
discount_amount = sum(
|
|
models.CarFinance.objects.get(car__vin=i.item_model.name).discount_amount
|
|
for i in data
|
|
)
|
|
|
|
additional_services = []
|
|
|
|
for i in data:
|
|
cf = models.CarFinance.objects.get(car__vin=i.item_model.name)
|
|
if cf.additional_services.exists():
|
|
additional_services.extend(
|
|
[
|
|
{"name": x.name, "price": x.price}
|
|
for x in cf.additional_services.all()
|
|
]
|
|
)
|
|
|
|
grand_total = Decimal(total) - Decimal(discount_amount)
|
|
vat_amount = round(Decimal(grand_total) * Decimal(vat.rate), 2)
|
|
return {
|
|
"car_and_item_info": car_and_item_info,
|
|
"total": total,
|
|
"discount_amount": discount_amount,
|
|
"additional_services": additional_services,
|
|
"grand_total": grand_total + vat_amount,
|
|
"vat_amount": vat_amount,
|
|
"vat": vat.rate,
|
|
}
|
|
|
|
|
|
def set_invoice_payment(dealer, entity, invoice, amount, payment_method):
|
|
vat_amount = 0
|
|
total_amount = 0
|
|
|
|
if invoice.terms == "on_receipt":
|
|
for x in invoice.get_itemtxs_data()[0].all():
|
|
vat_amount += models.Car.objects.get(
|
|
vin=x.item_model.name
|
|
).finances.vat_amount * Decimal(x.quantity)
|
|
total_amount += Decimal(x.unit_cost) * Decimal(x.quantity)
|
|
|
|
grand_total = total_amount - Decimal(vat_amount)
|
|
|
|
ledger = LedgerModel.objects.filter(
|
|
name__icontains=str(invoice.pk), entity=entity
|
|
).first()
|
|
journal = JournalEntryModel.objects.create(
|
|
posted=False,
|
|
description=f"Payment for Invoice {invoice.invoice_number}",
|
|
ledger=ledger,
|
|
locked=False,
|
|
origin="Payment",
|
|
)
|
|
credit_account = entity.get_default_coa_accounts().get(name="Sales Revenue")
|
|
debit_account = None
|
|
if payment_method == "cash":
|
|
debit_account = entity.get_default_coa_accounts().get(name="Cash", active=True)
|
|
elif payment_method == "credit":
|
|
debit_account = entity.get_default_coa_accounts().get(
|
|
name="Accounts Receivable", active=True
|
|
)
|
|
else:
|
|
debit_account = entity.get_default_coa_accounts().get(
|
|
name="Cash in Bank", active=True
|
|
)
|
|
|
|
vat_payable_account = entity.get_default_coa_accounts().get(
|
|
name="VAT Payable", active=True
|
|
)
|
|
TransactionModel.objects.create(
|
|
journal_entry=journal,
|
|
account=debit_account, # Debit Cash
|
|
amount=amount, # Payment amount
|
|
tx_type="debit",
|
|
description="Payment Received",
|
|
)
|
|
|
|
TransactionModel.objects.create(
|
|
journal_entry=journal,
|
|
account=credit_account, # Credit Accounts Receivable
|
|
amount=grand_total, # Payment amount
|
|
tx_type="credit",
|
|
description="Payment Received",
|
|
)
|
|
|
|
if vat_amount > 0:
|
|
TransactionModel.objects.create(
|
|
journal_entry=journal,
|
|
account=vat_payable_account, # Credit VAT Payable
|
|
amount=vat_amount,
|
|
tx_type="credit",
|
|
description="VAT Payable on Invoice",
|
|
)
|
|
|
|
invoice.make_payment(amount)
|
|
invoice.save()
|
|
|
|
|
|
def set_bill_payment(dealer, entity, bill, amount, payment_method):
|
|
total_amount = 0
|
|
for x in bill.get_itemtxs_data()[0].all():
|
|
total_amount += Decimal(x.unit_cost) * Decimal(x.quantity)
|
|
|
|
journal = JournalEntryModel.objects.create(
|
|
posted=False,
|
|
description=f"Payment for bill {bill.bill_number}",
|
|
ledger=bill.ledger,
|
|
locked=False,
|
|
origin="Payment",
|
|
)
|
|
|
|
cash_account = entity.get_default_coa_accounts().get(name="Cash", active=True)
|
|
|
|
account_payable = entity.get_default_coa_accounts().get(
|
|
name="Accounts Payable", active=True
|
|
)
|
|
|
|
|
|
TransactionModel.objects.create(
|
|
journal_entry=journal,
|
|
account=cash_account, # Debit Cash
|
|
amount=amount, # Payment amount
|
|
tx_type="debit",
|
|
description="Payment Received",
|
|
)
|
|
|
|
TransactionModel.objects.create(
|
|
journal_entry=journal,
|
|
account=account_payable, # Credit Accounts Receivable
|
|
amount=amount, # Payment amount
|
|
tx_type="credit",
|
|
description="Payment Received",
|
|
)
|
|
|
|
bill.make_payment(amount)
|
|
bill.save()
|
|
|
|
|
|
def transfer_to_dealer(request,cars, to_dealer, remarks=None):
|
|
dealer = get_user_type(request)
|
|
|
|
if not cars:
|
|
raise ValueError("No cars selected for transfer.")
|
|
|
|
from_dealer = cars[0].dealer # Assume all cars are from the same dealer
|
|
|
|
# Validate that all cars are from the same dealer
|
|
for car in cars:
|
|
if car.dealer != from_dealer:
|
|
raise ValueError("All cars must be from the same dealer.")
|
|
|
|
if from_dealer == to_dealer:
|
|
raise ValueError("Cannot transfer cars to the same dealer.")
|
|
|
|
# Log the transfer
|
|
transfer_log = models.CarTransferLog.objects.create(
|
|
from_dealer=from_dealer,
|
|
to_dealer=to_dealer,
|
|
remarks=remarks,
|
|
)
|
|
transfer_log.cars.set(cars) # Associate the cars with the transfer log
|
|
|
|
# Update the dealer for all cars
|
|
for car in cars:
|
|
car.dealer = to_dealer
|
|
car.save()
|
|
|
|
import random
|
|
def transfer_car(car,transfer):
|
|
from_dealer = transfer.from_dealer
|
|
to_dealer = transfer.to_dealer
|
|
# add transfer.to_dealer as customer in transfer.from_dealer entity
|
|
instance = models.Customer.objects.filter(
|
|
dealer=from_dealer,
|
|
email=to_dealer.user.email,
|
|
).first()
|
|
if not instance:
|
|
instance = models.Customer.objects.create(
|
|
dealer=from_dealer,
|
|
title=models.Title.MR,
|
|
email=to_dealer.user.email,
|
|
first_name=to_dealer.user.first_name,
|
|
last_name=to_dealer.user.last_name,
|
|
phone_number=to_dealer.phone_number,
|
|
address=to_dealer.address,
|
|
national_id=f"{random.randint(100, 9999)}",
|
|
dob="1990-01-01",
|
|
)
|
|
|
|
# create invoice from transfer.from_dealer to transfer.to_dealer
|
|
name = f"{instance.first_name} {instance.middle_name} {instance.last_name}"
|
|
customer = from_dealer.entity.get_customers().filter(customer_name=name).first()
|
|
|
|
invoice = from_dealer.entity.create_invoice(
|
|
customer_model=customer,
|
|
terms=InvoiceModel.TERMS_NET_30,
|
|
cash_account=from_dealer.entity.get_default_coa_accounts().get(name="Cash", active=True),
|
|
prepaid_account=from_dealer.entity.get_default_coa_accounts().get(name="Accounts Receivable", active=True),
|
|
coa_model=from_dealer.entity.get_default_coa(),
|
|
)
|
|
|
|
ledger = from_dealer.entity.create_ledger(name=str(invoice.pk))
|
|
invoice.ledgar = ledger
|
|
ledger.invoicemodel = invoice
|
|
ledger.save()
|
|
invoice.save()
|
|
item = from_dealer.entity.get_items_products().filter(name=car.vin).first()
|
|
if not item:
|
|
return
|
|
|
|
invoice_itemtxs = {
|
|
item.item_number: {
|
|
"unit_cost": car.finances.cost_price,
|
|
"quantity": transfer.quantity,
|
|
"total_amount": transfer.total_price,
|
|
}
|
|
}
|
|
|
|
invoice_itemtxs = invoice.migrate_itemtxs(
|
|
itemtxs=invoice_itemtxs,
|
|
commit=True,
|
|
operation=InvoiceModel.ITEMIZE_APPEND,
|
|
)
|
|
|
|
invoice.mark_as_review()
|
|
invoice.mark_as_approved(from_dealer.entity.slug, from_dealer.entity.admin)
|
|
invoice.mark_as_paid(from_dealer.entity.slug, from_dealer.entity.admin)
|
|
invoice.save()
|
|
|
|
#create car item product in to_dealer entity
|
|
uom = to_dealer.entity.get_uom_all().filter(name=item.uom.name).first()
|
|
|
|
product = to_dealer.entity.create_item_product(
|
|
name=item.name,
|
|
uom_model=uom,
|
|
item_type=item.item_type,
|
|
coa_model=to_dealer.entity.get_default_coa(),
|
|
)
|
|
|
|
car_dict = vars(car).copy()
|
|
del car_dict["_state"]
|
|
for key, value in car_dict.items():
|
|
if isinstance(value, datetime.datetime):
|
|
car_dict[key] = value.strftime('%Y-%m-%d %H:%M:%S')
|
|
product.additional_info = json.dumps({"car_info": car_dict})
|
|
product.save()
|
|
|
|
#add the sender as vendor and create a bill for it
|
|
vendor_instance, created = models.Vendor.objects.get_or_create(
|
|
dealer=to_dealer,
|
|
crn=from_dealer.crn,
|
|
vrn=from_dealer.vrn,
|
|
name=from_dealer.name,
|
|
email=from_dealer.user.email,
|
|
arabic_name=from_dealer.arabic_name,
|
|
address=from_dealer.address,
|
|
phone_number=from_dealer.phone_number,
|
|
contact_person='',
|
|
)
|
|
|
|
#transfer the car to to_dealer and create items record
|
|
|
|
vendor = to_dealer.entity.get_vendors().filter(vendor_name=vendor_instance.name).first()
|
|
|
|
bill = to_dealer.entity.create_bill(
|
|
vendor_model=vendor,
|
|
terms=BillModel.TERMS_NET_30,
|
|
cash_account=to_dealer.entity.get_default_coa_accounts().get(name="Cash", active=True),
|
|
prepaid_account=to_dealer.entity.get_default_coa_accounts().get(name="Prepaid Expenses", active=True),
|
|
coa_model=to_dealer.entity.get_default_coa(),
|
|
)
|
|
|
|
bill_itemtxs = {
|
|
item.item_number: {
|
|
"unit_cost": car.finances.cost_price,
|
|
"quantity": transfer.quantity,
|
|
"total_amount": transfer.total_price,
|
|
}
|
|
}
|
|
|
|
bill_itemtxs = bill.migrate_itemtxs(itemtxs=bill_itemtxs,
|
|
commit=True,
|
|
operation=BillModel.ITEMIZE_REPLACE)
|
|
|
|
|
|
car.dealer = to_dealer
|
|
car.vendor = vendor_instance
|
|
car.receiving_date = datetime.datetime.now()
|
|
car.finances.additional_services.clear()
|
|
if hasattr(car, "custom_cards"):
|
|
car.custom_cards.delete()
|
|
# car.finances.cost_price = 0
|
|
car.finances.selling_price = 0
|
|
car.finances.discount_amount = 0
|
|
car.finances.save()
|
|
car.location.owner = to_dealer
|
|
car.location.showroom = to_dealer
|
|
car.location.description = ""
|
|
car.location.save()
|
|
|
|
# car.reservations.all().delete()
|
|
car.status = models.CarStatusChoices.AVAILABLE
|
|
transfer.status = models.CarTransferStatusChoices.success
|
|
transfer.active = False
|
|
transfer.save()
|
|
car.save()
|
|
|
|
return True
|
|
#pay the pill
|
|
# set_bill_payment(to_dealer,to_dealer.entity,bill,transfer.total_price,"credit")
|
|
|
|
|
|
|