From 3ce318317e1d2894c32b3fddd2501413f14cc8b3 Mon Sep 17 00:00:00 2001 From: ismail Date: Wed, 25 Jun 2025 14:15:17 +0300 Subject: [PATCH 1/2] implement the dealer slug for inventory and sales --- inventory/context_processors.py | 4 +- inventory/management/commands/generate_vin.py | 61 ++-- inventory/middleware.py | 28 +- .../migrations/0011_dealer_business_name.py | 19 ++ .../0012_remove_dealer_business_name.py | 17 + inventory/mixins.py | 16 + inventory/templatetags/custom_filters.py | 3 + inventory/urls.py | 183 ++++++----- inventory/utils.py | 4 +- inventory/views.py | 301 ++++++++---------- templates/bill/bill_detail.html | 12 +- templates/bill/bill_update.html | 8 +- templates/bill/includes/card_bill.html | 14 +- templates/bill/tags/bill_item_formset.html | 4 +- templates/dashboards/manager.html | 2 +- templates/errors/400.html | 2 +- templates/header.html | 30 +- templates/index.html | 1 - templates/inventory/add_custom_card.html | 2 +- templates/inventory/car_detail.html | 86 ++--- templates/inventory/car_finance_form.html | 7 - templates/inventory/car_form.html | 2 +- .../inventory/car_form_qabl alfalsafa.html | 2 +- templates/inventory/car_inventory.html | 6 +- templates/inventory/car_list_view.html | 244 +++++++------- .../inventory/car_registration_form.html | 2 +- templates/inventory/inventory_stats.html | 2 +- templates/ledger/bills/bill_list.html | 10 +- .../ledger/coa_accounts/account_detail.html | 8 +- .../ledger/coa_accounts/account_list.html | 2 +- .../coa_accounts/partials/account_table.html | 4 +- templates/ledger/reports/dashboard-copy.html | 4 +- templates/partials/vehicle_dropdowns.html | 2 +- .../purchase_orders/includes/card_po.html | 18 +- .../includes/inventory_item_form.html | 2 +- .../includes/po_item_formset.html | 4 +- .../purchase_orders/partials/po-select.html | 2 +- templates/purchase_orders/po_delete.html | 6 +- templates/purchase_orders/po_detail.html | 19 +- templates/purchase_orders/po_list.html | 14 +- templates/purchase_orders/po_update.html | 8 +- .../purchase_orders/tags/po_item_table.html | 2 +- .../sales/estimates/estimate_detail.html | 40 ++- templates/sales/estimates/estimate_form.html | 6 +- templates/sales/estimates/estimate_list.html | 2 +- templates/sales/estimates/estimate_send.html | 2 +- .../sales/estimates/sale_order_form1.html | 2 +- templates/sales/invoices/invoice_detail.html | 55 ++-- templates/sales/invoices/invoice_list.html | 3 +- templates/sales/journals/journal_list.html | 2 +- templates/sales/payments/payment_form.html | 2 +- templates/sales/payments/payment_list.html | 6 +- templates/sales/saleorder_detail.html | 4 +- templates/sales/sales_list.html | 12 +- templates/send-mail.html | 2 +- 55 files changed, 659 insertions(+), 646 deletions(-) create mode 100644 inventory/migrations/0011_dealer_business_name.py create mode 100644 inventory/migrations/0012_remove_dealer_business_name.py diff --git a/inventory/context_processors.py b/inventory/context_processors.py index 7f749d6a..89af5dbd 100644 --- a/inventory/context_processors.py +++ b/inventory/context_processors.py @@ -1,5 +1,7 @@ from django.conf import settings +from inventory.utils import get_user_type + def currency_context(request): """ @@ -40,4 +42,4 @@ def breadcrumbs(request): for i in range(len(path)): url = "/" + "/".join(path[: i + 1]) + "/" breadcrumbs.append({"name": path[i].capitalize(), "url": url}) - return {"breadcrumbs": breadcrumbs} + return {"breadcrumbs": breadcrumbs} \ No newline at end of file diff --git a/inventory/management/commands/generate_vin.py b/inventory/management/commands/generate_vin.py index 36dc6132..f2af0af1 100644 --- a/inventory/management/commands/generate_vin.py +++ b/inventory/management/commands/generate_vin.py @@ -1,6 +1,6 @@ from django.core.management.base import BaseCommand -from inventory.services import get_model, decodevin +from inventory.services import get_make, get_model, decodevin from bs4 import BeautifulSoup import requests @@ -24,35 +24,36 @@ class Command(BaseCommand): ) self.stdout.write(self.style.SUCCESS(f"Generated VIN: {vin}")) self.stdout.write(self.style.SUCCESS(f"Description: {description}")) - self.stdout.write( - self.style.SUCCESS( - "####################################################################################################" - ) - ) - self.stdout.write( - self.style.SUCCESS( - "####################################################################################################" - ) - ) - self.stdout.write(self.style.SUCCESS(f"Decoded VIN: {result}")) - make, model, year_model = result.values() - self.stdout.write( - self.style.SUCCESS( - f"VIN: {vin} - Make {make} - Model {model} - Model Year {year_model}" - ) - ) - m = get_model(model) - self.stdout.write(self.style.SUCCESS(f"Make: {m.id_car_make} - Model: {m}")) - self.stdout.write( - self.style.SUCCESS( - "####################################################################################################" - ) - ) - self.stdout.write( - self.style.SUCCESS( - "####################################################################################################" - ) - ) + # self.stdout.write( + # self.style.SUCCESS( + # "####################################################################################################" + # ) + # ) + # self.stdout.write( + # self.style.SUCCESS( + # "####################################################################################################" + # ) + # ) + # self.stdout.write(self.style.SUCCESS(f"Decoded VIN: {result}")) + # make, model, year_model = result.values() + # self.stdout.write( + # self.style.SUCCESS( + # f"VIN: {vin} - Make {make} - Model {model} - Model Year {year_model}" + # ) + # ) + # make = get_make(make) + # m = get_model(model,make) + # self.stdout.write(self.style.SUCCESS(f"Make: {m.id_car_make} - Model: {m}")) + # self.stdout.write( + # self.style.SUCCESS( + # "####################################################################################################" + # ) + # ) + # self.stdout.write( + # self.style.SUCCESS( + # "####################################################################################################" + # ) + # ) def generate_vin(self): # url = "https://www.vindecoder.org/vin-decoder" diff --git a/inventory/middleware.py b/inventory/middleware.py index 3ee697b8..14010720 100644 --- a/inventory/middleware.py +++ b/inventory/middleware.py @@ -1,4 +1,7 @@ import logging + +from django.http import Http404, HttpResponseForbidden +from django.shortcuts import redirect from inventory import models from django.utils import timezone @@ -59,8 +62,11 @@ class InjectParamsMiddleware: def __call__(self, request): try: - # request.entity = request.user.dealer.entity - request.dealer = get_user_type(request) + if request.user.is_authenticated: + request.dealer = get_user_type(request) + request.entity = request.dealer.entity + else: + request.dealer = None except Exception: pass response = self.get_response(request) @@ -107,3 +113,21 @@ class InjectDealerMiddleware: # if request.user.is_authenticated and not request.session.get('otp_verified', False): # return redirect(reverse('verify_otp')) # return self.get_response(request) +class DealerSlugMiddleware: + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + response = self.get_response(request) + return response + + def process_view(self, request, view_func, view_args, view_kwargs): + if request.user.is_authenticated: + dealer = get_user_type(request) + if 'dealer_slug' not in view_kwargs: + return redirect('home', + dealer_slug=dealer.slug, + **view_kwargs) + elif view_kwargs['dealer_slug'] != dealer.slug: + raise Http404("Dealer slug mismatch") + return None diff --git a/inventory/migrations/0011_dealer_business_name.py b/inventory/migrations/0011_dealer_business_name.py new file mode 100644 index 00000000..e7dd6751 --- /dev/null +++ b/inventory/migrations/0011_dealer_business_name.py @@ -0,0 +1,19 @@ +# Generated by Django 5.2.1 on 2025-06-23 12:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('inventory', '0010_alter_saleorder_created_by_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='dealer', + name='business_name', + field=models.CharField(default='poiiiioioioi', max_length=255, verbose_name='Buiseness Name'), + preserve_default=False, + ), + ] diff --git a/inventory/migrations/0012_remove_dealer_business_name.py b/inventory/migrations/0012_remove_dealer_business_name.py new file mode 100644 index 00000000..c8e9444f --- /dev/null +++ b/inventory/migrations/0012_remove_dealer_business_name.py @@ -0,0 +1,17 @@ +# Generated by Django 5.2.1 on 2025-06-24 12:55 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('inventory', '0011_dealer_business_name'), + ] + + operations = [ + migrations.RemoveField( + model_name='dealer', + name='business_name', + ), + ] diff --git a/inventory/mixins.py b/inventory/mixins.py index ae55f329..b730dbb5 100644 --- a/inventory/mixins.py +++ b/inventory/mixins.py @@ -1,5 +1,9 @@ +from django.http import Http404 +from django.shortcuts import redirect from django.utils.translation import get_language +from inventory.utils import get_user_type + class AddClassMixin: """ @@ -60,3 +64,15 @@ class LocalizedNameMixin: # return super().form_valid(form) # else: # return form.errors + + +class DealerSlugMixin: + def dispatch(self, request, *args, **kwargs): + if request.user.is_authenticated: + if 'dealer_slug' not in kwargs: + return redirect('home', + dealer_slug=request.dealer.slug, + **kwargs) + elif kwargs['dealer_slug'] != request.dealer.slug: + raise Http404("Dealer slug mismatch") + return super().dispatch(request, *args, **kwargs) \ No newline at end of file diff --git a/inventory/templatetags/custom_filters.py b/inventory/templatetags/custom_filters.py index ecc41190..474bca31 100644 --- a/inventory/templatetags/custom_filters.py +++ b/inventory/templatetags/custom_filters.py @@ -442,6 +442,7 @@ def filter_by_role(accounts, role_prefix): @register.inclusion_tag("purchase_orders/tags/po_item_table.html", takes_context=True) def po_item_table1(context, queryset): return { + "dealer_slug": context["view"].kwargs["dealer_slug"], "entity_slug": context["entity_slug"], "po_model": context["po_model"], "po_item_list": queryset, @@ -459,6 +460,7 @@ def po_item_formset_table(context, po_model, itemtxs_formset): item_role="inventory" ) return { + "dealer_slug": context["view"].kwargs["dealer_slug"], "entity_slug": context["view"].kwargs["entity_slug"], "po_model": po_model, "itemtxs_formset": itemtxs_formset, @@ -468,6 +470,7 @@ def po_item_formset_table(context, po_model, itemtxs_formset): @register.inclusion_tag("bill/tags/bill_item_formset.html", takes_context=True) def bill_item_formset_table(context, item_formset): return { + "dealer_slug": context["view"].kwargs["dealer_slug"], "entity_slug": context["view"].kwargs["entity_slug"], "bill_pk": context["view"].kwargs["bill_pk"], "total_amount__sum": context["total_amount__sum"], diff --git a/inventory/urls.py b/inventory/urls.py index fb9a78ac..475b6cdf 100644 --- a/inventory/urls.py +++ b/inventory/urls.py @@ -1,13 +1,15 @@ -from django.conf.urls import handler403, handler400, handler404, handler500 -from django.urls import path -from django_tables2.export.export import TableExport - +from inventory.utils import get_user_type from . import views - +from django.urls import path +from django.urls import reverse_lazy +from django.views.generic import RedirectView +from django_tables2.export.export import TableExport +from django.conf.urls import handler403, handler400, handler404, handler500 urlpatterns = [ # main URLs path("", views.HomeView.as_view(), name="home"), + path("/", views.HomeView.as_view(), name="home"), path("welcome/", views.WelcomeView.as_view(), name="welcome"), # Accounts URLs # path("login/", allauth_views.LoginView.as_view(template_name="account/login.html"), name="account_login"), @@ -277,28 +279,28 @@ urlpatterns = [ name="vendor_delete", ), # Car URLs - path("cars/upload_cars/", views.upload_cars, name="upload_cars"), - path("cars//upload_cars/", views.upload_cars, name="upload_cars"), - path("cars/add/", views.CarCreateView.as_view(), name="car_add"), - path("cars/inventory/", views.CarInventory.as_view(), name="car_inventory_all"), + path("/cars/upload_cars/", views.upload_cars, name="upload_cars"), + path("/cars//upload_cars/", views.upload_cars, name="upload_cars"), + path("/cars/add/", views.CarCreateView.as_view(), name="car_add"), + path("/cars/inventory/", views.CarInventory.as_view(), name="car_inventory_all"), path( - "cars/inventory////", + "/cars/inventory////", views.CarInventory.as_view(), name="car_inventory", ), - path("cars/inventory/stats", views.inventory_stats_view, name="inventory_stats"), - path("cars/inventory/list", views.CarListView.as_view(), name="car_list"), - path("cars//", views.CarDetailView.as_view(), name="car_detail"), + path("/cars/inventory/stats", views.inventory_stats_view, name="inventory_stats"), + path("/cars/inventory/list", views.CarListView.as_view(), name="car_list"), + path("/cars//", views.CarDetailView.as_view(), name="car_detail"), path("cars//history/", views.car_history, name="car_history"), - path("cars//update/", views.CarUpdateView.as_view(), name="car_update"), - path("cars//delete/", views.CarDeleteView.as_view(), name="car_delete"), + path("/cars//update/", views.CarUpdateView.as_view(), name="car_update"), + path("/cars//delete/", views.CarDeleteView.as_view(), name="car_delete"), path( - "cars//finance/create/", + "/cars//finance/create/", views.CarFinanceCreateView.as_view(), name="car_finance_create", ), path( - "cars/finance//update/", + "/cars/finance//update/", views.CarFinanceUpdateView.as_view(), name="car_finance_update", ), @@ -307,12 +309,12 @@ urlpatterns = [ views.bulk_update_car_price, name="bulk_update_car_price", ), - path("ajax/", views.AjaxHandlerView.as_view(), name="ajax_handler"), + path("/ajax/", views.AjaxHandlerView.as_view(), name="ajax_handler"), path( - "cars//add-color/", views.CarColorCreate.as_view(), name="add_color" + "/cars//add-color/", views.CarColorCreate.as_view(), name="add_color" ), path( - "car/colors//update/", + "/car/colors//update/", views.CarColorsUpdateView.as_view(), name="car_colors_update", ), @@ -353,19 +355,19 @@ urlpatterns = [ ), path("cars/inventory/search/", views.SearchCodeView.as_view(), name="car_search"), # path('cars//colors//update/',views.CarColorUpdateView.as_view(),name='color_update'), - path("cars/reserve//", views.reserve_car_view, name="reserve_car"), + path("/cars/reserve//", views.reserve_car_view, name="reserve_car"), path( - "reservations//", + "/reservations//", views.manage_reservation, name="reservations", ), path( - "cars//add-custom-card/", + "/cars//add-custom-card/", views.CustomCardCreateView.as_view(), name="add_custom_card", ), path( - "cars//add-registration/", + "/cars//add-registration/", views.CarRegistrationCreateView.as_view(), name="add_registration", ), @@ -612,142 +614,146 @@ urlpatterns = [ ), # Bank Account path( - "bank_accounts/", views.BankAccountListView.as_view(), name="bank_account_list" + "/bank_accounts/", views.BankAccountListView.as_view(), name="bank_account_list" ), path( - "bank_accounts//", + "/bank_accounts//", views.BankAccountDetailView.as_view(), name="bank_account_detail", ), path( - "bank_accounts/create/", + "/bank_accounts/create/", views.BankAccountCreateView.as_view(), name="bank_account_create", ), path( - "bank_accounts//update/", + "/bank_accounts//update/", views.BankAccountUpdateView.as_view(), name="bank_account_update", ), path( - "bank_accounts//delete/", + "/bank_accounts//delete/", views.bank_account_delete, name="bank_account_delete", ), # Account - path("coa_accounts/", views.AccountListView.as_view(), name="account_list"), + path("/coa_accounts/", views.AccountListView.as_view(), name="account_list"), path( - "coa_accounts//", + "/coa_accounts//", views.AccountDetailView.as_view(), name="account_detail", ), path( - "coa_accounts/create/", views.AccountCreateView.as_view(), name="account_create" + "/coa_accounts/create/", views.AccountCreateView.as_view(), name="account_create" ), path( - "coa_accounts//update/", + "/coa_accounts//update/", views.AccountUpdateView.as_view(), name="account_update", ), - path("coa_accounts//delete/", views.account_delete, name="account_delete"), + path("/coa_accounts//delete/", views.account_delete, name="account_delete"), + ################################################# # Estimate - path("sales/estimates/", views.EstimateListView.as_view(), name="estimate_list"), + ################################################# + path("/sales/estimates/", views.EstimateListView.as_view(), name="estimate_list"), path( - "sales/estimates//", + "/sales/estimates//", views.EstimateDetailView.as_view(), name="estimate_detail", ), - path("sales/estimates/create/", views.create_estimate, name="estimate_create"), + path("/sales/estimates/create/", views.create_estimate, name="estimate_create"), path( - "sales/estimates/create//", + "/sales/estimates/create//", views.create_estimate, name="estimate_create_from_opportunity", ), path( - "sales/estimates//estimate_mark_as/", + "/sales/estimates//estimate_mark_as/", views.estimate_mark_as, name="estimate_mark_as", ), path( - "sales/estimates//preview/", + "/sales/estimates//preview/", views.EstimatePreviewView.as_view(), name="estimate_preview", ), path( - "sales/estimates//payment_request/", + "/sales/estimates//payment_request/", views.PaymentRequest.as_view(), name="payment_request", ), path( - "sales/estimates//send_email", views.send_email_view, name="send_email" + "/sales/estimates//send_email", views.send_email_view, name="send_email" ), path( - "sales/estimates//sale_order/", + "/sales/estimates//sale_order/", views.create_sale_order, name="create_sale_order", ), path( - "sales/estimates//sale_order//details/", + "/sales/estimates//sale_order//details/", views.SaleOrderDetail.as_view(), name="sale_order_details", ), path( - "sales/estimates//sale_order/preview/", + "/sales/estimates//sale_order/preview/", views.preview_sale_order, name="preview_sale_order", ), + ############################################### # Invoice - path("sales/invoices/", views.InvoiceListView.as_view(), name="invoice_list"), + ############################################### + path("/sales/invoices/", views.InvoiceListView.as_view(), name="invoice_list"), path( - "sales/invoices//create/", views.invoice_create, name="invoice_create" + "/sales/invoices//create/", views.invoice_create, name="invoice_create" ), path( - "sales/invoices//", + "/sales/invoices//", views.InvoiceDetailView.as_view(), name="invoice_detail", ), path( - "sales/invoices//preview/", + "/sales/invoices//preview/", views.InvoicePreviewView.as_view(), name="invoice_preview", ), path( - "sales/invoices//invoice_mark_as/", + "/sales/invoices//invoice_mark_as/", views.invoice_mark_as, name="invoice_mark_as", ), path( - "sales/invoices//draft_invoice_update/", + "/sales/invoices//draft_invoice_update/", views.DraftInvoiceModelUpdateFormView.as_view(), name="draft_invoice_update", ), path( - "sales/invoices//approved_invoice_update/", + "/sales/invoices//approved_invoice_update/", views.ApprovedInvoiceModelUpdateFormView.as_view(), name="approved_invoice_update", ), path( - "sales/invoices//paid_invoice_update/", + "/sales/invoices//paid_invoice_update/", views.PaidInvoiceModelUpdateFormView.as_view(), name="paid_invoice_update", ), # path('sales/estimates//preview/', views.EstimatePreviewView.as_view(), name='estimate_preview'), # path('send_email/', views.send_email, name='send_email'), # Payment - path("sales/payments/", views.PaymentListView, name="payment_list"), + path("/sales/payments/", views.PaymentListView, name="payment_list"), path( - "sales/payments//create/", + "/sales/payments//create/", views.PaymentCreateView, name="payment_create", ), # path("sales/payments/create/", views.PaymentCreateView, name="payment_create"), path( - "sales/payments//payment_details/", + "/sales/payments//payment_details/", views.PaymentDetailView, name="payment_details", ), path( - "sales/payments//payment_mark_as_paid/", + "/sales/payments//payment_mark_as_paid/", views.payment_mark_as_paid, name="payment_mark_as_paid", ), @@ -787,85 +793,86 @@ urlpatterns = [ name="item_expense_update", ), # Bills - path("items/bills/", views.BillListView.as_view(), name="bill_list"), + path("/items/bills/", views.BillListView.as_view(), name="bill_list"), # path("items/bills/create/", views.BillModelCreateViewView.as_view(), name="bill_create"), path( - "items/bills//create/", + "/items/bills//create/", views.BillModelCreateView.as_view(), name="bill-create", ), path( - "items/bills//create/purchase-order//", + "/items/bills//create/purchase-order//", views.BillModelCreateView.as_view(for_purchase_order=True), name="bill-create-po", ), path( - "items/bills//create/estimate//", + "/items/bills//create/estimate//", views.BillModelCreateView.as_view(for_estimate=True), name="bill-create-estimate", ), path( - "items/bills//detail//", + "/items/bills//detail//", views.BillModelDetailViewView.as_view(), name="bill-detail", ), path( - "items/bills//update//", + "/items/bills//update//", views.BillModelUpdateViewView.as_view(), name="bill-update", ), path( - "items/bills//update//items/", + "/items/bills//update//items/", views.BillModelUpdateViewView.as_view(action_update_items=True), name="bill-update-items", ), ############################################################ path( - "items/bills//actions//mark-as-draft/", + "/items/bills//actions//mark-as-draft/", views.BillModelActionMarkAsDraftView.as_view(), name="bill-action-mark-as-draft", ), path( - "items/bills//actions//mark-as-review/", + "/items/bills//actions//mark-as-review/", views.BillModelActionMarkAsInReviewView.as_view(), name="bill-action-mark-as-review", ), path( - "items/bills//actions//mark-as-approved/", + "/items/bills//actions//mark-as-approved/", views.BillModelActionMarkAsApprovedView.as_view(), name="bill-action-mark-as-approved", ), path( - "items/bills//actions//mark-as-paid/", + "/items/bills//actions//mark-as-paid/", views.BillModelActionMarkAsPaidView.as_view(), name="bill-action-mark-as-paid", ), path( - "items/bills//actions//mark-as-void/", + "/items/bills//actions//mark-as-void/", views.BillModelActionVoidView.as_view(), name="bill-action-mark-as-void", ), path( - "items/bills//actions//mark-as-canceled/", + "/items/bills//actions//mark-as-canceled/", views.BillModelActionCanceledView.as_view(), name="bill-action-mark-as-canceled", ), path( - "items/bills//actions//lock-ledger/", + "/items/bills//actions//lock-ledger/", views.BillModelActionLockLedgerView.as_view(), name="bill-action-lock-ledger", ), path( - "items/bills//actions//unlock-ledger/", + "/items/bills//actions//unlock-ledger/", views.BillModelActionUnlockLedgerView.as_view(), name="bill-action-unlock-ledger", ), path( - "items/bills//actions//force-migration/", + "/items/bills//actions//force-migration/", views.BillModelActionForceMigrateView.as_view(), name="bill-action-force-migrate", ), # path("items/bills/create/", views.bill_create, name="bill_create"), + # >>>>>>>>>>>>>>>>>>>>>>... path( "items/bills//bill_detail/", views.BillDetailView.as_view(), @@ -1039,78 +1046,78 @@ urlpatterns = [ ######### # Purchase Order path( - "purchase_orders/", + "/purchase_orders/", views.PurchaseOrderListView.as_view(), name="purchase_order_list", ), path( - "purchase_orders/new/", + "/purchase_orders/new/", views.PurchaseOrderCreateView, name="purchase_order_create", ), path( - "purchase_orders//detail/", + "/purchase_orders//detail/", views.PurchaseOrderDetailView.as_view(), name="purchase_order_detail", ), path( - "purchase_orders///update/", + "/purchase_orders///update/", views.PurchaseOrderUpdateView.as_view(), name="purchase_order_update", ), path( - "purchase_orders//update//update-items/", + "/purchase_orders//update//update-items/", views.PurchaseOrderUpdateView.as_view(action_update_items=True), name="purchase_order_update_items", ), path( - "purchase_orders/inventory_item/create/", + "/purchase_orders/inventory_item/create/", views.InventoryItemCreateView, name="inventory_item_create", ), path( - "purchase_orders/inventory_items_filter/", + "/purchase_orders/inventory_items_filter/", views.inventory_items_filter, name="inventory_items_filter", ), path( - "purchase_orders//delete//", + "/purchase_orders//delete//", views.PurchaseOrderModelDeleteView.as_view(), name="po-delete", ), path( - "purchase_orders///upload/", + "/purchase_orders///upload/", view=views.view_items_inventory, name="view_items_inventory", ), # Actions.... path( - "/action//mark-as-draft/", + "//action//mark-as-draft/", views.PurchaseOrderMarkAsDraftView.as_view(), name="po-action-mark-as-draft", ), path( - "/action//mark-as-review/", + "//action//mark-as-review/", views.PurchaseOrderMarkAsReviewView.as_view(), name="po-action-mark-as-review", ), path( - "/action//mark-as-approved/", + "//action//mark-as-approved/", views.PurchaseOrderMarkAsApprovedView.as_view(), name="po-action-mark-as-approved", ), path( - "/action//mark-as-fulfilled/", + "//action//mark-as-fulfilled/", views.PurchaseOrderMarkAsFulfilledView.as_view(), name="po-action-mark-as-fulfilled", ), path( - "/action//mark-as-canceled/", + "//action//mark-as-canceled/", views.PurchaseOrderMarkAsCanceledView.as_view(), name="po-action-mark-as-canceled", ), path( - "/action//mark-as-void/", + "//action//mark-as-void/", views.PurchaseOrderMarkAsVoidView.as_view(), name="po-action-mark-as-void", ), diff --git a/inventory/utils.py b/inventory/utils.py index 07b85a90..df409ca5 100644 --- a/inventory/utils.py +++ b/inventory/utils.py @@ -222,7 +222,7 @@ def reserve_car(car, request): except Exception as e: messages.error(request, f"Error reserving car: {e}") - return redirect("car_detail", slug=car.slug) + return redirect("car_detail", dealer_slug=request.dealer.slug, slug=car.slug) def calculate_vat_amount(amount): @@ -1011,7 +1011,7 @@ class CarFinanceCalculator: "make": car_info.get("make"), "model": car_info.get("model"), "year": car_info.get("year"), - "logo": item.item_model.car.id_car_make.logo.url, + "logo": getattr(item.item_model.car.id_car_make, "logo", ""), "trim": car_info.get("trim"), "mileage": car_info.get("mileage"), "cost_price": car_finance.get("cost_price"), diff --git a/inventory/views.py b/inventory/views.py index c31a1778..6af0e212 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -20,6 +20,7 @@ from pyzbar.pyzbar import decode from urllib.parse import urlparse, urlunparse ##################################################################### +from inventory.mixins import DealerSlugMixin from inventory.models import Status as LeadStatus from django.db import IntegrityError from background_task.models import Task @@ -348,10 +349,13 @@ class HomeView(LoginRequiredMixin, TemplateView): template_name = "index.html" - def dispatch(self, request, *args, **kwargs): + def dispatch(self, request,*args, **kwargs): # Redirect unauthenticated users to the welcome page if not request.user.is_authenticated: return redirect("welcome") + if not kwargs.get("dealer_slug"): + dealer = get_user_type(request) + return redirect("home", dealer_slug=dealer.slug) return super().dispatch(request, *args, **kwargs) @@ -616,8 +620,8 @@ class CarCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView): def get_success_url(self): """Determine the redirect URL based on user choice.""" if self.request.POST.get("add_another"): - return reverse("car_add") - return reverse("inventory_stats") + return reverse("car_add", kwargs={"dealer_slug": self.kwargs["dealer_slug"]}) + return reverse("inventory_stats", kwargs={"dealer_slug": self.kwargs["dealer_slug"]}) def form_valid(self, form): dealer = get_user_type(self.request) @@ -628,9 +632,7 @@ class CarCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - dealer = get_user_type(self.request) - context["vendor_exists"] = dealer.vendors.exists() - + context["vendor_exists"] = self.request.dealer.vendors.exists() return context @@ -673,7 +675,7 @@ class AjaxHandlerView(LoginRequiredMixin, View): :ivar request: Django request object containing HTTP request details. """ - def get(self, request, *args, **kwargs): + def get(self, request,dealer_slug, *args, **kwargs): action = request.GET.get("action") handlers = { "decode_vin": self.decode_vin, @@ -986,7 +988,7 @@ class CarColorCreate(LoginRequiredMixin, PermissionRequiredMixin, CreateView): return super().form_valid(form) def get_success_url(self): - return reverse_lazy("car_detail", kwargs={"slug": self.kwargs["slug"]}) + return reverse_lazy("car_detail", kwargs={"dealer_slug":self.request.dealer.slug,"slug": self.kwargs["slug"]}) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -1025,7 +1027,7 @@ class CarColorsUpdateView( """ # self.object refers to the CarColors instance that was just updated. # self.object.car then refers to the associated Car instance. - return reverse("car_detail", kwargs={"slug": self.object.car.slug}) + return reverse("car_detail", kwargs={"dealer_slug":self.request.dealer.slug,"slug": self.object.car.slug}) def get_context_data(self, **kwargs): """ @@ -1138,7 +1140,7 @@ class CarListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): @login_required -def inventory_stats_view(request): +def inventory_stats_view(request,dealer_slug): """ Handle the inventory stats view for a dealer, displaying detailed information about the cars, including counts grouped by make, model, and trim. @@ -1154,10 +1156,9 @@ def inventory_stats_view(request): "inventory/inventory_stats.html" template. :rtype: HttpResponse """ - dealer = get_user_type(request) # Base queryset for cars belonging to the dealer - cars = models.Car.objects.filter(dealer=dealer) + cars = models.Car.objects.filter(dealer=request.dealer) # Count for total, reserved, showroom, and unreserved cars total_cars = cars.count() @@ -1241,7 +1242,6 @@ def inventory_stats_view(request): for make_data in inventory.values() ], } - print(result["makes"]) return render(request, "inventory/inventory_stats.html", {"inventory": result}) @@ -1427,7 +1427,7 @@ class CarFinanceCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateVi return super().form_valid(form) def get_success_url(self): - return reverse("car_detail", kwargs={"slug": self.car.slug}) + return reverse("car_detail", kwargs={"dealer_slug":self.request.dealer.slug,"slug": self.car.slug}) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -1474,7 +1474,7 @@ class CarFinanceUpdateView( permission_required = ["inventory.change_carfinance"] def get_success_url(self): - return reverse("car_detail", kwargs={"slug": self.object.car.slug}) + return reverse("car_detail", kwargs={"dealer_slug":self.request.dealer.slug,"slug": self.object.car.slug}) def get_form_kwargs(self): kwargs = super().get_form_kwargs() @@ -1871,7 +1871,7 @@ class CustomCardCreateView(LoginRequiredMixin, CreateView): def get_success_url(self): messages.success(self.request, _("Custom Card added successfully")) - return reverse_lazy("car_detail", kwargs={"slug": self.kwargs["slug"]}) + return reverse_lazy("car_detail", kwargs={"dealer_slug":self.request.dealer.slug,"slug": self.kwargs["slug"]}) class CarRegistrationCreateView(LoginRequiredMixin, CreateView): @@ -1913,11 +1913,11 @@ class CarRegistrationCreateView(LoginRequiredMixin, CreateView): def get_success_url(self): messages.success(self.request, _("Registration added successfully")) - return reverse_lazy("car_detail", kwargs={"slug": self.kwargs["slug"]}) + return reverse_lazy("car_detail", kwargs={"dealer_slug":self.request.dealer.slug,"slug": self.kwargs["slug"]}) @login_required() -def reserve_car_view(request, slug): +def reserve_car_view(request, dealer_slug,slug): """ Handles car reservation requests. This view requires the user to be logged in and processes only POST requests. When invoked, it checks if the specified car @@ -1945,7 +1945,7 @@ def reserve_car_view(request, slug): @login_required -def manage_reservation(request, reservation_id): +def manage_reservation(request,dealer_slug, reservation_id): """ Handles the management of a car reservation, providing options to renew or cancel an existing reservation associated with the logged-in user. @@ -1974,7 +1974,7 @@ def manage_reservation(request, reservation_id): reservation.reserved_until = timezone.now() + timezone.timedelta(hours=24) reservation.save() messages.success(request, _("Reservation renewed successfully")) - return redirect("car_detail", slug=reservation.car.slug) + return redirect("car_detail",dealer_slug=request.dealer.slug, slug=reservation.car.slug) elif action == "cancel": car = reservation.car @@ -1982,7 +1982,7 @@ def manage_reservation(request, reservation_id): car.status = models.CarStatusChoices.AVAILABLE car.save() messages.success(request, _("Reservation canceled successfully")) - return redirect("car_detail", slug=reservation.car.slug) + return redirect("car_detail",dealer_slug=request.dealer.slug, slug=reservation.car.slug) else: return JsonResponse( @@ -3444,21 +3444,20 @@ class BankAccountUpdateView( model = BankAccountModel form_class = BankAccountUpdateForm template_name = "ledger/bank_accounts/bank_account_form.html" - success_url = reverse_lazy("bank_account_list") success_message = _("Bank account updated successfully") permission_required = ["inventory.view_carfinance"] def get_form_kwargs(self): - dealer = get_user_type(self.request) + dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"]) entity = dealer.entity kwargs = super().get_form_kwargs() kwargs["entity_slug"] = entity.slug # Get entity_slug from URL kwargs["user_model"] = entity.admin # Get user_model from the request return kwargs - - + def get_success_url(self): + return reverse_lazy("bank_account_detail", kwargs={"dealer_slug": self.kwargs["dealer_slug"], "pk": self.object.pk}) @login_required -def bank_account_delete(request, pk): +def bank_account_delete(request,dealer_slug, pk): """ Delete a bank account entry from the database. @@ -3478,11 +3477,12 @@ def bank_account_delete(request, pk): rendering the confirmation template if accessed via GET. :rtype: HttpResponse """ + dealer = get_object_or_404(models.Dealer, slug=dealer_slug) bank_account = get_object_or_404(BankAccountModel, pk=pk) if request.method == "POST": bank_account.delete() messages.success(request, _("Bank account deleted successfully")) - return redirect("bank_account_list") + return redirect("bank_account_list", dealer_slug=dealer_slug) return render( request, "ledger/bank_accounts/bank_account_delete.html", @@ -3568,7 +3568,6 @@ class AccountCreateView( model = AccountModel form_class = AccountModelCreateForm template_name = "ledger/coa_accounts/account_form.html" - success_url = reverse_lazy("account_list") success_message = _("Account created successfully") permission_required = ["inventory.view_carfinance"] @@ -3591,6 +3590,8 @@ class AccountCreateView( entity = get_user_type(self.request).entity form.initial["coa_model"] = entity.get_default_coa() return form + def get_success_url(self): + return reverse("account_list", kwargs={"dealer_slug":self.kwargs["dealer_slug"]}) class AccountDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView): @@ -3682,7 +3683,6 @@ class AccountUpdateView( model = AccountModel form_class = AccountModelUpdateForm template_name = "ledger/coa_accounts/account_form.html" - success_url = reverse_lazy("account_list") success_message = _("Account updated successfully") permission_required = ["inventory.view_carfinance"] @@ -3691,11 +3691,12 @@ class AccountUpdateView( form.fields["_ref_node_id"].widget = HiddenInput() form.fields["_position"].widget = HiddenInput() return form - + def get_success_url(self): + return reverse_lazy("account_list", kwargs={"dealer_slug":self.kwargs["dealer_slug"]}) @login_required @permission_required("inventory.view_carfinance") -def account_delete(request, pk): +def account_delete(request, dealer_slug,pk): """ Handles the deletion of an account object identified by its primary key (pk). Ensures that the user has the necessary permissions to perform the deletion. Successfully @@ -3708,11 +3709,13 @@ def account_delete(request, pk): :return: An HTTP redirect response to the account list page. :rtype: HttpResponse """ + + dealer = get_object_or_404(models.Dealer, slug=dealer_slug) account = get_object_or_404(AccountModel, pk=pk) account.delete() messages.success(request, _("Account deleted successfully")) - return redirect("account_list") + return redirect("account_list",dealer_slug=dealer_slug) # Sales list @@ -3809,7 +3812,7 @@ class EstimateListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): # @csrf_exempt @login_required @permission_required("django_ledger.add_estimatemodel", raise_exception=True) -def create_estimate(request, slug=None): +def create_estimate(request, dealer_slug,slug=None): """ Creates a new estimate based on the provided data and saves it. This function processes a POST request and expects a JSON payload containing details of the estimate such as @@ -3829,7 +3832,7 @@ def create_estimate(request, slug=None): estimate creation form. :rtype: JsonResponse or HttpResponse """ - dealer = get_user_type(request) + dealer = get_object_or_404(models.Dealer, slug=dealer_slug) entity = dealer.entity if request.method == "POST": @@ -4002,7 +4005,7 @@ def create_estimate(request, slug=None): opportunity.estimate = estimate opportunity.save() - url = reverse("estimate_detail", kwargs={"pk": estimate.pk}) + url = reverse("estimate_detail", kwargs={"dealer_slug": dealer.slug,"pk": estimate.pk}) return JsonResponse( { "status": "success", @@ -4108,7 +4111,7 @@ class EstimateDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView @login_required @permission_required("inventory.add_saleorder", raise_exception=True) -def create_sale_order(request, pk): +def create_sale_order(request,dealer_slug, pk): """ Creates a sale order for a given estimate and updates associated item and car data. @@ -4127,7 +4130,7 @@ def create_sale_order(request, pk): POST data, or redirects to the estimate detail view upon successful creation. :rtype: HttpResponse """ - dealer = get_user_type(request) + dealer = get_object_or_404(models.Dealer, slug=dealer_slug) estimate = get_object_or_404(EstimateModel, pk=pk) items = estimate.get_itemtxs_data()[0].all() if request.method == "POST": @@ -4157,7 +4160,7 @@ def create_sale_order(request, pk): else: print(form.errors) messages.error(request, "Invalid form data") - return redirect("estimate_detail", pk=estimate.pk) + return redirect("estimate_detail", dealer_slug=dealer_slug, pk=estimate.pk) form = forms.SaleOrderForm() customer = estimate.customer.customer_set.first() @@ -4201,7 +4204,7 @@ class SaleOrderDetail(DetailView): @login_required -def preview_sale_order(request, pk): +def preview_sale_order(request, dealer_slug,pk): """ Handles rendering of the sale order preview page for a specific estimate. @@ -4216,6 +4219,7 @@ def preview_sale_order(request, pk): :return: HTTP response containing the rendered sale order preview page :rtype: HttpResponse """ + dealer = get_object_or_404(models.Dealer, slug=dealer_slug) estimate = get_object_or_404(EstimateModel, pk=pk) data = get_car_finance_data(estimate) return render( @@ -4289,19 +4293,18 @@ class EstimatePreviewView(LoginRequiredMixin, PermissionRequiredMixin, DetailVie permission_required = ["django_ledger.view_estimatemodel"] def get_context_data(self, **kwargs): - dealer = get_user_type(self.request) estimate = kwargs.get("object") if estimate.get_itemtxs_data(): # data = get_financial_values(estimate) calculator = CarFinanceCalculator(estimate) kwargs["data"] = calculator.get_finance_data() - kwargs["dealer"] = dealer + return super().get_context_data(**kwargs) @login_required @permission_required("django_ledger.change_estimatemodel", raise_exception=True) -def estimate_mark_as(request, pk): +def estimate_mark_as(request,dealer_slug, pk): """ Marks an estimate with a specified status based on the requested action and permissions. The marking possibilities include review, approval, rejection, @@ -4317,35 +4320,36 @@ def estimate_mark_as(request, pk): :return: A redirect response to the estimate detail view. :rtype: HttpResponseRedirect """ + dealer = get_object_or_404(models.Dealer, slug=dealer_slug) estimate = get_object_or_404(EstimateModel, pk=pk) mark = request.GET.get("mark") if mark: if mark == "review": if not estimate.can_review(): messages.error(request, _("Quotation is not ready for review")) - return redirect("estimate_detail", pk=estimate.pk) + return redirect("estimate_detail",dealer_slug=dealer.slug, pk=estimate.pk) estimate.mark_as_review() elif mark == "approved": if not estimate.can_approve(): messages.error(request, _("Quotation is not ready for approval")) - return redirect("estimate_detail", pk=estimate.pk) + return redirect("estimate_detail",dealer_slug=dealer.slug, pk=estimate.pk) estimate.mark_as_approved() messages.success(request, _("Quotation approved successfully")) elif mark == "rejected": if not estimate.can_cancel(): messages.error(request, _("Quotation is not ready for rejection")) - return redirect("estimate_detail", pk=estimate.pk) + return redirect("estimate_detail",dealer_slug=dealer.slug, pk=estimate.pk) estimate.mark_as_canceled() messages.success(request, _("Quotation canceled successfully")) elif mark == "completed": if not estimate.can_complete(): messages.error(request, _("Quotation is not ready for completion")) - return redirect("estimate_detail", pk=estimate.pk) + return redirect("estimate_detail",dealer_slug=dealer.slug, pk=estimate.pk) elif mark == "canceled": if not estimate.can_cancel(): messages.error(request, _("Quotation is not ready for cancellation")) - return redirect("estimate_detail", pk=estimate.pk) + return redirect("estimate_detail", dealer_slug=dealer.slug, pk=estimate.pk) estimate.mark_as_canceled() try: car = models.Car.objects.get( @@ -4359,7 +4363,7 @@ def estimate_mark_as(request, pk): estimate.save() messages.success(request, _("Quotation marked as ") + mark.upper()) - return redirect("estimate_detail", pk=estimate.pk) + return redirect("estimate_detail", dealer_slug=dealer.slug, pk=estimate.pk) # Invoice @@ -4392,8 +4396,8 @@ class InvoiceListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): permission_required = ["django_ledger.view_invoicemodel"] def get_queryset(self): + dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"]) query = self.request.GET.get("q") - dealer = get_user_type(self.request) invoices = dealer.entity.get_invoices() return apply_search_filters(invoices, query) @@ -4474,7 +4478,7 @@ class DraftInvoiceModelUpdateFormView( def get_form_kwargs(self): kwargs = super().get_form_kwargs() - dealer = get_user_type(self.request) + dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"]) kwargs["entity_slug"] = dealer.entity kwargs["user_model"] = dealer.entity.admin return kwargs @@ -4516,13 +4520,13 @@ class ApprovedInvoiceModelUpdateFormView( def get_form_kwargs(self): kwargs = super().get_form_kwargs() - dealer = get_user_type(self.request) + dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"]) kwargs["entity_slug"] = dealer.entity kwargs["user_model"] = dealer.entity.admin return kwargs def get_success_url(self): - return reverse_lazy("invoice_detail", kwargs={"pk": self.object.pk}) + return reverse_lazy("invoice_detail", kwargs={"dealer_slug":self.kwargs["dealer_slug"],"pk": self.object.pk}) class PaidInvoiceModelUpdateFormView( @@ -4561,13 +4565,13 @@ class PaidInvoiceModelUpdateFormView( def get_form_kwargs(self): kwargs = super().get_form_kwargs() - dealer = get_user_type(self.request) + dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"]) kwargs["entity_slug"] = dealer.entity kwargs["user_model"] = dealer.entity.admin return kwargs def get_success_url(self): - return reverse_lazy("invoice_detail", kwargs={"pk": self.object.pk}) + return reverse_lazy("invoice_detail", kwargs={"dealer_slug":self.kwargs["dealer_slug"],"pk": self.object.pk}) def form_valid(self, form): invoice = form.save() @@ -4583,7 +4587,7 @@ class PaidInvoiceModelUpdateFormView( @login_required @permission_required("django_ledger.change_invoicemodel", raise_exception=True) -def invoice_mark_as(request, pk): +def invoice_mark_as(request,dealer_slug, pk): """ Marks an invoice as approved if it meets the required conditions. @@ -4600,23 +4604,23 @@ def invoice_mark_as(request, pk): :return: An HTTP redirect response to the invoice detail page after processing. :rtype: django.http.HttpResponse """ + dealer = get_object_or_404(models.Dealer, slug=dealer_slug) invoice = get_object_or_404(InvoiceModel, pk=pk) - dealer = get_user_type(request) mark = request.GET.get("mark") if mark and mark == "accept": if not invoice.can_approve(): messages.error(request, "invoice is not ready for approval") - return redirect("invoice_detail", pk=invoice.pk) + return redirect("invoice_detail",dealer_slug=dealer_slug, pk=invoice.pk) invoice.mark_as_approved( entity_slug=dealer.entity.slug, user_model=dealer.entity.admin ) invoice.save() - return redirect("invoice_detail", pk=invoice.pk) + return redirect("invoice_detail",dealer_slug=dealer_slug, pk=invoice.pk) @login_required @permission_required("django_ledger.add_invoicemodel", raise_exception=True) -def invoice_create(request, pk): +def invoice_create(request,dealer_slug, pk): """ Handles the creation of a new invoice associated with a given estimate. It validates the submitted data through a form, processes the invoice, updates related models, and @@ -4632,8 +4636,8 @@ def invoice_create(request, pk): creation or renders the invoice creation form template otherwise. :rtype: HttpResponse """ + dealer = get_object_or_404(models.Dealer,slug=dealer_slug) estimate = get_object_or_404(EstimateModel, pk=pk) - dealer = get_user_type(request) entity = dealer.entity if request.method == "POST": @@ -4674,7 +4678,7 @@ def invoice_create(request, pk): estimate.save() invoice.save() messages.success(request, "Invoice created successfully") - return redirect("invoice_detail", pk=invoice.pk) + return redirect("invoice_detail", dealer_slug=dealer.slug,pk=invoice.pk) else: print(form.errors) form = forms.InvoiceModelCreateForm( @@ -4722,7 +4726,7 @@ class InvoicePreviewView(LoginRequiredMixin, PermissionRequiredMixin, DetailView permission_required = ["django_ledger.view_invoicemodel"] def get_context_data(self, **kwargs): - dealer = get_user_type(self.request) + dealer = get_object_or_404(models.Dealer,slug=self.kwargs["dealer_slug"]) invoice = kwargs.get("object") if invoice.get_itemtxs_data(): calculator = CarFinanceCalculator(invoice) @@ -4737,7 +4741,7 @@ class InvoicePreviewView(LoginRequiredMixin, PermissionRequiredMixin, DetailView @login_required @permission_required("django_ledger.add_journalentrymodel", raise_exception=True) -def PaymentCreateView(request, pk): +def PaymentCreateView(request,dealer_slug, pk): """ Handles the creation of a payment entry associated with an invoice or bill. Validates the payment data against the model's current state and reflects the changes in @@ -4760,10 +4764,10 @@ def PaymentCreateView(request, pk): redirect to the detail view of the processed invoice or bill, re-render the payment form with error messages or indicate success in payment creation. """ + dealer = get_object_or_404(models.Dealer,slug=dealer_slug) invoice = InvoiceModel.objects.filter(pk=pk).first() bill = BillModel.objects.filter(pk=pk).first() model = invoice if invoice else bill - dealer = get_user_type(request) entity = dealer.entity form = forms.PaymentForm() if request.method == "POST": @@ -4780,10 +4784,10 @@ def PaymentCreateView(request, pk): model.mark_as_approved(user_model=entity.admin) if model.amount_paid == model.amount_due: messages.error(request, _("fully paid")) - return redirect(redirect_url, pk=model.pk) + return redirect(redirect_url, dealer_slug=dealer.slug,pk=model.pk) if model.amount_paid + amount > model.amount_due: messages.error(request, _("Amount exceeds due amount")) - return redirect(redirect_url, pk=model.pk) + return redirect(redirect_url, dealer_slug=dealer.slug, pk=model.pk) try: if invoice: @@ -4791,7 +4795,7 @@ def PaymentCreateView(request, pk): elif bill: set_bill_payment(dealer, entity, bill, amount, payment_method) messages.success(request, _("Payment created successfully")) - return redirect(redirect_url, pk=model.pk) + return redirect(redirect_url, dealer_slug=dealer.slug, pk=model.pk) except Exception as e: messages.error(request, f"Error creating payment: {str(e)}") else: @@ -4812,7 +4816,7 @@ def PaymentCreateView(request, pk): @login_required @permission_required("django_ledger.view_journalentrymodel", raise_exception=True) -def PaymentListView(request): +def PaymentListView(request,dealer_slug): """ Handles the view for listing payment information associated with the journals of a specific entity. This view is protected to ensure only authenticated and authorized users can @@ -4828,7 +4832,7 @@ def PaymentListView(request): :return: The rendered HTML response displaying the list of payments. :rtype: HttpResponse """ - dealer = get_user_type(request) + dealer = get_object_or_404(models.Dealer,slug=dealer_slug) entity = dealer.entity journals = JournalEntryModel.objects.filter(ledger__entity=entity).all() @@ -4842,7 +4846,7 @@ def PaymentListView(request): @login_required @permission_required("django_ledger.view_journalentrymodel", raise_exception=True) -def PaymentDetailView(request, pk): +def PaymentDetailView(request,dealer_slug, pk): """ This function handles the detail view for a payment by fetching a journal entry and its associated transactions. It ensures that the request is authenticated @@ -4856,6 +4860,7 @@ def PaymentDetailView(request, pk): entry and its associated transactions. :rtype: HttpResponse """ + dealer = get_object_or_404(models.Dealer,slug=dealer_slug) journal = JournalEntryModel.objects.filter(pk=pk).first() transactions = ( TransactionModel.objects.filter(journal_entry=journal) @@ -4871,7 +4876,7 @@ def PaymentDetailView(request, pk): @login_required @permission_required("django_ledger.change_journalentrymodel", raise_exception=True) -def payment_mark_as_paid(request, pk): +def payment_mark_as_paid(request, dealer_slug,pk): """ Marks an invoice as paid if it meets the conditions of being fully paid and eligible for payment. Also ensures that related ledger journal entries are locked and posted @@ -4890,6 +4895,7 @@ def payment_mark_as_paid(request, pk): :raises: In case of an exception during the process, an error message is displayed to the user through Django's messaging framework. """ + dealer = get_object_or_404(models.Dealer,slug=dealer_slug) invoice = get_object_or_404(InvoiceModel, pk=pk) if request.method == "POST": try: @@ -4914,7 +4920,7 @@ def payment_mark_as_paid(request, pk): ) except Exception as e: messages.error(request, f"Error: {str(e)}") - return redirect("invoice_detail", pk=invoice.pk) + return redirect("invoice_detail",dealer_slug=dealer_slug, pk=invoice.pk) # activity log @@ -6645,7 +6651,8 @@ class BillModelCreateView(CreateView): for_purchase_order = False for_estimate = False - def get(self, request, **kwargs): + def get(self, request, dealer_slug,**kwargs): + dealer = get_object_or_404(models.Dealer,slug=dealer_slug) if not request.user.is_authenticated: return HttpResponseForbidden() @@ -6658,7 +6665,7 @@ class BillModelCreateView(CreateView): ) if not estimate_model.can_bind(): return HttpResponseNotFound("404 Not Found") - return super(BillModelCreateView, self).get(request, **kwargs) + return super(BillModelCreateView, self).get(request,dealer_slug, **kwargs) def get_context_data(self, **kwargs): context = super(BillModelCreateView, self).get_context_data(**kwargs) @@ -6687,6 +6694,7 @@ class BillModelCreateView(CreateView): reverse( "bill-create-po", kwargs={ + "dealer_slug": self.kwargs["dealer_slug"], "entity_slug": self.kwargs["entity_slug"], "po_pk": po_model.uuid, }, @@ -6704,6 +6712,7 @@ class BillModelCreateView(CreateView): form_action = reverse( "bill-create-estimate", kwargs={ + "dealer_slug": self.kwargs["dealer_slug"], "entity_slug": self.kwargs["entity_slug"], "ce_pk": estimate_model.uuid, }, @@ -6712,6 +6721,7 @@ class BillModelCreateView(CreateView): form_action = reverse( "bill-create", kwargs={ + "dealer_slug": self.kwargs["dealer_slug"], "entity_slug": self.kwargs["entity_slug"], }, ) @@ -6787,28 +6797,33 @@ class BillModelCreateView(CreateView): po_pk = self.kwargs["po_pk"] return reverse( "purchase_order_update", - kwargs={"entity_slug": entity_slug, "po_pk": po_pk}, + kwargs={"dealer_slug": self.kwargs["dealer_slug"],"entity_slug": entity_slug, "po_pk": po_pk}, ) elif self.for_estimate: return reverse( "customer-estimate-detail", - kwargs={"entity_slug": entity_slug, "ce_pk": self.kwargs["ce_pk"]}, + kwargs={"dealer_slug": self.kwargs["dealer_slug"],"entity_slug": entity_slug, "ce_pk": self.kwargs["ce_pk"]}, ) bill_model: BillModel = self.object return reverse( "bill-detail", - kwargs={"entity_slug": entity_slug, "bill_pk": bill_model.uuid}, + kwargs={"dealer_slug": self.kwargs["dealer_slug"],"entity_slug": entity_slug, "bill_pk": bill_model.uuid}, ) class BillModelDetailViewView(BillModelDetailView): template_name = "bill/bill_detail.html" + def get_context_data(self, **kwargs): + context = super(BillModelDetailViewView, self).get_context_data(**kwargs) + context["dealer"] = self.request.dealer + return context + class BillModelUpdateViewView(BillModelUpdateView): template_name = "bill/bill_update.html" - def post(self, request, *args, **kwargs): + def post(self, request, dealer_slug,entity_slug,bill_pk, *args, **kwargs): if self.action_update_items: if not request.user.is_authenticated: return HttpResponseForbidden() @@ -6865,6 +6880,7 @@ class BillModelUpdateViewView(BillModelUpdateView): redirect_to=reverse( "bill-update", kwargs={ + "dealer_slug": dealer_slug, "entity_slug": entity_model.slug, "bill_pk": bill_pk, }, @@ -6872,12 +6888,13 @@ class BillModelUpdateViewView(BillModelUpdateView): ) context = self.get_context_data(itemtxs_formset=itemtxs_formset) return self.render_to_response(context=context) - return super(BillModelUpdateViewView, self).post(request, **kwargs) + return super(BillModelUpdateViewView, self).post(request,dealer_slug,entity_slug,bill_pk, **kwargs) def get_success_url(self): return reverse( "bill-update", kwargs={ + "dealer_slug": self.kwargs["dealer_slug"], "entity_slug": self.kwargs["entity_slug"], "bill_pk": self.kwargs["bill_pk"], }, @@ -7074,7 +7091,7 @@ class OrderListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): # email @login_required @permission_required("django_ledger.view_estimatemodel", raise_exception=True) -def send_email_view(request, pk): +def send_email_view(request,dealer_slug, pk): """ View function to send an email for an estimate. This function allows authenticated and authorized users to send an email containing the estimate details to the customer. @@ -7090,15 +7107,15 @@ def send_email_view(request, pk): :rtype: HttpResponseRedirect :raises Http404: If the estimate with the given primary key does not exist. """ - dealer = get_user_type(request) + dealer = get_object_or_404(models.Dealer, slug=dealer_slug) estimate = get_object_or_404(EstimateModel, pk=pk) if not estimate.get_itemtxs_data()[0]: messages.error(request, _("Quotation has no items")) - return redirect("estimate_detail", pk=estimate.pk) + return redirect("estimate_detail", dealer_slug=dealer_slug,pk=estimate.pk) link = request.build_absolute_uri( - reverse_lazy("estimate_preview", kwargs={"pk": estimate.pk}) + reverse_lazy("estimate_preview", kwargs={"dealer_slug":dealer_slug,"pk": estimate.pk}) ) msg = f""" @@ -7135,7 +7152,7 @@ def send_email_view(request, pk): estimate.mark_as_review() messages.success(request, _("Email sent successfully")) - return redirect("estimate_detail", pk=estimate.pk) + return redirect("estimate_detail", dealer_slug=dealer.slug,pk=estimate.pk) # errors @@ -9041,15 +9058,15 @@ def permenant_delete_account(request, content_type, slug): ##################################################################### -def PurchaseOrderCreateView(request): - dealer = get_user_type(request) +def PurchaseOrderCreateView(request, dealer_slug): + dealer = get_object_or_404(models.Dealer, slug=dealer_slug) entity = dealer.entity if request.method == "POST": po = entity.create_purchase_order(po_title=request.POST.get("po_title")) po.entity = entity po.save() messages.success(request, _("Purchase order created successfully")) - return redirect("purchase_order_detail", pk=po.pk) + return redirect("purchase_order_detail", dealer_slug=dealer.slug, pk=po.pk) form = PurchaseOrderModelCreateForm( entity_slug=entity.slug, user_model=entity.admin @@ -9057,9 +9074,9 @@ def PurchaseOrderCreateView(request): return render(request, "purchase_orders/po_form.html", {"form": form}) -def InventoryItemCreateView(request): +def InventoryItemCreateView(request,dealer_slug): + dealer = get_object_or_404(models.Dealer, slug=dealer_slug) for_po = request.GET.get("for_po") - dealer = get_user_type(request) entity = dealer.entity coa = entity.get_default_coa() @@ -9098,7 +9115,7 @@ def InventoryItemCreateView(request): .first() ): messages.error(request, _("Inventory item already exists")) - return redirect(f"{reverse('inventory_item_create')}?for_po={for_po}") + return redirect(f"{reverse('inventory_item_create')}?for_po={for_po}", dealer_slug=dealer.slug) uom = entity.get_uom_all().get(name="Unit") entity.create_item_inventory( name=inventory_name, @@ -9108,9 +9125,10 @@ def InventoryItemCreateView(request): coa_model=coa, ) messages.success(request, _("Inventory item created successfully")) - return redirect("purchase_order_list") + return redirect("purchase_order_list", dealer_slug=dealer.slug) if for_po: form = forms.CSVUploadForm() + form.fields["vendor"].queryset = dealer.vendors.filter(active=True) context = { "make_data": models.CarMake.objects.all(), "inventory_accounts": inventory_accounts, @@ -9129,8 +9147,8 @@ def InventoryItemCreateView(request): ) -def inventory_items_filter(request): - dealer = get_user_type(request) +def inventory_items_filter(request,dealer_slug): + dealer = get_object_or_404(models.Dealer, slug=dealer_slug) make = request.GET.get("make") model = request.GET.get("model") serie = request.GET.get("serie") @@ -9175,38 +9193,6 @@ class PurchaseOrderDetailView(PurchaseOrderModelDetailViewBase): return context -# def PurchaseOrderDetailView(request, pk): -# po = get_object_or_404(PurchaseOrderModel, pk=pk) -# dealer = get_user_type(request) - -# make = request.GET.get('make') -# model = request.GET.get('model') -# serie = request.GET.get('serie') -# make_data = models.CarMake.objects.all() -# model_data = models.CarModel.objects.none() -# serie_data = models.CarSerie.objects.none() -# trim_data = models.CarTrim.objects.none() -# if make: -# make = models.CarMake.objects.get(pk=make) -# model_data = make.carmodel_set.all() -# elif model: -# model = models.CarModel.objects.get(pk=model) -# serie_data = model.carserie_set.all() -# elif serie: -# serie = models.CarSerie.objects.get(pk=serie) -# trim_data = serie.cartrim_set.all() -# context = { -# 'make_data': make_data, -# 'model_data': model_data, -# 'serie_data': serie_data, -# 'trim_data': trim_data, -# 'po': po, -# 'inventory_accounts': dealer.entity.get_coa_accounts().filter(role="asset_ca_inv"), -# 'inventory_items': dealer.entity.get_items_inventory(), -# } -# return render(request, "purchase_orders/po_detail.html", context) - - class PurchaseOrderListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): model = PurchaseOrderModel context_object_name = "purchase_orders" @@ -9231,15 +9217,10 @@ class PurchaseOrderUpdateView(PurchaseOrderModelUpdateViewBase): context_object_name = "po_model" def get_context_data(self, itemtxs_formset=None, **kwargs): - dealer = get_user_type(self.request) + dealer = self.request.dealer context = super().get_context_data(**kwargs) context["entity_slug"] = dealer.entity.slug po_model: PurchaseOrderModel = self.object - # context["make_data"] = models.CarMake.objects.all() - # context["model_data"] = models.CarModel.objects.none() - # context["serie_data"] = models.CarSerie.objects.none() - # context["trim_data"] = models.CarTrim.objects.none() - # itemtxs_qs = dealer.entity.get_items_inventory().filter(item_role="inventory") if not itemtxs_formset: itemtxs_qs = self.get_po_itemtxs_qs(po_model) itemtxs_qs, itemtxs_agg = po_model.get_itemtxs_data(queryset=itemtxs_qs) @@ -9261,36 +9242,35 @@ class PurchaseOrderUpdateView(PurchaseOrderModelUpdateViewBase): return reverse( "purchase_order_update", kwargs={ + "dealer_slug": self.kwargs["dealer_slug"], "entity_slug": self.kwargs["entity_slug"], "po_pk": self.kwargs["po_pk"], }, ) - def get(self, request, entity_slug, po_pk, *args, **kwargs): + def get(self, request, dealer_slug, entity_slug, po_pk, *args, **kwargs): if self.action_update_items: return HttpResponseRedirect( redirect_to=reverse( "purchase_order_update", - kwargs={"entity_slug": entity_slug, "po_pk": po_pk}, + kwargs={"dealer_slug": dealer_slug,"entity_slug": entity_slug, "po_pk": po_pk}, ) ) return super(PurchaseOrderUpdateView, self).get( - request, entity_slug, po_pk, *args, **kwargs + request, dealer_slug, entity_slug, po_pk, *args, **kwargs ) - def post(self, request, entity_slug, *args, **kwargs): - dealer = get_user_type(self.request) + def post(self, request, dealer_slug, entity_slug, *args, **kwargs): if self.action_update_items: if not request.user.is_authenticated: return HttpResponseForbidden() - queryset = self.get_queryset() po_model: PurchaseOrderModel = self.get_object(queryset=queryset) self.object = po_model po_itemtxs_formset_class = get_po_itemtxs_formset_class(po_model) itemtxs_formset = po_itemtxs_formset_class( request.POST, - user_model=dealer.entity.admin, + user_model=request.dealer.entity.admin, po_model=po_model, entity_slug=entity_slug, ) @@ -9309,6 +9289,7 @@ class PurchaseOrderUpdateView(PurchaseOrderModelUpdateViewBase): redirect_url = reverse( "bill-create-po", kwargs={ + "dealer_slug": self.kwargs["dealer_slug"], "entity_slug": self.kwargs["entity_slug"], "po_pk": po_model.uuid, }, @@ -9337,7 +9318,7 @@ class PurchaseOrderUpdateView(PurchaseOrderModelUpdateViewBase): context=self.get_context_data(itemtxs_formset=itemtxs_formset) ) return super(PurchaseOrderUpdateView, self).post( - request, entity_slug, *args, **kwargs + request,dealer_slug, entity_slug, *args, **kwargs ) def get_form(self, form_class=None): @@ -9368,19 +9349,19 @@ class PurchaseOrderUpdateView(PurchaseOrderModelUpdateViewBase): class BasePurchaseOrderActionActionView(BasePurchaseOrderActionActionViewBase): - def get_redirect_url(self, entity_slug, po_pk, *args, **kwargs): + def get_redirect_url(self,dealer_slug, entity_slug, po_pk, *args, **kwargs): return reverse( - "purchase_order_update", kwargs={"entity_slug": entity_slug, "po_pk": po_pk} + "purchase_order_update", kwargs={"dealer_slug":dealer_slug,"entity_slug": entity_slug, "po_pk": po_pk} ) - def get(self, request, *args, **kwargs): + def get(self, request,dealer_slug, entity_slug, po_pk, *args, **kwargs): # kwargs["user_model"] = self.request.user - dealer = get_user_type(request) + dealer = get_object_or_404(models.Dealer, slug=dealer_slug) kwargs["user_model"] = dealer.entity.admin if not self.action_name: raise ImproperlyConfigured("View attribute action_name is required.") response = super(BasePurchaseOrderActionActionView, self).get( - request, *args, **kwargs + request,dealer_slug,entity_slug,po_pk, *args, **kwargs ) po_model: PurchaseOrderModel = self.get_object() @@ -9393,11 +9374,6 @@ class BasePurchaseOrderActionActionView(BasePurchaseOrderActionActionViewBase): ) except ValidationError as e: print(e) - # messages.add_message( - # request, - # message=e.message, - # level=messages.ERROR, - # ) return response @@ -9405,7 +9381,12 @@ class PurchaseOrderModelDeleteView(PurchaseOrderModelDeleteViewBase): template_name = "purchase_orders/po_delete.html" def get_success_url(self): - return reverse("purchase_order_list") + messages.add_message( + self.request, + message="PO deleted successfully.", + level=messages.SUCCESS, + ) + return reverse("purchase_order_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"]}) class PurchaseOrderMarkAsDraftView(BasePurchaseOrderActionActionView): @@ -9434,9 +9415,9 @@ class PurchaseOrderMarkAsVoidView(BasePurchaseOrderActionActionView): ##############################bil class BaseBillActionView(BaseBillActionViewBase): - def get_redirect_url(self, entity_slug, bill_pk, *args, **kwargs): + def get_redirect_url(self,dealer_slug, entity_slug, bill_pk, *args, **kwargs): return reverse( - "bill-update", kwargs={"entity_slug": entity_slug, "bill_pk": bill_pk} + "bill-update", kwargs={"dealer_slug": self.kwargs["dealer_slug"],"entity_slug": entity_slug, "bill_pk": bill_pk} ) @@ -9484,8 +9465,8 @@ class BillModelActionForceMigrateView(BaseBillActionView): ############################################################### -def view_items_inventory(request, entity_slug, po_pk): - dealer = get_user_type(request) +def view_items_inventory(request,dealer_slug, entity_slug, po_pk): + dealer = get_object_or_404(models.Dealer, slug=dealer_slug) po = PurchaseOrderModel.objects.get(pk=po_pk) items = po.get_itemtxs_data()[0] items_per_page = 30 @@ -9505,17 +9486,17 @@ def view_items_inventory(request, entity_slug, po_pk): ) -def upload_cars(request, pk=None): +def upload_cars(request,dealer_slug, pk=None): item = None - dealer = get_user_type(request) - response = redirect("upload_cars") + dealer = get_object_or_404(models.Dealer, slug=dealer_slug) + response = redirect("upload_cars",dealer_slug=dealer_slug) if pk: item = get_object_or_404(ItemTransactionModel, pk=pk) - response = redirect("upload_cars", pk=pk) + response = redirect("upload_cars", dealer_slug=dealer_slug,pk=pk) if item.item_model.additional_info.get("uploaded"): messages.add_message(request, messages.ERROR, "Item already uploaded.") return redirect( - "view_items_inventory", entity_slug=dealer.slug, po_pk=item.po_model.pk + "view_items_inventory",dealer_slug=dealer_slug, entity_slug=dealer.entity.slug, po_pk=item.po_model.pk ) if request.method == "POST": @@ -9560,7 +9541,7 @@ def upload_cars(request, pk=None): if not csv_file.name.endswith(".csv"): messages.error(request, "Please upload a CSV file") - return redirect("upload_cars") + return redirect("upload_cars",dealer_slug=dealer_slug) try: # Read the file content file_content = csv_file.read().decode("utf-8") diff --git a/templates/bill/bill_detail.html b/templates/bill/bill_detail.html index aff81525..a0d3ecbe 100644 --- a/templates/bill/bill_detail.html +++ b/templates/bill/bill_detail.html @@ -42,11 +42,11 @@
- {% include 'bill/includes/card_bill.html' with bill=bill entity_slug=view.kwargs.entity_slug style='bill-detail' %} + {% include 'bill/includes/card_bill.html' with dealer_slug=request.dealer.slug bill=bill entity_slug=view.kwargs.entity_slug style='bill-detail' %}
{% include 'bill/includes/card_vendor.html' with vendor=bill.vendor %}
- {% trans 'Bill List' %} @@ -65,7 +65,7 @@
{% trans 'Cash Account' %}: - {{ bill.cash_account.code }} @@ -80,7 +80,7 @@
{% trans 'Prepaid Account' %}: - {{ bill.prepaid_account.code }} @@ -94,7 +94,7 @@
{% trans 'Accounts Payable' %}: - {{ bill.unearned_account.code }} @@ -185,7 +185,7 @@ {% if bill_item.po_model_id %} + href="{% url 'purchase_order_detail' request.dealer.slug bill_item.po_model_id %}"> {% trans 'View PO' %} {% endif %} diff --git a/templates/bill/bill_update.html b/templates/bill/bill_update.html index 36b0d754..80417b15 100644 --- a/templates/bill/bill_update.html +++ b/templates/bill/bill_update.html @@ -17,9 +17,9 @@
- {% include 'bill/includes/card_bill.html' with bill=bill_model style='bill-detail' entity_slug=view.kwargs.entity_slug %} + {% include 'bill/includes/card_bill.html' with dealer_slug=request.dealer.slug bill=bill_model style='bill-detail' entity_slug=view.kwargs.entity_slug %} -
+ {% csrf_token %}
@@ -30,12 +30,12 @@ {% trans 'Save Bill' %} - {% trans 'Back to Bill Detail' %} - {% trans 'Bill List' %} diff --git a/templates/bill/includes/card_bill.html b/templates/bill/includes/card_bill.html index 8695cbf3..38a0a563 100644 --- a/templates/bill/includes/card_bill.html +++ b/templates/bill/includes/card_bill.html @@ -201,48 +201,48 @@ -
{% endblock %} diff --git a/templates/crm/opportunities/opportunity_list.html b/templates/crm/opportunities/opportunity_list.html index bcdfb32a..13b82df5 100644 --- a/templates/crm/opportunities/opportunity_list.html +++ b/templates/crm/opportunities/opportunity_list.html @@ -90,14 +90,14 @@
{% include 'crm/opportunities/partials/opportunity_grid.html' %}
- {% if page_obj.paginator.num_pages > 1 %} - -
- -
- {% include 'partials/pagination.html'%} -
- -
- {% endif %} + {% if page_obj.paginator.num_pages > 1 %} + +
+ +
+ {% include 'partials/pagination.html'%} +
+ +
+ {% endif %} {% endblock %} \ No newline at end of file diff --git a/templates/customers/customer_list.html b/templates/customers/customer_list.html index a913ca67..cbf6a168 100644 --- a/templates/customers/customer_list.html +++ b/templates/customers/customer_list.html @@ -109,15 +109,15 @@ {% endif %} - {% if page_obj.paginator.num_pages > 1 %} - -
- -
- {% include 'partials/pagination.html'%} -
- -
- {% endif %} + {% if page_obj.paginator.num_pages > 1 %} + +
+ +
+ {% include 'partials/pagination.html'%} +
+ +
+ {% endif %} {% include 'modal/delete_modal.html' %} {% endblock %} \ No newline at end of file diff --git a/templates/groups/group_list.html b/templates/groups/group_list.html index 0ec7a11d..f50937a9 100644 --- a/templates/groups/group_list.html +++ b/templates/groups/group_list.html @@ -46,13 +46,13 @@
{% if page_obj.paginator.num_pages > 1 %} - -
- -
- {% include 'partials/pagination.html'%} -
- + +
+ +
+ {% include 'partials/pagination.html'%} +
+
{% endif %}
diff --git a/templates/header.html b/templates/header.html index ab136a22..95fcb815 100644 --- a/templates/header.html +++ b/templates/header.html @@ -98,7 +98,7 @@ {% endif %} - + {% if perms.django_ledger.view_invoicemodel %} {% endif %}
- {% endif %} + {% endif %}
diff --git a/templates/inventory/car_detail.html b/templates/inventory/car_detail.html index 67294700..8aeb3428 100644 --- a/templates/inventory/car_detail.html +++ b/templates/inventory/car_detail.html @@ -163,14 +163,14 @@ {% trans "Custom Card" %} - + >{% trans 'Add' %} {% endif %} @@ -196,7 +196,7 @@ hx-get="{% url 'add_registration' request.dealer.slug car.slug %}" hx-target=".main-modal-body" hx-swap="innerHTML" - >{% trans 'Add' %} + >{% trans 'Add' %} diff --git a/templates/inventory/car_list_view.html b/templates/inventory/car_list_view.html index d12e6662..8b566764 100644 --- a/templates/inventory/car_list_view.html +++ b/templates/inventory/car_list_view.html @@ -25,83 +25,83 @@ {% endblock customCSS %} {% block content %} -
+
-
-

