implement the dealer slug for inventory and sales

This commit is contained in:
ismail 2025-06-25 14:15:17 +03:00
parent 55d6e56233
commit 3ce318317e
55 changed files with 659 additions and 646 deletions

View File

@ -1,5 +1,7 @@
from django.conf import settings from django.conf import settings
from inventory.utils import get_user_type
def currency_context(request): def currency_context(request):
""" """
@ -40,4 +42,4 @@ def breadcrumbs(request):
for i in range(len(path)): for i in range(len(path)):
url = "/" + "/".join(path[: i + 1]) + "/" url = "/" + "/".join(path[: i + 1]) + "/"
breadcrumbs.append({"name": path[i].capitalize(), "url": url}) breadcrumbs.append({"name": path[i].capitalize(), "url": url})
return {"breadcrumbs": breadcrumbs} return {"breadcrumbs": breadcrumbs}

View File

@ -1,6 +1,6 @@
from django.core.management.base import BaseCommand 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 from bs4 import BeautifulSoup
import requests 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"Generated VIN: {vin}"))
self.stdout.write(self.style.SUCCESS(f"Description: {description}")) self.stdout.write(self.style.SUCCESS(f"Description: {description}"))
self.stdout.write( # self.stdout.write(
self.style.SUCCESS( # self.style.SUCCESS(
"####################################################################################################" # "####################################################################################################"
) # )
) # )
self.stdout.write( # self.stdout.write(
self.style.SUCCESS( # self.style.SUCCESS(
"####################################################################################################" # "####################################################################################################"
) # )
) # )
self.stdout.write(self.style.SUCCESS(f"Decoded VIN: {result}")) # self.stdout.write(self.style.SUCCESS(f"Decoded VIN: {result}"))
make, model, year_model = result.values() # make, model, year_model = result.values()
self.stdout.write( # self.stdout.write(
self.style.SUCCESS( # self.style.SUCCESS(
f"VIN: {vin} - Make {make} - Model {model} - Model Year {year_model}" # f"VIN: {vin} - Make {make} - Model {model} - Model Year {year_model}"
) # )
) # )
m = get_model(model) # make = get_make(make)
self.stdout.write(self.style.SUCCESS(f"Make: {m.id_car_make} - Model: {m}")) # m = get_model(model,make)
self.stdout.write( # self.stdout.write(self.style.SUCCESS(f"Make: {m.id_car_make} - Model: {m}"))
self.style.SUCCESS( # self.stdout.write(
"####################################################################################################" # self.style.SUCCESS(
) # "####################################################################################################"
) # )
self.stdout.write( # )
self.style.SUCCESS( # self.stdout.write(
"####################################################################################################" # self.style.SUCCESS(
) # "####################################################################################################"
) # )
# )
def generate_vin(self): def generate_vin(self):
# url = "https://www.vindecoder.org/vin-decoder" # url = "https://www.vindecoder.org/vin-decoder"

View File

@ -1,4 +1,7 @@
import logging import logging
from django.http import Http404, HttpResponseForbidden
from django.shortcuts import redirect
from inventory import models from inventory import models
from django.utils import timezone from django.utils import timezone
@ -59,8 +62,11 @@ class InjectParamsMiddleware:
def __call__(self, request): def __call__(self, request):
try: try:
# request.entity = request.user.dealer.entity if request.user.is_authenticated:
request.dealer = get_user_type(request) request.dealer = get_user_type(request)
request.entity = request.dealer.entity
else:
request.dealer = None
except Exception: except Exception:
pass pass
response = self.get_response(request) response = self.get_response(request)
@ -107,3 +113,21 @@ class InjectDealerMiddleware:
# if request.user.is_authenticated and not request.session.get('otp_verified', False): # if request.user.is_authenticated and not request.session.get('otp_verified', False):
# return redirect(reverse('verify_otp')) # return redirect(reverse('verify_otp'))
# return self.get_response(request) # 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

View File

@ -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,
),
]

View File

@ -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',
),
]

View File

@ -1,5 +1,9 @@
from django.http import Http404
from django.shortcuts import redirect
from django.utils.translation import get_language from django.utils.translation import get_language
from inventory.utils import get_user_type
class AddClassMixin: class AddClassMixin:
""" """
@ -60,3 +64,15 @@ class LocalizedNameMixin:
# return super().form_valid(form) # return super().form_valid(form)
# else: # else:
# return form.errors # 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)

View File

