diff --git a/inventory/migrations/0012_saleorder_created.py b/inventory/migrations/0012_saleorder_created.py new file mode 100644 index 00000000..e140e7ba --- /dev/null +++ b/inventory/migrations/0012_saleorder_created.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.17 on 2025-01-29 12:59 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('inventory', '0011_alter_saleorder_estimate'), + ] + + operations = [ + migrations.AddField( + model_name='saleorder', + name='created', + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), + preserve_default=False, + ), + ] diff --git a/inventory/migrations/0013_alter_saleorder_options.py b/inventory/migrations/0013_alter_saleorder_options.py new file mode 100644 index 00000000..8aff2cc4 --- /dev/null +++ b/inventory/migrations/0013_alter_saleorder_options.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.17 on 2025-01-29 13:02 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('inventory', '0012_saleorder_created'), + ] + + operations = [ + migrations.AlterModelOptions( + name='saleorder', + options={'ordering': ['created']}, + ), + ] diff --git a/inventory/models.py b/inventory/models.py index 14d6a75c..e4d18dd2 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -1562,6 +1562,10 @@ class SaleOrder(models.Model): ]) comments = models.TextField(blank=True, null=True) formatted_order_id = models.CharField(max_length=10, unique=True, editable=False) + created = models.DateTimeField(auto_now_add=True) + + class Meta: + ordering = ['-created'] def save(self, *args, **kwargs): if not self.formatted_order_id: diff --git a/inventory/templatetags/custom_filters.py b/inventory/templatetags/custom_filters.py index fec36bb5..a60f2857 100644 --- a/inventory/templatetags/custom_filters.py +++ b/inventory/templatetags/custom_filters.py @@ -1,7 +1,7 @@ from django import template from calendar import month_abbr from django.urls import reverse -from django_ledger.io.io_core import get_localdate +from django_ledger.io.io_core import get_localdate,validate_activity register = template.Library() @@ -146,3 +146,35 @@ def balance_sheet_statement(context, io_model, to_date=None): 'user_model': user_model, 'tx_digest': io_digest.get_io_data(), } + +@register.inclusion_tag('django_ledger/financial_statements/tags/income_statement.html', takes_context=True) +def income_statement_table(context, io_model, from_date=None, to_date=None): + user_model = context['user'] + activity = context['request'].GET.get('activity') + activity = validate_activity(activity, raise_404=True) + entity_slug = context['view'].kwargs.get('entity_slug') + + if not from_date: + from_date = context['from_date'] + if not to_date: + to_date = context['to_date'] + + io_digest = io_model.digest( + activity=activity, + user_model=user_model, + entity_slug=entity_slug, + unit_slug=context['unit_slug'], + by_unit=context['by_unit'], + from_date=from_date, + to_date=to_date, + equity_only=True, + process_groups=True, + income_statement=True, + signs=True + ) + + return { + 'entity_slug': entity_slug, + 'user_model': user_model, + 'tx_digest': io_digest.get_io_data() + } diff --git a/inventory/urls.py b/inventory/urls.py index 7b323a58..c2007bc8 100644 --- a/inventory/urls.py +++ b/inventory/urls.py @@ -546,7 +546,23 @@ urlpatterns = [ path('entity//balance-sheet/date////', views.DateBalanceSheetView.as_view(), name='entity-bs-date'), - + # INCOME STATEMENT Reports ---- + # Entity ..... + path('entity//income-statement/', + views.BaseIncomeStatementRedirectViewBase.as_view(), + name='entity-ic'), + path('entity//income-statement/year//', + views.FiscalYearIncomeStatementViewBase.as_view(), + name='entity-ic-year'), + # path('entity//income-statement/quarter///', + # views.QuarterlyIncomeStatementView.as_view(), + # name='entity-ic-quarter'), + # path('entity//income-statement/month///', + # views.MonthlyIncomeStatementView.as_view(), + # name='entity-ic-month'), + # path('entity//income-statement/date////', + # views.MonthlyIncomeStatementView.as_view(), + # name='entity-ic-date'), ] diff --git a/inventory/utils.py b/inventory/utils.py index 62857d74..5eaef5f9 100644 --- a/inventory/utils.py +++ b/inventory/utils.py @@ -284,15 +284,11 @@ 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) - total_amount + calculator = CarFinanceCalculator(invoice) + finance_data = calculator.get_finance_data() + # if invoice.terms == "on_receipt": + # for x in invoice.get_itemtxs_data()[0].all(): + # total_amount += Decimal(x.unit_cost) * Decimal(x.quantity) ledger = LedgerModel.objects.filter( name__icontains=str(invoice.pk), entity=entity @@ -323,28 +319,26 @@ def set_invoice_payment(dealer, entity, invoice, amount, payment_method): TransactionModel.objects.create( journal_entry=journal, account=debit_account, # Debit Cash - amount=amount, # Payment amount + amount=finance_data["grand_total"], # Payment amount tx_type="debit", description="Payment Received", ) - # if total_amount + invoice. - TransactionModel.objects.create( journal_entry=journal, account=credit_account, # Credit Accounts Receivable - amount=total_amount, # Payment amount + amount=finance_data["total_price"], # 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", + + TransactionModel.objects.create( + journal_entry=journal, + account=vat_payable_account, # Credit VAT Payable + amount=finance_data["total_vat_amount"], + tx_type="credit", + description="VAT Payable on Invoice", ) invoice.make_payment(amount) @@ -622,7 +616,8 @@ class CarFinanceCalculator: "make": car_info.get('make'), "model": car_info.get('model'), "year": car_info.get('year'), - "trim": car_info.get('mileage'), # Verify if this should actually be mileage + "trim": car_info.get('trim'), + "mileage": car_info.get('mileage'), "cost_price": car_finance.get('cost_price'), "selling_price": car_finance.get('selling_price'), "discount": car_finance.get('discount_amount'), @@ -657,7 +652,7 @@ class CarFinanceCalculator: "total_price": total_price, "total_vat_amount": total_vat_amount, "total_discount": total_discount, - "grand_total": (total_price + total_vat_amount) - total_discount, + "grand_total": (total_price + total_vat_amount) - total_discount , } def get_finance_data(self): @@ -668,6 +663,7 @@ class CarFinanceCalculator: "quantity": sum(self._get_quantity(item) for item in self.item_transactions), "total_price": totals['total_price'], "total_vat": totals['total_vat_amount'] + totals['total_price'], + "total_vat_amount": totals['total_vat_amount'], "total_discount": totals['total_discount'], "grand_total": totals['grand_total'], "additionals": self.additional_services, diff --git a/inventory/views.py b/inventory/views.py index 2581940f..d7c9982b 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -2380,16 +2380,9 @@ class EstimateDetailView(LoginRequiredMixin, DetailView): def get_context_data(self, **kwargs): estimate = kwargs.get("object") - if estimate.get_itemtxs_data(): - # data = get_financial_values(estimate) + if estimate.get_itemtxs_data(): calculator = CarFinanceCalculator(estimate) - finance_data = calculator.get_finance_data() - # kwargs["vat_amount"] = data["vat_amount"] - # kwargs["total"] = data["grand_total"] - # kwargs["discount_amount"] = data["discount_amount"] - # kwargs["vat"] = data["vat"] - # kwargs["car_and_item_info"] = data["car_and_item_info"] - # kwargs["additional_services"] = data["additional_services"] + finance_data = calculator.get_finance_data() kwargs['data'] = finance_data print(finance_data) kwargs["invoice"] = ( @@ -2517,16 +2510,10 @@ class InvoiceDetailView(LoginRequiredMixin, DetailView): def get_context_data(self, **kwargs): invoice = kwargs.get("object") - if invoice.get_itemtxs_data(): - # data = get_financial_values(invoice) + if invoice.get_itemtxs_data(): calculator = CarFinanceCalculator(invoice) finance_data = calculator.get_finance_data() - # kwargs["vat_amount"] = data["vat_amount"] - # kwargs["total"] = data["grand_total"] - # kwargs["discount_amount"] = data["discount_amount"] - # kwargs["vat"] = data["vat"] - # kwargs["car_and_item_info"] = data["car_and_item_info"] - # kwargs["additional_services"] = data["additional_services"] + print((finance_data["total_vat_amount"]+finance_data["total_price"]) == finance_data["grand_total"]) kwargs["data"] = finance_data kwargs["payments"] = JournalEntryModel.objects.filter( ledger=invoice.ledger @@ -2627,38 +2614,41 @@ def invoice_create(request, pk): ledger.save() invoice.save() - unit_items = estimate.get_itemtxs_data()[0] - vat = models.VatRate.objects.filter(is_active=True).first() - total = 0 - discount_amount = 0 + # unit_items = estimate.get_itemtxs_data()[0] + # vat = models.VatRate.objects.filter(is_active=True).first() + calculator = CarFinanceCalculator(estimate) + finance_data = calculator.get_finance_data() + + # total = 0 + # discount_amount = 0 - itemtxs = [] - for item in unit_items: - car = models.Car.objects.get(vin=item.item_model.name) + # itemtxs = [] + # for item in unit_items: + # car = models.Car.objects.get(vin=item.item_model.name) - total = Decimal(car.finances.total) * Decimal(item.ce_quantity) - discount_amount = car.finances.discount_amount + # total = Decimal(car.finances.total) * Decimal(item.ce_quantity) + # discount_amount = car.finances.discount_amount - grand_total = Decimal(total) - Decimal(discount_amount) - vat_amount = round(Decimal(grand_total) * Decimal(vat.rate), 2) - grand_total += Decimal(vat_amount) - unit_cost = grand_total / Decimal(item.ce_quantity) - itemtxs.append( - { - "item_number": item.item_model.item_number, - "unit_cost": unit_cost, - "unit_revenue": unit_cost, - "quantity": item.ce_quantity, - "total_amount": grand_total, - } - ) + # grand_total = Decimal(total) - Decimal(discount_amount) + # vat_amount = round(Decimal(grand_total) * Decimal(vat.rate), 2) + # grand_total += Decimal(vat_amount) + # unit_cost = grand_total / Decimal(item.ce_quantity) + # itemtxs.append( + # { + # "item_number": item.item_model.item_number, + # "unit_cost": unit_cost, + # "unit_revenue": unit_cost, + # "quantity": item.ce_quantity, + # "total_amount": grand_total, + # } + # ) invoice_itemtxs = { i.get("item_number"): { - "unit_cost": i.get("unit_cost"), + "unit_cost": i.get("total_vat"), "quantity": i.get("quantity"), - "total_amount": i.get("total_amount"), + "total_amount": i.get("total_vat"), } - for i in itemtxs + for i in finance_data.get("cars") } invoice_itemtxs = invoice.migrate_itemtxs( @@ -2705,14 +2695,16 @@ class InvoicePreviewView(LoginRequiredMixin, DetailView): def get_context_data(self, **kwargs): invoice = kwargs.get("object") if invoice.get_itemtxs_data(): - data = get_financial_values(invoice) - - kwargs["vat_amount"] = data["vat_amount"] - kwargs["total"] = data["grand_total"] - kwargs["discount_amount"] = data["discount_amount"] - kwargs["vat"] = data["vat"] - kwargs["car_and_item_info"] = data["car_and_item_info"] - kwargs["additional_services"] = data["additional_services"] + # data = get_financial_values(invoice) + calculator = CarFinanceCalculator(invoice) + finance_data = calculator.get_finance_data() + kwargs["data"] = finance_data + # kwargs["vat_amount"] = data["vat_amount"] + # kwargs["total"] = data["grand_total"] + # kwargs["discount_amount"] = data["discount_amount"] + # kwargs["vat"] = data["vat"] + # kwargs["car_and_item_info"] = data["car_and_item_info"] + # kwargs["additional_services"] = data["additional_services"] return super().get_context_data(**kwargs) @@ -3433,7 +3425,8 @@ class SubscriptionPlans(ListView): class OrderListView(ListView): model = models.SaleOrder template_name = "sales/orders/order_list.html" - context_object_name = "orders" + context_object_name = "orders" + # email def send_email_view(request, pk): @@ -3509,7 +3502,7 @@ def custom_bad_request_view(request, exception=None): # from django_ledger.io.io_core import get_localdate # from django_ledger.views.mixins import (DjangoLedgerSecurityMixIn) # from django.views.generic import RedirectView -from django_ledger.views.financial_statement import FiscalYearBalanceSheetView +from django_ledger.views.financial_statement import FiscalYearBalanceSheetView,BaseIncomeStatementRedirectView,FiscalYearIncomeStatementView from django.views.generic import DetailView, RedirectView from django_ledger.io.io_core import get_localdate @@ -3548,3 +3541,34 @@ class DateBalanceSheetView(FiscalYearBalanceSheetViewBase, DateReportMixIn): """ Date Balance Sheet View. """ + +class BaseIncomeStatementRedirectViewBase(BaseIncomeStatementRedirectView): + + def get_redirect_url(self, *args, **kwargs): + year = get_localdate().year + dealer = get_user_type(self.request) + return reverse('entity-ic-year', + kwargs={ + 'entity_slug': dealer.entity.slug, + 'year': year + }) + +class FiscalYearIncomeStatementViewBase(FiscalYearIncomeStatementView): + template_name = "ledger/reports/income_statement.html" + +class QuarterlyIncomeStatementView(FiscalYearIncomeStatementView, QuarterlyReportMixIn): + """ + Quarter Income Statement View. + """ + + +class MonthlyIncomeStatementView(FiscalYearIncomeStatementView, MonthlyReportMixIn): + """ + Monthly Income Statement View. + """ + + +class DateModelIncomeStatementView(FiscalYearIncomeStatementView, DateReportMixIn): + """ + Date Income Statement View. + """ diff --git a/requirements.txt b/requirements.txt index 4deb40fc..2f8a2658 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,252 +1,252 @@ -aiohappyeyeballs==2.4.4 -aiohttp==3.11.11 -aiohttp-retry==2.9.1 -aiosignal==1.3.2 -alabaster==1.0.0 -albucore==0.0.23 -albumentations==2.0.1 -annotated-types==0.7.0 -anyio==4.8.0 -arabic-reshaper==3.0.0 -asgiref==3.8.1 -astor==0.8.1 -astroid==3.3.8 -attrs==23.2.0 -autopep8==2.3.2 -Babel==2.15.0 -beautifulsoup4==4.12.3 -bleach==6.2.0 -blinker==1.9.0 -Brotli==1.1.0 -certifi==2024.12.14 -cffi==1.17.1 -chardet==5.2.0 -charset-normalizer==3.4.1 -click==8.1.8 -colorama==0.4.6 -commonmark==0.9.1 -contourpy==1.3.1 -crispy-bootstrap5==2024.10 -cryptography==44.0.0 -cssselect2==0.7.0 -ctranslate2==4.5.0 -cycler==0.12.1 -Cython==3.0.11 -decorator==5.1.1 -desert==2022.9.22 -dill==0.3.9 -distro==1.9.0 -dj-rest-auth==7.0.1 -dj-shop-cart==7.1.1 -Django==5.1.5 -django-allauth==65.3.1 -django-appointment==3.7.4 -django-autoslug==1.9.9 -django-bootstrap5==24.3 -django-classy-tags==4.1.0 -django-cors-headers==4.6.0 -django-countries==7.6.1 -django-crispy-forms==2.3 -django-debug-toolbar==5.0.1 -django-extensions==3.2.3 -django-filter==24.3 -django-formtools==2.5.1 -django-ledger==0.7.3 -django-money==3.5.3 -django-next-url-mixin==0.4.0 -django-nine==0.2.7 -django-nonefield==0.4 -django-ordered-model==3.7.4 -django-phonenumber-field==8.0.0 -django-picklefield==3.2 -django-plans==1.2.0 -django-prometheus==2.3.1 -django-q2==1.7.6 -django-sekizai==4.1.0 -django-sequences==3.0 -django-silk==5.3.2 -django-sms==0.7.0 -django-sslserver==0.22 -django-tables2==2.7.5 -django-treebeard==4.7.1 -django-view-breadcrumbs==2.5.1 -djangocms-admin-style==3.3.1 -djangorestframework==3.15.2 -djangorestframework_simplejwt==5.4.0 -djangoviz==0.1.1 -docutils==0.21.2 -easy-thumbnails==2.10 -emoji==2.14.1 -et_xmlfile==2.0.0 -Faker==35.0.0 -filelock==3.17.0 -fire==0.7.0 -Flask==3.1.0 -fonttools==4.55.6 -frozenlist==1.5.0 -fsspec==2024.12.0 -gprof2dot==2024.6.6 -graphqlclient==0.2.4 -greenlet==3.1.1 -h11==0.14.0 -h2==4.1.0 -hpack==4.1.0 -hstspreload==2025.1.1 -httpcore==1.0.7 -httpx==0.28.1 -hyperframe==6.1.0 -idna==3.10 -imageio==2.37.0 -imagesize==1.4.1 -imgaug==0.4.0 -iso4217==1.12.20240625 -isodate==0.7.2 -isort==5.13.2 -itsdangerous==2.2.0 -Jinja2==3.1.5 -jiter==0.8.2 -joblib==1.4.2 -kiwisolver==1.4.8 -lazy_loader==0.4 -ledger==1.0.1 -libretranslatepy==2.1.4 -lmdb==1.6.2 -lxml==5.3.0 -Markdown==3.7 -markdown-it-py==3.0.0 -MarkupSafe==3.0.2 -marshmallow==3.26.0 -matplotlib==3.10.0 -mccabe==0.7.0 -mdurl==0.1.2 -MouseInfo==0.1.3 -mpmath==1.3.0 -multidict==6.1.0 -mypy-extensions==1.0.0 -networkx==3.4.2 -newrelic==10.4.0 -nltk==3.9.1 -numpy==2.2.2 -oauthlib==3.2.2 -ofxtools==0.9.5 -openai==1.60.0 -opencv-contrib-python==4.11.0.86 -opencv-python==4.11.0.86 -opencv-python-headless==4.11.0.86 -openpyxl==3.1.5 -opt_einsum==3.4.0 -outcome==1.3.0.post0 -packaging==24.2 -pandas==2.2.3 -pango==0.0.1 -pdfkit==1.0.0 -phonenumbers==8.13.42 -pillow==10.4.0 -platformdirs==4.3.6 -prometheus_client==0.21.1 -propcache==0.2.1 -protobuf==5.29.3 -psycopg==3.2.4 -psycopg-binary==3.2.4 -psycopg-c==3.2.4 -py-moneyed==3.0 -PyAutoGUI==0.9.54 -pyclipper==1.3.0.post6 -pycodestyle==2.12.1 -pycparser==2.22 -pydantic==2.10.5 -pydantic_core==2.27.2 -pydotplus==2.0.2 -pydyf==0.11.0 -PyGetWindow==0.0.9 -Pygments==2.19.1 -PyJWT==2.10.1 -pylint==3.3.3 -PyMsgBox==1.0.9 -PyMySQL==1.1.1 -pyobjc-core==11.0 -pyobjc-framework-Cocoa==11.0 -pyobjc-framework-Quartz==11.0 -pyparsing==3.2.1 -pyperclip==1.9.0 -pyphen==0.17.2 -pypng==0.20220715.0 -PyRect==0.2.0 -PyScreeze==1.0.1 -pyserial==3.5 -PySocks==1.7.1 -python-bidi==0.6.3 -python-dateutil==2.9.0.post0 -python-docx==1.1.2 -python-openid==2.2.5 -python-stdnum==1.20 -python3-saml==1.16.0 -pytweening==1.2.0 -pytz==2024.2 -pyvin==0.0.2 -pywa==2.7.0 -pywhat==5.1.0 -pywhatkit==5.4 -PyYAML==6.0.2 -pyzbar==0.1.9 -qrcode==8.0 -RapidFuzz==3.11.0 -regex==2024.11.6 -reportlab==4.2.5 -requests==2.32.3 -requests-oauthlib==2.0.0 -rfc3986==2.0.0 -rich==13.9.4 -rubicon-objc==0.5.0 -sacremoses==0.1.1 -scikit-image==0.25.0 -scikit-learn==1.6.1 -scipy==1.15.1 -selenium==4.28.1 -sentencepiece==0.2.0 -shapely==2.0.6 -simsimd==6.2.1 -six==1.17.0 -sniffio==1.3.1 -snowballstemmer==2.2.0 -sortedcontainers==2.4.0 -soupsieve==2.6 -SQLAlchemy==2.0.37 -sqlparse==0.5.3 -stanza==1.10.1 -stringzilla==3.11.3 -suds==1.2.0 -swapper==1.3.0 -sympy==1.13.1 -tablib==3.8.0 -termcolor==2.5.0 -threadpoolctl==3.5.0 -tifffile==2025.1.10 -tinycss2==1.4.0 -tinyhtml5==2.0.0 -tomli==2.2.1 -tomlkit==0.13.2 -torch==2.5.1 -tqdm==4.67.1 -trio==0.28.0 -trio-websocket==0.11.1 -twilio==9.4.3 -typing-inspect==0.9.0 -typing_extensions==4.12.2 -tzdata==2025.1 -Unidecode==1.3.8 -upgrade-requirements==1.7.0 -urllib3==2.3.0 -vin==0.6.2 -vininfo==1.8.0 -vishap==0.1.5 -vpic-api==0.7.4 -weasyprint==63.1 -webencodings==0.5.1 -websocket-client==1.8.0 -Werkzeug==3.1.3 -wikipedia==1.4.0 -wsproto==1.2.0 -xmlsec==1.3.14 -yarl==1.18.3 -zopfli==0.2.3.post1 +aiohappyeyeballs +aiohttp +aiohttp-retry +aiosignal +alabaster +albucore +albumentations +annotated-types +anyio +arabic-reshaper +asgiref +astor +astroid +attrs +autopep8 +Babel +beautifulsoup4 +bleach +blinker +Brotli +certifi +cffi +chardet +charset-normalizer +click +colorama +commonmark +contourpy +crispy-bootstrap5 +cryptography +cssselect2 +ctranslate2 +cycler +Cython +decorator +desert +dill +distro +dj-rest-auth +dj-shop-cart +Django +django-allauth +django-appointment +django-autoslug +django-bootstrap5 +django-classy-tags +django-cors-headers +django-countries +django-crispy-forms +django-debug-toolbar +django-extensions +django-filter +django-formtools +django-ledger +django-money +django-next-url-mixin +django-nine +django-nonefield +django-ordered-model +django-phonenumber-field +django-picklefield +django-plans +django-prometheus +django-q2 +django-sekizai +django-sequences +django-silk +django-sms +django-sslserver +django-tables2 +django-treebeard +django-view-breadcrumbs +djangocms-admin-style +djangorestframework +djangorestframework_simplejwt +djangoviz +docutils +easy-thumbnails +emoji +et_xmlfile +Faker +filelock +fire +Flask +fonttools +frozenlist +fsspec +gprof2dot +graphqlclient +greenlet +h11 +h2 +hpack +hstspreload +httpcore +httpx +hyperframe +idna +imageio +imagesize +imgaug +iso4217 +isodate +isort +itsdangerous +Jinja2 +jiter +joblib +kiwisolver +lazy_loader +ledger +libretranslatepy +lmdb +lxml +Markdown +markdown-it-py +MarkupSafe +marshmallow +matplotlib +mccabe +mdurl +MouseInfo +mpmath +multidict +mypy-extensions +networkx +newrelic +nltk +numpy +oauthlib +ofxtools +openai +opencv-contrib-python +opencv-python +opencv-python-headless +openpyxl +opt_einsum +outcome +packaging +pandas +pango +pdfkit +phonenumbers +pillow +platformdirs +prometheus_client +propcache +protobuf +psycopg +psycopg-binary +psycopg-c +py-moneyed +PyAutoGUI +pyclipper +pycodestyle +pycparser +pydantic +pydantic_core +pydotplus +pydyf +PyGetWindow +Pygments +PyJWT +pylint +PyMsgBox +PyMySQL +pyobjc-core +pyobjc-framework-Cocoa +pyobjc-framework-Quartz +pyparsing +pyperclip +pyphen +pypng +PyRect +PyScreeze +pyserial +PySocks +python-bidi +python-dateutil +python-docx +python-openid +python-stdnum +python3-saml +pytweening +pytz +pyvin +pywa +pywhat +pywhatkit +PyYAML +pyzbar +qrcode +RapidFuzz +regex +reportlab +requests +requests-oauthlib +rfc3986 +rich +rubicon-objc +sacremoses +scikit-image +scikit-learn +scipy +selenium +sentencepiece +shapely +simsimd +six +sniffio +snowballstemmer +sortedcontainers +soupsieve +SQLAlchemy +sqlparse +stanza +stringzilla +suds +swapper +sympy +tablib +termcolor +threadpoolctl +tifffile +tinycss2 +tinyhtml5 +tomli +tomlkit +torch +tqdm +trio +trio-websocket +twilio +typing-inspect +typing_extensions +tzdata +Unidecode +upgrade-requirements +urllib3 +vin +vininfo +vishap +vpic-api +weasyprint +webencodings +websocket-client +Werkzeug +wikipedia +wsproto +xmlsec +yarl +zopfli diff --git a/scripts/run.py b/scripts/run.py index 7b0b7c9f..49d99a63 100644 --- a/scripts/run.py +++ b/scripts/run.py @@ -35,11 +35,11 @@ def run(): invoice_itemtxs = { i.get("item_number"): { - "unit_cost": i.get("total"), + "unit_cost": i.get("total_price"), "quantity": i.get("quantity"), "total_amount": i.get("total_vat"), } for i in finance_data.get("cars") } - print(invoice_itemtxs) \ No newline at end of file + print(finance_data) \ No newline at end of file diff --git a/templates/header.html b/templates/header.html index d0a49a30..f86811f1 100644 --- a/templates/header.html +++ b/templates/header.html @@ -235,6 +235,29 @@
{% trans 'bills'|capfirst %}
+ + + + + +