{{ _("Inventory") }}

-
+
+

{{ _("Inventory") }}

+
- -
- - {% csrf_token %} -
- - -
+ +
+ + {% csrf_token %} +
+ + +
+ +
+
+
+
+ Loading... +
+ -
-
-
- Loading... -
-
+
@@ -165,147 +165,147 @@ {{ _("Search") }}
-
-
-
-
-
- {{ _("Select All") }} -
- {% for car in cars %} -
-
-
-
-
- -
+
+
+
+
+
+ {{ _("Select All") }} +
+ {% for car in cars %} +
+
+
+
+
+
+
-
-
- {{ car.vin }} -
+
+
+ {{ car.vin }}
+
-
-
+
+
-
-
{{ car.year }}
-

- - {{ car.id_car_make.get_local_name }} - - {{ car.id_car_model.get_local_name }} -

- - {{ car.id_car_trim }} - -
+
+
{{ car.year }}
+

+ + {{ car.id_car_make.get_local_name }} + + {{ car.id_car_model.get_local_name }} +

+ + {{ car.id_car_trim }} + +
-
-

- {{ car.colors.exterior.get_local_name }} -

- - {{ car.receiving_date|naturalday|capfirst }} - -
+
+

+ {{ car.colors.exterior.get_local_name }} +

