diff --git a/inventory/signals.py b/inventory/signals.py index 93ded9ae..33a902f7 100644 --- a/inventory/signals.py +++ b/inventory/signals.py @@ -15,7 +15,11 @@ from django_ledger.models import ( ItemModelAbstract, UnitOfMeasureModel, VendorModel, - EstimateModel, CustomerModel + EstimateModel, + CustomerModel, + JournalEntryModel, + TransactionModel, + LedgerModel ) from . import models from django.utils.timezone import now @@ -654,7 +658,23 @@ def create_ledger_vendor(sender, instance, created, **kwargs): }, } ) + + coa = entity.get_default_coa() + last_account = entity.get_all_accounts().filter(role=roles.LIABILITY_CL_ACC_PAYABLE).order_by('-created').first() + # code = f"{int(last_account.code)}{1:03d}" + 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}" + account = entity.create_account( + name=instance.name, + code=code, + role=roles.LIABILITY_CL_ACC_PAYABLE, + coa_model=coa, + balance_type="credit", + active=True + ) print(f"VendorModel created for Vendor: {instance.name}") @@ -915,4 +935,97 @@ def check_if_vat_exists(sender, instance, created, **kwargs): def create_make_ledger_accounts(sender, instance, created, **kwargs): if created: entity_name = instance.user.dealer.name - entity = EntityModel.objects.get(name=entity_name) \ No newline at end of file + entity = EntityModel.objects.get(name=entity_name) + + +# @receiver(post_save, sender=VendorModel) +# def create_vendor_accounts(sender, instance, created, **kwargs): +# if created: +# entity = instance.entity_model +# last_account = entity.get_all_accounts().filter(role=roles.LIABILITY_CL_ACC_PAYABLE).order_by('-created').first() +# code = str(int(last_account.code) + 1) +# account = entity.create_account( +# name=instance.vendor_name, +# code=code, +# role=roles.LIABILITY_CL_ACC_PAYABLE, +# coa_model=entity.get_default_coa(), +# balance_type="credit", +# active=True +# ) + +@receiver(post_save, sender=models.CarFinance) +def update_finance_cost(sender, instance, created, **kwargs): + entity = instance.car.dealer.entity + ledger,created = LedgerModel.objects.get_or_create(name=instance.car.vin, entity=entity) + vendor = instance.car.vendor + + if created: + journal = JournalEntryModel.objects.create( + posted=False, + description=f"Finances of Car:{instance.car.vin} for Vendor:{instance.car.vendor.vendor_name}", + ledger=ledger, + locked=False, + origin="Payment", + ) + ledger.additional_info["je_number"] = journal.je_number + ledger.save() + + inventory_account = entity.get_default_coa_accounts().filter(role=roles.ASSET_CA_INVENTORY).first() + vendor_account = entity.get_default_coa_accounts().get(name=vendor.vendor_name) + + # Debit Inventory Account + TransactionModel.objects.create( + journal_entry=journal, + account=inventory_account, + amount=instance.total + instance.total_additionals, + tx_type='debit' + ) + + # Credit Vendor Account + TransactionModel.objects.create( + journal_entry=journal, + account=vendor_account, + amount=instance.cost_price, + tx_type='credit' + ) + else: + if not ledger.additional_info.get("je_number"): + journal = JournalEntryModel.objects.create( + posted=False, + description=f"Finances of Car:{instance.car.vin} for Vendor:{instance.car.vendor.vendor_name}", + ledger=ledger, + locked=False, + origin="Payment", + ) + ledger.additional_info["je_number"] = journal.je_number + ledger.save() + + inventory_account = entity.get_default_coa_accounts().filter(role=roles.ASSET_CA_INVENTORY).first() + vendor_account = entity.get_default_coa_accounts().get(name=vendor.vendor_name, active=True) + + # Debit Inventory Account + TransactionModel.objects.create( + journal_entry=journal, + account=inventory_account, + amount=instance.cost_price, + tx_type='debit' + ) + + # Credit Vendor Account + TransactionModel.objects.create( + journal_entry=journal, + account=vendor_account, + amount=instance.cost_price, + tx_type='credit' + ) + + else: + journal = JournalEntryModel.objects.filter(je_number=ledger.additional_info.get("je_number")).first() + debit = journal.get_transaction_queryset().filter(tx_type='debit').first() + credit = journal.get_transaction_queryset().filter(tx_type='credit').first() + + debit.amount = instance.cost_price + credit.amount = instance.cost_price + + debit.save() + credit.save() \ No newline at end of file diff --git a/inventory/utils.py b/inventory/utils.py index 8d6bfe38..6609239b 100644 --- a/inventory/utils.py +++ b/inventory/utils.py @@ -1,3 +1,4 @@ +from django_ledger.io import roles from django.core.exceptions import ObjectDoesNotExist import json import random @@ -22,7 +23,8 @@ from django_ledger.models import ( BillModel, VendorModel, CustomerModel, - ItemTransactionModel + ItemTransactionModel, + AccountModel ) from decimal import Decimal from django.utils.translation import get_language @@ -286,43 +288,43 @@ def set_invoice_payment(dealer, entity, invoice, amount, payment_method): calculator = CarFinanceCalculator(invoice) finance_data = calculator.get_finance_data() - journal = JournalEntryModel.objects.create( - posted=False, - description=f"Payment for Invoice {invoice.invoice_number}", - ledger=invoice.ledger, - locked=False, - origin="Payment", - ) + # journal = JournalEntryModel.objects.create( + # posted=False, + # description=f"Payment for Invoice {invoice.invoice_number}", + # ledger=invoice.ledger, + # locked=False, + # origin="Payment", + # ) - credit_account = entity.get_default_coa_accounts().get(name="Sales Revenue") - debit_account = entity.get_default_coa_accounts().get(name="Cash", active=True) - vat_payable_account = entity.get_default_coa_accounts().get(name="VAT Payable", active=True) + # credit_account = entity.get_default_coa_accounts().get(name="Sales Revenue") + # debit_account = entity.get_default_coa_accounts().get(name="Cash", 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 Account - amount=Decimal(finance_data["grand_total"]), - tx_type="debit", - description="Payment Received", - ) + # TransactionModel.objects.create( + # journal_entry=journal, + # account=debit_account, # Debit Account + # amount=Decimal(finance_data["grand_total"]), + # tx_type="debit", + # description="Payment Received", + # ) - TransactionModel.objects.create( - journal_entry=journal, - account=credit_account, # Credit Accounts Receivable - amount=Decimal(finance_data["total_price"] + finance_data["total_additionals"]), - tx_type="credit", - description="Payment Received", - ) + # TransactionModel.objects.create( + # journal_entry=journal, + # account=credit_account, # Credit Accounts Receivable + # amount=Decimal(finance_data["total_price"] + finance_data["total_additionals"]), + # tx_type="credit", + # description="Payment Received", + # ) - TransactionModel.objects.create( - journal_entry=journal, - account=vat_payable_account, # Credit VAT Payable - amount=finance_data.get("total_vat_amount"), - tx_type="credit", - description="VAT Payable on Invoice", - ) - + # TransactionModel.objects.create( + # journal_entry=journal, + # account=vat_payable_account, # Credit VAT Payable + # amount=finance_data.get("total_vat_amount"), + # tx_type="credit", + # description="VAT Payable on Invoice", + # ) + handle_account_process(invoice,amount,finance_data) invoice.make_payment(amount) invoice.save() @@ -848,3 +850,88 @@ def get_local_name(self): return getattr(self, 'arabic_name', None) return getattr(self, 'name', None) + +def handle_account_process(invoice,amount,finance_data): + for i in invoice.get_itemtxs_data()[0]: + car = models.Car.objects.get(vin=invoice.get_itemtxs_data()[0].first().item_model.name) + 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}" + + make_account = entity.create_account( + name=car.id_car_make.name, + 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}" + + additional_services_account = entity.create_account( + name="Additional Services", + code=code, + role=roles.COGS, + coa_model=coa, + balance_type="debit", + 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( + posted=False, + description=f"Payment for Invoice {invoice.invoice_number}", + ledger=invoice.ledger, + locked=False, + origin="Payment", + ) + + TransactionModel.objects.create( + journal_entry=journal, + account=make_account, # Debit car make Account + amount=Decimal(car.finances.total), + tx_type="debit", + description="Payment Received", + ) + TransactionModel.objects.create( + journal_entry=journal, + account=additional_services_account, # Debit Additional Services + amount=Decimal(car.finances.total_additionals), + tx_type="debit", + description="Additional Services", + ) + + TransactionModel.objects.create( + journal_entry=journal, + account=inventory_account, # Credit Inventory account + amount=Decimal(car.finances.total), + tx_type="credit", + description="Account Adjustment", + ) + + TransactionModel.objects.create( + journal_entry=journal, + account=vat_payable_account, # Credit VAT Payable + amount=finance_data.get("total_vat_amount"), + tx_type="credit", + description="VAT Payable on Invoice", + ) \ No newline at end of file diff --git a/requirements.txt.save b/requirements.txt.save new file mode 100644 index 00000000..3ca8098c --- /dev/null +++ b/requirements.txt.save @@ -0,0 +1,253 @@ +aiohappyeyeballs +aiohttp3.11.12 +aiohttp-retry2.9.1 +aiosignal1.3.2 +alabaster1.0.0 +albucore0.0.23 +albumentations2.0.4 +annotated-types0.7.0 +anyio4.8.0 +arabic-reshaper3.0.0 +asgiref3.8.1 +astor0.8.1 +astroid3.3.8 +attrs25.1.0 +autopep82.3.2 +Babel2.15.0 +beautifulsoup44.13.3 +bleach6.2.0 +blinker1.9.0 +Brotli1.1.0 +cattrs24.1.2 +certifi2025.1.31 +cffi1.17.1 +chardet5.2.0 +charset-normalizer3.4.1 +click +colorama0.4.6 +commonmark0.9.1 +contourpy1.3.1 +crispy-bootstrap52024.10 +cryptography44.0.1 +cssselect20.7.0 +ctranslate24.5.0 +cycler0.12.1 +Cython3.1.0a1 +decorator5.1.1 +defusedxml0.7.1 +desert2020.11.18 +diff-match-patch20241021 +dill0.3.9 +distro1.9.0 +dj-rest-auth7.0.1 +dj-shop-cart8.0.0a2 +Django5.1.6 +django-allauth65.4.1 +django-appointment3.8.0 +django-autoslug1.9.9 +django-bootstrap524.3 +django-classy-tags4.1.0 +django-cors-headers4.7.0 +django-countries7.6.1 +django-crispy-forms2.3 +django-debug-toolbar5.0.1 +django-extensions3.2.3 +django-filter25.1 +django-formtools2.5.1 +django-import-export4.3.5 +django-ledger +django-model-utils5.0.0 +django-money3.5.3 +django-next-url-mixin0.4.0 +django-nine0.2.7 +django-nonefield0.4 +django-ordered-model3.7.4 +django-pdf-actions0.1.39 +django-phonenumber-field8.0.0 +django-picklefield3.2 +django-plans1.2.0 +django-prometheus2.3.1 +django-q21.7.6 +django-schema-graph3.1.0 +django-sekizai4.1.0 +django-sequences3.0 +django-silk5.3.2 +django-sms0.7.0 +django-sslserver0.22 +django-tables22.7.5 +django-treebeard4.7.1 +django-vie-breadcrumbs2.5.1 +djangocms-admin-style3.3.1 +djangorestframeork3.15.2 +djangorestframeork_simplejt5.4.0 +djangoviz0.1.1 +docopt0.6.2 +docutils0.21.2 +easy-thumbnails2.10 +emoji2.14.1 +et_xmlfile2.0.0 +Faker36.1.1 +filelock3.17.0 +fire0.7.0 +fonttools4.56.0 +fpdf22.8.2 +frozenlist1.5.0 +fsspec2025.2.0 +gprof2dot2024.6.6 +graphqlclient0.2.4 +greenlet3.1.1 +h110.14.0 +h24.2.0 +hpack4.1.0 +hstspreload2025.1.1 +httpcore1.0.7 +httpx0.28.1 +hyperframe6.1.0 +icalendar6.1.1 +idna3.10 +imageio2.37.0 +imagesize1.4.1 +imgaug0.4.0 +iso42171.12.20240625 +isodate0.7.2 +isort6.0.0 +itsdangerous2.2.0 +Jinja23.1.5 +jiter0.8.2 +joblib1.4.2 +kiisolver1.4.8 +lazy_loader0.4 +ledger1.0.1 +libretranslatepy2.1.4 +lmdb1.6.2 +lxml5.3.1 +Markdon3.7 +markdon-it-py3.0.0 +MarkupSafe3.0.2 +marshmallo3.26.1 +matplotlib3.10.0 +mccabe0.7.0 +mdurl0.1.2 +MouseInfo0.1.3 +mpmath1.3.0 +multidict6.1.0 +mypy-extensions1.0.0 +netorkx3.4.2 +nerelic10.6.0 +nltk3.9.1 +num2ords0.5.14 +numpy2.2.3 +oauthlib3.2.2 +ofxtools0.9.5 +openai1.63.1 +opencv-contrib-python4.11.0.86 +opencv-python4.11.0.86 +opencv-python-headless4.11.0.86 +openpyxl3.1.5 +opt_einsum3.4.0 +outcome1.3.0.post0 +packaging24.2 +pandas2.2.3 +pango0.0.1 +pdfkit1.0.0 +platformdirs4.3.6 +prometheus_client0.21.1 +propcache0.2.1 +protobuf5.29.3 +psycopg-binary3.2.4 +py-moneyed3.0 +PyAutoGUI0.9.54 +pyclipper1.3.0.post6 +pycodestyle2.12.1 +pycparser2.22 +pydotplus2.0.2 +pydyf0.11.0 +PyGetindo0.0.9 +Pygments2.19.1 +PyJT2.10.1 +pylint3.3.4 +PyMsgBox1.0.9 +pyparsing3.2.1 +pypdf5.3.0 +PyPDF23.0.1 +pyperclip1.9.0 +pyphen0.17.2 +pypng0.20220715.0 +PyRect0.2.0 +PyScreeze1.0.1 +pyserial3.5 +PySocks1.7.1 +python-bidi0.6.3 +python-dateutil2.9.0.post0 +python-docx1.1.2 +python-openid2.2.5 +python-stdnum1.20 +python3-saml1.16.0 +pyteening1.2.0 +pytz2025.1 +pyvin0.0.2 +pya2.7.0 +PyYAML6.0.2 +pyzbar0.1.9 +qrcode8.0 +RapidFuzz3.12.1 +regex2024.11.6 +reportlab4.3.1 +requests2.32.3 +requests-oauthlib2.0.0 +rfc39862.0.0 +rich13.9.4 +rubicon-objc0.5.0 +sacremoses0.1.1 +scikit-image0.25.1 +scikit-learn1.6.1 +scipy1.15.2 +selenium4.28.1 +sentencepiece0.2.0 +shapely2.0.7 +simsimd6.2.1 +six1.17.0 +sniffio1.3.1 +snoballstemmer2.2.0 +sortedcontainers2.4.0 +soupsieve2.6 +SQLAlchemy2.0.38 +sqlparse0.5.3 +stanza1.10.1 +stringzilla3.11.3 +suds1.2.0 +sympy1.13.1 +tablib3.8.0 +termcolor2.5.0 +threadpoolctl3.5.0 +tifffile2025.1.10 +tinycss21.4.0 +tinyhtml52.0.0 +tomli2.2.1 +tomlkit0.13.2 +torch2.6.0 +tqdm4.67.1 +trio0.29.0 +trio-ebsocket0.12.0 +tilio9.4.5 +typing-inspect0.9.0 +typing_extensions4.12.2 +tzdata2025.1 +Unidecode1.3.8 +upgrade-requirements1.7.0 +urllib32.3.0 +vin0.6.2 +vininfo1.8.0 +vishap0.1.5 +vpic-api0.7.4 +easyprint64.0 +ebencodings0.5.1 +ebsocket-client1.8.0 +erkzeug3.1.3 +ikipedia1.4.0 +sproto1.2.0 +xmlsec1.3.14 +yarl1.18.3 +zopfli0.2.3.post1 +python-dotenv +psycopg2-binary diff --git a/scripts/run.py b/scripts/run.py index 68973e77..da6299e6 100644 --- a/scripts/run.py +++ b/scripts/run.py @@ -1,3 +1,5 @@ +from django_ledger.forms.account import AccountModelUpdateForm,AccountModelCreateForm +import requests import os from dotenv import load_dotenv from django.contrib.auth.models import Permission @@ -156,16 +158,104 @@ def run(): # print(os.getenv("DJANGO_ALLOWED_HOSTS")) - car_makes = CarMake.objects.all()[:1] - entity = EntityModel.objects.get(admin__email="ismail.mosa.ibrahim@gmail.com") + car_makes = CarMake.objects.all()[:10] + + # Fetch the entity and COGS account + entity = EntityModel.objects.get(admin__email="ismail.mosa.ibrahim@gmail.com") coa = entity.get_default_coa() - cogs = entity.get_default_coa_accounts().filter(role=roles.COGS).first() + + # Loop through car makes and create accounts + for make in range(len(car_makes)): # Start from 0 to include all items + # Generate a unique code - for index,make in enumerate(car_makes): - code = f"{cogs.code}000{index}" - coa_account,account = entity.create_account(name=make.name,code=code,role=roles.COGS,coa_model=coa,balance_type="debit",active=True) - account = cogs.add_child(instance=account) - account.refresh_from_db() - account.save() - \ No newline at end of file + # Create the account + # account = AccountModel.objects.create( + # name=car_makes[make].name, + # code=code, + # role=roles.COGS, + # coa_model=coa, + # balance_type="debit", + # active=True, + # depth=2, + # path=code + # ) + # account = entity.create_account( + # name=car_makes[make].name, + # code=code, + # role=roles.COGS, + # coa_model=coa, + # balance_type="debit", + # active=True + # ) + 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}" + + # account = entity.create_account( + # name=car_makes[make].name, + # code=code, + # role=roles.COGS, + # coa_model=coa, + # balance_type="debit", + # active=True + # ) + account = AccountModel( + name=car_makes[make].name, + code=code, + role=roles.COGS, + coa_model=coa, + balance_type="debit", + active=True, + depth=3, + ) + #00060004001S + last_account = entity.get_all_accounts().filter(role=roles.COGS).order_by('-created').first() + path = '' + if len(last_account.code) == 12: + path = f"{int(last_account.path)}{1:03d}" + elif len(last_account.code) > 12: + path = f"{int(last_account.path)+1}" + # account.path = path + try: + account = cogs.add_child(instance=account) + account.move(cogs, pos="sorted-sibling") + account.refresh_from_db() + account.save() + except Exception as e: + print(e) + + # form_data = { + # 'name': car_makes[make].name, + # 'code': code, + # 'role': roles.COGS, + # 'balance_type': 'debit', + # 'active': True, + # 'coa_model': coa # Ensure the COA model is included + # } + + # Create the form instance with the data + # create_form = AccountModelCreateForm(data=form_data, coa_model=coa) + # # Validate and save the form + # if create_form.is_valid(): + # account = create_form.save(commit=False) + # account.coa_model = coa # Set the entity for the account + + # Add the account as a child of the COGS account + # cogs.add_child(instance=account) + + # print(f"Account '{account.name}' created successfully.") + # else: + # print(f"Failed to create account. Errors: {create_form.errors}") + # form = AccountModelUpdateForm(instance=account) + + # if form.is_valid(): + # instance = form.save(commit=False) + # instance._position = "sorted-sibling" + # instance._ref_node_id = cogs.pk + # instance.save() + # print(f"Account {account.name} created successfully.") + # else: + # print(f"Failed to create account {account.name}. Errors: {form.errors}") \ No newline at end of file diff --git a/scripts/run1.py b/scripts/run1.py new file mode 100644 index 00000000..ee02fa03 --- /dev/null +++ b/scripts/run1.py @@ -0,0 +1,71 @@ +from django_ledger.forms.account import AccountModelUpdateForm,AccountModelCreateForm +import requests +import os +from dotenv import load_dotenv +from django.contrib.auth.models import Permission +from django.contrib.auth.models import Group +from django_ledger.models.invoice import InvoiceModel +from django_ledger.utils import accruable_net_summary +from decimal import Decimal +from django_ledger.models import EstimateModel,EntityModel,ItemModel,ItemTransactionModel,AccountModel,CustomerModel,EntityManagementModel +from rich import print +from datetime import date +from inventory.models import Car, Dealer, VatRate,Lead,CarMake,CarModel,Schedule,CustomGroup +from inventory.utils import CarFinanceCalculator +from appointment.models import Appointment,AppointmentRequest,Service,StaffMember +from django.contrib.auth import get_user_model +from django_ledger.io.io_core import get_localdate +from datetime import datetime, timedelta +from django.utils import timezone +import hashlib +from django_ledger.io import roles + +User = get_user_model() + +load_dotenv(".env") +def run(): + car_makes = CarMake.objects.all()[:10] + + # Fetch the entity and COGS account + entity = EntityModel.objects.get(admin__email="ismail.mosa.ibrahim@gmail.com") + coa = entity.get_default_coa() + cogs = entity.get_default_coa_accounts().filter(role=roles.COGS).first() + + last_account = entity.get_all_accounts().filter(role=roles.LIABILITY_CL_ACC_PAYABLE).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}" + + print(code) + + # # Loop through car makes and create accounts + # for make in range(len(car_makes)): # Start from 0 to include all items + # # Generate a unique code + # code = f"{cogs.code}{make + 1:03d}" # Example: "COGS-001", "COGS-002", etc. + # account = entity.create_account( + # name=car_makes[make].name, + # code=code, + # role=roles.COGS, + # coa_model=coa, + # balance_type="debit", + # active=True + # ) + # try: + # account = cogs.add_child(instance=account) + # account.move(cogs, pos="sorted-sibling") + + # account.refresh_from_db() + # account.save() + # except Exception as e: + # print(e) + # form_data = { + # 'name': car_makes[make].name, + # 'code': code, + # 'role': roles.COGS, + # 'balance_type': 'debit', + # 'active': True, + # 'coa_model': coa # Ensure the COA model is included + # } + + \ No newline at end of file diff --git a/templates/ledger/journal_entry/journal_entry_list.html b/templates/ledger/journal_entry/journal_entry_list.html index 5f03d337..8e6e6241 100644 --- a/templates/ledger/journal_entry/journal_entry_list.html +++ b/templates/ledger/journal_entry/journal_entry_list.html @@ -32,10 +32,10 @@