From 9209bab9adc0dfe781026a98384297c3c2c19506 Mon Sep 17 00:00:00 2001 From: gitea Date: Mon, 23 Dec 2024 14:38:14 +0000 Subject: [PATCH] ledger update --- inventory/models.py | 2 +- inventory/signals.py | 230 +++++++++++++++++++++++++++---------------- inventory/views.py | 108 ++++++++++++++------ 3 files changed, 222 insertions(+), 118 deletions(-) diff --git a/inventory/models.py b/inventory/models.py index 3ce243c4..3ecbb932 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -798,4 +798,4 @@ class SalesOrder(models.Model): ) 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}" \ No newline at end of file diff --git a/inventory/signals.py b/inventory/signals.py index a0bc8f9f..935e0118 100644 --- a/inventory/signals.py +++ b/inventory/signals.py @@ -1,21 +1,23 @@ 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_ledger.models import (EntityModel, - VendorModel, - CustomerModel, - UnitOfMeasureModel, - AccountModel, - ItemModelAbstract - ) +from django_ledger.models import ( + EntityModel, + VendorModel, + CustomerModel, + UnitOfMeasureModel, + AccountModel, + ItemModelAbstract, + ItemModel +) +from django.contrib.auth import get_user_model from django.utils.translation import gettext_lazy as _ from . import models - # @receiver(post_save, sender=models.SaleQuotation) # def link_quotation_to_entity(sender, instance, created, **kwargs): # if created: @@ -28,21 +30,72 @@ from . import models # user = instance.user # if user: # 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) 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: if created: if instance.dealer is None: - raise ValueError(f"Cannot create CarLocation for car {instance.vin}: dealer is missing.") + raise ValueError( + f"Cannot create CarLocation for car {instance.vin}: dealer is missing." + ) models.CarLocation.objects.create( car=instance, owner=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") except Exception as e: @@ -69,82 +122,85 @@ def update_car_status_on_reservation_delete(sender, instance, **kwargs): @receiver(post_save, sender=models.Dealer) def create_ledger_entity(sender, instance, created, **kwargs): if created: - entity, created = EntityModel.objects.get_or_create( - name=instance.get_root_dealer.name, - admin=instance.get_root_dealer.user, - # address_1=instance.address, - accrual_method=False, - fy_start_month=1, - # depth=0, - ) - print(entity) - if created: - 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}") + # Group.objects.get(name=instance.dealer_type.lower()).user_set.add(instance.user) + try: + entity, created = EntityModel.objects.get_or_create( + name=instance.get_root_dealer.name, + admin=instance.get_root_dealer.user, + # address_1=instance.address, + accrual_method=False, + fy_start_month=1, + depth=0, + ) + if created: + 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}") - # entity.create_account( - # coa_model=coa, - # code=1010, - # role='asset_ca_cash', - # name=_('Cash'), - # balance_type="debit", - # ) - # entity.create_account( - # coa_model=coa, - # code=1100, - # role='asset_ca_recv', - # name=_('Accounts Receivable'), - # balance_type="debit", - # ) - # entity.create_account( - # coa_model=coa, - # code=1200, - # role='asset_ca_inv', - # name=_('Inventory'), - # balance_type="debit", - # active=True) - # - # 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) + entity.create_account( + coa_model=default_coa, + code="10100", + role='asset_ca_cash', + name=_('Cash'), + balance_type="debit", + ) + entity.create_account( + coa_model=default_coa, + code="11000", + role='asset_ca_recv', + name=_('Accounts Receivable'), + balance_type="debit", + ) + entity.create_account( + coa_model=default_coa, + code="12000", + role='asset_ca_inv', + name=_('Inventory'), + balance_type="debit", + 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() + # # uom_name = _("Unit") # unit_abbr = _("U") # # entity.create_uom(uom_name, unit_abbr) - # 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() @@ -159,8 +215,8 @@ def create_ledger_vendor(sender, instance, created, **kwargs): additional_info={ "arabic_name": instance.arabic_name, "contact_person": instance.contact_person, - }) - + }, + ) print(f"VendorModel created for Vendor: {instance.name}") @@ -168,20 +224,22 @@ def create_ledger_vendor(sender, instance, created, **kwargs): @receiver(post_save, sender=models.Customer) def create_customer(sender, instance, created, **kwargs): if created: - entity = EntityModel.objects.filter(name=instance.dealer.get_root_dealer.name).first() + entity = EntityModel.objects.filter( + name=instance.dealer.get_root_dealer.name + ).first() name = f"{instance.first_name} {instance.middle_name} {instance.last_name}" - entity.create_customer( - customer_model_kwargs={ - "customer_name": name, + entity.create_customer( + customer_model_kwargs={ + "customer_name": name, "address_1": instance.address, "phone": instance.phone_number, "email": instance.email, "sales_tax_rate": 0.15, "active": True, "hidden": False, - "additional_info": {} - } + "additional_info": {}, + } ) print(f"Customer created: {name}") diff --git a/inventory/views.py b/inventory/views.py index 54012fe8..5d00bb4c 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -1,8 +1,8 @@ -from django_ledger.models import EntityModel, InvoiceModel +from django_ledger.models import EntityModel, InvoiceModel,EntityUnitModel,LedgerModel import logging import json from decimal import Decimal - +from django_ledger.models import TransactionModel, AccountModel,JournalEntryModel from django.shortcuts import HttpResponse from django.template.loader import render_to_string from weasyprint import HTML @@ -784,8 +784,6 @@ class QuotationListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): def get_queryset(self): 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() if status: queryset = queryset.filter(status=status) @@ -810,51 +808,99 @@ class QuotationDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailVie @login_required 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: messages.error( request, "Quotation must be approved before converting to an invoice." ) else: entity = quotation.entity - customer = ( - entity.get_customers() - .filter(customer_name=quotation.customer.get_full_name) - .first() - ) + coa_qs, coa_map = entity.get_all_coa_accounts() + cash_account = coa_qs.first().get_coa_accounts().filter(name="Cash") + customer = entity.get_customers().filter(customer_name=quotation.customer.get_full_name).first() - invoices = entity.create_invoice( - customer_model=customer.customer_number, terms=InvoiceModel.TERMS_NET_30 + invoice_model = entity.create_invoice( + customer_model=customer, + terms=InvoiceModel.TERMS_NET_30, + cash_account=cash_account.first(), + coa_model=coa_qs.first(), ) - # invoice_itemtxs = { - # f"{qc}": { - # "unit_cost": f"{qc.car.finances.selling_price}", - # "quantity": f"{qc.quantity}", - # "total_amount": f"{qc.total_vat}", - # } - # for qc in quotation.quotation_cars.all() - # } + + name_list = [f"{instance.car.year} {instance.car.id_car_make} {instance.car.id_car_model} {instance.car.id_car_trim}" for instance in quotation.quotation_cars.all()] + + invoices_item_models = invoice_model.get_item_model_qs().filter(name__in=name_list) invoice_itemtxs = { - "test":{ - "unit_cost": "1000", - "quantity": "1", - "total_amount": "1000", - }, - "test1":{ - "unit_cost": "1000", - "quantity": "1", - "total_amount": "1000", + im.item_number: { + "unit_cost": im.default_amount, + "quantity": 1, + "total_amount": im.default_amount, } + for im in invoices_item_models } - invoice_itemtxs = invoices.migrate_itemtxs( + + invoice_itemtxs = invoice_model.migrate_itemtxs( itemtxs=invoice_itemtxs, commit=True, operation=InvoiceModel.ITEMIZE_APPEND ) + + ledger = entity.create_ledger( + name=f"Payment Ledger for Invoice {invoice_model}", + posted=True + ) + + entity_unit,created = EntityUnitModel.objects.get_or_create( + name="Sales Department", + entity=entity, + document_prefix="SD" + ) + + journal_entry = JournalEntryModel.objects.create( + entity_unit=entity_unit, + posted=False, + description=f"Payment for Invoice {invoice_model}", + ledger=ledger, + locked=False, + origin="Payment", + ) + + + + accounts_receivable = coa_qs.first().get_coa_accounts().filter(name="Accounts Receivable").first() + if not accounts_receivable: + accounts_receivable = entity.create_account( + code="AR", + role="asset", + name="Accounts Receivable", + coa_model=coa_qs.first(), + balance_type="credit" + ) + + TransactionModel.objects.create( + journal_entry=journal_entry, + account=cash_account.first(), # Debit Cash + amount=invoice_model.amount_due, # Payment amount + tx_type='debit', + description="Payment Received", + ) + + TransactionModel.objects.create( + journal_entry=journal_entry, + account=accounts_receivable, # Credit Accounts Receivable + amount=invoice_model.amount_due, # Payment amount + tx_type='credit', + description="Payment Received", + ) + invoice_model.mark_as_review() + print("reviewed") + invoice_model.mark_as_approved(entity_slug=entity.slug, user_model=request.user.dealer.get_root_dealer.user) + print("approved") + invoice_model.mark_as_paid(entity_slug=entity.slug, user_model=request.user.dealer.get_root_dealer.user) + print("paid") + messages.success(request, "Invoice created") return redirect("quotation_detail", pk=pk) # return redirect('django_ledger:invoice-detail', entity_slug=quotation.entity.slug, invoice_pk=invoice.uuid) - @login_required def confirm_quotation(request, pk): quotation = get_object_or_404(models.SaleQuotation, pk=pk)