+ + {{ car.receiving_date|naturalday|capfirst }} + +
-
- {% if car.status == "available" %} - {{ _("Available") }} - {% elif car.status == "reserved" %} - {{ _("Reserved") }} - {% elif car.status == "sold" %} - {{ _("Sold") }} - {% elif car.status == "transfer" %} - {{ _("Transfer") }} - {% endif %} -
+
+ {% if car.status == "available" %} + {{ _("Available") }} + {% elif car.status == "reserved" %} + {{ _("Reserved") }} + {% elif car.status == "sold" %} + {{ _("Sold") }} + {% elif car.status == "transfer" %} + {{ _("Transfer") }} + {% endif %} +
-
-
- {{ _("Inventory Ready") }} - {% if car.ready %} - - Ready - - {{ _("Yes") }} - {% else %} - - Not Ready - - {{ _("No") }} - {% endif %} -
+
+
+ {{ _("Inventory Ready") }} + {% if car.ready %} + + Ready + + {{ _("Yes") }} + {% else %} + + Not Ready + + {{ _("No") }} + {% endif %}
+
- - {% empty %} -
-
- -

{{ _("No vehicles found") }}

-

{{ _("Try adjusting your search criteria or filters") }}

-
+
+ {% empty %} +
+
+ +

{{ _("No vehicles found") }}