@ -442,6 +442,7 @@ def filter_by_role(accounts, role_prefix):
@register.inclusion_tag("purchase_orders/tags/po_item_table.html", takes_context=True) @register.inclusion_tag("purchase_orders/tags/po_item_table.html", takes_context=True)
def po_item_table1(context, queryset): def po_item_table1(context, queryset):
return { return {
"dealer_slug": context["view"].kwargs["dealer_slug"],
"entity_slug": context["entity_slug"], "entity_slug": context["entity_slug"],
"po_model": context["po_model"], "po_model": context["po_model"],
"po_item_list": queryset, "po_item_list": queryset,
@ -459,6 +460,7 @@ def po_item_formset_table(context, po_model, itemtxs_formset):
item_role="inventory" item_role="inventory"
) )
return { return {
"dealer_slug": context["view"].kwargs["dealer_slug"],
"entity_slug": context["view"].kwargs["entity_slug"], "entity_slug": context["view"].kwargs["entity_slug"],
"po_model": po_model, "po_model": po_model,
"itemtxs_formset": itemtxs_formset, "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) @register.inclusion_tag("bill/tags/bill_item_formset.html", takes_context=True)
def bill_item_formset_table(context, item_formset): def bill_item_formset_table(context, item_formset):
return { return {
"dealer_slug": context["view"].kwargs["dealer_slug"],
"entity_slug": context["view"].kwargs["entity_slug"], "entity_slug": context["view"].kwargs["entity_slug"],
"bill_pk": context["view"].kwargs["bill_pk"], "bill_pk": context["view"].kwargs["bill_pk"],
"total_amount__sum": context["total_amount__sum"], "total_amount__sum": context["total_amount__sum"],

View File

@ -1,13 +1,15 @@
from django.conf.urls import handler403, handler400, handler404, handler500 from inventory.utils import get_user_type
from django.urls import path
from django_tables2.export.export import TableExport
from . import views 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 = [ urlpatterns = [
# main URLs # main URLs
path("", views.HomeView.as_view(), name="home"), path("", views.HomeView.as_view(), name="home"),
path("<slug:dealer_slug>/", views.HomeView.as_view(), name="home"),
path("welcome/", views.WelcomeView.as_view(), name="welcome"), path("welcome/", views.WelcomeView.as_view(), name="welcome"),
# Accounts URLs # Accounts URLs
# path("login/", allauth_views.LoginView.as_view(template_name="account/login.html"), name="account_login"), # path("login/", allauth_views.LoginView.as_view(template_name="account/login.html"), name="account_login"),
@ -277,28 +279,28 @@ urlpatterns = [
name="vendor_delete", name="vendor_delete",
), ),
# Car URLs # Car URLs
path("cars/upload_cars/", views.upload_cars, name="upload_cars"), path("<slug:dealer_slug>/cars/upload_cars/", views.upload_cars, name="upload_cars"),
path("cars/<uuid:pk>/upload_cars/", views.upload_cars, name="upload_cars"), path("<slug:dealer_slug>/cars/<uuid:pk>/upload_cars/", views.upload_cars, name="upload_cars"),
path("cars/add/", views.CarCreateView.as_view(), name="car_add"), path("<slug:dealer_slug>/cars/add/", views.CarCreateView.as_view(), name="car_add"),
path("cars/inventory/", views.CarInventory.as_view(), name="car_inventory_all"), path("<slug:dealer_slug>/cars/inventory/", views.CarInventory.as_view(), name="car_inventory_all"),
path( path(
"cars/inventory/<slug:make_id>/<slug:model_id>/<slug:trim_id>/", "<slug:dealer_slug>/cars/inventory/<slug:make_id>/<slug:model_id>/<slug:trim_id>/",
views.CarInventory.as_view(), views.CarInventory.as_view(),
name="car_inventory", name="car_inventory",
), ),
path("cars/inventory/stats", views.inventory_stats_view, name="inventory_stats"), path("<slug:dealer_slug>/cars/inventory/stats", views.inventory_stats_view, name="inventory_stats"),
path("cars/inventory/list", views.CarListView.as_view(), name="car_list"), path("<slug:dealer_slug>/cars/inventory/list", views.CarListView.as_view(), name="car_list"),
path("cars/<slug:slug>/", views.CarDetailView.as_view(), name="car_detail"), path("<slug:dealer_slug>/cars/<slug:slug>/", views.CarDetailView.as_view(), name="car_detail"),
path("cars/<slug:slug>/history/", views.car_history, name="car_history"), path("cars/<slug:slug>/history/", views.car_history, name="car_history"),
path("cars/<slug:slug>/update/", views.CarUpdateView.as_view(), name="car_update"), path("<slug:dealer_slug>/cars/<slug:slug>/update/", views.CarUpdateView.as_view(), name="car_update"),
path("cars/<slug:slug>/delete/", views.CarDeleteView.as_view(), name="car_delete"), path("<slug:dealer_slug>/cars/<slug:slug>/delete/", views.CarDeleteView.as_view(), name="car_delete"),
path( path(
"cars/<slug:slug>/finance/create/", "<slug:dealer_slug>/cars/<slug:slug>/finance/create/",
views.CarFinanceCreateView.as_view(), views.CarFinanceCreateView.as_view(),
name="car_finance_create", name="car_finance_create",
), ),
path( path(
"cars/finance/<int:pk>/update/", "<slug:dealer_slug>/cars/finance/<int:pk>/update/",
views.CarFinanceUpdateView.as_view(), views.CarFinanceUpdateView.as_view(),
name="car_finance_update", name="car_finance_update",
), ),
@ -307,12 +309,12 @@ urlpatterns = [
views.bulk_update_car_price, views.bulk_update_car_price,
name="bulk_update_car_price", name="bulk_update_car_price",
), ),
path("ajax/", views.AjaxHandlerView.as_view(), name="ajax_handler"), path("<slug:dealer_slug>/ajax/", views.AjaxHandlerView.as_view(), name="ajax_handler"),
path( path(
"cars/<slug:slug>/add-color/", views.CarColorCreate.as_view(), name="add_color" "<slug:dealer_slug>/cars/<slug:slug>/add-color/", views.CarColorCreate.as_view(), name="add_color"
), ),
path( path(
"car/colors/<slug:slug>/update/", "<slug:dealer_slug>/car/colors/<slug:slug>/update/",
views.CarColorsUpdateView.as_view(), views.CarColorsUpdateView.as_view(),
name="car_colors_update", name="car_colors_update",
), ),
@ -353,19 +355,19 @@ urlpatterns = [
), ),
path("cars/inventory/search/", views.SearchCodeView.as_view(), name="car_search"), path("cars/inventory/search/", views.SearchCodeView.as_view(), name="car_search"),
# path('cars/<int:car_pk>/colors/<int:pk>/update/',views.CarColorUpdateView.as_view(),name='color_update'), # path('cars/<int:car_pk>/colors/<int:pk>/update/',views.CarColorUpdateView.as_view(),name='color_update'),
path("cars/reserve/<slug:slug>/", views.reserve_car_view, name="reserve_car"), path("<slug:dealer_slug>/cars/reserve/<slug:slug>/", views.reserve_car_view, name="reserve_car"),
path( path(
"reservations/<int:reservation_id>/", "<slug:dealer_slug>/reservations/<int:reservation_id>/",
views.manage_reservation, views.manage_reservation,
name="reservations", name="reservations",
), ),
path( path(
"cars/<slug:slug>/add-custom-card/", "<slug:dealer_slug>/cars/<slug:slug>/add-custom-card/",
views.CustomCardCreateView.as_view(), views.CustomCardCreateView.as_view(),
name="add_custom_card", name="add_custom_card",
), ),
path( path(
"cars/<slug:slug>/add-registration/", "<slug:dealer_slug>/cars/<slug:slug>/add-registration/",
views.CarRegistrationCreateView.as_view(), views.CarRegistrationCreateView.as_view(),
name="add_registration", name="add_registration",
), ),
@ -612,142 +614,146 @@ urlpatterns = [
), ),
# Bank Account # Bank Account
path( path(
"bank_accounts/", views.BankAccountListView.as_view(), name="bank_account_list" "<slug:dealer_slug>/bank_accounts/", views.BankAccountListView.as_view(), name="bank_account_list"
), ),
path( path(
"bank_accounts/<uuid:pk>/", "<slug:dealer_slug>/bank_accounts/<uuid:pk>/",
views.BankAccountDetailView.as_view(), views.BankAccountDetailView.as_view(),
name="bank_account_detail", name="bank_account_detail",
), ),
path( path(
"bank_accounts/create/", "<slug:dealer_slug>/bank_accounts/create/",
views.BankAccountCreateView.as_view(), views.BankAccountCreateView.as_view(),
name="bank_account_create", name="bank_account_create",
), ),
path( path(
"bank_accounts/<uuid:pk>/update/", "<slug:dealer_slug>/bank_accounts/<uuid:pk>/update/",
views.BankAccountUpdateView.as_view(), views.BankAccountUpdateView.as_view(),
name="bank_account_update", name="bank_account_update",
), ),
path( path(
"bank_accounts/<uuid:pk>/delete/", "<slug:dealer_slug>/bank_accounts/<uuid:pk>/delete/",
views.bank_account_delete, views.bank_account_delete,
name="bank_account_delete", name="bank_account_delete",
), ),
# Account # Account
path("coa_accounts/", views.AccountListView.as_view(), name="account_list"), path("<slug:dealer_slug>/coa_accounts/", views.AccountListView.as_view(), name="account_list"),
path( path(
"coa_accounts/<uuid:pk>/", "<slug:dealer_slug>/coa_accounts/<uuid:pk>/",
views.AccountDetailView.as_view(), views.AccountDetailView.as_view(),
name="account_detail", name="account_detail",
), ),
path( path(
"coa_accounts/create/", views.AccountCreateView.as_view(), name="account_create" "<slug:dealer_slug>/coa_accounts/create/", views.AccountCreateView.as_view(), name="account_create"
), ),
path( path(
"coa_accounts/<uuid:pk>/update/", "<slug:dealer_slug>/coa_accounts/<uuid:pk>/update/",
views.AccountUpdateView.as_view(), views.AccountUpdateView.as_view(),
name="account_update", name="account_update",
), ),
path("coa_accounts/<uuid:pk>/delete/", views.account_delete, name="account_delete"), path("<slug:dealer_slug>/coa_accounts/<uuid:pk>/delete/", views.account_delete, name="account_delete"),
#################################################
# Estimate # Estimate
path("sales/estimates/", views.EstimateListView.as_view(), name="estimate_list"), #################################################
path("<slug:dealer_slug>/sales/estimates/", views.EstimateListView.as_view(), name="estimate_list"),
path( path(
"sales/estimates/<uuid:pk>/", "<slug:dealer_slug>/sales/estimates/<uuid:pk>/",
views.EstimateDetailView.as_view(), views.EstimateDetailView.as_view(),
name="estimate_detail", name="estimate_detail",
), ),
path("sales/estimates/create/", views.create_estimate, name="estimate_create"), path("<slug:dealer_slug>/sales/estimates/create/", views.create_estimate, name="estimate_create"),
path( path(
"sales/estimates/create/<slug:slug>/", "<slug:dealer_slug>/sales/estimates/create/<slug:slug>/",
views.create_estimate, views.create_estimate,
name="estimate_create_from_opportunity", name="estimate_create_from_opportunity",
), ),
path( path(
"sales/estimates/<uuid:pk>/estimate_mark_as/", "<slug:dealer_slug>/sales/estimates/<uuid:pk>/estimate_mark_as/",
views.estimate_mark_as, views.estimate_mark_as,
name="estimate_mark_as", name="estimate_mark_as",
), ),
path( path(
"sales/estimates/<uuid:pk>/preview/", "<slug:dealer_slug>/sales/estimates/<uuid:pk>/preview/",
views.EstimatePreviewView.as_view(), views.EstimatePreviewView.as_view(),
name="estimate_preview", name="estimate_preview",
), ),
path( path(
"sales/estimates/<uuid:pk>/payment_request/", "<slug:dealer_slug>/sales/estimates/<uuid:pk>/payment_request/",
views.PaymentRequest.as_view(), views.PaymentRequest.as_view(),
name="payment_request", name="payment_request",
), ),
path( path(
"sales/estimates/<uuid:pk>/send_email", views.send_email_view, name="send_email" "<slug:dealer_slug>/sales/estimates/<uuid:pk>/send_email", views.send_email_view, name="send_email"
), ),
path( path(
"sales/estimates/<uuid:pk>/sale_order/", "<slug:dealer_slug>/sales/estimates/<uuid:pk>/sale_order/",
views.create_sale_order, views.create_sale_order,
name="create_sale_order", name="create_sale_order",
), ),
path( path(
"sales/estimates/<uuid:pk>/sale_order/<int:order_pk>/details/", "<slug:dealer_slug>/sales/estimates/<uuid:pk>/sale_order/<int:order_pk>/details/",
views.SaleOrderDetail.as_view(), views.SaleOrderDetail.as_view(),
name="sale_order_details", name="sale_order_details",
), ),
path( path(
"sales/estimates/<uuid:pk>/sale_order/preview/", "<slug:dealer_slug>/sales/estimates/<uuid:pk>/sale_order/preview/",
views.preview_sale_order, views.preview_sale_order,
name="preview_sale_order", name="preview_sale_order",
), ),
###############################################
# Invoice # Invoice
path("sales/invoices/", views.InvoiceListView.as_view(), name="invoice_list"), ###############################################
path("<slug:dealer_slug>/sales/invoices/", views.InvoiceListView.as_view(), name="invoice_list"),
path( path(
"sales/invoices/<uuid:pk>/create/", views.invoice_create, name="invoice_create" "<slug:dealer_slug>/sales/invoices/<uuid:pk>/create/", views.invoice_create, name="invoice_create"
), ),
path( path(
"sales/invoices/<uuid:pk>/", "<slug:dealer_slug>/sales/invoices/<uuid:pk>/",
views.InvoiceDetailView.as_view(), views.InvoiceDetailView.as_view(),
name="invoice_detail", name="invoice_detail",
), ),
path( path(
"sales/invoices/<uuid:pk>/preview/", "<slug:dealer_slug>/sales/invoices/<uuid:pk>/preview/",
views.InvoicePreviewView.as_view(), views.InvoicePreviewView.as_view(),
name="invoice_preview", name="invoice_preview",
), ),
path( path(
"sales/invoices/<uuid:pk>/invoice_mark_as/", "<slug:dealer_slug>/sales/invoices/<uuid:pk>/invoice_mark_as/",
views.invoice_mark_as, views.invoice_mark_as,
name="invoice_mark_as", name="invoice_mark_as",
), ),
path( path(
"sales/invoices/<uuid:pk>/draft_invoice_update/", "<slug:dealer_slug>/sales/invoices/<uuid:pk>/draft_invoice_update/",
views.DraftInvoiceModelUpdateFormView.as_view(), views.DraftInvoiceModelUpdateFormView.as_view(),
name="draft_invoice_update", name="draft_invoice_update",
), ),
path( path(
"sales/invoices/<uuid:pk>/approved_invoice_update/", "<slug:dealer_slug>/sales/invoices/<uuid:pk>/approved_invoice_update/",
views.ApprovedInvoiceModelUpdateFormView.as_view(), views.ApprovedInvoiceModelUpdateFormView.as_view(),
name="approved_invoice_update", name="approved_invoice_update",
), ),
path( path(
"sales/invoices/<uuid:pk>/paid_invoice_update/", "<slug:dealer_slug>/sales/invoices/<uuid:pk>/paid_invoice_update/",
views.PaidInvoiceModelUpdateFormView.as_view(), views.PaidInvoiceModelUpdateFormView.as_view(),
name="paid_invoice_update", name="paid_invoice_update",
), ),
# path('sales/estimates/<uuid:pk>/preview/', views.EstimatePreviewView.as_view(), name='estimate_preview'), # path('sales/estimates/<uuid:pk>/preview/', views.EstimatePreviewView.as_view(), name='estimate_preview'),
# path('send_email/<uuid:pk>', views.send_email, name='send_email'), # path('send_email/<uuid:pk>', views.send_email, name='send_email'),
# Payment # Payment
path("sales/payments/", views.PaymentListView, name="payment_list"), path("<slug:dealer_slug>/sales/payments/", views.PaymentListView, name="payment_list"),
path( path(
"sales/payments/<uuid:pk>/create/", "<slug:dealer_slug>/sales/payments/<uuid:pk>/create/",
views.PaymentCreateView, views.PaymentCreateView,
name="payment_create", name="payment_create",
), ),
# path("sales/payments/create/", views.PaymentCreateView, name="payment_create"), # path("sales/payments/create/", views.PaymentCreateView, name="payment_create"),
path( path(
"sales/payments/<uuid:pk>/payment_details/", "<slug:dealer_slug>/sales/payments/<uuid:pk>/payment_details/",
views.PaymentDetailView, views.PaymentDetailView,
name="payment_details", name="payment_details",
), ),
path( path(
"sales/payments/<uuid:pk>/payment_mark_as_paid/", "<slug:dealer_slug>/sales/payments/<uuid:pk>/payment_mark_as_paid/",
views.payment_mark_as_paid, views.payment_mark_as_paid,
name="payment_mark_as_paid", name="payment_mark_as_paid",
), ),
@ -787,85 +793,86 @@ urlpatterns = [
name="item_expense_update", name="item_expense_update",
), ),
# Bills # Bills
path("items/bills/", views.BillListView.as_view(), name="bill_list"), path("<slug:dealer_slug>/items/bills/", views.BillListView.as_view(), name="bill_list"),
# path("items/bills/create/", views.BillModelCreateViewView.as_view(), name="bill_create"), # path("items/bills/create/", views.BillModelCreateViewView.as_view(), name="bill_create"),
path( path(
"items/bills/<slug:entity_slug>/create/", "<slug:dealer_slug>/items/bills/<slug:entity_slug>/create/",
views.BillModelCreateView.as_view(), views.BillModelCreateView.as_view(),
name="bill-create", name="bill-create",
), ),
path( path(
"items/bills/<slug:entity_slug>/create/purchase-order/<uuid:po_pk>/", "<slug:dealer_slug>/items/bills/<slug:entity_slug>/create/purchase-order/<uuid:po_pk>/",
views.BillModelCreateView.as_view(for_purchase_order=True), views.BillModelCreateView.as_view(for_purchase_order=True),
name="bill-create-po", name="bill-create-po",
), ),
path( path(
"items/bills/<slug:entity_slug>/create/estimate/<uuid:ce_pk>/", "<slug:dealer_slug>/items/bills/<slug:entity_slug>/create/estimate/<uuid:ce_pk>/",
views.BillModelCreateView.as_view(for_estimate=True), views.BillModelCreateView.as_view(for_estimate=True),
name="bill-create-estimate", name="bill-create-estimate",
), ),
path( path(
"items/bills/<slug:entity_slug>/detail/<uuid:bill_pk>/", "<slug:dealer_slug>/items/bills/<slug:entity_slug>/detail/<uuid:bill_pk>/",
views.BillModelDetailViewView.as_view(), views.BillModelDetailViewView.as_view(),
name="bill-detail", name="bill-detail",
), ),
path( path(
"items/bills/<slug:entity_slug>/update/<uuid:bill_pk>/", "<slug:dealer_slug>/items/bills/<slug:entity_slug>/update/<uuid:bill_pk>/",
views.BillModelUpdateViewView.as_view(), views.BillModelUpdateViewView.as_view(),
name="bill-update", name="bill-update",
), ),
path( path(
"items/bills/<slug:entity_slug>/update/<uuid:bill_pk>/items/", "<slug:dealer_slug>/items/bills/<slug:entity_slug>/update/<uuid:bill_pk>/items/",
views.BillModelUpdateViewView.as_view(action_update_items=True), views.BillModelUpdateViewView.as_view(action_update_items=True),
name="bill-update-items", name="bill-update-items",
), ),
############################################################ ############################################################
path( path(
"items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-draft/", "<slug:dealer_slug>/items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-draft/",
views.BillModelActionMarkAsDraftView.as_view(), views.BillModelActionMarkAsDraftView.as_view(),
name="bill-action-mark-as-draft", name="bill-action-mark-as-draft",
), ),
path( path(
"items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-review/", "<slug:dealer_slug>/items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-review/",
views.BillModelActionMarkAsInReviewView.as_view(), views.BillModelActionMarkAsInReviewView.as_view(),
name="bill-action-mark-as-review", name="bill-action-mark-as-review",
), ),
path( path(
"items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-approved/", "<slug:dealer_slug>/items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-approved/",
views.BillModelActionMarkAsApprovedView.as_view(), views.BillModelActionMarkAsApprovedView.as_view(),
name="bill-action-mark-as-approved", name="bill-action-mark-as-approved",
), ),
path( path(
"items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-paid/", "<slug:dealer_slug>/items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-paid/",
views.BillModelActionMarkAsPaidView.as_view(), views.BillModelActionMarkAsPaidView.as_view(),
name="bill-action-mark-as-paid", name="bill-action-mark-as-paid",
), ),
path( path(
"items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-void/", "<slug:dealer_slug>/items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-void/",
views.BillModelActionVoidView.as_view(), views.BillModelActionVoidView.as_view(),
name="bill-action-mark-as-void", name="bill-action-mark-as-void",
), ),
path( path(
"items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-canceled/", "<slug:dealer_slug>/items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-canceled/",
views.BillModelActionCanceledView.as_view(), views.BillModelActionCanceledView.as_view(),
name="bill-action-mark-as-canceled", name="bill-action-mark-as-canceled",
), ),
path( path(
"items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/lock-ledger/", "<slug:dealer_slug>/items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/lock-ledger/",
views.BillModelActionLockLedgerView.as_view(), views.BillModelActionLockLedgerView.as_view(),
name="bill-action-lock-ledger", name="bill-action-lock-ledger",
), ),
path( path(
"items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/unlock-ledger/", "<slug:dealer_slug>/items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/unlock-ledger/",
views.BillModelActionUnlockLedgerView.as_view(), views.BillModelActionUnlockLedgerView.as_view(),
name="bill-action-unlock-ledger", name="bill-action-unlock-ledger",
), ),
path( path(
"items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/force-migration/", "<slug:dealer_slug>/items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/force-migration/",
views.BillModelActionForceMigrateView.as_view(), views.BillModelActionForceMigrateView.as_view(),
name="bill-action-force-migrate", name="bill-action-force-migrate",
), ),
# path("items/bills/create/", views.bill_create, name="bill_create"), # path("items/bills/create/", views.bill_create, name="bill_create"),
# >>>>>>>>>>>>>>>>>>>>>>...
path( path(
"items/bills/<uuid:pk>/bill_detail/", "items/bills/<uuid:pk>/bill_detail/",
views.BillDetailView.as_view(), views.BillDetailView.as_view(),
@ -1039,78 +1046,78 @@ urlpatterns = [
######### #########
# Purchase Order # Purchase Order
path( path(
"purchase_orders/", "<slug:dealer_slug>/purchase_orders/",
views.PurchaseOrderListView.as_view(), views.PurchaseOrderListView.as_view(),
name="purchase_order_list", name="purchase_order_list",
), ),
path( path(
"purchase_orders/new/", "<slug:dealer_slug>/purchase_orders/new/",
views.PurchaseOrderCreateView, views.PurchaseOrderCreateView,
name="purchase_order_create", name="purchase_order_create",
), ),
path( path(
"purchase_orders/<uuid:pk>/detail/", "<slug:dealer_slug>/purchase_orders/<uuid:pk>/detail/",
views.PurchaseOrderDetailView.as_view(), views.PurchaseOrderDetailView.as_view(),
name="purchase_order_detail", name="purchase_order_detail",
), ),
path( path(
"purchase_orders/<slug:entity_slug>/<uuid:po_pk>/update/", "<slug:dealer_slug>/purchase_orders/<slug:entity_slug>/<uuid:po_pk>/update/",
views.PurchaseOrderUpdateView.as_view(), views.PurchaseOrderUpdateView.as_view(),
name="purchase_order_update", name="purchase_order_update",
), ),
path( path(
"purchase_orders/<slug:entity_slug>/update/<uuid:po_pk>/update-items/", "<slug:dealer_slug>/purchase_orders/<slug:entity_slug>/update/<uuid:po_pk>/update-items/",
views.PurchaseOrderUpdateView.as_view(action_update_items=True), views.PurchaseOrderUpdateView.as_view(action_update_items=True),
name="purchase_order_update_items", name="purchase_order_update_items",
), ),
path( path(
"purchase_orders/inventory_item/create/", "<slug:dealer_slug>/purchase_orders/inventory_item/create/",
views.InventoryItemCreateView, views.InventoryItemCreateView,
name="inventory_item_create", name="inventory_item_create",
), ),
path( path(
"purchase_orders/inventory_items_filter/", "<slug:dealer_slug>/purchase_orders/inventory_items_filter/",
views.inventory_items_filter, views.inventory_items_filter,
name="inventory_items_filter", name="inventory_items_filter",
), ),
path( path(
"purchase_orders/<slug:entity_slug>/delete/<uuid:po_pk>/", "<slug:dealer_slug>/purchase_orders/<slug:entity_slug>/delete/<uuid:po_pk>/",
views.PurchaseOrderModelDeleteView.as_view(), views.PurchaseOrderModelDeleteView.as_view(),
name="po-delete", name="po-delete",
), ),
path( path(
"purchase_orders/<slug:entity_slug>/<uuid:po_pk>/upload/", "<slug:dealer_slug>/purchase_orders/<slug:entity_slug>/<uuid:po_pk>/upload/",
view=views.view_items_inventory, view=views.view_items_inventory,
name="view_items_inventory", name="view_items_inventory",
), ),
# Actions.... # Actions....
path( path(
"<slug:entity_slug>/action/<uuid:po_pk>/mark-as-draft/", "<slug:dealer_slug>/<slug:entity_slug>/action/<uuid:po_pk>/mark-as-draft/",
views.PurchaseOrderMarkAsDraftView.as_view(), views.PurchaseOrderMarkAsDraftView.as_view(),
name="po-action-mark-as-draft", name="po-action-mark-as-draft",
), ),
path( path(
"<slug:entity_slug>/action/<uuid:po_pk>/mark-as-review/", "<slug:dealer_slug>/<slug:entity_slug>/action/<uuid:po_pk>/mark-as-review/",
views.PurchaseOrderMarkAsReviewView.as_view(), views.PurchaseOrderMarkAsReviewView.as_view(),
name="po-action-mark-as-review", name="po-action-mark-as-review",
), ),
path( path(
"<slug:entity_slug>/action/<uuid:po_pk>/mark-as-approved/", "<slug:dealer_slug>/<slug:entity_slug>/action/<uuid:po_pk>/mark-as-approved/",
views.PurchaseOrderMarkAsApprovedView.as_view(), views.PurchaseOrderMarkAsApprovedView.as_view(),
name="po-action-mark-as-approved", name="po-action-mark-as-approved",
), ),
path( path(
"<slug:entity_slug>/action/<uuid:po_pk>/mark-as-fulfilled/", "<slug:dealer_slug>/<slug:entity_slug>/action/<uuid:po_pk>/mark-as-fulfilled/",
views.PurchaseOrderMarkAsFulfilledView.as_view(), views.PurchaseOrderMarkAsFulfilledView.as_view(),
name="po-action-mark-as-fulfilled", name="po-action-mark-as-fulfilled",
), ),
path( path(
"<slug:entity_slug>/action/<uuid:po_pk>/mark-as-canceled/", "<slug:dealer_slug>/<slug:entity_slug>/action/<uuid:po_pk>/mark-as-canceled/",
views.PurchaseOrderMarkAsCanceledView.as_view(), views.PurchaseOrderMarkAsCanceledView.as_view(),
name="po-action-mark-as-canceled", name="po-action-mark-as-canceled",
), ),
path( path(
"<slug:entity_slug>/action/<uuid:po_pk>/mark-as-void/", "<slug:dealer_slug>/<slug:entity_slug>/action/<uuid:po_pk>/mark-as-void/",
views.PurchaseOrderMarkAsVoidView.as_view(), views.PurchaseOrderMarkAsVoidView.as_view(),
name="po-action-mark-as-void", name="po-action-mark-as-void",
), ),

View File

@ -222,7 +222,7 @@ def reserve_car(car, request):
except Exception as e: except Exception as e:
messages.error(request, f"Error reserving car: {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): def calculate_vat_amount(amount):
@ -1011,7 +1011,7 @@ class CarFinanceCalculator:
"make": car_info.get("make"), "make": car_info.get("make"),
"model": car_info.get("model"), "model": car_info.get("model"),
"year": car_info.get("year"), "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"), "trim": car_info.get("trim"),
"mileage": car_info.get("mileage"), "mileage": car_info.get("mileage"),
"cost_price": car_finance.get("cost_price"), "cost_price": car_finance.get("cost_price"),

View File

@ -20,6 +20,7 @@ from pyzbar.pyzbar import decode
from urllib.parse import urlparse, urlunparse from urllib.parse import urlparse, urlunparse
##################################################################### #####################################################################
from inventory.mixins import DealerSlugMixin
from inventory.models import Status as LeadStatus from inventory.models import Status as LeadStatus
from django.db import IntegrityError from django.db import IntegrityError
from background_task.models import Task from background_task.models import Task
@ -348,10 +349,13 @@ class HomeView(LoginRequiredMixin, TemplateView):
template_name = "index.html" template_name = "index.html"
def dispatch(self, request, *args, **kwargs): def dispatch(self, request,*args, **kwargs):
# Redirect unauthenticated users to the welcome page # Redirect unauthenticated users to the welcome page
if not request.user.is_authenticated: if not request.user.is_authenticated:
return redirect("welcome") 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) return super().dispatch(request, *args, **kwargs)
@ -616,8 +620,8 @@ class CarCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
def get_success_url(self): def get_success_url(self):
"""Determine the redirect URL based on user choice.""" """Determine the redirect URL based on user choice."""
if self.request.POST.get("add_another"): if self.request.POST.get("add_another"):
return reverse("car_add") return reverse("car_add", kwargs={"dealer_slug": self.kwargs["dealer_slug"]})
return reverse("inventory_stats") return reverse("inventory_stats", kwargs={"dealer_slug": self.kwargs["dealer_slug"]})
def form_valid(self, form): def form_valid(self, form):
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
@ -628,9 +632,7 @@ class CarCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
dealer = get_user_type(self.request) context["vendor_exists"] = self.request.dealer.vendors.exists()
context["vendor_exists"] = dealer.vendors.exists()
return context return context
@ -673,7 +675,7 @@ class AjaxHandlerView(LoginRequiredMixin, View):
:ivar request: Django request object containing HTTP request details. :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") action = request.GET.get("action")
handlers = { handlers = {
"decode_vin": self.decode_vin, "decode_vin": self.decode_vin,
@ -986,7 +988,7 @@ class CarColorCreate(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
return super().form_valid(form) return super().form_valid(form)
def get_success_url(self): 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): def get_context_data(self, **kwargs):
context = super().get_context_data(**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 refers to the CarColors instance that was just updated.
# self.object.car then refers to the associated Car instance. # 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): def get_context_data(self, **kwargs):
""" """
@ -1138,7 +1140,7 @@ class CarListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
@login_required @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 Handle the inventory stats view for a dealer, displaying detailed information
about the cars, including counts grouped by make, model, and trim. 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. "inventory/inventory_stats.html" template.
:rtype: HttpResponse :rtype: HttpResponse
""" """
dealer = get_user_type(request)
# Base queryset for cars belonging to the dealer # 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 # Count for total, reserved, showroom, and unreserved cars
total_cars = cars.count() total_cars = cars.count()
@ -1241,7 +1242,6 @@ def inventory_stats_view(request):
for make_data in inventory.values() for make_data in inventory.values()
], ],
} }
print(result["makes"])
return render(request, "inventory/inventory_stats.html", {"inventory": result}) return render(request, "inventory/inventory_stats.html", {"inventory": result})
@ -1427,7 +1427,7 @@ class CarFinanceCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateVi
return super().form_valid(form) return super().form_valid(form)
def get_success_url(self): 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): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -1474,7 +1474,7 @@ class CarFinanceUpdateView(
permission_required = ["inventory.change_carfinance"] permission_required = ["inventory.change_carfinance"]
def get_success_url(self): 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): def get_form_kwargs(self):
kwargs = super().get_form_kwargs() kwargs = super().get_form_kwargs()
@ -1871,7 +1871,7 @@ class CustomCardCreateView(LoginRequiredMixin, CreateView):
def get_success_url(self): def get_success_url(self):
messages.success(self.request, _("Custom Card added successfully")) 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): class CarRegistrationCreateView(LoginRequiredMixin, CreateView):
@ -1913,11 +1913,11 @@ class CarRegistrationCreateView(LoginRequiredMixin, CreateView):
def get_success_url(self): def get_success_url(self):
messages.success(self.request, _("Registration added successfully")) 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() @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 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 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 @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 Handles the management of a car reservation, providing options to renew or
cancel an existing reservation associated with the logged-in user. 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.reserved_until = timezone.now() + timezone.timedelta(hours=24)
reservation.save() reservation.save()
messages.success(request, _("Reservation renewed successfully")) 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": elif action == "cancel":
car = reservation.car car = reservation.car
@ -1982,7 +1982,7 @@ def manage_reservation(request, reservation_id):
car.status = models.CarStatusChoices.AVAILABLE car.status = models.CarStatusChoices.AVAILABLE
car.save() car.save()
messages.success(request, _("Reservation canceled successfully")) 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: else:
return JsonResponse( return JsonResponse(
@ -3444,21 +3444,20 @@ class BankAccountUpdateView(
model = BankAccountModel model = BankAccountModel
form_class = BankAccountUpdateForm form_class = BankAccountUpdateForm
template_name = "ledger/bank_accounts/bank_account_form.html" template_name = "ledger/bank_accounts/bank_account_form.html"
success_url = reverse_lazy("bank_account_list")
success_message = _("Bank account updated successfully") success_message = _("Bank account updated successfully")
permission_required = ["inventory.view_carfinance"] permission_required = ["inventory.view_carfinance"]
def get_form_kwargs(self): 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 entity = dealer.entity
kwargs = super().get_form_kwargs() kwargs = super().get_form_kwargs()
kwargs["entity_slug"] = entity.slug # Get entity_slug from URL kwargs["entity_slug"] = entity.slug # Get entity_slug from URL
kwargs["user_model"] = entity.admin # Get user_model from the request kwargs["user_model"] = entity.admin # Get user_model from the request
return kwargs 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 @login_required
def bank_account_delete(request, pk): def bank_account_delete(request,dealer_slug, pk):
""" """
Delete a bank account entry from the database. 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. rendering the confirmation template if accessed via GET.
:rtype: HttpResponse :rtype: HttpResponse
""" """
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
bank_account = get_object_or_404(BankAccountModel, pk=pk) bank_account = get_object_or_404(BankAccountModel, pk=pk)
if request.method == "POST": if request.method == "POST":
bank_account.delete() bank_account.delete()
messages.success(request, _("Bank account deleted successfully")) messages.success(request, _("Bank account deleted successfully"))
return redirect("bank_account_list") return redirect("bank_account_list", dealer_slug=dealer_slug)
return render( return render(
request, request,
"ledger/bank_accounts/bank_account_delete.html", "ledger/bank_accounts/bank_account_delete.html",
@ -3568,7 +3568,6 @@ class AccountCreateView(
model = AccountModel model = AccountModel
form_class = AccountModelCreateForm form_class = AccountModelCreateForm
template_name = "ledger/coa_accounts/account_form.html" template_name = "ledger/coa_accounts/account_form.html"
success_url = reverse_lazy("account_list")
success_message = _("Account created successfully") success_message = _("Account created successfully")
permission_required = ["inventory.view_carfinance"] permission_required = ["inventory.view_carfinance"]
@ -3591,6 +3590,8 @@ class AccountCreateView(
entity = get_user_type(self.request).entity entity = get_user_type(self.request).entity
form.initial["coa_model"] = entity.get_default_coa() form.initial["coa_model"] = entity.get_default_coa()
return form return form
def get_success_url(self):
return reverse("account_list", kwargs={"dealer_slug":self.kwargs["dealer_slug"]})
class AccountDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView): class AccountDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
@ -3682,7 +3683,6 @@ class AccountUpdateView(
model = AccountModel model = AccountModel
form_class = AccountModelUpdateForm form_class = AccountModelUpdateForm
template_name = "ledger/coa_accounts/account_form.html" template_name = "ledger/coa_accounts/account_form.html"
success_url = reverse_lazy("account_list")
success_message = _("Account updated successfully") success_message = _("Account updated successfully")
permission_required = ["inventory.view_carfinance"] permission_required = ["inventory.view_carfinance"]
@ -3691,11 +3691,12 @@ class AccountUpdateView(
form.fields["_ref_node_id"].widget = HiddenInput() form.fields["_ref_node_id"].widget = HiddenInput()
form.fields["_position"].widget = HiddenInput() form.fields["_position"].widget = HiddenInput()
return form return form
def get_success_url(self):
return reverse_lazy("account_list", kwargs={"dealer_slug":self.kwargs["dealer_slug"]})
@login_required @login_required
@permission_required("inventory.view_carfinance") @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 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 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. :return: An HTTP redirect response to the account list page.
:rtype: HttpResponse :rtype: HttpResponse
""" """
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
account = get_object_or_404(AccountModel, pk=pk) account = get_object_or_404(AccountModel, pk=pk)
account.delete() account.delete()
messages.success(request, _("Account deleted successfully")) messages.success(request, _("Account deleted successfully"))
return redirect("account_list") return redirect("account_list",dealer_slug=dealer_slug)
# Sales list # Sales list
@ -3809,7 +3812,7 @@ class EstimateListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# @csrf_exempt # @csrf_exempt
@login_required @login_required
@permission_required("django_ledger.add_estimatemodel", raise_exception=True) @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 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 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. estimate creation form.
:rtype: JsonResponse or HttpResponse :rtype: JsonResponse or HttpResponse
""" """
dealer = get_user_type(request) dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
entity = dealer.entity entity = dealer.entity
if request.method == "POST": if request.method == "POST":
@ -4002,7 +4005,7 @@ def create_estimate(request, slug=None):
opportunity.estimate = estimate opportunity.estimate = estimate
opportunity.save() opportunity.save()
url = reverse("estimate_detail", kwargs={"pk": estimate.pk}) url = reverse("estimate_detail", kwargs={"dealer_slug": dealer.slug,"pk": estimate.pk})
return JsonResponse( return JsonResponse(
{ {
"status": "success", "status": "success",
@ -4108,7 +4111,7 @@ class EstimateDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
@login_required @login_required
@permission_required("inventory.add_saleorder", raise_exception=True) @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. 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. POST data, or redirects to the estimate detail view upon successful creation.
:rtype: HttpResponse :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) estimate = get_object_or_404(EstimateModel, pk=pk)
items = estimate.get_itemtxs_data()[0].all() items = estimate.get_itemtxs_data()[0].all()
if request.method == "POST": if request.method == "POST":
@ -4157,7 +4160,7 @@ def create_sale_order(request, pk):
else: else:
print(form.errors) print(form.errors)
messages.error(request, "Invalid form data") 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() form = forms.SaleOrderForm()
customer = estimate.customer.customer_set.first() customer = estimate.customer.customer_set.first()
@ -4201,7 +4204,7 @@ class SaleOrderDetail(DetailView):
@login_required @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. 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 :return: HTTP response containing the rendered sale order preview page
:rtype: HttpResponse :rtype: HttpResponse
""" """
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
estimate = get_object_or_404(EstimateModel, pk=pk) estimate = get_object_or_404(EstimateModel, pk=pk)
data = get_car_finance_data(estimate) data = get_car_finance_data(estimate)
return render( return render(
@ -4289,19 +4293,18 @@ class EstimatePreviewView(LoginRequiredMixin, PermissionRequiredMixin, DetailVie
permission_required = ["django_ledger.view_estimatemodel"] permission_required = ["django_ledger.view_estimatemodel"]
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
dealer = get_user_type(self.request)
estimate = kwargs.get("object") estimate = kwargs.get("object")
if estimate.get_itemtxs_data(): if estimate.get_itemtxs_data():
# data = get_financial_values(estimate) # data = get_financial_values(estimate)
calculator = CarFinanceCalculator(estimate) calculator = CarFinanceCalculator(estimate)
kwargs["data"] = calculator.get_finance_data() kwargs["data"] = calculator.get_finance_data()
kwargs["dealer"] = dealer
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
@login_required @login_required
@permission_required("django_ledger.change_estimatemodel", raise_exception=True) @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 Marks an estimate with a specified status based on the requested action and
permissions. The marking possibilities include review, approval, rejection, 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. :return: A redirect response to the estimate detail view.
:rtype: HttpResponseRedirect :rtype: HttpResponseRedirect
""" """
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
estimate = get_object_or_404(EstimateModel, pk=pk) estimate = get_object_or_404(EstimateModel, pk=pk)
mark = request.GET.get("mark") mark = request.GET.get("mark")
if mark: if mark:
if mark == "review": if mark == "review":
if not estimate.can_review(): if not estimate.can_review():
messages.error(request, _("Quotation is not ready for 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() estimate.mark_as_review()
elif mark == "approved": elif mark == "approved":
if not estimate.can_approve(): if not estimate.can_approve():
messages.error(request, _("Quotation is not ready for approval")) 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() estimate.mark_as_approved()
messages.success(request, _("Quotation approved successfully")) messages.success(request, _("Quotation approved successfully"))
elif mark == "rejected": elif mark == "rejected":
if not estimate.can_cancel(): if not estimate.can_cancel():
messages.error(request, _("Quotation is not ready for rejection")) 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() estimate.mark_as_canceled()
messages.success(request, _("Quotation canceled successfully")) messages.success(request, _("Quotation canceled successfully"))
elif mark == "completed": elif mark == "completed":
if not estimate.can_complete(): if not estimate.can_complete():
messages.error(request, _("Quotation is not ready for completion")) 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": elif mark == "canceled":
if not estimate.can_cancel(): if not estimate.can_cancel():
messages.error(request, _("Quotation is not ready for cancellation")) 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() estimate.mark_as_canceled()
try: try:
car = models.Car.objects.get( car = models.Car.objects.get(
@ -4359,7 +4363,7 @@ def estimate_mark_as(request, pk):
estimate.save() estimate.save()
messages.success(request, _("Quotation marked as ") + mark.upper()) 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 # Invoice
@ -4392,8 +4396,8 @@ class InvoiceListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
permission_required = ["django_ledger.view_invoicemodel"] permission_required = ["django_ledger.view_invoicemodel"]
def get_queryset(self): def get_queryset(self):
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
query = self.request.GET.get("q") query = self.request.GET.get("q")
dealer = get_user_type(self.request)
invoices = dealer.entity.get_invoices() invoices = dealer.entity.get_invoices()
return apply_search_filters(invoices, query) return apply_search_filters(invoices, query)
@ -4474,7 +4478,7 @@ class DraftInvoiceModelUpdateFormView(
def get_form_kwargs(self): def get_form_kwargs(self):
kwargs = super().get_form_kwargs() 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["entity_slug"] = dealer.entity
kwargs["user_model"] = dealer.entity.admin kwargs["user_model"] = dealer.entity.admin
return kwargs return kwargs
@ -4516,13 +4520,13 @@ class ApprovedInvoiceModelUpdateFormView(
def get_form_kwargs(self): def get_form_kwargs(self):
kwargs = super().get_form_kwargs() 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["entity_slug"] = dealer.entity
kwargs["user_model"] = dealer.entity.admin kwargs["user_model"] = dealer.entity.admin
return kwargs return kwargs
def get_success_url(self): 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( class PaidInvoiceModelUpdateFormView(
@ -4561,13 +4565,13 @@ class PaidInvoiceModelUpdateFormView(
def get_form_kwargs(self): def get_form_kwargs(self):
kwargs = super().get_form_kwargs() 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["entity_slug"] = dealer.entity
kwargs["user_model"] = dealer.entity.admin kwargs["user_model"] = dealer.entity.admin
return kwargs return kwargs
def get_success_url(self): 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): def form_valid(self, form):
invoice = form.save() invoice = form.save()
@ -4583,7 +4587,7 @@ class PaidInvoiceModelUpdateFormView(
@login_required @login_required
@permission_required("django_ledger.change_invoicemodel", raise_exception=True) @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. 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. :return: An HTTP redirect response to the invoice detail page after processing.
:rtype: django.http.HttpResponse :rtype: django.http.HttpResponse
""" """
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
invoice = get_object_or_404(InvoiceModel, pk=pk) invoice = get_object_or_404(InvoiceModel, pk=pk)
dealer = get_user_type(request)
mark = request.GET.get("mark") mark = request.GET.get("mark")
if mark and mark == "accept": if mark and mark == "accept":
if not invoice.can_approve(): if not invoice.can_approve():
messages.error(request, "invoice is not ready for approval") 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( invoice.mark_as_approved(
entity_slug=dealer.entity.slug, user_model=dealer.entity.admin entity_slug=dealer.entity.slug, user_model=dealer.entity.admin
) )
invoice.save() invoice.save()
return redirect("invoice_detail", pk=invoice.pk) return redirect("invoice_detail",dealer_slug=dealer_slug, pk=invoice.pk)
@login_required @login_required
@permission_required("django_ledger.add_invoicemodel", raise_exception=True) @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 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 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. creation or renders the invoice creation form template otherwise.
:rtype: HttpResponse :rtype: HttpResponse
""" """
dealer = get_object_or_404(models.Dealer,slug=dealer_slug)
estimate = get_object_or_404(EstimateModel, pk=pk) estimate = get_object_or_404(EstimateModel, pk=pk)
dealer = get_user_type(request)
entity = dealer.entity entity = dealer.entity
if request.method == "POST": if request.method == "POST":
@ -4674,7 +4678,7 @@ def invoice_create(request, pk):
estimate.save() estimate.save()
invoice.save() invoice.save()
messages.success(request, "Invoice created successfully") 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: else:
print(form.errors) print(form.errors)
form = forms.InvoiceModelCreateForm( form = forms.InvoiceModelCreateForm(
@ -4722,7 +4726,7 @@ class InvoicePreviewView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
permission_required = ["django_ledger.view_invoicemodel"] permission_required = ["django_ledger.view_invoicemodel"]
def get_context_data(self, **kwargs): 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") invoice = kwargs.get("object")
if invoice.get_itemtxs_data(): if invoice.get_itemtxs_data():
calculator = CarFinanceCalculator(invoice) calculator = CarFinanceCalculator(invoice)
@ -4737,7 +4741,7 @@ class InvoicePreviewView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
@login_required @login_required
@permission_required("django_ledger.add_journalentrymodel", raise_exception=True) @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 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 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 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. 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() invoice = InvoiceModel.objects.filter(pk=pk).first()
bill = BillModel.objects.filter(pk=pk).first() bill = BillModel.objects.filter(pk=pk).first()
model = invoice if invoice else bill model = invoice if invoice else bill
dealer = get_user_type(request)
entity = dealer.entity entity = dealer.entity
form = forms.PaymentForm() form = forms.PaymentForm()
if request.method == "POST": if request.method == "POST":
@ -4780,10 +4784,10 @@ def PaymentCreateView(request, pk):
model.mark_as_approved(user_model=entity.admin) model.mark_as_approved(user_model=entity.admin)
if model.amount_paid == model.amount_due: if model.amount_paid == model.amount_due:
messages.error(request, _("fully paid")) 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: if model.amount_paid + amount > model.amount_due:
messages.error(request, _("Amount exceeds due amount")) 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: try:
if invoice: if invoice:
@ -4791,7 +4795,7 @@ def PaymentCreateView(request, pk):
elif bill: elif bill:
set_bill_payment(dealer, entity, bill, amount, payment_method) set_bill_payment(dealer, entity, bill, amount, payment_method)
messages.success(request, _("Payment created successfully")) 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: except Exception as e:
messages.error(request, f"Error creating payment: {str(e)}") messages.error(request, f"Error creating payment: {str(e)}")
else: else:
@ -4812,7 +4816,7 @@ def PaymentCreateView(request, pk):
@login_required @login_required
@permission_required("django_ledger.view_journalentrymodel", raise_exception=True) @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 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 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. :return: The rendered HTML response displaying the list of payments.
:rtype: HttpResponse :rtype: HttpResponse
""" """
dealer = get_user_type(request) dealer = get_object_or_404(models.Dealer,slug=dealer_slug)
entity = dealer.entity entity = dealer.entity
journals = JournalEntryModel.objects.filter(ledger__entity=entity).all() journals = JournalEntryModel.objects.filter(ledger__entity=entity).all()
@ -4842,7 +4846,7 @@ def PaymentListView(request):
@login_required @login_required
@permission_required("django_ledger.view_journalentrymodel", raise_exception=True) @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 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 and its associated transactions. It ensures that the request is authenticated
@ -4856,6 +4860,7 @@ def PaymentDetailView(request, pk):
entry and its associated transactions. entry and its associated transactions.
:rtype: HttpResponse :rtype: HttpResponse
""" """
dealer = get_object_or_404(models.Dealer,slug=dealer_slug)
journal = JournalEntryModel.objects.filter(pk=pk).first() journal = JournalEntryModel.objects.filter(pk=pk).first()
transactions = ( transactions = (
TransactionModel.objects.filter(journal_entry=journal) TransactionModel.objects.filter(journal_entry=journal)
@ -4871,7 +4876,7 @@ def PaymentDetailView(request, pk):
@login_required @login_required
@permission_required("django_ledger.change_journalentrymodel", raise_exception=True) @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 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 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 :raises: In case of an exception during the process, an error message is
displayed to the user through Django's messaging framework. 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) invoice = get_object_or_404(InvoiceModel, pk=pk)
if request.method == "POST": if request.method == "POST":
try: try:
@ -4914,7 +4920,7 @@ def payment_mark_as_paid(request, pk):
) )
except Exception as e: except Exception as e:
messages.error(request, f"Error: {str(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 # activity log
@ -6645,7 +6651,8 @@ class BillModelCreateView(CreateView):
for_purchase_order = False for_purchase_order = False
for_estimate = 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: if not request.user.is_authenticated:
return HttpResponseForbidden() return HttpResponseForbidden()
@ -6658,7 +6665,7 @@ class BillModelCreateView(CreateView):
) )
if not estimate_model.can_bind(): if not estimate_model.can_bind():
return HttpResponseNotFound("404 Not Found") 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): def get_context_data(self, **kwargs):
context = super(BillModelCreateView, self).get_context_data(**kwargs) context = super(BillModelCreateView, self).get_context_data(**kwargs)
@ -6687,6 +6694,7 @@ class BillModelCreateView(CreateView):
reverse( reverse(
"bill-create-po", "bill-create-po",
kwargs={ kwargs={
"dealer_slug": self.kwargs["dealer_slug"],
"entity_slug": self.kwargs["entity_slug"], "entity_slug": self.kwargs["entity_slug"],
"po_pk": po_model.uuid, "po_pk": po_model.uuid,
}, },
@ -6704,6 +6712,7 @@ class BillModelCreateView(CreateView):
form_action = reverse( form_action = reverse(
"bill-create-estimate", "bill-create-estimate",
kwargs={ kwargs={
"dealer_slug": self.kwargs["dealer_slug"],
"entity_slug": self.kwargs["entity_slug"], "entity_slug": self.kwargs["entity_slug"],
"ce_pk": estimate_model.uuid, "ce_pk": estimate_model.uuid,
}, },
@ -6712,6 +6721,7 @@ class BillModelCreateView(CreateView):
form_action = reverse( form_action = reverse(
"bill-create", "bill-create",
kwargs={ kwargs={
"dealer_slug": self.kwargs["dealer_slug"],
"entity_slug": self.kwargs["entity_slug"], "entity_slug": self.kwargs["entity_slug"],
}, },
) )
@ -6787,28 +6797,33 @@ class BillModelCreateView(CreateView):
po_pk = self.kwargs["po_pk"] po_pk = self.kwargs["po_pk"]
return reverse( return reverse(
"purchase_order_update", "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: elif self.for_estimate:
return reverse( return reverse(
"customer-estimate-detail", "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 bill_model: BillModel = self.object
return reverse( return reverse(
"bill-detail", "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): class BillModelDetailViewView(BillModelDetailView):
template_name = "bill/bill_detail.html" 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): class BillModelUpdateViewView(BillModelUpdateView):
template_name = "bill/bill_update.html" 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 self.action_update_items:
if not request.user.is_authenticated: if not request.user.is_authenticated:
return HttpResponseForbidden() return HttpResponseForbidden()
@ -6865,6 +6880,7 @@ class BillModelUpdateViewView(BillModelUpdateView):
redirect_to=reverse( redirect_to=reverse(
"bill-update", "bill-update",
kwargs={ kwargs={
"dealer_slug": dealer_slug,
"entity_slug": entity_model.slug, "entity_slug": entity_model.slug,
"bill_pk": bill_pk, "bill_pk": bill_pk,
}, },
@ -6872,12 +6888,13 @@ class BillModelUpdateViewView(BillModelUpdateView):
) )
context = self.get_context_data(itemtxs_formset=itemtxs_formset) context = self.get_context_data(itemtxs_formset=itemtxs_formset)
return self.render_to_response(context=context) 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): def get_success_url(self):
return reverse( return reverse(
"bill-update", "bill-update",
kwargs={ kwargs={
"dealer_slug": self.kwargs["dealer_slug"],
"entity_slug": self.kwargs["entity_slug"], "entity_slug": self.kwargs["entity_slug"],
"bill_pk": self.kwargs["bill_pk"], "bill_pk": self.kwargs["bill_pk"],
}, },
@ -7074,7 +7091,7 @@ class OrderListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# email # email
@login_required @login_required
@permission_required("django_ledger.view_estimatemodel", raise_exception=True) @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 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. 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 :rtype: HttpResponseRedirect
:raises Http404: If the estimate with the given primary key does not exist. :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) estimate = get_object_or_404(EstimateModel, pk=pk)
if not estimate.get_itemtxs_data()[0]: if not estimate.get_itemtxs_data()[0]:
messages.error(request, _("Quotation has no items")) 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( 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""" msg = f"""
@ -7135,7 +7152,7 @@ def send_email_view(request, pk):
estimate.mark_as_review() estimate.mark_as_review()
messages.success(request, _("Email sent successfully")) 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 # errors
@ -9041,15 +9058,15 @@ def permenant_delete_account(request, content_type, slug):
##################################################################### #####################################################################
def PurchaseOrderCreateView(request): def PurchaseOrderCreateView(request, dealer_slug):
dealer = get_user_type(request) dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
entity = dealer.entity entity = dealer.entity
if request.method == "POST": if request.method == "POST":
po = entity.create_purchase_order(po_title=request.POST.get("po_title")) po = entity.create_purchase_order(po_title=request.POST.get("po_title"))
po.entity = entity po.entity = entity
po.save() po.save()
messages.success(request, _("Purchase order created successfully")) 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( form = PurchaseOrderModelCreateForm(
entity_slug=entity.slug, user_model=entity.admin 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}) 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") for_po = request.GET.get("for_po")
dealer = get_user_type(request)
entity = dealer.entity entity = dealer.entity
coa = entity.get_default_coa() coa = entity.get_default_coa()
@ -9098,7 +9115,7 @@ def InventoryItemCreateView(request):
.first() .first()
): ):
messages.error(request, _("Inventory item already exists")) 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") uom = entity.get_uom_all().get(name="Unit")
entity.create_item_inventory( entity.create_item_inventory(
name=inventory_name, name=inventory_name,
@ -9108,9 +9125,10 @@ def InventoryItemCreateView(request):
coa_model=coa, coa_model=coa,
) )
messages.success(request, _("Inventory item created successfully")) messages.success(request, _("Inventory item created successfully"))
return redirect("purchase_order_list") return redirect("purchase_order_list", dealer_slug=dealer.slug)
if for_po: if for_po:
form = forms.CSVUploadForm() form = forms.CSVUploadForm()
form.fields["vendor"].queryset = dealer.vendors.filter(active=True)
context = { context = {
"make_data": models.CarMake.objects.all(), "make_data": models.CarMake.objects.all(),
"inventory_accounts": inventory_accounts, "inventory_accounts": inventory_accounts,
@ -9129,8 +9147,8 @@ def InventoryItemCreateView(request):
) )
def inventory_items_filter(request): def inventory_items_filter(request,dealer_slug):
dealer = get_user_type(request) dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
make = request.GET.get("make") make = request.GET.get("make")
model = request.GET.get("model") model = request.GET.get("model")
serie = request.GET.get("serie") serie = request.GET.get("serie")
@ -9175,38 +9193,6 @@ class PurchaseOrderDetailView(PurchaseOrderModelDetailViewBase):
return context 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): class PurchaseOrderListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
model = PurchaseOrderModel model = PurchaseOrderModel
context_object_name = "purchase_orders" context_object_name = "purchase_orders"
@ -9231,15 +9217,10 @@ class PurchaseOrderUpdateView(PurchaseOrderModelUpdateViewBase):
context_object_name = "po_model" context_object_name = "po_model"
def get_context_data(self, itemtxs_formset=None, **kwargs): 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 = super().get_context_data(**kwargs)
context["entity_slug"] = dealer.entity.slug context["entity_slug"] = dealer.entity.slug
po_model: PurchaseOrderModel = self.object 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: if not itemtxs_formset:
itemtxs_qs = self.get_po_itemtxs_qs(po_model) itemtxs_qs = self.get_po_itemtxs_qs(po_model)
itemtxs_qs, itemtxs_agg = po_model.get_itemtxs_data(queryset=itemtxs_qs) itemtxs_qs, itemtxs_agg = po_model.get_itemtxs_data(queryset=itemtxs_qs)
@ -9261,36 +9242,35 @@ class PurchaseOrderUpdateView(PurchaseOrderModelUpdateViewBase):
return reverse( return reverse(
"purchase_order_update", "purchase_order_update",
kwargs={ kwargs={
"dealer_slug": self.kwargs["dealer_slug"],
"entity_slug": self.kwargs["entity_slug"], "entity_slug": self.kwargs["entity_slug"],
"po_pk": self.kwargs["po_pk"], "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: if self.action_update_items:
return HttpResponseRedirect( return HttpResponseRedirect(
redirect_to=reverse( redirect_to=reverse(
"purchase_order_update", "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( 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): def post(self, request, dealer_slug, entity_slug, *args, **kwargs):
dealer = get_user_type(self.request)
if self.action_update_items: if self.action_update_items:
if not request.user.is_authenticated: if not request.user.is_authenticated:
return HttpResponseForbidden() return HttpResponseForbidden()
queryset = self.get_queryset() queryset = self.get_queryset()
po_model: PurchaseOrderModel = self.get_object(queryset=queryset) po_model: PurchaseOrderModel = self.get_object(queryset=queryset)
self.object = po_model self.object = po_model
po_itemtxs_formset_class = get_po_itemtxs_formset_class(po_model) po_itemtxs_formset_class = get_po_itemtxs_formset_class(po_model)
itemtxs_formset = po_itemtxs_formset_class( itemtxs_formset = po_itemtxs_formset_class(
request.POST, request.POST,
user_model=dealer.entity.admin, user_model=request.dealer.entity.admin,
po_model=po_model, po_model=po_model,
entity_slug=entity_slug, entity_slug=entity_slug,
) )
@ -9309,6 +9289,7 @@ class PurchaseOrderUpdateView(PurchaseOrderModelUpdateViewBase):
redirect_url = reverse( redirect_url = reverse(
"bill-create-po", "bill-create-po",
kwargs={ kwargs={
"dealer_slug": self.kwargs["dealer_slug"],
"entity_slug": self.kwargs["entity_slug"], "entity_slug": self.kwargs["entity_slug"],
"po_pk": po_model.uuid, "po_pk": po_model.uuid,
}, },
@ -9337,7 +9318,7 @@ class PurchaseOrderUpdateView(PurchaseOrderModelUpdateViewBase):
context=self.get_context_data(itemtxs_formset=itemtxs_formset) context=self.get_context_data(itemtxs_formset=itemtxs_formset)
) )
return super(PurchaseOrderUpdateView, self).post( return super(PurchaseOrderUpdateView, self).post(
request, entity_slug, *args, **kwargs request,dealer_slug, entity_slug, *args, **kwargs
) )
def get_form(self, form_class=None): def get_form(self, form_class=None):
@ -9368,19 +9349,19 @@ class PurchaseOrderUpdateView(PurchaseOrderModelUpdateViewBase):
class BasePurchaseOrderActionActionView(BasePurchaseOrderActionActionViewBase): 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( 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 # 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 kwargs["user_model"] = dealer.entity.admin
if not self.action_name: if not self.action_name:
raise ImproperlyConfigured("View attribute action_name is required.") raise ImproperlyConfigured("View attribute action_name is required.")
response = super(BasePurchaseOrderActionActionView, self).get( response = super(BasePurchaseOrderActionActionView, self).get(
request, *args, **kwargs request,dealer_slug,entity_slug,po_pk, *args, **kwargs
) )
po_model: PurchaseOrderModel = self.get_object() po_model: PurchaseOrderModel = self.get_object()
@ -9393,11 +9374,6 @@ class BasePurchaseOrderActionActionView(BasePurchaseOrderActionActionViewBase):
) )
except ValidationError as e: except ValidationError as e:
print(e) print(e)
# messages.add_message(
# request,
# message=e.message,
# level=messages.ERROR,
# )
return response return response
@ -9405,7 +9381,12 @@ class PurchaseOrderModelDeleteView(PurchaseOrderModelDeleteViewBase):
template_name = "purchase_orders/po_delete.html" template_name = "purchase_orders/po_delete.html"
def get_success_url(self): 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): class PurchaseOrderMarkAsDraftView(BasePurchaseOrderActionActionView):
@ -9434,9 +9415,9 @@ class PurchaseOrderMarkAsVoidView(BasePurchaseOrderActionActionView):
##############################bil ##############################bil
class BaseBillActionView(BaseBillActionViewBase): 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( 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): def view_items_inventory(request,dealer_slug, entity_slug, po_pk):
dealer = get_user_type(request) dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
po = PurchaseOrderModel.objects.get(pk=po_pk) po = PurchaseOrderModel.objects.get(pk=po_pk)
items = po.get_itemtxs_data()[0] items = po.get_itemtxs_data()[0]
items_per_page = 30 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 item = None
dealer = get_user_type(request) dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
response = redirect("upload_cars") response = redirect("upload_cars",dealer_slug=dealer_slug)
if pk: if pk:
item = get_object_or_404(ItemTransactionModel, pk=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"): if item.item_model.additional_info.get("uploaded"):
messages.add_message(request, messages.ERROR, "Item already uploaded.") messages.add_message(request, messages.ERROR, "Item already uploaded.")
return redirect( 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": if request.method == "POST":
@ -9560,7 +9541,7 @@ def upload_cars(request, pk=None):
if not csv_file.name.endswith(".csv"): if not csv_file.name.endswith(".csv"):
messages.error(request, "Please upload a CSV file") messages.error(request, "Please upload a CSV file")
return redirect("upload_cars") return redirect("upload_cars",dealer_slug=dealer_slug)
try: try:
# Read the file content # Read the file content
file_content = csv_file.read().decode("utf-8") file_content = csv_file.read().decode("utf-8")

View File

@ -42,11 +42,11 @@
<div class="col-lg-4"> <div class="col-lg-4">
<div class="card shadow-sm" > <div class="card shadow-sm" >
<div class="card-body"> <div class="card-body">
{% 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' %}
<hr class="my-4"> <hr class="my-4">
{% include 'bill/includes/card_vendor.html' with vendor=bill.vendor %} {% include 'bill/includes/card_vendor.html' with vendor=bill.vendor %}
<div class="d-grid mt-4"> <div class="d-grid mt-4">
<a href="{% url 'bill_list' %}" <a href="{% url 'bill_list' request.dealer.slug %}"
class="btn btn-phoenix-primary"> class="btn btn-phoenix-primary">
<i class="fas fa-arrow-left me-1"></i> {% trans 'Bill List' %} <i class="fas fa-arrow-left me-1"></i> {% trans 'Bill List' %}
</a> </a>
@ -65,7 +65,7 @@
<div class="border rounded p-3"> <div class="border rounded p-3">
<h6 class="text-uppercase text-xs text-muted mb-2"> <h6 class="text-uppercase text-xs text-muted mb-2">
{% trans 'Cash Account' %}: {% trans 'Cash Account' %}:
<a href="{% url 'account_detail' bill.cash_account.uuid %}" <a href="{% url 'account_detail' request.dealer.slug bill.cash_account.uuid %}"
class="text-decoration-none ms-1"> class="text-decoration-none ms-1">
{{ bill.cash_account.code }} {{ bill.cash_account.code }}
</a> </a>
@ -80,7 +80,7 @@
<div class="border rounded p-3"> <div class="border rounded p-3">
<h6 class="text-uppercase text-xs text-muted mb-2"> <h6 class="text-uppercase text-xs text-muted mb-2">
{% trans 'Prepaid Account' %}: {% trans 'Prepaid Account' %}:
<a href="{% url 'account_detail' bill.prepaid_account.uuid %}" <a href="{% url 'account_detail' request.dealer.slug bill.prepaid_account.uuid %}"
class="text-decoration-none ms-1"> class="text-decoration-none ms-1">
{{ bill.prepaid_account.code }} {{ bill.prepaid_account.code }}
</a> </a>
@ -94,7 +94,7 @@
<div class="border rounded p-3"> <div class="border rounded p-3">
<h6 class="text-uppercase text-xs text-muted mb-2"> <h6 class="text-uppercase text-xs text-muted mb-2">
{% trans 'Accounts Payable' %}: {% trans 'Accounts Payable' %}:
<a href="{% url 'account_detail' bill.unearned_account.uuid %}" <a href="{% url 'account_detail' request.dealer.slug bill.unearned_account.uuid %}"
class="text-decoration-none ms-1"> class="text-decoration-none ms-1">
{{ bill.unearned_account.code }} {{ bill.unearned_account.code }}
</a> </a>
@ -185,7 +185,7 @@
<td class="align-items-start white-space-nowrap pe-2"> <td class="align-items-start white-space-nowrap pe-2">
{% if bill_item.po_model_id %} {% if bill_item.po_model_id %}
<a class="btn btn-sm btn-phoenix-primary" <a class="btn btn-sm btn-phoenix-primary"
href="{% url 'purchase_order_detail' bill_item.po_model_id %}"> href="{% url 'purchase_order_detail' request.dealer.slug bill_item.po_model_id %}">
{% trans 'View PO' %} {% trans 'View PO' %}
</a> </a>
{% endif %} {% endif %}

View File

@ -17,9 +17,9 @@
<div class="col-12"> <div class="col-12">
<div class="card mb-4"> <div class="card mb-4">
<div class="card-body"> <div class="card-body">
{% 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 %}
<form action="{% url 'bill-update' entity_slug=view.kwargs.entity_slug bill_pk=bill_model.uuid %}" method="post"> <form action="{% url 'bill-update' dealer_slug=request.dealer.slug entity_slug=view.kwargs.entity_slug bill_pk=bill_model.uuid %}" method="post">
{% csrf_token %} {% csrf_token %}
<div class="mb-3"> <div class="mb-3">
@ -30,12 +30,12 @@
<i class="fas fa-save me-2"></i>{% trans 'Save Bill' %} <i class="fas fa-save me-2"></i>{% trans 'Save Bill' %}
</button> </button>
<a href="{% url 'bill-detail' entity_slug=view.kwargs.entity_slug bill_pk=bill_model.uuid %}" <a href="{% url 'bill-detail' dealer_slug=request.dealer.slug entity_slug=view.kwargs.entity_slug bill_pk=bill_model.uuid %}"
class="btn btn-phoenix-secondary w-100 mb-2"> class="btn btn-phoenix-secondary w-100 mb-2">
<i class="fas fa-arrow-left me-2"></i>{% trans 'Back to Bill Detail' %} <i class="fas fa-arrow-left me-2"></i>{% trans 'Back to Bill Detail' %}
</a> </a>
<a href="{% url 'bill_list' %}" <a href="{% url 'bill_list' request.dealer.slug %}"
class="btn btn-phoenix-info w-100 mb-2"> class="btn btn-phoenix-info w-100 mb-2">
<i class="fas fa-list me-2"></i>{% trans 'Bill List' %} <i class="fas fa-list me-2"></i>{% trans 'Bill List' %}
</a> </a>

View File

@ -201,48 +201,48 @@
<div class="card-footer p-0"> <div class="card-footer p-0">
<div class="d-flex flex-wrap gap-2 mt-2"> <div class="d-flex flex-wrap gap-2 mt-2">
<!-- Update Button --> <!-- Update Button -->
<a href="{% url 'bill-update' entity_slug=entity_slug bill_pk=bill.uuid %}" class="btn btn-phoenix-primary"> <a href="{% url 'bill-update' dealer_slug=dealer_slug entity_slug=entity_slug bill_pk=bill.uuid %}" class="btn btn-phoenix-primary">
<i class="fas fa-edit me-2"></i>{% trans 'Update' %} <i class="fas fa-edit me-2"></i>{% trans 'Update' %}
</a> </a>
<!-- Mark as Draft --> <!-- Mark as Draft -->
{% if bill.can_draft %} {% if bill.can_draft %}
<button class="btn btn-phoenix-success" <button class="btn btn-phoenix-success"
onclick="showPOModal('Mark as Draft', '{% url 'bill-action-mark-as-draft' entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Draft')"> onclick="showPOModal('Mark as Draft', '{% url 'bill-action-mark-as-draft' dealer_slug=request.dealer.slug entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Draft')">
<i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Draft' %} <i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Draft' %}
</button> </button>
{% endif %} {% endif %}
<!-- Mark as Review --> <!-- Mark as Review -->
{% if bill.can_review %} {% if bill.can_review %}
<button class="btn btn-phoenix-warning" <button class="btn btn-phoenix-warning"
onclick="showPOModal('Mark as Review', '{% url 'bill-action-mark-as-review' entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Review')"> onclick="showPOModal('Mark as Review', '{% url 'bill-action-mark-as-review' dealer_slug=request.dealer.slug entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Review')">
<i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Review' %} <i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Review' %}
</button> </button>
{% endif %} {% endif %}
<!-- Mark as Approved --> <!-- Mark as Approved -->
{% if bill.can_approve %} {% if bill.can_approve %}
<button class="btn btn-phoenix-success" <button class="btn btn-phoenix-success"
onclick="showPOModal('Mark as Approved', '{% url 'bill-action-mark-as-approved' entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Approved')"> onclick="showPOModal('Mark as Approved', '{% url 'bill-action-mark-as-approved' dealer_slug=request.dealer.slug entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Approved')">
<i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Approved' %} <i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Approved' %}
</button> </button>
{% endif %} {% endif %}
<!-- Mark as Paid --> <!-- Mark as Paid -->
{% if bill.can_pay %} {% if bill.can_pay %}
<button class="btn btn-phoenix-success" <button class="btn btn-phoenix-success"
onclick="showPOModal('Mark as Paid', '{% url 'bill-action-mark-as-paid' entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Paid')"> onclick="showPOModal('Mark as Paid', '{% url 'bill-action-mark-as-paid' dealer_slug=request.dealer.slug entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Paid')">
<i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Paid' %} <i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Paid' %}
</button> </button>
{% endif %} {% endif %}
<!-- Void Button --> <!-- Void Button -->
{% if bill.can_void %} {% if bill.can_void %}
<button class="btn btn-phoenix-danger" <button class="btn btn-phoenix-danger"
onclick="showPOModal('Mark as Void', '{% url 'bill-action-mark-as-void' entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Void')"> onclick="showPOModal('Mark as Void', '{% url 'bill-action-mark-as-void' dealer_slug=request.dealer.slug entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Void')">
<i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Void' %} <i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Void' %}
</button> </button>
{% endif %} {% endif %}
<!-- Cancel Button --> <!-- Cancel Button -->
{% if bill.can_cancel %} {% if bill.can_cancel %}
<button class="btn btn-phoenix-danger" <button class="btn btn-phoenix-danger"
onclick="showPOModal('Mark as Canceled', '{% url 'bill-action-mark-as-canceled' entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Canceled')"> onclick="showPOModal('Mark as Canceled', '{% url 'bill-action-mark-as-canceled' dealer_slug=request.dealer.slug entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Canceled')">
<i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Canceled' %} <i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Canceled' %}
</button> </button>
{% modal_action_v2 bill bill.get_mark_as_canceled_url bill.get_mark_as_canceled_message bill.get_mark_as_canceled_html_id %} {% modal_action_v2 bill bill.get_mark_as_canceled_url bill.get_mark_as_canceled_message bill.get_mark_as_canceled_html_id %}

View File

@ -3,7 +3,7 @@
{% load django_ledger %} {% load django_ledger %}
{% load widget_tweaks %} {% load widget_tweaks %}
<form action="{% url 'bill-update-items' entity_slug=entity_slug bill_pk=bill_pk %}" method="post"> <form action="{% url 'bill-update-items' dealer_slug=dealer_slug entity_slug=entity_slug bill_pk=bill_pk %}" method="post">
<div class="container-fluid py-4"> <div class="container-fluid py-4">
<!-- Page Header --> <!-- Page Header -->
<div class="row mb-4"> <div class="row mb-4">
@ -72,7 +72,7 @@
{% currency_symbol %}{{ f.instance.po_total_amount | currency_format }} {% currency_symbol %}{{ f.instance.po_total_amount | currency_format }}
</span> </span>
<a class="btn btn-sm btn-phoenix-info mt-1" <a class="btn btn-sm btn-phoenix-info mt-1"
href="{% url 'purchase_order_detail' f.instance.po_model_id %}"> href="{% url 'purchase_order_detail' dealer_slug f.instance.po_model_id %}">
{% trans 'View PO' %} {% trans 'View PO' %}
</a> </a>
</div> </div>

View File

@ -27,7 +27,7 @@
</div> </div>
<div class="col-6 col-md-4 col-xxl-2 text-center border-translucent border-start-xxl border-end-xxl-0 border-bottom-xxl-0 border-end border-bottom pb-4 pb-xxl-0 "> <div class="col-6 col-md-4 col-xxl-2 text-center border-translucent border-start-xxl border-end-xxl-0 border-bottom-xxl-0 border-end border-bottom pb-4 pb-xxl-0 ">
<span class="uil fs-5 lh-1 uil-bill text-info"></span> <span class="uil fs-5 lh-1 uil-bill text-info"></span>
<a href="{% url 'invoice_list' %}"><h4 class="fs-6 pt-3">{{ invoices }}</h4></a> <a href="{% url 'invoice_list' request.dealer.slug %}"><h4 class="fs-6 pt-3">{{ invoices }}</h4></a>
<p class="fs-9 mb-0">{{ _("Invoices")}}</p> <p class="fs-9 mb-0">{{ _("Invoices")}}</p>
</div> </div>
<div class="col-6 col-md-4 col-xxl-2 text-center border-translucent border-start-xxl border-end-xxl-0 border-bottom-xxl-0 border-end border-bottom pb-4 pb-xxl-0 "> <div class="col-6 col-md-4 col-xxl-2 text-center border-translucent border-start-xxl border-end-xxl-0 border-bottom-xxl-0 border-end border-bottom pb-4 pb-xxl-0 ">

View File

@ -43,6 +43,6 @@
<div class="error-page"> <div class="error-page">
<h1 class="error-code">{% trans "400" %}</h1> <h1 class="error-code">{% trans "400" %}</h1>
<p class="error-message">{% trans "Bad Request" %}</p> <p class="error-message">{% trans "Bad Request" %}</p>
<a href="{% url 'inventory_stats' %}" class="error-button">{% trans "Go Back" %}</a> <a href="{% url 'inventory_stats' request.dealer.slug %}" class="error-button">{% trans "Go Back" %}</a>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -22,44 +22,44 @@
<li class="collapsed-nav-item-title d-none">{% trans "Inventory"|capfirst %}</li> <li class="collapsed-nav-item-title d-none">{% trans "Inventory"|capfirst %}</li>
{% if perms.inventory.add_car %} {% if perms.inventory.add_car %}
<li class="nav-item"> <li class="nav-item">
<a id="btn-add-car" class="nav-link btn-add-car" href="{% url 'car_add' %}"> <a id="btn-add-car" class="nav-link btn-add-car" href="{% url 'car_add' request.dealer.slug %}">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-plus-circle"></span></span><span class="nav-link-text">{% trans "add car"|capfirst %}</span> <span class="nav-link-icon"><span class="fas fa-plus-circle"></span></span><span class="nav-link-text">{% trans "add car"|capfirst %}</span>
</div> </div>
</a> </a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'inventory_item_create' %}"> <a class="nav-link" href="{% url 'inventory_item_create' request.dealer.slug %}">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-plus-circle"></span></span><span class="nav-link-text">{% trans "add invenotry item"|capfirst %}</span> <span class="nav-link-icon"><span class="fas fa-plus-circle"></span></span><span class="nav-link-text">{% trans "add invenotry item"|capfirst %}</span>
</div> </div>
</a> </a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'purchase_order_list' %}"> <a class="nav-link" href="{% url 'purchase_order_list' request.dealer.slug %}">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-warehouse"></span></span><span class="nav-link-text">{% trans "purchase Orders"|capfirst %}</span> <span class="nav-link-icon"><span class="fas fa-warehouse"></span></span><span class="nav-link-text">{% trans "purchase Orders"|capfirst %}</span>
</div> </div>
</a> </a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'upload_cars' %}"> <a class="nav-link" href="{% url 'upload_cars' request.dealer.slug %}">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-file-invoice"></span></span><span class="nav-link-text">{% trans "Upload Cars"|capfirst %}</span> <span class="nav-link-icon"><span class="fas fa-file-import"></span></span><span class="nav-link-text">{% trans "Bulk Upload"|capfirst %}</span>
</div> </div>
</a> </a>
</li> </li>
{% endif %} {% endif %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'inventory_stats' %}"> <a class="nav-link" href="{% url 'inventory_stats' request.dealer.slug %}">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-car-side"></span></span><span class="nav-link-text">{% trans 'Cars'|capfirst %}</span> <span class="nav-link-icon"><span class="fas fa-car-side"></span></span><span class="nav-link-text">{% trans 'Cars'|capfirst %}</span>
</div> </div>
</a> </a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'car_list' %}"> <a class="nav-link" href="{% url 'car_list' request.dealer.slug %}">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-car-side"></span></span><span class="nav-link-text">{% trans 'Stock'|capfirst %}</span> <span class="nav-link-icon"><span class="fas fa-car-side"></span></span><span class="nav-link-text">{% trans 'Stock'|capfirst %}</span>
</div> </div>
@ -82,7 +82,7 @@
<li class="collapsed-nav-item-title d-none">{% trans 'sales'|capfirst %}</li> <li class="collapsed-nav-item-title d-none">{% trans 'sales'|capfirst %}</li>
{% if perms.django_ledger.add_estimatemodel %} {% if perms.django_ledger.add_estimatemodel %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'estimate_create' %}"> <a class="nav-link" href="{% url 'estimate_create' request.dealer.slug %}">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-list-ul"></span></span><span class="nav-link-text">{% trans "create quotation"|capfirst %}</span> <span class="nav-link-icon"><span class="fas fa-list-ul"></span></span><span class="nav-link-text">{% trans "create quotation"|capfirst %}</span>
</div> </div>
@ -91,7 +91,7 @@
{% endif %} {% endif %}
{% if perms.django_ledger.view_estimatemodel %} {% if perms.django_ledger.view_estimatemodel %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'estimate_list' %}"> <a class="nav-link" href="{% url 'estimate_list' request.dealer.slug %}">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-clipboard-list"></span></span><span class="nav-link-text">{% trans "quotations"|capfirst %}</span> <span class="nav-link-icon"><span class="fas fa-clipboard-list"></span></span><span class="nav-link-text">{% trans "quotations"|capfirst %}</span>
</div> </div>
@ -101,7 +101,7 @@
{% if perms.django_ledger.view_invoicemodel %} {% if perms.django_ledger.view_invoicemodel %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'invoice_list' %}"> <a class="nav-link" href="{% url 'invoice_list' request.dealer.slug %}">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-file-invoice"></span></span><span class="nav-link-text">{% trans "invoices"|capfirst %}</span> <span class="nav-link-icon"><span class="fas fa-file-invoice"></span></span><span class="nav-link-text">{% trans "invoices"|capfirst %}</span>
</div> </div>
@ -110,7 +110,7 @@
{% endif %} {% endif %}
{% if perms.django_ledger.view_journalentrymodel %} {% if perms.django_ledger.view_journalentrymodel %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'payment_list' %}"> <a class="nav-link" href="{% url 'payment_list' request.dealer.slug %}">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-money-check"></span></span><span class="nav-link-text">{% trans "payments"|capfirst %}</span> <span class="nav-link-icon"><span class="fas fa-money-check"></span></span><span class="nav-link-text">{% trans "payments"|capfirst %}</span>
</div> </div>
@ -212,7 +212,7 @@
<li class="collapsed-nav-item-title d-none">{% trans 'Financials' %}</li> <li class="collapsed-nav-item-title d-none">{% trans 'Financials' %}</li>
{% if perms.django_ledger.view_accountmodel %} {% if perms.django_ledger.view_accountmodel %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'account_list' %}"> <a class="nav-link" href="{% url 'account_list' request.dealer.slug %}">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-book-open"></span></span><span class="nav-link-text">{% trans 'Chart of Accounts'|capfirst %}</span> <span class="nav-link-icon"><span class="fas fa-book-open"></span></span><span class="nav-link-text">{% trans 'Chart of Accounts'|capfirst %}</span>
</div> </div>
@ -221,7 +221,7 @@
{% endif %} {% endif %}
{% if perms.django_ledger.view_bankaccountmodel %} {% if perms.django_ledger.view_bankaccountmodel %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'bank_account_list' %}"> <a class="nav-link" href="{% url 'bank_account_list' request.dealer.slug %}">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span class="nav-link-icon"><span data-feather="credit-card"></span></span><span class="nav-link-text">{% trans 'Bank Accounts'|capfirst %}</span> <span class="nav-link-icon"><span data-feather="credit-card"></span></span><span class="nav-link-text">{% trans 'Bank Accounts'|capfirst %}</span>
</div> </div>
@ -264,7 +264,7 @@
{% endif %} {% endif %}
{% if perms.django_ledger.view_billmodel %} {% if perms.django_ledger.view_billmodel %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'bill_list' %}"> <a class="nav-link" href="{% url 'bill_list' request.dealer.slug %}">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fa-solid fa-money-bills"></span></span><span class="nav-link-text">{% trans 'bills'|capfirst %}</span> <span class="nav-link-icon"><span class="fa-solid fa-money-bills"></span></span><span class="nav-link-text">{% trans 'bills'|capfirst %}</span>
</div> </div>
@ -362,7 +362,7 @@
aria-label="Toggle Navigation"> aria-label="Toggle Navigation">
<span class="navbar-toggle-icon"><span class="toggle-line"></span></span> <span class="navbar-toggle-icon"><span class="toggle-line"></span></span>
</button> </button>
<a class="navbar-brand me-1 me-sm-3" href="{% url 'home' %}"> <a class="navbar-brand me-1 me-sm-3" href="{% url 'home' request.dealer.slug %}">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<img class="logo-img d-dark-none" src="{% static 'images/logos/logo-d.png' %}" alt="haikal" width="27" /> <img class="logo-img d-dark-none" src="{% static 'images/logos/logo-d.png' %}" alt="haikal" width="27" />
<img class="logo-img d-light-none" src="{% static 'images/logos/logo.png' %}" alt="haikal" width="27" /> <img class="logo-img d-light-none" src="{% static 'images/logos/logo.png' %}" alt="haikal" width="27" />

View File

@ -15,5 +15,4 @@
</div> </div>
</div> </div>
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View File

@ -2,7 +2,7 @@
{% load crispy_forms_filters %} {% load crispy_forms_filters %}
<form method="post" <form method="post"
id="customCardForm" id="customCardForm"
action="{% url 'add_custom_card' car.slug %}"> action="{% url 'add_custom_card' request.dealer.slug car.slug %}">
{% csrf_token %} {% csrf_token %}
{{ form|crispy }} {{ form|crispy }}
<div class="d-flex gap-1"> <div class="d-flex gap-1">

View File

@ -163,10 +163,14 @@
<tr> <tr>
<th>{% trans "Custom Card" %}</th> <th>{% trans "Custom Card" %}</th>
<td> <td>
<button type="button" <button type="button"
class="btn btn-sm btn-phoenix-success" class="btn btn-sm btn-phoenix-success"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#customCardModal">{% trans 'Add' %}</button> data-bs-target="#mainModal"
hx-get="{% url 'add_custom_card' request.dealer.slug car.slug %}"
hx-target=".main-modal-body"
hx-swap="innerHTML"
>{% trans 'Add' %}</button>
</td> </td>
</tr> </tr>
{% endif %} {% endif %}
@ -188,7 +192,12 @@
<button type="button" <button type="button"
class="btn btn-sm btn-phoenix-success" class="btn btn-sm btn-phoenix-success"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#registrationModal">{% trans 'Add' %}</button> data-bs-target="#mainModal"
hx-get="{% url 'add_registration' request.dealer.slug car.slug %}"
hx-target=".main-modal-body"
hx-swap="innerHTML"
>{% trans 'Add' %}</button>
</td> </td>
</tr> </tr>
{% endif %} {% endif %}
@ -219,7 +228,7 @@
<div> <div>
{% if not car.get_transfer %} {% if not car.get_transfer %}
{% if perms.inventory.change_car %} {% if perms.inventory.change_car %}
<a href="{% url 'car_update' car.slug %}" <a href="{% url 'car_update' request.dealer.slug car.slug %}"
class="btn btn-phoenix-warning btn-sm mt-1">{% trans "Edit" %}</a> class="btn btn-phoenix-warning btn-sm mt-1">{% trans "Edit" %}</a>
<a href="{% url 'transfer' car.slug %}" <a href="{% url 'transfer' car.slug %}"
class="btn btn-phoenix-danger btn-sm"> class="btn btn-phoenix-danger btn-sm">
@ -277,7 +286,7 @@
<tr> <tr>
<td colspan="2"> <td colspan="2">
{% if not car.get_transfer %} {% if not car.get_transfer %}
<a href="{% url 'car_finance_update' car.finances.pk %}" <a href="{% url 'car_finance_update' request.dealer.slug car.finances.pk %}"
class="btn btn-phoenix-warning btn-sm mb-3">{% trans "Edit" %}</a> class="btn btn-phoenix-warning btn-sm mb-3">{% trans "Edit" %}</a>
{% else %} {% else %}
<span class="badge bg-danger">{% trans "Cannot Edit, Car in Transfer." %}</span> <span class="badge bg-danger">{% trans "Cannot Edit, Car in Transfer." %}</span>
@ -285,7 +294,7 @@
{% else %} {% else %}
<p>{% trans "No finance details available." %}</p> <p>{% trans "No finance details available." %}</p>
{% if perms.inventory.add_carfinance %} {% if perms.inventory.add_carfinance %}
<a href="{% url 'car_finance_create' car.slug %}" <a href="{% url 'car_finance_create' request.dealer.slug car.slug %}"
class="btn btn-phoenix-success btn-sm mb-3">{% trans "Add" %}</a> class="btn btn-phoenix-success btn-sm mb-3">{% trans "Add" %}</a>
{% endif %} {% endif %}
</td> </td>
@ -327,7 +336,7 @@
<tr> <tr>
<td colspan="2"> <td colspan="2">
{% if not car.get_transfer %} {% if not car.get_transfer %}
<a href="{% url 'car_colors_update' car.slug %}" <a href="{% url 'car_colors_update' request.dealer.slug car.slug %}"
class="btn btn-phoenix-warning btn-sm mb-3">{% trans "Edit" %}</a> class="btn btn-phoenix-warning btn-sm mb-3">{% trans "Edit" %}</a>
{% else %} {% else %}
<span class="badge bg-danger">{% trans "Cannot Edit, Car in Transfer." %}</span> <span class="badge bg-danger">{% trans "Cannot Edit, Car in Transfer." %}</span>
@ -340,7 +349,7 @@
<td colspan="2"> <td colspan="2">
<p>{% trans "No color details available." %}</p> <p>{% trans "No color details available." %}</p>
{% if perms.inventory.add_carcolors %} {% if perms.inventory.add_carcolors %}
<a class="btn btn-phoenix-success btn-sm mb-3" href="{% url 'add_color' car.slug %}">{{ _("Add Color") }}</a> <a class="btn btn-phoenix-success btn-sm mb-3" href="{% url 'add_color' request.dealer.slug car.slug %}">{{ _("Add Color") }}</a>
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
@ -372,7 +381,7 @@
<td>{{ reservation.reserved_until }}</td> <td>{{ reservation.reserved_until }}</td>
<td> <td>
{% if reservation.is_active %} {% if reservation.is_active %}
<form method="post" action="{% url 'reservations' reservation.id %}"> <form method="post" action="{% url 'reservations' request.dealer.slug reservation.id %}">
{% csrf_token %} {% csrf_token %}
<div class="btn-group"> <div class="btn-group">
<button type="submit" <button type="submit"
@ -495,22 +504,22 @@
</div> </div>
</div> </div>
</div> </div>
<!-- Registration Modal --> <!-- Main Modal -->
<div class="modal fade" <div class="modal fade"
id="registrationModal" id="mainModal"
tabindex="-1" tabindex="-1"
aria-labelledby="registrationModalLabel" aria-labelledby="mainModalLabel"
aria-hidden="true"> aria-hidden="true">
<div class="modal-dialog modal-sm"> <div class="modal-dialog modal-sm">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title" id="registrationModalLabel">{% trans 'Registration' %}</h5> <h5 class="modal-title" id="mainModalLabel">{% trans 'Registration' %}</h5>
<button type="button" <button type="button"
class="btn-close" class="btn-close"
data-bs-dismiss="modal" data-bs-dismiss="modal"
aria-label="Close"></button> aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="main-modal-body" style="padding: 20px;">
<!-- Content will be loaded here via AJAX --> <!-- Content will be loaded here via AJAX -->
</div> </div>
</div> </div>
@ -532,7 +541,7 @@
aria-label="Close"></button> aria-label="Close"></button>
</div> </div>
<div class="modal-body">{% trans 'Are you sure you want to reserve this car?' %}</div> <div class="modal-body">{% trans 'Are you sure you want to reserve this car?' %}</div>
<form method="POST" action="{% url 'reserve_car' car.slug %}" class="form "> <form method="POST" action="{% url 'reserve_car' request.dealer.slug car.slug %}" class="form">
{% csrf_token %} {% csrf_token %}
<div class="p-1"> <div class="p-1">
<div class="d-flex gap-1"> <div class="d-flex gap-1">
@ -577,52 +586,11 @@
<script> <script>
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
const csrftoken = getCookie("csrftoken"); const csrftoken = getCookie("csrftoken");
const ajaxUrl = "{% url 'ajax_handler' %}"; const ajaxUrl = "{% url 'ajax_handler' request.dealer.slug %}";
const customCardModal = document.getElementById("customCardModal");
const modalBody = customCardModal.querySelector(".modal-body"); const modalBody = customCardModal.querySelector(".modal-body");
// When the modal is triggered, load the form
customCardModal.addEventListener("show.bs.modal", function () {
const url = "{% url 'add_custom_card' car.slug %}";
fetch(url)
.then((response) => response.text())
.then((html) => {
modalBody.innerHTML = html;
})
.catch((error) => {
modalBody.innerHTML = '<p class="text-danger">Error loading form. Please try again later.</p>';
console.error("Error loading form:", error);
});
});
customCardModal.addEventListener("hidden.bs.modal", function () {
modalBody.innerHTML = "";
});
const registrationModal = document.getElementById("registrationModal");
const modalBody_r = registrationModal.querySelector(".modal-body");
// When the modal is triggered, load the form
registrationModal.addEventListener("show.bs.modal", function () {
const url = "{% url 'add_registration' car.slug %}";
fetch(url)
.then((response) => response.text())
.then((html) => {
modalBody_r.innerHTML = html;
})
.catch((error) => {
modalBody_r.innerHTML = '<p class="text-danger">{{_("Error loading form. Please try again later")}}.</p>';
console.error("Error loading form:", error);
});
});
registrationModal.addEventListener("hidden.bs.modal", function () {
modalBody_r.innerHTML = "";
});
const showSpecificationButton = document.getElementById("specification-btn"); const showSpecificationButton = document.getElementById("specification-btn");
const specificationsContent = document.getElementById("specificationsContent"); const specificationsContent = document.getElementById("specificationsContent");
@ -689,7 +657,7 @@
document.querySelectorAll(".reserve-btn").forEach((button) => { document.querySelectorAll(".reserve-btn").forEach((button) => {
button.addEventListener("click", async function () { button.addEventListener("click", async function () {
try { try {
const response = await fetch(`{% url 'reserve_car' car.slug %}`, { const response = await fetch(`{% url 'reserve_car' request.dealer.slug car.slug %}`, {
method: "POST", method: "POST",
headers: { headers: {
"X-CSRFToken": csrfToken, "X-CSRFToken": csrfToken,

View File

@ -29,13 +29,6 @@
{{ form|crispy }} {{ form|crispy }}
</div> </div>
</div> </div>
{% comment %} <div class="row g-1">
<div class="btn-group">
<button type="submit" class="btn btn-sm btn-success me-1"><i class="fa-solid fa-floppy-disk"></i>{% trans "Save" %}</button>
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban"></i>{% trans "Cancel" %}</a>
</div>
</div> {% endcomment %}
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
<button class="btn btn-sm btn-phoenix-success me-2" type="submit"> <button class="btn btn-sm btn-phoenix-success me-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i> <i class="fa-solid fa-floppy-disk me-1"></i>

View File

@ -346,7 +346,7 @@
const optionsContent = document.getElementById("optionsContent") const optionsContent = document.getElementById("optionsContent")
const generationContainer = document.getElementById("generation-div") const generationContainer = document.getElementById("generation-div")
const ajaxUrl = "{% url 'ajax_handler' %}"; const ajaxUrl = "{% url 'ajax_handler' request.dealer.slug %}";
const closeButton = document.querySelector(".btn-close"); const closeButton = document.querySelector(".btn-close");
const scanVinBtn = document.getElementById("scan-vin-btn"); const scanVinBtn = document.getElementById("scan-vin-btn");

View File

@ -330,7 +330,7 @@
const optionsContent = document.getElementById("optionsContent") const optionsContent = document.getElementById("optionsContent")
const generationContainer = document.getElementById("generation-div") const generationContainer = document.getElementById("generation-div")
const ajaxUrl = "{% url 'ajax_handler' %}"; const ajaxUrl = "{% url 'ajax_handler' request.dealer.slug %}";
const closeButton = document.querySelector(".btn-close"); const closeButton = document.querySelector(".btn-close");
const scanVinBtn = document.getElementById("scan-vin-btn"); const scanVinBtn = document.getElementById("scan-vin-btn");

View File

@ -93,7 +93,7 @@
{% endif %} {% endif %}
</td> </td>
<td class="align-middle white-space-nowrap text-start"> <td class="align-middle white-space-nowrap text-start">
<a class="fs-9 fw-bold" href="{% url 'car_detail' car.slug %}">{{ car.vin }}</a> <a class="fs-9 fw-bold" href="{% url 'car_detail' request.dealer.slug car.slug %}">{{ car.vin }}</a>
</td> </td>
<td class="align-middle white-space-nowrap text-center fw-bold">{{ car.year }}</td> <td class="align-middle white-space-nowrap text-center fw-bold">{{ car.year }}</td>
{% if car.colors %} {% if car.colors %}
@ -147,14 +147,14 @@
</td> </td>
<td class="align-middle white-space-nowrap text-end pe-0 ps-4"> <td class="align-middle white-space-nowrap text-end pe-0 ps-4">
<a class="btn btn-sm btn-phoenix-success" <a class="btn btn-sm btn-phoenix-success"
href="{% url 'car_detail' car.slug %}">{% trans "view"|capfirst %}</a> href="{% url 'car_detail' request.dealer.slug car.slug %}">{% trans "view"|capfirst %}</a>
</td> </td>
</tr> </tr>
{% empty %} {% empty %}
<tr> <tr>
<td colspan="7" class="d-flex flex-column align-items-center"> <td colspan="7" class="d-flex flex-column align-items-center">
<p class="text-muted">{% trans "No cars available." %}</p> <p class="text-muted">{% trans "No cars available." %}</p>
<a href="{% url 'add_car' %}" class="btn btn-phoenix-primary">{% trans "Add a Car" %}</a> <a href="{% url 'add_car' request.dealer.slug %}" class="btn btn-phoenix-primary">{% trans "Add a Car" %}</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@ -44,19 +44,19 @@
hx-on::before-request="on_before_request()" hx-on::before-request="on_before_request()"
hx-on::after-request="on_after_request()"> hx-on::after-request="on_after_request()">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link px-2 py-1 active" aria-current="page" href="{% url 'car_list' %}"><span>{{ _("All") }}</span><span class="text-body-tertiary fw-semibold">({{ stats.all }})</span></a> <a class="nav-link px-2 py-1 active" aria-current="page" href="{% url 'car_list' request.dealer.slug %}"><span>{{ _("All") }}</span><span class="text-body-tertiary fw-semibold">({{ stats.all }})</span></a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link px-2 py-1" href="{% url 'car_list' %}?status=available"><span>{{ _("Available") }}</span><span class="text-body-tertiary fw-semibold">({{ stats.available }})</span></a> <a class="nav-link px-2 py-1" href="{% url 'car_list' request.dealer.slug %}?status=available"><span>{{ _("Available") }}</span><span class="text-body-tertiary fw-semibold">({{ stats.available }})</span></a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link px-2 py-1" href="{% url 'car_list' %}?status=reserved"><span>{{ _("Reserved") }}</span><span class="text-body-tertiary fw-semibold">({{ stats.reserved }})</span></a> <a class="nav-link px-2 py-1" href="{% url 'car_list' request.dealer.slug %}?status=reserved"><span>{{ _("Reserved") }}</span><span class="text-body-tertiary fw-semibold">({{ stats.reserved }})</span></a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link px-2 py-1" href="{% url 'car_list' %}?status=transfer"><span>{{ _("Transfer") }}</span><span class="text-body-tertiary fw-semibold">({{ stats.transfer }})</span></a> <a class="nav-link px-2 py-1" href="{% url 'car_list' request.dealer.slug %}?status=transfer"><span>{{ _("Transfer") }}</span><span class="text-body-tertiary fw-semibold">({{ stats.transfer }})</span></a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link px-2 py-1" href="{% url 'car_list' %}?status=sold"><span>{{ _("Sold") }}</span><span class="text-body-tertiary fw-semibold">({{ stats.sold }})</span></a> <a class="nav-link px-2 py-1" href="{% url 'car_list' request.dealer.slug %}?status=sold"><span>{{ _("Sold") }}</span><span class="text-body-tertiary fw-semibold">({{ stats.sold }})</span></a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<button hx-on:click="toggle_filter()" class="btn btn-sm btn-phoenix-primary px-2 py-1"> <button hx-on:click="toggle_filter()" class="btn btn-sm btn-phoenix-primary px-2 py-1">
@ -88,7 +88,7 @@
type="search" type="search"
placeholder="Search" placeholder="Search"
aria-label="Search" aria-label="Search"
hx-get="{% url 'car_list' %}" hx-get="{% url 'car_list' request.dealer.slug %}"
hx-trigger="keyup changed delay:500ms" hx-trigger="keyup changed delay:500ms"
hx-target=".table-responsive" hx-target=".table-responsive"
hx-select=".table-responsive" hx-select=".table-responsive"
@ -106,7 +106,7 @@
<div class="row"> <div class="row">
<div class="d-flex align-items-center d-none filter"> <div class="d-flex align-items-center d-none filter">
<select <select
hx-get="{% url 'car_list' %}" hx-get="{% url 'car_list' request.dealer.slug %}"
name="make" name="make"
hx-target=".model-select" hx-target=".model-select"
hx-select=".model-select" hx-select=".model-select"
@ -122,7 +122,7 @@
{% endfor %} {% endfor %}
</select> </select>
<select <select
hx-get="{% url 'car_list' %}" hx-get="{% url 'car_list' request.dealer.slug %}"
hx-include=".make" hx-include=".make"
name="model" name="model"
hx-target=".year" hx-target=".year"
@ -153,7 +153,7 @@
</select> </select>
<button <button
id="search" id="search"
hx-get="{% url 'car_list' %}" hx-get="{% url 'car_list' request.dealer.slug %}"
hx-include=".make,.model,.year,.car_status" hx-include=".make,.model,.year,.car_status"
hx-indicator=".htmx-indicator" hx-indicator=".htmx-indicator"
hx-target=".table-responsive" hx-target=".table-responsive"
@ -177,121 +177,119 @@
hx-swap="innerHTML show:window:top" hx-swap="innerHTML show:window:top"
hx-indicator=".htmx-indicator" hx-indicator=".htmx-indicator"
hx-on::before-request="on_before_request()" hx-on::before-request="on_before_request()"
hx-on::after-request="on_after_request()"> hx-on::after-request="on_after_request()"></div>
</div> <div class="w-100 list table-responsive" >
<table class="table fs-9 mb-0 border-top border-translucent"> <div class="form-check">
<thead> <input class="form-check-input ms-4" type="checkbox" id="select-all" /> <span class="ms-1 text-body-tertiary">{{ _("Select All") }}</span>
<tr> </div>
<th class="sort white-space-nowrap align-middle" scope="col"> {% for car in cars %}
<div class="form-check"> <div class="card border mb-3 py-0 px-0" id="project-list-table-body">
<input class="form-check-input" type="checkbox" id="select-all" /> <div class="card-body">
</div> <div class="row align-items-center">
</th> <div class="col-auto">
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("VIN") }}</th> <div class="form-check">
<th class="sort white-space-nowrap align-middle" scope="col" data-sort="make">{{ _("Make") }}</th> <input class="form-check-input car-checkbox" type="checkbox" name="car" value="{{ car.pk }}" id="car-{{car.pk}}" />
<th class="sort white-space-nowrap align-middle" scope="col" data-sort="model">{{ _("Model") }}</th>
<th class="sort white-space-nowrap align-middle" scope="col" data-sort="year">{{ _("Year") }}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Trim") }}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Color") }}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Date Received") }}</th>
<th class="sort white-space-nowrap align-middle" scope="col" data-sort="car_status">{{ _("Status") }}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{{ _("Inventory Ready") }}</th>
<th class="sort white-space-nowrap align-middle" scope="col"></th>
</tr>
</thead>
<tbody class="list" id="project-list-table-body">
{% for car in cars %}
<tr class="position-static">
<td class="align-middle time white-space-nowrap">
<div class="form-check">
<input class="form-check-input car-checkbox"
type="checkbox"
name="car"
value="{{ car.pk }}"
id="car-{{car.pk}}" />
</div>
</td>
<td class="align-middle white-space-nowrap assignees">
<a class="fw-bold" href="{% url 'car_detail' car.slug %}">{{ car.vin }}</a>
</td>
<td class="align-middle white-space-nowrap make">
<p class="mb-0 fs-9 text-body">{{ car.id_car_make.get_local_name|default:car.id_car_make.name }}</p>
</td>
<td class="align-middle white-space-nowrap model">
<p class="mb-0 fs-9 text-body">{{ car.id_car_model.get_local_name|default:car.id_car_model.name }}</p>
</td>
<td class="align-middle white-space-nowrap year">
<p class="fw-bo text-body fs-9 mb-0">{{ car.year }}</p>
</td>
<td class="align-middle white-space-nowrap">
<p class="text-body-secondary fs-10 mb-0">{{ car.id_car_trim }}</p>
</td>
<td class="align-middle white-space-nowrap">
<div class="d-flex flex-row align-items-center">
<div class="d-flex flex-column align-items-center">
<span class="color-div"
style="background: linear-gradient(90deg, rgba({{ car.colors.exterior.rgb }},1) 10%, rgba({{ car.colors.exterior.rgb }},0.10) 100%)"
title="{{ car.colors.exterior.get_local_name }}"></span><span>{{ car.colors.exterior.get_local_name }}</span>
</div>
<div class="d-flex flex-column align-items-center">
<span class="color-div"
style="background: linear-gradient(90deg, rgba({{ car.colors.interior.rgb }},1) 10%, rgba({{ car.colors.interior.rgb }},0.10) 100%)"
title="{{ car.colors.interior.get_local_name }}"></span><span>{{ car.colors.interior.get_local_name }}</span>
</div>
</div>
</td>
<td class="align-middle white-space-nowrap">
<p class="fw-bold text-body mb-0">{{ car.receiving_date|naturalday|capfirst }}</p>
</td>
<td class="align-middle white-space-nowrap statuses">
{% if car.status == "available" %}
<span class="badge badge-phoenix fs-11 badge-phoenix-success">{{ _("Available") }}</span>
{% elif car.status == "reserved" %}
<span class="badge badge-phoenix fs-11 badge-phoenix-danger">{{ _("Reserved") }}</span>
{% elif car.status == "sold" %}
<span class="badge badge-phoenix fs-11 badge-phoenix-info">{{ _("Sold") }}</span>
{% elif car.status == "transfer" %}
<span class="badge badge-phoenix fs-11 badge-phoenix-warning">{{ _("Transfer") }}</span>
{% endif %}
</td>
<td class="align-middle white-space-nowrap">
{% if not car.ready %}
<span class="text-danger"> {{ _("NO") }} </span>
{%else%}
<span class="text-success"> {{ _("YES") }} </span>
{%endif%}
</td>
<td class="align-middle text-end white-space-nowrap pe-0 action">
<div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10"
type="button"
data-bs-toggle="dropdown"
data-boundary="window"
aria-haspopup="true"
aria-expanded="false"
data-bs-reference="parent">
<span class="fas fa-ellipsis-h fs-10"></span>
</button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a class="dropdown-item" href="{% url 'car_detail' car.slug %}">{{ _("View") }}</a>
<a class="dropdown-item" href="#!">{{ _("Export") }}</a>
</div>
</div>
</td>
</tr>
{% empty %}
<div class="col-12">
<div class="text-center py-5">
<div class="text-body-secondary">
<i class="fas fa-car fa-4x mb-3 opacity-50"></i>
<h4 class="text-body-secondary">{{ _("No vehicles found") }}</h4>
<p class="text-body-tertiary">{{ _("Try adjusting your search criteria or filters") }}</p>
</div>
</div>
</div> </div>
{% endfor %} </div>
</tbody> <!-- Vehicle Image/Icon -->
</table> <div class="col-auto">
<div class="avatar avatar-3xl">
<img class="rounded-soft shadow shadow-lg" src="{% static 'images/cars/' %}{{ car.vin }}.png" alt="{{ car.vin }}" />
</div>
</div>
<!-- Vehicle Details -->
<div class="col">
<div class="row">
<!-- Make/Model/Specs -->
<div class="col-md-4">
<h5 class="text-body-emphasis fw-bold">{{ car.year }}</h5>
<p class="text-body-emphasis fw-bold">
<a href="{% url 'car_detail' request.dealer.slug car.slug %}" class="text-decoration-none text-body-emphasis">
{{ car.id_car_make.get_local_name }}
</a>
<small>{{ car.id_car_model.get_local_name }}</small>
</p>
<small class="text-body-secondary" dir="ltr">
{{ car.id_car_trim }}
</small>
</div>
<!-- Color and Date -->
<div class="col-md-3">
<p class="text-body mb-1">
{{ car.colors.exterior.get_local_name }}
</p>
<small class="text-body-secondary">
{{ car.receiving_date|naturalday|capfirst }}
</small>
</div>
<!-- Status Badge -->
<div class="col-md-3">
{% if car.status == "available" %}
<span class="badge badge-phoenix fs-10 badge-phoenix-success text-uppercase px-3 py-2">{{ _("Available") }}</span>
{% elif car.status == "reserved" %}
<span class="badge badge-phoenix fs-10 badge-phoenix-warning text-uppercase px-3 py-2">{{ _("Reserved") }}</span>
{% elif car.status == "sold" %}
<span class="badge badge-phoenix fs-10 badge-phoenix-danger text-uppercase px-3 py-2">{{ _("Sold") }}</span>
{% elif car.status == "transfer" %}
<span class="badge badge-phoenix fs-10 badge-phoenix-info text-uppercase px-3 py-2">{{ _("Transfer") }}</span>
{% endif %}
</div>
<!-- Ready Status -->
<div class="col-md-2">
<div class="d-flex align-items-center">
<span class="fs-10 fw-light me-2">{{ _("Inventory Ready") }}</span>
{% if car.ready %}
<span class="badge bg-success rounded-circle p-1 me-2">
<span class="visually-hidden">Ready</span>
</span>
<span class="text-success fw-bold">{{ _("Yes") }}</span>
{% else %}
<span class="badge bg-danger rounded-circle p-1 me-2">
<span class="visually-hidden">Not Ready</span>
</span>
<span class="text-danger fw-bold">{{ _("No") }}</span>
{% endif %}
</div>
</div>
</div>
</div>
<!-- Action Menu -->
<div class="col-auto">
<div class="btn-reveal-trigger position-static">
<button
class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10"
type="button"
data-bs-toggle="dropdown"
data-boundary="window"
aria-haspopup="true"
aria-expanded="false"
data-bs-reference="parent">
<span class="fas fa-ellipsis-h fs-10"></span>
</button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a class="dropdown-item" href="{% url 'car_detail' request.dealer.slug car.slug %}"> <span class="fas fa-eye me-2"></span>{{ _("View") }} </a>
<a class="dropdown-item" href="{% url 'car_update' request.dealer.slug car.slug %}"> <span class="fas fa-edit me-2"></span>{{ _("Edit") }} </a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger" href="{% url 'car_delete' request.dealer.slug car.slug %}"> <span class="fas fa-trash me-2"></span>{{ _("Remove") }} </a>
</div>
</div>
</div>
</div>
</div>
</div>
{% empty %}
<div class="text-center py-5">
<div class="text-body-secondary">
<span class="fas fa-car fa-4x mb-3 opacity-50"></span>
<h4 class="text-body-secondary">{{ _("No vehicles found") }}</h4>
<p class="text-body-tertiary">{{ _("Try adjusting your search criteria or filters") }}</p>
</div>
</div>
{% endfor %}
</div> </div>
</div> </div>
{% if page_obj.paginator.num_pages > 1 %} {% if page_obj.paginator.num_pages > 1 %}

View File

@ -3,7 +3,7 @@
<div class="w-100 g-3"> <div class="w-100 g-3">
<form method="post" <form method="post"
id="registrationForm" id="registrationForm"
action="{% url 'add_registration' car.slug %}"> action="{% url 'add_registration' request.dealer.slug car.slug %}">
{% csrf_token %} {% csrf_token %}
{{ form|crispy }} {{ form|crispy }}
<div class="d-flex gap-1"> <div class="d-flex gap-1">

View File

@ -67,7 +67,7 @@
<ul> <ul>
{% for trim in model.trims %} {% for trim in model.trims %}
<li> <li>
<a href="{% url 'car_inventory' make_id=make.slug model_id=model.slug trim_id=trim.slug %}">{{ trim.trim_name }}</a>&nbsp;-&nbsp;{% trans "Total" %}: <a href="{% url 'car_inventory' dealer_slug=request.dealer.slug make_id=make.slug model_id=model.slug trim_id=trim.slug %}">{{ trim.trim_name }}</a>&nbsp;-&nbsp;{% trans "Total" %}:
<strong>{{ trim.total_cars }}</strong> <strong>{{ trim.total_cars }}</strong>
</li> </li>
{% empty %} {% empty %}

View File

@ -14,7 +14,7 @@
<div class="row mt-4"> <div class="row mt-4">
<div class="d-flex justify-content-between mb-2"> <div class="d-flex justify-content-between mb-2">
<h3 class="">{% trans "Bills" %}</h3> <h3 class="">{% trans "Bills" %}</h3>
<a href="{% url 'bill-create' entity.slug %}" class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans 'New Bill' %}</a> <a href="{% url 'bill-create' request.dealer.slug entity.slug %}" class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans 'New Bill' %}</a>
</div> </div>
<div class="col-12"> <div class="col-12">
@ -81,7 +81,7 @@
<div class="btn-reveal-trigger position-static"> <div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button> <button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
<div class="dropdown-menu dropdown-menu-end py-2"> <div class="dropdown-menu dropdown-menu-end py-2">
<a href="{% url 'bill-detail' entity_slug=entity.slug bill_pk=bill.pk %}" class="dropdown-item text-success-dark">{% trans 'View Bill detail' %}</a> <a href="{% url 'bill-detail' dealer_slug=request.dealer.slug entity_slug=entity.slug bill_pk=bill.pk %}" class="dropdown-item text-success-dark">{% trans 'View' %}</a>
</div> </div>
</div> </div>
</td> </td>
@ -97,13 +97,13 @@
</table> </table>
</div> </div>
{% if page_obj.paginator.num_pages > 1 %} {% if page_obj.paginator.num_pages > 1 %}
<div class="d-flex justify-content-end mt-3"> <div class="d-flex justify-content-end mt-3">
<div class="d-flex"> <div class="d-flex">
{% include 'partials/pagination.html'%} {% include 'partials/pagination.html'%}
</div> </div>
</div> </div>
{% endif %} {% endif %}
</div> </div>

View File

@ -17,7 +17,7 @@
<div class="btn-group"> <div class="btn-group">
<button type="button" class="btn btn-sm btn-phoenix-secondary" data-bs-dismiss="modal">{% trans 'No' %}</button> <button type="button" class="btn btn-sm btn-phoenix-secondary" data-bs-dismiss="modal">{% trans 'No' %}</button>
<div class="btn btn-sm btn-phoenix-danger"> <div class="btn btn-sm btn-phoenix-danger">
<form action="{% url 'account_delete' account.pk %}" method="post"> <form action="{% url 'account_delete' request.dealer.slug account.pk %}" method="post">
{% csrf_token %} {% csrf_token %}
<button type="submit" class="btn btn-sm btn-phoenix-danger">{% trans 'Yes' %}</button> <button type="submit" class="btn btn-sm btn-phoenix-danger">{% trans 'Yes' %}</button>
</form> </form>
@ -99,7 +99,7 @@
<div class="btn-reveal-trigger position-static"> <div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button> <button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
<div class="dropdown-menu dropdown-menu-end py-2"> <div class="dropdown-menu dropdown-menu-end py-2">
<a class="dropdown-item text-success" href="{% url 'payment_details' tx.journal_entry.pk %}">{% trans 'View Transacrions'|capfirst %}</a> <a class="dropdown-item" href="{% url 'payment_details' request.dealer.slug tx.journal_entry.pk %}">{% trans 'view'|capfirst %}</a>
</div> </div>
</div> </div>
</td> </td>
@ -135,7 +135,7 @@
</div> </div>
<div class="mt-3 d-flex"> <div class="mt-3 d-flex">
<a class="btn btn-sm btn-phoenix-primary me-1" href="{% url 'account_update' account.pk %}"> <a class="btn btn-sm btn-phoenix-primary me-1" href="{% url 'account_update' request.dealer.slug account.pk %}">
<!-- <i class="bi bi-pencil-square"></i> --> <!-- <i class="bi bi-pencil-square"></i> -->
<i class="fa-solid fa-pen-to-square"></i> {{ _('Edit') }} <i class="fa-solid fa-pen-to-square"></i> {{ _('Edit') }}
</a> </a>
@ -143,7 +143,7 @@
<!-- <i class="bi bi-trash-fill"></i> --> <!-- <i class="bi bi-trash-fill"></i> -->
<i class="fa-solid fa-trash"></i> {{ _('Delete') }} <i class="fa-solid fa-trash"></i> {{ _('Delete') }}
</a> </a>
<a class="btn btn-sm btn-phoenix-secondary" href="{% url 'account_list' %}"> <a class="btn btn-sm btn-phoenix-secondary" href="{% url 'account_list' request.dealer.slug %}">
<!-- <i class="bi bi-arrow-left-square-fill"></i> --> <!-- <i class="bi bi-arrow-left-square-fill"></i> -->
<i class="fa-regular fa-circle-left"></i> {% trans 'Back to List' %} <i class="fa-regular fa-circle-left"></i> {% trans 'Back to List' %}
</a> </a>

View File

@ -11,7 +11,7 @@
<div class="row mt-4"> <div class="row mt-4">
<div class="d-flex justify-content-between mb-2"> <div class="d-flex justify-content-between mb-2">
<h3 class=""><i class="fa-solid fa-book"></i> {% trans "Accounts" %}</h3> <h3 class=""><i class="fa-solid fa-book"></i> {% trans "Accounts" %}</h3>
<a href="{% url 'account_create' %}" class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans 'New Account' %}</a> <a href="{% url 'account_create' request.dealer.slug %}" class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans 'New Account' %}</a>
</div> </div>
<!-- Account Type Tabs --> <!-- Account Type Tabs -->

View File

@ -38,8 +38,8 @@
<div class="btn-reveal-trigger position-static"> <div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button> <button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
<div class="dropdown-menu dropdown-menu-end py-2"> <div class="dropdown-menu dropdown-menu-end py-2">
<a href="{% url 'account_detail' account.uuid %}" class="dropdown-item text-success-dark"> <a href="{% url 'account_detail' request.dealer.slug account.uuid %}" class="dropdown-item text-success-dark">
{% trans "View Journal Entries" %} {% trans "View" %}
</a> </a>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<button class="dropdown-item text-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">{% trans "Delete" %}</button> <button class="dropdown-item text-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">{% trans "Delete" %}</button>

View File

@ -88,11 +88,11 @@
{% endif %} {% endif %}
{% for bill in bills %} {% for bill in bills %}
<div class="col"> <div class="col">
{% include 'django_ledger/bills/includes/card_bill.html' with bill=bill entity_slug=entity.slug style='dashboard' %} {% include 'django_ledger/bills/includes/card_bill.html' with dealer_slug=request.dealer.slug bill=bill entity_slug=entity.slug style='dashboard' %}
</div> </div>
{% endfor %} {% endfor %}
<div class="col"> <div class="col">
{% include 'django_ledger/bills/includes/card_bill.html' with create_bill=True entity_slug=entity.slug style='dashboard' %} {% include 'django_ledger/bills/includes/card_bill.html' with dealer_slug=request.dealer.slug create_bill=True entity_slug=entity.slug style='dashboard' %}
</div> </div>
</div> </div>
</div> </div>

View File

@ -56,7 +56,7 @@
<div class="mt-3"> <div class="mt-3">
<button type="submit" class="btn btn-phoenix-primary">Save</button> <button type="submit" class="btn btn-phoenix-primary">Save</button>
<a href="{% url 'purchase_order_list' %}" class="btn btn-phoenix-secondary">Cancel</a> <a href="{% url 'purchase_order_list' request.dealer.slug %}" class="btn btn-phoenix-secondary">Cancel</a>
</div> </div>
</form> </form>
</div> </div>

View File

@ -162,7 +162,7 @@
<div class="card-footer bg-light"> <div class="card-footer bg-light">
<div class="d-flex flex-wrap gap-2 justify-content-between"> <div class="d-flex flex-wrap gap-2 justify-content-between">
<a href="{% url 'purchase_order_update' entity_slug=entity_slug po_pk=po_model.pk %}" <a href="{% url 'purchase_order_update' dealer_slug=request.dealer.slug entity_slug=entity_slug po_pk=po_model.pk %}"
class="btn btn-phoenix-primary"> class="btn btn-phoenix-primary">
<i class="fas fa-edit me-2"></i>{% trans 'Update' %} <i class="fas fa-edit me-2"></i>{% trans 'Update' %}
</a> </a>
@ -171,28 +171,28 @@
{# Status Action Buttons #} {# Status Action Buttons #}
{% if po_model.can_draft %} {% if po_model.can_draft %}
<button class="btn btn-phoenix-secondary" <button class="btn btn-phoenix-secondary"
onclick="showPOModal('Draft PO', '{% url 'po-action-mark-as-draft' entity_slug po_model.pk %}', 'Mark As Draft')"> onclick="showPOModal('Draft PO', '{% url 'po-action-mark-as-draft' request.dealer.slug entity_slug po_model.pk %}', 'Mark As Draft')">
<i class="fas fa-file me-2"></i>{% trans 'Mark as Draft' %} <i class="fas fa-file me-2"></i>{% trans 'Mark as Draft' %}
</button> </button>
{% endif %} {% endif %}
{% if po_model.can_review %} {% if po_model.can_review %}
<button class="btn btn-phoenix-warning" <button class="btn btn-phoenix-warning"
onclick="showPOModal('Review PO', '{% url 'po-action-mark-as-review' entity_slug po_model.pk %}', 'Mark As Review')"> onclick="showPOModal('Review PO', '{% url 'po-action-mark-as-review' request.dealer.slug entity_slug po_model.pk %}', 'Mark As Review')">
<i class="fas fa-search me-2"></i>{% trans 'Mark as Review' %} <i class="fas fa-search me-2"></i>{% trans 'Mark as Review' %}
</button> </button>
{% endif %} {% endif %}
{% if po_model.can_approve %} {% if po_model.can_approve %}
<button class="btn btn-phoenix-success" <button class="btn btn-phoenix-success"
onclick="showPOModal('Approve PO', '{% url 'po-action-mark-as-approved' entity_slug po_model.pk %}', 'Mark As Approved')"> onclick="showPOModal('Approve PO', '{% url 'po-action-mark-as-approved' request.dealer.slug entity_slug po_model.pk %}', 'Mark As Approved')">
<i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Approved' %} <i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Approved' %}
</button> </button>
{% endif %} {% endif %}
{% if po_model.can_fulfill %} {% if po_model.can_fulfill %}
<button class="btn btn-phoenix-primary" <button class="btn btn-phoenix-primary"
onclick="showPOModal('Fulfill PO', '{% url 'po-action-mark-as-fulfilled' entity_slug po_model.pk %}', 'Mark As Fulfilled')"> onclick="showPOModal('Fulfill PO', '{% url 'po-action-mark-as-fulfilled' request.dealer.slug entity_slug po_model.pk %}', 'Mark As Fulfilled')">
<i class="fas fa-truck me-2"></i>{% trans 'Mark as Fulfilled' %} <i class="fas fa-truck me-2"></i>{% trans 'Mark as Fulfilled' %}
</button> </button>
@ -201,21 +201,21 @@
{# Danger Action Buttons #} {# Danger Action Buttons #}
{% if po_model.can_delete %} {% if po_model.can_delete %}
<button class="btn btn-outline-danger" <button class="btn btn-outline-danger"
onclick="showPOModal('Cancel PO', '{% url 'po-delete' entity_slug po_model.pk %}', 'Mark As Cancelled')"> onclick="showPOModal('Delete PO', '{% url 'po-delete' request.dealer.slug entity_slug po_model.pk %}', 'Delete')">
<i class="fas fa-ban me-2"></i>{% trans 'Delete' %} <i class="fas fa-ban me-2"></i>{% trans 'Delete' %}
</button> </button>
{% endif %} {% endif %}
{% if po_model.can_void %} {% if po_model.can_void %}
<button class="btn btn-outline-danger" <button class="btn btn-outline-danger"
onclick="showPOModal('Void PO', '{% url 'po-action-mark-as-void' entity_slug po_model.pk %}', 'Mark As Void')"> onclick="showPOModal('Void PO', '{% url 'po-action-mark-as-void' request.dealer.slug entity_slug po_model.pk %}', 'Mark As Void')">
<i class="fas fa-times-circle me-2"></i>{% trans 'Void' %} <i class="fas fa-times-circle me-2"></i>{% trans 'Void' %}
</button> </button>
{% endif %} {% endif %}
{% if po_model.can_cancel %} {% if po_model.can_cancel %}
<button class="btn btn-outline-danger" <button class="btn btn-outline-danger"
onclick="showPOModal('Cancel PO', '{% url 'po-action-mark-as-canceled' entity_slug po_model.pk %}', 'Mark As Cancelled')"> onclick="showPOModal('Cancel PO', '{% url 'po-action-mark-as-canceled' request.dealer.slug entity_slug po_model.pk %}', 'Mark As Cancelled')">
<i class="fas fa-ban me-2"></i>{% trans 'Cancel' %} <i class="fas fa-ban me-2"></i>{% trans 'Cancel' %}
</button> </button>
@ -228,7 +228,7 @@
{% else %} {% else %}
<div class="card border-0 shadow-sm text-center py-5"> <div class="card border-0 shadow-sm text-center py-5">
<div class="card-body"> <div class="card-body">
<a href="{% url 'purchase_order_create' %}" class="text-decoration-none"> <a href="{% url 'purchase_order_create' request.dealer.slug %}" class="text-decoration-none">
<span class="text-muted mb-3 d-inline-block">{% icon "ic:baseline-add-circle-outline" 48 %}</span> <span class="text-muted mb-3 d-inline-block">{% icon "ic:baseline-add-circle-outline" 48 %}</span>
<h3 class="h4 text-muted">{% trans 'New Purchase Order' %}</h3> <h3 class="h4 text-muted">{% trans 'New Purchase Order' %}</h3>
</a> </a>

View File

@ -3,7 +3,7 @@
{% block content %} {% block content %}
<form action="{% url 'inventory_item_create' po_model.pk %}" method="post"> <form action="{% url 'inventory_item_create' request.dealer.slug po_model.pk %}" method="post">
{% csrf_token %} {% csrf_token %}
{% include "purchase_orders/partials/po-select.html" with name="make" target="model" data=make_data pk=po_model.pk %} {% include "purchase_orders/partials/po-select.html" with name="make" target="model" data=make_data pk=po_model.pk %}
{% include "purchase_orders/partials/po-select.html" with name="model" target="serie" data=model_data pk=po_model.pk %} {% include "purchase_orders/partials/po-select.html" with name="model" target="serie" data=model_data pk=po_model.pk %}

View File

@ -4,7 +4,7 @@
{% load custom_filters %} {% load custom_filters %}
{% load widget_tweaks %} {% load widget_tweaks %}
<form action="{% url 'purchase_order_update_items' entity_slug=entity_slug po_pk=po_model.uuid %}" <form action="{% url 'purchase_order_update_items' dealer_slug=dealer_slug entity_slug=entity_slug po_pk=po_model.uuid %}"
method="post"> method="post">
<div class="row g-3"> <div class="row g-3">
<div class="col-12"> <div class="col-12">
@ -60,7 +60,7 @@
{{ f.create_bill|add_class:"form-check-input" }} {{ f.create_bill|add_class:"form-check-input" }}
{% elif f.instance.bill_model %} {% elif f.instance.bill_model %}
<a class="btn btn-sm btn-phoenix-secondary" <a class="btn btn-sm btn-phoenix-secondary"
href="{% url 'bill-detail' entity_slug=entity_slug bill_pk=f.instance.bill_model_id %}"> href="{% url 'bill-detail' dealer_slug=dealer_slug entity_slug=entity_slug bill_pk=f.instance.bill_model_id %}">
{% trans 'View Bill' %} {% trans 'View Bill' %}
</a> </a>
{% endif %} {% endif %}

View File

@ -3,7 +3,7 @@
<select class="form-control" <select class="form-control"
name="{{name}}" id="{{name}}" name="{{name}}" id="{{name}}"
{% if name != "trim" %} {% if name != "trim" %}
hx-get="{% url 'inventory_items_filter' %}" hx-get="{% url 'inventory_items_filter' request.dealer.slug %}"
hx-target="#form-{{target}}" hx-target="#form-{{target}}"
hx-select="#form-{{target}}" hx-select="#form-{{target}}"
hx-swap="outerHTML" hx-swap="outerHTML"

View File

@ -6,7 +6,7 @@
{% block content %} {% block content %}
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
<form action="{% url 'po-delete' entity_slug=view.kwargs.entity_slug po_pk=po_model.uuid %}" <form action="{% url 'po-delete' dealer_slug=request.dealer.slug entity_slug=view.kwargs.entity_slug po_pk=po_model.uuid %}"
method="post"> method="post">
{% csrf_token %} {% csrf_token %}
<div class="card shadow"> <div class="card shadow">
@ -15,10 +15,10 @@
Purchase Order {{ po_model.po_number }}?</h2> Purchase Order {{ po_model.po_number }}?</h2>
<p class="card-text text-muted mb-4">All transactions associated with this Purchase Order will be deleted. <p class="card-text text-muted mb-4">All transactions associated with this Purchase Order will be deleted.
If you want to void the PO instead, <a href="{% url 'purchase_order_detail' entity_slug=view.kwargs.entity_slug po_pk=po_model.uuid %}" class="text-decoration-none">click here</a></p> If you want to void the PO instead, <a href="{% url 'purchase_order_detail' dealer_slug=request.dealer.slug pk=po_model.uuid %}" class="text-decoration-none">click here</a></p>
<div class="d-flex justify-content-center gap-3 mt-4"> <div class="d-flex justify-content-center gap-3 mt-4">
<a href="{% url 'purchase_order_update' entity_slug=view.kwargs.entity_slug po_pk=po_model.uuid %}" <a href="{% url 'purchase_order_update' dealer_slug=request.dealer.slug entity_slug=view.kwargs.entity_slug po_pk=po_model.uuid %}"
class="btn btn-phoenix-primary px-4">{% trans 'Go Back' %}</a> class="btn btn-phoenix-primary px-4">{% trans 'Go Back' %}</a>
<button type="submit" class="btn btn-phoenix-danger px-4">{% trans 'Delete' %}</button> <button type="submit" class="btn btn-phoenix-danger px-4">{% trans 'Delete' %}</button>
</div> </div>

View File

@ -7,19 +7,28 @@
{% block content %} {% block content %}
<div class="container-fluid mt-4"> <div class="container-fluid mt-4">
<div class="row g-1"> <div class="row g-1">
<div class="col-lg-12"> <div class="col-lg-12">
<div class="d-flex flex-column gap-3"> <div class="d-flex flex-column gap-3">
<!-- PO Card --> <!-- PO Card -->
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
{% include 'purchase_orders/includes/card_po.html' with po_model=po_model entity_slug=entity_slug style='po-detail' %} {% include 'purchase_orders/includes/card_po.html' with dealer_slug=request.dealer.slug po_model=po_model entity_slug=entity_slug style='po-detail' %}
</div> </div>
</div> </div>
<!-- PO Stats Card--> <!-- PO List Button -->
<a class="btn btn-phoenix-primary w-100 py-2"
<div class="card mb-4"> href="{% url 'purchase_order_list' request.dealer.slug %}">
<i class="fas fa-list me-2"></i>{% trans 'PO List' %}
</a>
</div>
</div>
<!-- Main Content -->
<div class="col-lg-8">
<!-- Stats Cards -->
<div class="card mb-4">
<div class="card-body"> <div class="card-body">
<div class="row text-center"> <div class="row text-center">
<div class="col-md-6 border-end"> <div class="col-md-6 border-end">

View File

@ -19,9 +19,9 @@
{{ _("Purchase Orders") |capfirst }} {{ _("Purchase Orders") |capfirst }}
</h2> </h2>
<div> <div>
<a href="{% url 'purchase_order_create' %}" <a href="{% url 'purchase_order_create' request.dealer.slug %}"
class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{{ _("Create New PO") }}</a> class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{{ _("Create New PO") }}</a>
<a href="{% url 'inventory_item_create' %}?for_po=1" <a href="{% url 'inventory_item_create' request.dealer.slug %}?for_po=1"
class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{{ _("Create Inventory Item for PO") }}</a> class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{{ _("Create Inventory Item for PO") }}</a>
</div> </div>
</div> </div>
@ -67,8 +67,8 @@
<div class="btn-reveal-trigger position-static"> <div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button> <button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
<div class="dropdown-menu dropdown-menu-end py-2"> <div class="dropdown-menu dropdown-menu-end py-2">
<a href="{% url 'purchase_order_detail' po.pk %}" class="dropdown-item text-success-dark">{% trans 'PO Detail' %}</a> <a href="{% url 'purchase_order_detail' request.dealer.slug po.pk %}" class="dropdown-item text-success-dark">{% trans 'Detail' %}</a>
<a href="{% url 'view_items_inventory' entity_slug=entity_slug po_pk=po.pk %}" class="dropdown-item text-success-dark">{% trans 'View Inventory Items' %}</a> <a href="{% url 'view_items_inventory' dealer_slug=request.dealer.slug entity_slug=entity_slug po_pk=po.pk %}" class="dropdown-item text-success-dark">{% trans 'View Inventory Items' %}</a>
</div> </div>
</div> </div>
</td> </td>
@ -83,13 +83,13 @@
</table> </table>
</div> </div>
{% if page_obj.paginator.num_pages > 1 %} {% if page_obj.paginator.num_pages > 1 %}
<div class="d-flex justify-content-end mt-3"> <div class="d-flex justify-content-end mt-3">
<div class="d-flex"> <div class="d-flex">
{% include 'partials/pagination.html'%} {% include 'partials/pagination.html'%}
</div> </div>
</div> </div>
{% endif %} {% endif %}
</div> </div>

View File

@ -12,12 +12,12 @@
<div class="row g-4"> <div class="row g-4">
<div class="col-12"> <div class="col-12">
{% include 'purchase_orders/includes/card_po.html' with style='po-detail' po_model=po_model entity_slug=entity_slug %} {% include 'purchase_orders/includes/card_po.html' with style='po-detail' dealer_slug=request.dealer.slug po_model=po_model entity_slug=entity_slug %}
</div> </div>
<div class="col-12"> <div class="col-12">
<div class="card shadow-sm"> <div class="card shadow-sm">
<div class="card-body"> <div class="card-body">
<form action="{% url 'purchase_order_update' entity_slug=view.kwargs.entity_slug po_pk=po_model.uuid %}" <form action="{% url 'purchase_order_update' dealer_slug=request.dealer.slug entity_slug=view.kwargs.entity_slug po_pk=po_model.uuid %}"
method="post"> method="post">
<div class="row g-3"> <div class="row g-3">
<div class="col-12"> <div class="col-12">
@ -26,9 +26,9 @@
<button type="submit" <button type="submit"
class="btn btn-phoenix-success w-100 my-2">{% trans 'Save PO' %} class="btn btn-phoenix-success w-100 my-2">{% trans 'Save PO' %}
</button> </button>
<a href="{% url 'purchase_order_detail' po_model.uuid %}" <a href="{% url 'purchase_order_detail' request.dealer.slug po_model.uuid %}"
class="btn btn-phoenix-secondary w-100 my-2">{% trans 'Back to PO Detail' %}</a> class="btn btn-phoenix-secondary w-100 my-2">{% trans 'Back to PO Detail' %}</a>
<a href="{% url 'purchase_order_list' %}" <a href="{% url 'purchase_order_list' request.dealer.slug %}"
class="btn btn-phoenix-info class="btn btn-phoenix-info
info w-100 my-2">{% trans 'PO List' %}</a> info w-100 my-2">{% trans 'PO List' %}</a>
</div> </div>

View File

@ -28,7 +28,7 @@
</td> </td>
<td class="has-text-centered">{% if item.bill_model_id %} <td class="has-text-centered">{% if item.bill_model_id %}
<a class="is-small is-info button" <a class="is-small is-info button"
href="{% url 'bill-detail' entity_slug=entity_slug bill_pk=item.bill_model_id %}">View href="{% url 'bill-detail' dealer_slug=dealer_slug entity_slug=entity_slug bill_pk=item.bill_model_id %}">View
Bill</a>{% endif %} Bill</a>{% endif %}
</td> </td>
</tr> </tr>

View File

@ -16,7 +16,7 @@
<p>{% trans "Are you sure you want to Cancel this Estimate?" %}</p> <p>{% trans "Are you sure you want to Cancel this Estimate?" %}</p>
</div> </div>
<div class="modal-footer flex justify-content-center border-top-0"> <div class="modal-footer flex justify-content-center border-top-0">
<a type="button" class="btn btn-sm btn-phoenix-danger w-100" href="{% url 'estimate_mark_as' estimate.pk %}?mark=canceled"> <a type="button" class="btn btn-sm btn-phoenix-danger w-100" href="{% url 'estimate_mark_as' request.dealer.slug estimate.pk %}?mark=canceled">
<i class="fa-solid fa-circle-check"></i> {% trans "Yes" %} <i class="fa-solid fa-circle-check"></i> {% trans "Yes" %}
</a> </a>
</div> </div>
@ -40,7 +40,7 @@
<div class="modal-body"> <div class="modal-body">
{% trans 'Are you sure ?' %} {% trans 'Are you sure ?' %}
<div class="modal-footer flex justify-content-center border-top-0"> <div class="modal-footer flex justify-content-center border-top-0">
<form id="confirmForm" method="POST" action="{% url 'estimate_mark_as' estimate.pk %}?mark=approved" class="form"> <form id="confirmForm" method="POST" action="{% url 'estimate_mark_as' request.dealer.slug estimate.pk %}?mark=approved" class="form">
{% csrf_token %} {% csrf_token %}
<div class="container-fluid m-0 p-0"> <div class="container-fluid m-0 p-0">
<button type="button" class="btn btn-phoenix-danger btn-sm" data-bs-dismiss="modal"><i class="fa-solid fa-ban"></i> {% trans 'No' %}</button> <button type="button" class="btn btn-phoenix-danger btn-sm" data-bs-dismiss="modal"><i class="fa-solid fa-ban"></i> {% trans 'No' %}</button>
@ -74,32 +74,28 @@
</div> </div>
</div> </div>
<div class="d-flex align-items-center gap-2"> <div class="d-flex align-items-center gap-2">
{% if estimate.status == 'draft' %} {% if estimate.invoicemodel_set.first %}
<a href="{% url 'send_email' estimate.pk %}" class="btn btn-phoenix-primary me-2"><span class="fa-regular fa-paper-plane me-sm-2"></span><span class="d-none d-sm-inline-block">{% trans 'Send Quotation' %}</span></a> <a href="{% url 'invoice_detail' request.dealer.slug estimate.invoicemodel_set.first.pk %}" class="btn btn-phoenix-primary btn-sm" type="button"><i class="fa-solid fa-receipt"></i>
{{ _("View Invoice")}}</a>
<button class="btn btn-phoenix-primary" data-bs-toggle="modal" data-bs-target="#POModal"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-receipt"></i> {% trans 'View Purchase Order' %}</span></button>
{% endif %}
{% if estimate.status == 'draft' %}
<a href="{% url 'send_email' request.dealer.slug estimate.pk %}" class="btn btn-phoenix-primary me-2"><span class="fa-regular fa-paper-plane me-sm-2"></span><span class="d-none d-sm-inline-block">{% trans 'Send Quotation' %}</span></a>
<button id="mark_as_sent_estimate" class="btn btn-phoenix-secondary" onclick="setFormAction('review')" data-bs-toggle="modal" data-bs-target="#confirmModal"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-check-double"></i> {% trans 'Mark As Sent' %}</span></button> <button id="mark_as_sent_estimate" class="btn btn-phoenix-secondary" onclick="setFormAction('review')" data-bs-toggle="modal" data-bs-target="#confirmModal"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-check-double"></i> {% trans 'Mark As Sent' %}</span></button>
{% elif estimate.status == 'in_review' %} {% elif estimate.status == 'in_review' %}
<button id="accept_estimate" onclick="setFormAction('approved')" class="btn btn-phoenix-secondary" data-bs-toggle="modal" data-bs-target="#confirmModal"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-check-double"></i> {% trans 'Mark As Accept' %}</span></button> <button id="accept_estimate" onclick="setFormAction('approved')" class="btn btn-phoenix-secondary" data-bs-toggle="modal" data-bs-target="#confirmModal"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-check-double"></i> {% trans 'Mark As Accept' %}</span></button>
{% elif estimate.status == 'approved' %} {% elif estimate.status == 'approved' %}
{% if estimate.sale_orders.first %} {% if estimate.sale_orders.first %}
<!--if there is a sales order for an estimate--> <a href="{% url 'invoice_create' request.dealer.slug estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-receipt"></i> {% trans 'Create Invoice' %}</span></a>
<!--View sales Order--> <a href="{% url 'preview_sale_order' request.dealer.slug estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{{ _("Preview Sale Order") }}</span></a>
<a href="{% url 'order_detail' estimate.sale_orders.first.pk %}" class="btn btn-phoenix-primary btn-sm" type="button"><i class="fa-solid fa-cart-shopping"></i>
{{ _("View Sales Order")}}
</a>
{% if estimate.sale_orders.first.invoice %}
<a href="{% url 'invoice_detail' estimate.invoicemodel_set.first.pk %}" class="btn btn-phoenix-primary btn-sm" type="button"><i class="fa-solid fa-receipt"></i>
{{ _("View Invoice")}}</a>
{% else %}
<!--if there is no invoice for a sale order create invoice -->
<a href="{% url 'invoice_create' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-receipt"></i> {% trans 'Create Invoice' %}</span></a>
{% endif %}
{% else %} {% else %}
<!--if no sales order for the estimate Create sales order--> <a href="{% url 'create_sale_order' request.dealer.slug estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-file-import"></i> {% trans 'Create Sale Order' %}</span></a>
<a href="{% url 'create_sale_order' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-file-import"></i> {% trans 'Create Sale Order' %}</span></a> {% comment %} {% endcomment %}
{% endif %} {% endif %}
{% elif estimate.status == 'in_review' %} {% elif estimate.status == 'in_review' %}
<a href="{% url 'estimate_preview' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-regular fa-eye"></i> {% trans 'Preview' %}</span></a> <a href="{% url 'estimate_preview' request.dealer.slug estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-regular fa-eye"></i> {% trans 'Preview' %}</span></a>
{% endif %} {% endif %}
{% if estimate.can_cancel %} {% if estimate.can_cancel %}
{% if perms.django_ledger.change_estimatemodel %} {% if perms.django_ledger.change_estimatemodel %}
@ -144,7 +140,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="px-0"> <div class="px-0">
<div class="table-responsive scrollbar"> <div class="table-responsive scrollbar">
<table id="estimate-table" class="table fs-9 text-body mb-0"> <table id="estimate-table" class="table fs-9 text-body mb-0">
@ -245,7 +241,7 @@
// Get the form element // Get the form element
const form = document.getElementById('confirmForm'); const form = document.getElementById('confirmForm');
// Set the form action with the query parameter // Set the form action with the query parameter
form.action = "{% url 'estimate_mark_as' estimate.pk %}?mark=" + action; form.action = "{% url 'estimate_mark_as' request.dealer.slug estimate.pk %}?mark=" + action;
} }
</script> </script>

View File

@ -17,14 +17,14 @@
{% if not items %} {% if not items %}
<div class="alert alert-outline-warning d-flex align-items-center" role="alert"> <div class="alert alert-outline-warning d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-info fs-6"></i> <i class="fa-solid fa-circle-info fs-6"></i>
<p class="mb-0 flex-1">{{ _("Please add at least one car before creating a quotation.") }}<a class="ms-3 text-body-primary fs-9" href="{% url 'car_add' %}"> {{ _("Add Car") }} </a></p> <p class="mb-0 flex-1">{{ _("Please add at least one car before creating a quotation.") }}<a class="ms-3 text-body-primary fs-9" href="{% url 'car_add' request.dealer.slug %}"> {{ _("Add Car") }} </a></p>
<button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button> <button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button>
</div> </div>
{% endif %} {% endif %}
{% if not customer_count %} {% if not customer_count %}
<div class="alert alert-outline-warning d-flex align-items-center" role="alert"> <div class="alert alert-outline-warning d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-info fs-6"></i>&nbsp;&nbsp; <i class="fa-solid fa-circle-info fs-6"></i>&nbsp;&nbsp;
<p class="mb-0 flex-1"> {{ _("Please add at least one customer before creating a quotation.") }}<a class="ms-3 text-body-primary fs-9" href="{% url 'customer_create' %}"> {{ _("Add Customer") }} </a></p> <p class="mb-0 flex-1"> {{ _("Please add at least one customer before creating a quotation.") }}<a class="ms-3 text-body-primary fs-9" href="{% url 'customer_create' request.dealer.slug %}"> {{ _("Add Customer") }} </a></p>
<button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button> <button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button>
</div> </div>
{% endif %} {% endif %}
@ -163,7 +163,7 @@
try { try {
// Send data to the server using fetch // Send data to the server using fetch
const response = await fetch("{% url 'estimate_create' %}", { const response = await fetch("{% url 'estimate_create' request.dealer.slug %}", {
method: 'POST', method: 'POST',
headers: { headers: {
'X-CSRFToken': formData.csrfmiddlewaretoken, 'X-CSRFToken': formData.csrfmiddlewaretoken,

View File

@ -44,7 +44,7 @@
<td class="align-middle product white-space-nowrap">{{ estimate.get_status_action_date }}</td> <td class="align-middle product white-space-nowrap">{{ estimate.get_status_action_date }}</td>
<td class="align-middle product white-space-nowrap">{{ estimate.created }}</td> <td class="align-middle product white-space-nowrap">{{ estimate.created }}</td>
<td class="align-middle product white-space-nowrap"> <td class="align-middle product white-space-nowrap">
<a href="{% url 'estimate_detail' estimate.pk %}" <a href="{% url 'estimate_detail' request.dealer.slug estimate.pk %}"
class="btn btn-sm btn-phoenix-success"> class="btn btn-sm btn-phoenix-success">
<i class="fa-regular fa-eye me-1"></i> <i class="fa-regular fa-eye me-1"></i>
{% trans "view"|capfirst %} {% trans "view"|capfirst %}

View File

@ -23,7 +23,7 @@
</div> </div>
<div class="d-flex justify-content-between align-items-center"> <div class="d-flex justify-content-between align-items-center">
<div class="d-flex"> <div class="d-flex">
<a href="{% url 'estimate_detail' estimate.pk %}" class="btn btn-sm btn-phoenix-secondary text-body fs-10 me-1">{{ _("Cancel") }}</a> <a href="{% url 'estimate_detail' request.dealer.slug estimate.pk %}" class="btn btn-sm btn-phoenix-secondary text-body fs-10 me-1">{{ _("Cancel") }}</a>
<button class="btn btn-sm btn-phoenix-primary fs-10" type="submit">{{ _("Send") }}<span class="fa-solid fa-paper-plane ms-1"></span></button> <button class="btn btn-sm btn-phoenix-primary fs-10" type="submit">{{ _("Send") }}<span class="fa-solid fa-paper-plane ms-1"></span></button>
</div> </div>
</div> </div>

View File

@ -172,7 +172,7 @@
<!-- Form Actions --> <!-- Form Actions -->
<div class="form-actions mt-4"> <div class="form-actions mt-4">
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<a href="{% url 'estimate_detail' estimate.pk %}" type="button" class="btn btn-phoenix-secondary"> <a href="{% url 'estimate_detail' request.dealer.slug estimate.pk %}" type="button" class="btn btn-phoenix-secondary">
<i class="fas fa-times me-2"></i> Cancel <i class="fas fa-times me-2"></i> Cancel
</a> </a>
<div> <div>

View File

@ -26,7 +26,7 @@
class="btn btn-sm btn-phoenix-danger" class="btn btn-sm btn-phoenix-danger"
data-bs-dismiss="modal"><i class="fa-solid fa-ban"></i> {% trans 'No' %} data-bs-dismiss="modal"><i class="fa-solid fa-ban"></i> {% trans 'No' %}
</button> </button>
<form id="confirmForm" method="POST" action="{% url 'invoice_mark_as' invoice.pk %}?mark=accept" class="d-inline"> <form id="confirmForm" method="POST" action="{% url 'invoice_mark_as' request.dealer.slug invoice.pk %}?mark=accept" class="d-inline">
{% csrf_token %} {% csrf_token %}
<button type="submit" class="btn btn-phoenix-success btn-sm"><i class="fa-solid fa-circle-check"></i> {% trans "Yes" %}</button> <button type="submit" class="btn btn-phoenix-success btn-sm"><i class="fa-solid fa-circle-check"></i> {% trans "Yes" %}</button>
</form> </form>
@ -35,7 +35,7 @@
</div> </div>
</div> </div>
</div> </div>
<!-- ============================================--> <!-- ============================================-->
<div class="modal fade" id="mark_as_paid_Modal" tabindex="-1" aria-labelledby="confirmModalLabel" aria-hidden="true"> <div class="modal fade" id="mark_as_paid_Modal" tabindex="-1" aria-labelledby="confirmModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm"> <div class="modal-dialog modal-sm">
<div class="modal-content"> <div class="modal-content">
@ -51,7 +51,7 @@
data-bs-dismiss="modal"> data-bs-dismiss="modal">
<i class="fa-solid fa-ban"></i> {% trans 'No' %} <i class="fa-solid fa-ban"></i> {% trans 'No' %}
</button> </button>
<form id="confirmForm" method="POST" action="{% url 'payment_mark_as_paid' invoice.pk %}" class="d-inline"> <form id="confirmForm" method="POST" action="{% url 'payment_mark_as_paid' request.dealer.slug invoice.pk %}" class="d-inline">
{% csrf_token %} {% csrf_token %}
<button type="submit" class="btn btn-phoenix-success btn-sm"><i class="fa-solid fa-circle-check"></i> {% trans "Yes" %}</button> <button type="submit" class="btn btn-phoenix-success btn-sm"><i class="fa-solid fa-circle-check"></i> {% trans "Yes" %}</button>
</form> </form>
@ -60,7 +60,7 @@
</div> </div>
</div> </div>
</div> </div>
<!-- ============================================--> <!-- ============================================-->
<!-- <section> begin ============================--> <!-- <section> begin ============================-->
<section class="pt-5 pb-9 bg-body-emphasis dark__bg-gray-1200 border-top"> <section class="pt-5 pb-9 bg-body-emphasis dark__bg-gray-1200 border-top">
<div class="row-small mt-3 mx-3"> <div class="row-small mt-3 mx-3">
@ -82,40 +82,21 @@
</div> </div>
</div> </div>
<div class="d-flex align-items-center gap-2"> <div class="d-flex align-items-center gap-2">
{# Accept Invoice Button #} {% if invoice.invoice_status == 'in_review' %}
{% if invoice.invoice_status == 'in_review' %} <button id="accept_invoice" class="btn btn-phoenix-secondary" data-bs-toggle="modal" data-bs-target="#confirmModal"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-check-double"></i> {% trans 'Accept' %}</span></button>
<button id="accept_invoice" class="btn btn-phoenix-secondary btn-sm" data-bs-toggle="modal" data-bs-target="#confirmModal"> {% endif %}
<i class="fa-solid fa-check-double me-1 me-sm-0 me-md-1"></i> {# Icon always visible, adjusted margin #} {% if invoice.invoice_status == 'approved' %}
<span class="d-none d-sm-inline-block">{% trans 'Accept' %}</span> {# Text hidden on xs, shown on sm+ #} <a href="{% url 'payment_create' request.user.dealer.slug invoice.pk %}" class="btn btn-phoenix-success"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-money-bill"></i> {% trans 'Record Payment' %}</span></a>
</button> {% endif %}
{% endif %} {% if not invoice.is_paid %}
<button {% if invoice.is_review or invoice.amount_paid|to_int < invoice.amount_due|to_int %}disabled{% endif %} id="mark_invoice_as_paid" class="btn btn-phoenix-secondary" data-bs-toggle="modal" data-bs-target="#mark_as_paid_Modal"><span class="d-none d-sm-inline-block"><span class="icon-saudi_riyal"></span> {% trans 'Mark as Paid' %}</span></button>
{# Record Payment Button #} {% endif %}
{% if invoice.invoice_status == 'approved' %} <a href="{% url 'invoice_preview' request.user.dealer.slug invoice.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-regular fa-eye"></i> {% trans 'Preview' %}</span></a>
<a href="{% url 'payment_create' invoice.pk %}" class="btn btn-phoenix-success btn-sm"> </div>
<i class="fa-solid fa-money-bill me-1 me-sm-0 me-md-1"></i> {# Icon always visible, adjusted margin #}
<span class="d-none d-sm-inline-block">{% trans 'Record Payment' %}</span> {# Text hidden on xs, shown on sm+ #}
</a>
{% endif %}
{# Mark as Paid Button #}
{% if not invoice.is_paid %}
<button {% if invoice.is_review or invoice.amount_paid|to_int < invoice.amount_due|to_int %}disabled{% endif %} id="mark_invoice_as_paid" class="btn btn-phoenix-secondary btn-sm" data-bs-toggle="modal" data-bs-target="#mark_as_paid_Modal">
<span class="icon-saudi_riyal me-1 me-sm-0 me-md-1"></span> {# Icon always visible, adjusted margin #}
<span class="d-none d-sm-inline-block">{% trans 'Mark as Paid' %}</span> {# Text hidden on xs, shown on sm+ #}
</button>
{% endif %}
{# Preview Button #}
<a href="{% url 'invoice_preview' invoice.pk %}" class="btn btn-phoenix-primary btn-sm">
<i class="fa-regular fa-eye me-1 me-sm-0 me-md-1"></i> {# Icon always visible, adjusted margin #}
<span class="d-none d-sm-inline-block">{% trans 'Preview' %}</span> {# Text hidden on xs, shown on sm+ #}
</a>
</div>
</div> </div>
{{invoice.amount_owned}} {{invoice.amount_owned}}
<!-- ============================================--> <!-- ============================================-->
<div class="card mb-5 {% if invoice.is_review %}disabled{% endif %}"> <div class="card mb-5 {% if invoice.is_review %}disabled{% endif %}">
<div class="card-body"> <div class="card-body">
<div class="row g-4 g-xl-1 g-xxl-3 justify-content-between"> <div class="row g-4 g-xl-1 g-xxl-3 justify-content-between">
@ -190,7 +171,7 @@
<!-- <section> begin ============================--> <!-- <section> begin ============================-->
<div class="container bg-body dark__bg-gray-1100 p-4 mb-4 rounded-2 text-body-tertiary {% if invoice.is_review %}disabled{% endif %}"> <div class="container bg-body dark__bg-gray-1100 p-4 mb-4 rounded-2 text-body-tertiary {% if invoice.is_review %}disabled{% endif %}">
<!----> <!---->
<div class="row"> <div class="row">
<div class="col mb-2"> <div class="col mb-2">
<h6 class="mb-0 me-3"><i class="fa-solid fa-hashtag"></i> {% trans "Invoice Number" %} :</h6> <h6 class="mb-0 me-3"><i class="fa-solid fa-hashtag"></i> {% trans "Invoice Number" %} :</h6>
@ -223,7 +204,7 @@
<span class="badge text-bg-success">{% trans "Paid" %}</span> <span class="badge text-bg-success">{% trans "Paid" %}</span>
{% endif %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -4,7 +4,6 @@
{% block title %}{{ _("Invoices") }}{% endblock title %} {% block title %}{{ _("Invoices") }}{% endblock title %}
{% block content %} {% block content %}
<div class="row mt-4"> <div class="row mt-4">
<h3 class="mb-3"><i class="fa-solid fa-receipt"></i> {% trans "Invoices" %}</h3> <h3 class="mb-3"><i class="fa-solid fa-receipt"></i> {% trans "Invoices" %}</h3>
@ -55,7 +54,7 @@
</td> </td>
<td class="align-middle product white-space-nowrap">{{ invoice.created }}</td> <td class="align-middle product white-space-nowrap">{{ invoice.created }}</td>
<td class="align-middle product white-space-nowrap"> <td class="align-middle product white-space-nowrap">
<a href="{% url 'invoice_detail' invoice.pk %}" <a href="{% url 'invoice_detail' request.dealer.slug invoice.pk %}"
class="btn btn-sm btn-phoenix-success"> class="btn btn-sm btn-phoenix-success">
<i class="fa-regular fa-eye me-1"></i> <i class="fa-regular fa-eye me-1"></i>
{% trans "View" %} {% trans "View" %}

View File

@ -29,7 +29,7 @@
<td class="align-middle product white-space-nowrap">{{ journal. }}</td> <td class="align-middle product white-space-nowrap">{{ journal. }}</td>
<td class="align-middle product white-space-nowrap">{{ journal. }}</td> <td class="align-middle product white-space-nowrap">{{ journal. }}</td>
<td class="text-center"> <td class="text-center">
<a href="{% url 'invoice_detail' invoice.pk %}" <a href="{% url 'invoice_detail' request.dealer.slug invoice.pk %}"
class="btn btn-sm btn-phoenix-success"> class="btn btn-sm btn-phoenix-success">
{% trans "view" %} {% trans "view" %}
</a> </a>

View File

@ -23,7 +23,7 @@
{% endif %} {% endif %}
<div class="card-body"> <div class="card-body">
{% if model %} {% if model %}
<form method="post" action="{% url 'payment_create' pk=model.pk %}"> <form method="post" action="{% url 'payment_create' request.dealer.slug model.pk %}">
{% endif %} {% endif %}
{% csrf_token %} {% csrf_token %}
{{ form|crispy }} {{ form|crispy }}

View File

@ -30,11 +30,11 @@
<td class="align-middle product white-space-nowrap py-0">{{ journal.je_number }}</td> <td class="align-middle product white-space-nowrap py-0">{{ journal.je_number }}</td>
{% if journal.ledger.invoicemodel %} {% if journal.ledger.invoicemodel %}
<td class="align-middle product white-space-nowrap py-0"> <td class="align-middle product white-space-nowrap py-0">
<a href="{% url 'invoice_detail' journal.ledger.invoicemodel.pk %}"><i class="fa-solid fa-receipt"></i> {{ journal.ledger.invoicemodel }}</a> <a href="{% url 'invoice_detail' request.dealer.slug journal.ledger.invoicemodel.pk %}"><i class="fa-solid fa-receipt"></i> {{ journal.ledger.invoicemodel }}</a>
</td> </td>
{% elif journal.ledger.billmodel %} {% elif journal.ledger.billmodel %}
<td class="align-middle product white-space-nowrap py-0"> <td class="align-middle product white-space-nowrap py-0">
<a href="{% url 'bill_detail' journal.ledger.billmodel.pk %}"><i class="fa-solid fa-money-bill"></i> {{ journal.ledger.billmodel }}</a> <a href="{% url 'bill-detail' request.dealer.slug request.dealer.entity.slug journal.ledger.billmodel.pk %}"><i class="fa-solid fa-money-bill"></i> {{ journal.ledger.billmodel }}</a>
</td> </td>
{% else %} {% else %}
<td class="align-middle product white-space-nowrap py-0"></td> <td class="align-middle product white-space-nowrap py-0"></td>
@ -42,7 +42,7 @@
<td class="align-middle product white-space-nowrap py-0">{{ journal.timestamp }}</td> <td class="align-middle product white-space-nowrap py-0">{{ journal.timestamp }}</td>
<td class="align-middle product white-space-nowrap py-0">{{ journal.description }}</td> <td class="align-middle product white-space-nowrap py-0">{{ journal.description }}</td>
<td class="align-middle product white-space-nowrap"> <td class="align-middle product white-space-nowrap">
<a href="{% url 'payment_details' journal.pk %}" class="btn btn-sm btn-phoenix-primary"><i class="fa-solid fa-eye me-1"></i> {% trans "View Tranactions"|capfirst %}</a> <a href="{% url 'payment_details' request.dealer.slug journal.pk %}" class="btn btn-sm btn-phoenix-primary"><i class="fa-solid fa-eye me-1"></i> {% trans "View Tranactions"|capfirst %}</a>
</td> </td>
</tr> </tr>
{% empty %} {% empty %}

View File

@ -253,13 +253,13 @@
<!-- Add links to view full estimate and invoice if they exist --> <!-- Add links to view full estimate and invoice if they exist -->
{% if sale_order.estimate %} {% if sale_order.estimate %}
<a href="{% url 'estimate_detail' sale_order.estimate.pk %}" class="btn btn-phoenix-info ms-2"> <a href="{% url 'estimate_detail' request.dealer.slug sale_order.estimate.pk %}" class="btn btn-info ms-2">
{% trans "View Full Estimate" %} {% trans "View Full Estimate" %}
</a> </a>
{% endif %} {% endif %}
{% if sale_order.invoice %} {% if sale_order.invoice %}
<a href="{% url 'invoice_detail' sale_order.invoice.pk %}" class="btn btn-phoenix-info ms-2"> <a href="{% url 'invoice_detail' request.dealer.slug sale_order.invoice.pk %}" class="btn btn-info ms-2">
{% trans "View Full Invoice" %} {% trans "View Full Invoice" %}
</a> </a>
{% endif %} {% endif %}

View File

@ -47,7 +47,7 @@
<div class="spinner-border mx-3 htmx-indicator" role="status"><span class="visually-hidden">Loading...</span></div> <div class="spinner-border mx-3 htmx-indicator" role="status"><span class="visually-hidden">Loading...</span></div>
<div class="search-box me-3"> <div class="search-box me-3">
<form class="position-relative"> <form class="position-relative">
<input class="form-control search-input search" name='search' type="search" placeholder="{{ _("Search") }}" aria-label="Search" hx-get="{% url 'car_list' %}" hx-trigger='keyup changed delay:500ms' hx-target='.table-responsive' hx-select='.table-responsive' hx-swap="innerHTML show:window:top" hx-indicator=".htmx-indicator" <input class="form-control search-input search" name='search' type="search" placeholder="{{ _("Search") }}" aria-label="Search" hx-get="{% url 'car_list' request.dealer.slug %}" hx-trigger='keyup changed delay:500ms' hx-target='.table-responsive' hx-select='.table-responsive' hx-swap="innerHTML show:window:top" hx-indicator=".htmx-indicator"
hx-on::before-request="on_before_request()" hx-on::before-request="on_before_request()"
hx-on::after-request="on_after_request()" hx-on::after-request="on_after_request()"
/> />
@ -58,7 +58,7 @@
</div> </div>
</div> </div>
<div class="d-flex align-items-center d-none filter"> <div class="d-flex align-items-center d-none filter">
<select hx-get="{% url 'car_list' %}" name="make" hx-target='.model-select' hx-select='.model-select' hx-swap="outerHTML show:window:top" hx-indicator=".htmx-indicator" class="form-select make" aria-label="Default select example" <select hx-get="{% url 'car_list' request.dealer.slug %}" name="make" hx-target='.model-select' hx-select='.model-select' hx-swap="outerHTML show:window:top" hx-indicator=".htmx-indicator" class="form-select make" aria-label="Default select example"
hx-on::before-request="filter_before_request()" hx-on::before-request="filter_before_request()"
hx-on::after-request="filter_after_request()" hx-on::after-request="filter_after_request()"
> >
@ -67,7 +67,7 @@
<option value="{{ m.pk }}">{{ m.name }}</option> <option value="{{ m.pk }}">{{ m.name }}</option>
{% endfor %} {% endfor %}
</select> </select>
<select hx-get="{% url 'car_list' %}" hx-include=".make" name="model" hx-target='.year' hx-select='.year' hx-swap="outerHTML show:window:top" hx-indicator=".htmx-indicator" class="form-select model-select" aria-label="Default select example" <select hx-get="{% url 'car_list' request.dealer.slug %}" hx-include=".make" name="model" hx-target='.year' hx-select='.year' hx-swap="outerHTML show:window:top" hx-indicator=".htmx-indicator" class="form-select model-select" aria-label="Default select example"
hx-on::before-request="filter_before_request()" hx-on::before-request="filter_before_request()"
hx-on::after-request="filter_after_request()" hx-on::after-request="filter_after_request()"
> >
@ -89,7 +89,7 @@
<option value="sold">Sold</option> <option value="sold">Sold</option>
<option value="transfer">Transfer</option> <option value="transfer">Transfer</option>
</select> </select>
<button id="search" hx-get="{% url 'car_list' %}" hx-include=".make,.model,.year,.car_status" hx-indicator=".htmx-indicator" hx-target='.table-responsive' hx-select='.table-responsive' hx-swap="outerHTML show:window:top" class="btn btn-sm btn-phoenix-primary" <button id="search" hx-get="{% url 'car_list' request.dealer.slug %}" hx-include=".make,.model,.year,.car_status" hx-indicator=".htmx-indicator" hx-target='.table-responsive' hx-select='.table-responsive' hx-swap="outerHTML show:window:top" class="btn btn-sm btn-phoenix-primary"
hx-on::before-request="filter_before_request()" hx-on::before-request="filter_before_request()"
hx-on::after-request="filter_after_request()">Search</button> hx-on::after-request="filter_after_request()">Search</button>
</div> </div>
@ -149,7 +149,7 @@
<td class="align-middle white-space-nowrap quotation"> <td class="align-middle white-space-nowrap quotation">
{% if tx.estimate %} {% if tx.estimate %}
<p class="fw-bo text-body fs-9 mb-0"> <p class="fw-bo text-body fs-9 mb-0">
<a href="{% url 'estimate_detail' tx.estimate.uuid %}"> <a href="{% url 'estimate_detail' request.dealer.slug tx.estimate.uuid %}">
{{tx.estimate.estimate_number}} {{tx.estimate.estimate_number}}
</a><br> </a><br>
{% if tx.estimate.status == "draft" %} {% if tx.estimate.status == "draft" %}
@ -167,7 +167,7 @@
<td class="align-middle white-space-nowrap invoice"> <td class="align-middle white-space-nowrap invoice">
{% if tx.invoice %} {% if tx.invoice %}
<p class="fw-bo text-body fs-9 mb-0"> <p class="fw-bo text-body fs-9 mb-0">
<a href="{% url 'invoice_detail' tx.invoice.uuid %}"> <a href="{% url 'invoice_detail' request.dealer.slug tx.invoice.uuid %}">
{{tx.invoice.invoice_number}} {{tx.invoice.invoice_number}}
</a><br> </a><br>
{% if tx.invoice.is_draft %} {% if tx.invoice.is_draft %}

View File

@ -32,7 +32,7 @@
<input class="d-none" id="emailPhotos" type="file" accept="image/*" /> <input class="d-none" id="emailPhotos" type="file" accept="image/*" />
</div> </div>
<div class="d-flex"> <div class="d-flex">
<a href="{% url 'estimate_detail' estimate.pk %}" class="btn btn-link text-body fs-10 text-decoration-none">Discard</a> <a href="{% url 'estimate_detail' request.dealer.slug estimate.pk %}" class="btn btn-link text-body fs-10 text-decoration-none">Discard</a>
<button class="btn btn-phoenix-primary fs-10" type="submit">Send<span class="fa-solid fa-paper-plane ms-1"></span></button> <button class="btn btn-phoenix-primary fs-10" type="submit">Send<span class="fa-solid fa-paper-plane ms-1"></span></button>
</div> </div>
</div> </div>