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 @@