+

{{ _("Try adjusting your search criteria or filters") }}

- {% endfor %} -
-
- {% if page_obj.paginator.num_pages > 1 %} - -
- -
- {% include 'partials/pagination.html'%} -
- -
- {% endif %} +
+ {% endfor %}
+ {% if page_obj.paginator.num_pages > 1 %} + +
+ +
+ {% include 'partials/pagination.html'%} +
+ +
+ {% endif %} +
-
+
+
{% endblock %} {% block customJS %} diff --git a/templates/inventory/inventory_stats.html b/templates/inventory/inventory_stats.html index 16c50ce4..c59f22f8 100644 --- a/templates/inventory/inventory_stats.html +++ b/templates/inventory/inventory_stats.html @@ -86,15 +86,15 @@ {% endfor %}
{% if is_paginated %} - -
- -
- {% include 'partials/pagination.html'%} -
- + +
+ +
+ {% include 'partials/pagination.html'%} +
+
- {% endif %} + {% endif %}
{% endblock %} diff --git a/templates/inventory/tags/inventory_table.html b/templates/inventory/tags/inventory_table.html index 8fc14eb3..9ff9e909 100644 --- a/templates/inventory/tags/inventory_table.html +++ b/templates/inventory/tags/inventory_table.html @@ -13,12 +13,12 @@ - + {% for i in inventory_list %} - + - - {{ i.item_model__name }} + + {{ i.item_model__name }} {{ i.item_model__name }} {{ i.item_model__uom__name }} {{ i.total_quantity | floatformat:3 }} diff --git a/templates/items/expenses/expenses_list.html b/templates/items/expenses/expenses_list.html index 4f1c69d3..630aad73 100644 --- a/templates/items/expenses/expenses_list.html +++ b/templates/items/expenses/expenses_list.html @@ -61,16 +61,16 @@
- {% if page_obj.paginator.num_pages > 1 %} - -
- -
- {% include 'partials/pagination.html'%} -
- + {% if page_obj.paginator.num_pages > 1 %} + +
+ +
+ {% include 'partials/pagination.html'%} +
+
- {% endif %} + {% endif %} {% endif %}
{% endblock %} \ No newline at end of file diff --git a/templates/items/service/service_list.html b/templates/items/service/service_list.html index 031c5249..e45368af 100644 --- a/templates/items/service/service_list.html +++ b/templates/items/service/service_list.html @@ -62,16 +62,16 @@
- {% if page_obj.paginator.num_pages > 1 %} - -
- -
- {% include 'partials/pagination.html'%} -
- + {% if page_obj.paginator.num_pages > 1 %} + +
+ +
+ {% include 'partials/pagination.html'%} +
+
- {% endif %} + {% endif %} {% endif %}
{% endblock %} \ No newline at end of file diff --git a/templates/ledger/bank_accounts/bank_account_list.html b/templates/ledger/bank_accounts/bank_account_list.html index 331ed4f3..9c8187e1 100644 --- a/templates/ledger/bank_accounts/bank_account_list.html +++ b/templates/ledger/bank_accounts/bank_account_list.html @@ -52,14 +52,14 @@
- {% if page_obj.paginator.num_pages > 1 %} -
- -
- {% include 'partials/pagination.html'%} -
- -
+ {% if page_obj.paginator.num_pages > 1 %} +
+ +
+ {% include 'partials/pagination.html'%} +
+ +
{% endif %} {% endif %} diff --git a/templates/ledger/bills/bill_list.html b/templates/ledger/bills/bill_list.html index 53dfaf28..49b27b57 100644 --- a/templates/ledger/bills/bill_list.html +++ b/templates/ledger/bills/bill_list.html @@ -96,16 +96,16 @@
- {% if page_obj.paginator.num_pages > 1 %} + {% if page_obj.paginator.num_pages > 1 %} -
+
-
- {% include 'partials/pagination.html'%} -
+
+ {% include 'partials/pagination.html'%} +
-
- {% endif %} +
+ {% endif %}
{% endblock %} diff --git a/templates/ledger/journal_entry/journal_entry_list.html b/templates/ledger/journal_entry/journal_entry_list.html index 4dfb790c..85bc6f04 100644 --- a/templates/ledger/journal_entry/journal_entry_list.html +++ b/templates/ledger/journal_entry/journal_entry_list.html @@ -113,16 +113,16 @@
- {% if page_obj.paginator.num_pages > 1 %} - -
- -
- {% include 'partials/pagination.html'%} -
- -
- {% endif %} + {% if page_obj.paginator.num_pages > 1 %} + +
+ +
+ {% include 'partials/pagination.html'%} +
+ +
+ {% endif %}
diff --git a/templates/ledger/journal_entry/journal_entry_transactions.html b/templates/ledger/journal_entry/journal_entry_transactions.html index fcf5a989..1e1fae34 100644 --- a/templates/ledger/journal_entry/journal_entry_transactions.html +++ b/templates/ledger/journal_entry/journal_entry_transactions.html @@ -42,14 +42,14 @@
- {% if page_obj.paginator.num_pages > 1 %} - -
- -
- {% include 'partials/pagination.html'%} -
- + {% if page_obj.paginator.num_pages > 1 %} + +
+ +
+ {% include 'partials/pagination.html'%} +
+
{% endif %}
diff --git a/templates/ledger/ledger/ledger_list.html b/templates/ledger/ledger/ledger_list.html index 82ce253b..e08ed35f 100644 --- a/templates/ledger/ledger/ledger_list.html +++ b/templates/ledger/ledger/ledger_list.html @@ -121,15 +121,15 @@
- {% if page_obj.paginator.num_pages > 1 %} - -
- -
- {% include 'partials/pagination.html'%} -
- + {% if page_obj.paginator.num_pages > 1 %} + +
+ +
+ {% include 'partials/pagination.html'%}
+ +
{% endif %}
{% endblock %} \ No newline at end of file diff --git a/templates/organizations/organization_list.html b/templates/organizations/organization_list.html index 497e6e3a..03589420 100644 --- a/templates/organizations/organization_list.html +++ b/templates/organizations/organization_list.html @@ -24,9 +24,9 @@
-
- {% include 'partials/search_box.html' %} -
+
+ {% include 'partials/search_box.html' %} +
@@ -123,16 +123,16 @@
- {% if page_obj.paginator.num_pages > 1 %} - -
- -
- {% include 'partials/pagination.html'%} -
- -
- {% endif %} + {% if page_obj.paginator.num_pages > 1 %} + +
+ +
+ {% include 'partials/pagination.html'%} +
+ +
+ {% endif %}
{% endblock %} diff --git a/templates/partials/pagination.html b/templates/partials/pagination.html index 66bec0ef..a3b89dbc 100644 --- a/templates/partials/pagination.html +++ b/templates/partials/pagination.html @@ -1,90 +1,90 @@ {% load i18n static %}
-
- {{ _("Showing") }} {{ page_obj.start_index }} {{ _("to") }} {{ page_obj.end_index }} - {{ _("of") }} {{ page_obj.paginator.count }} {{ _("results") }} -
-
\ No newline at end of file diff --git a/templates/plans/billing_info_create_or_update.html b/templates/plans/billing_info_create_or_update.html index e2d07dab..a0b01280 100644 --- a/templates/plans/billing_info_create_or_update.html +++ b/templates/plans/billing_info_create_or_update.html @@ -11,11 +11,11 @@

{% trans "Provide billing data"|upper %}

{% csrf_token %} {{ form|crispy }} - + - {% if object %} + {% if object %} {{ _("Delete") }} {% endif %} diff --git a/templates/purchase_orders/po_detail.html b/templates/purchase_orders/po_detail.html index f9194caa..79465d8b 100644 --- a/templates/purchase_orders/po_detail.html +++ b/templates/purchase_orders/po_detail.html @@ -50,29 +50,29 @@
- +
-
-
-

{{ po_model.po_title }}

+
+
+

{{ po_model.po_title }}

-
- {% po_item_table1 po_items %} -
+
+ {% po_item_table1 po_items %}
- - - {% trans 'PO List' %} -
+ + + {% trans 'PO List' %} +
+
{% include "purchase_orders/includes/mark_as.html" %} {% endblock %} diff --git a/templates/purchase_orders/po_list.html b/templates/purchase_orders/po_list.html index c51e2cbe..0240eabf 100644 --- a/templates/purchase_orders/po_list.html +++ b/templates/purchase_orders/po_list.html @@ -82,16 +82,16 @@ - {% if page_obj.paginator.num_pages > 1 %} + {% if page_obj.paginator.num_pages > 1 %} -
- -
- {% include 'partials/pagination.html'%} -
+
+
+ {% include 'partials/pagination.html'%}
- {% endif %} + +
+ {% endif %}
{% include 'modal/delete_modal.html' %} {% endblock %} \ No newline at end of file diff --git a/templates/purchase_orders/po_upload_cars.html b/templates/purchase_orders/po_upload_cars.html index b9a34597..4fddd7cc 100644 --- a/templates/purchase_orders/po_upload_cars.html +++ b/templates/purchase_orders/po_upload_cars.html @@ -57,14 +57,14 @@ {% if page_obj.paginator.num_pages > 1 %} - -
- -
- {% include 'partials/pagination.html'%} -
- -
- {% endif %} + +
+ +
+ {% include 'partials/pagination.html'%} +
+ +
+ {% endif %}
{% endblock content %} \ No newline at end of file diff --git a/templates/sales/estimates/estimate_detail.html b/templates/sales/estimates/estimate_detail.html index f9c7bb78..cf2ca8b9 100644 --- a/templates/sales/estimates/estimate_detail.html +++ b/templates/sales/estimates/estimate_detail.html @@ -105,40 +105,40 @@
-
-
-
{% trans 'Quotation Number' %}:
-

{{estimate.estimate_number}}

-
-
-
{% trans 'Quotation Date' %}:
-

{{estimate.created}}

-
-
-
{% trans 'Customer' %}:
-

{{estimate.customer.customer_name}}

-
-
-
{% trans 'Email' %}:
-

{{estimate.customer.email}}

-
-
-
{% trans "Quotation Status" %}:
-
- {% if estimate.status == 'draft' %} - {% trans "Draft" %} - {% elif estimate.status == 'in_review' %} - {% trans "In Review" %} - {% elif estimate.status == 'approved' %} - {% trans "Approved" %} - {% elif estimate.status == 'completed' %} - {% trans "Completed" %} - {% elif estimate.status == 'canceled' %} - {% trans "Canceled" %} - {% endif %} -
-
+
+
+
{% trans 'Quotation Number' %}:
+

{{estimate.estimate_number}}

+
+
{% trans 'Quotation Date' %}:
+

{{estimate.created}}

+
+
+
{% trans 'Customer' %}:
+

{{estimate.customer.customer_name}}

+
+
+
{% trans 'Email' %}:
+

{{estimate.customer.email}}

+
+
+
{% trans "Quotation Status" %}:
+
+ {% if estimate.status == 'draft' %} + {% trans "Draft" %} + {% elif estimate.status == 'in_review' %} + {% trans "In Review" %} + {% elif estimate.status == 'approved' %} + {% trans "Approved" %} + {% elif estimate.status == 'completed' %} + {% trans "Completed" %} + {% elif estimate.status == 'canceled' %} + {% trans "Canceled" %} + {% endif %} +
+
+
diff --git a/templates/sales/estimates/estimate_list.html b/templates/sales/estimates/estimate_list.html index c548f272..8255a8ea 100644 --- a/templates/sales/estimates/estimate_list.html +++ b/templates/sales/estimates/estimate_list.html @@ -60,11 +60,11 @@
{% if page_obj.paginator.num_pages > 1 %} -
-
- {% include 'partials/pagination.html'%} -
-
- {% endif %} +
+
+ {% include 'partials/pagination.html'%} +
+
+ {% endif %}
{% endblock %} \ No newline at end of file diff --git a/templates/sales/invoices/invoice_detail.html b/templates/sales/invoices/invoice_detail.html index 1f180cd0..a97dd8a9 100644 --- a/templates/sales/invoices/invoice_detail.html +++ b/templates/sales/invoices/invoice_detail.html @@ -172,41 +172,41 @@
-
-
-
{% trans "Invoice Number" %} :
-

{{invoice.invoice_number}}

-
-
-
{% trans "Invoice Date" %} :
-

{{invoice.created}}

-
-
-
{% trans "Customer Name" %} :
-

{{invoice.customer.customer_name}}

-
-
-
{% trans "Customer Email" %} :
-

{{invoice.customer.email}}

-
-
-
{% trans "Invoice Status" %} :
-
- {% if invoice.invoice_status == 'draft' %} - {% trans "Draft" %} - {% elif invoice.invoice_status == 'in_review' %} - {% trans "In Review" %} - {% elif invoice.invoice_status == 'approved' %} - {% trans "Approved" %} - {% elif invoice.invoice_status == 'declined' %} - {% trans "Declined" %} - {% elif invoice.invoice_status == 'paid' %} - {% trans "Paid" %} - {% endif %} -
- -
+
+
+
{% trans "Invoice Number" %} :
+

{{invoice.invoice_number}}

+
+
+
{% trans "Invoice Date" %} :
+

{{invoice.created}}

+
+
+
{% trans "Customer Name" %} :
+

{{invoice.customer.customer_name}}

+
+
+
{% trans "Customer Email" %} :
+

{{invoice.customer.email}}

+
+
+
{% trans "Invoice Status" %} :
+
+ {% if invoice.invoice_status == 'draft' %} + {% trans "Draft" %} + {% elif invoice.invoice_status == 'in_review' %} + {% trans "In Review" %} + {% elif invoice.invoice_status == 'approved' %} + {% trans "Approved" %} + {% elif invoice.invoice_status == 'declined' %} + {% trans "Declined" %} + {% elif invoice.invoice_status == 'paid' %} + {% trans "Paid" %} + {% endif %}
+ +
+
diff --git a/templates/sales/invoices/invoice_list.html b/templates/sales/invoices/invoice_list.html index c1213490..73e937a9 100644 --- a/templates/sales/invoices/invoice_list.html +++ b/templates/sales/invoices/invoice_list.html @@ -70,12 +70,12 @@
- {% if page_obj.paginator.num_pages > 1 %} -
-
- {% include 'partials/pagination.html'%} -
-
+ {% if page_obj.paginator.num_pages > 1 %} +
+
+ {% include 'partials/pagination.html'%} +
+
{% endif %}
{% endblock %} \ No newline at end of file diff --git a/templates/sales/journals/journal_list.html b/templates/sales/journals/journal_list.html index 30b211e1..c8e3bae1 100644 --- a/templates/sales/journals/journal_list.html +++ b/templates/sales/journals/journal_list.html @@ -44,11 +44,11 @@
{% if page_obj.paginator.num_pages > 1%} -
-
- {% include 'partials/pagination.html'%} -
-
+
+
+ {% include 'partials/pagination.html'%} +
+
{% endif %} {% endblock %} \ No newline at end of file diff --git a/templates/sales/orders/order_list.html b/templates/sales/orders/order_list.html index 8014aad8..e9c98181 100644 --- a/templates/sales/orders/order_list.html +++ b/templates/sales/orders/order_list.html @@ -53,11 +53,11 @@ {% if page_obj.paginator.num_pages > 1%} -
-
- {% include 'partials/pagination.html'%} -
-
+
+
+ {% include 'partials/pagination.html'%} +
+
{% endif %} diff --git a/templates/sales/payments/payment_list.html b/templates/sales/payments/payment_list.html index d2e1ece3..894411a4 100644 --- a/templates/sales/payments/payment_list.html +++ b/templates/sales/payments/payment_list.html @@ -54,11 +54,11 @@ {% if page_obj.paginator.num_pages > 1 %} -
-
- {% include 'partials/pagination.html'%} -
-
+
+
+ {% include 'partials/pagination.html'%} +
+
{% endif %} {% endblock %} \ No newline at end of file diff --git a/templates/sales/saleorder_detail.html b/templates/sales/saleorder_detail.html index bb2d50b1..bfd46022 100644 --- a/templates/sales/saleorder_detail.html +++ b/templates/sales/saleorder_detail.html @@ -247,7 +247,7 @@