Merge pull request 'Dashboard fix' (#209) from frontend into main

Reviewed-on: #209
This commit is contained in:
ismail 2025-08-28 14:15:25 +03:00
commit 572bdbafd4
11 changed files with 11821 additions and 11929 deletions

View File

@ -762,7 +762,8 @@ class Car(Base):
make = self.id_car_make.name if self.id_car_make else "Unknown Make" make = self.id_car_make.name if self.id_car_make else "Unknown Make"
model = self.id_car_model.name if self.id_car_model else "Unknown Model" model = self.id_car_model.name if self.id_car_model else "Unknown Model"
trim = self.id_car_trim.name if self.id_car_trim else "Unknown Trim" trim = self.id_car_trim.name if self.id_car_trim else "Unknown Trim"
return f"{self.year} - {make} - {model} - {trim}" vin=self.vin if self.vin else None
return f"{self.year} - {make} - {model} - {trim}-{vin}"
@property @property
def product(self): def product(self):

View File

@ -10,8 +10,8 @@ urlpatterns = [
# main URLs # main URLs
path("", views.WelcomeView, name="welcome"), path("", views.WelcomeView, name="welcome"),
path("signup/", views.dealer_signup, name="account_signup"), path("signup/", views.dealer_signup, name="account_signup"),
path("", views.HomeView.as_view(), name="home"), path("", views.HomeView, name="home"),
path("<slug:dealer_slug>/", views.HomeView.as_view(), name="home"), path("<slug:dealer_slug>/", views.HomeView, name="home"),
# Tasks # Tasks
path("legal/", views.terms_and_privacy, name="terms_and_privacy"), path("legal/", views.terms_and_privacy, name="terms_and_privacy"),
# path('tasks/<int:task_id>/detail/', views.task_detail, name='task_detail'), # path('tasks/<int:task_id>/detail/', views.task_detail, name='task_detail'),
@ -40,18 +40,13 @@ urlpatterns = [
views.assign_car_makes, views.assign_car_makes,
name="assign_car_makes", name="assign_car_makes",
), ),
# dashboards for manager, dealer, inventory and accounatant
path(
"dashboards/<slug:dealer_slug>/general/", #dashboards for manager, dealer, inventory and accounatant
views.general_dashboard, path("dashboards/<slug:dealer_slug>/general/", views.general_dashboard,name="general_dashboard"),
name="general_dashboard", #dashboard for sales
), path("dashboards/<slug:dealer_slug>/sales/", views.sales_dashboard, name="sales_dashboard"),
# dashboard for sales
path(
"dashboards/<slug:dealer_slug>/sales/",
views.sales_dashboard,
name="sales_dashboard",
),
path( path(
"<slug:dealer_slug>/cars/aging-inventory/list", "<slug:dealer_slug>/cars/aging-inventory/list",
views.aging_inventory_list_view, views.aging_inventory_list_view,
@ -782,11 +777,7 @@ urlpatterns = [
views.EstimateDetailView.as_view(), views.EstimateDetailView.as_view(),
name="estimate_detail", name="estimate_detail",
), ),
path( path('<slug:dealer_slug>/sales/estimates/print/<uuid:pk>/', views.EstimatePrintView.as_view(), name='estimate_print'),
"<slug:dealer_slug>/sales/estimates/print/<uuid:pk>/",
views.EstimatePrintView.as_view(),
name="estimate_print",
),
path( path(
"<slug:dealer_slug>/sales/estimates/create/", "<slug:dealer_slug>/sales/estimates/create/",
views.create_estimate, views.create_estimate,
@ -943,6 +934,7 @@ urlpatterns = [
views.ItemServiceUpdateView.as_view(), views.ItemServiceUpdateView.as_view(),
name="item_service_update", name="item_service_update",
), ),
# Expanese # Expanese
path( path(
"<slug:dealer_slug>/items/expeneses/", "<slug:dealer_slug>/items/expeneses/",
@ -1101,47 +1093,32 @@ urlpatterns = [
name="entity-ic-date", name="entity-ic-date",
), ),
# Chart of Accounts... # Chart of Accounts...
path( path('<slug:dealer_slug>/chart-of-accounts/<slug:entity_slug>/list/',
"<slug:dealer_slug>/chart-of-accounts/<slug:entity_slug>/list/",
views.ChartOfAccountModelListView.as_view(), views.ChartOfAccountModelListView.as_view(),
name="coa-list", name='coa-list'),
), path('<slug:dealer_slug>/chart-of-accounts/<slug:entity_slug>/list/inactive/',
path( views.ChartOfAccountModelListView.as_view(inactive=True),
"<slug:dealer_slug>/chart-of-accounts/<slug:entity_slug>/list/inactive/", name='coa-list-inactive'),
views.ChartOfAccountModelListView.as_view(inactive=True), path('<slug:dealer_slug>/<slug:entity_slug>/create/',
name="coa-list-inactive", views.ChartOfAccountModelCreateView.as_view(),
), name='coa-create'),
path( path('<slug:dealer_slug>/<slug:entity_slug>/detail/<slug:coa_slug>/',
"<slug:dealer_slug>/<slug:entity_slug>/create/", views.ChartOfAccountModelListView.as_view(),
views.ChartOfAccountModelCreateView.as_view(), name='coa-detail'),
name="coa-create", path('<slug:dealer_slug>/<slug:entity_slug>/update/<slug:coa_slug>/',
), views.ChartOfAccountModelUpdateView.as_view(),
path( name='coa-update'),
"<slug:dealer_slug>/<slug:entity_slug>/detail/<slug:coa_slug>/",
views.ChartOfAccountModelListView.as_view(),
name="coa-detail",
),
path(
"<slug:dealer_slug>/<slug:entity_slug>/update/<slug:coa_slug>/",
views.ChartOfAccountModelUpdateView.as_view(),
name="coa-update",
),
# ACTIONS.... # ACTIONS....
path( path('<slug:dealer_slug>/<slug:entity_slug>/action/<slug:coa_slug>/mark-as-default/',
"<slug:dealer_slug>/<slug:entity_slug>/action/<slug:coa_slug>/mark-as-default/", views.CharOfAccountModelActionView.as_view(action_name='mark_as_default'),
views.CharOfAccountModelActionView.as_view(action_name="mark_as_default"), name='coa-action-mark-as-default'),
name="coa-action-mark-as-default", path('<slug:dealer_slug>/<slug:entity_slug>/action/<slug:coa_slug>/mark-as-active/',
), views.CharOfAccountModelActionView.as_view(action_name='mark_as_active'),
path( name='coa-action-mark-as-active'),
"<slug:dealer_slug>/<slug:entity_slug>/action/<slug:coa_slug>/mark-as-active/", path('<slug:dealer_slug>/<slug:entity_slug>/action/<slug:coa_slug>/mark-as-inactive/',
views.CharOfAccountModelActionView.as_view(action_name="mark_as_active"), views.CharOfAccountModelActionView.as_view(action_name='mark_as_inactive'),
name="coa-action-mark-as-active", name='coa-action-mark-as-inactive'),
),
path(
"<slug:dealer_slug>/<slug:entity_slug>/action/<slug:coa_slug>/mark-as-inactive/",
views.CharOfAccountModelActionView.as_view(action_name="mark_as_inactive"),
name="coa-action-mark-as-inactive",
),
# CASH FLOW STATEMENTS... # CASH FLOW STATEMENTS...
# Entities... # Entities...
path( path(
@ -1317,74 +1294,40 @@ urlpatterns = [
views.PurchaseOrderMarkAsVoidView.as_view(), views.PurchaseOrderMarkAsVoidView.as_view(),
name="po-action-mark-as-void", name="po-action-mark-as-void",
), ),
# reports # reports
path( path(
"<slug:dealer_slug>/purchase-report/", "<slug:dealer_slug>/purchase-report/",
views.purchase_report_view, views.purchase_report_view,
name="po-report", name="po-report",
), ),
path( path('purchase-report/<slug:dealer_slug>/csv/', views.purchase_report_csv_export, name='purchase-report-csv-export'),
"purchase-report/<slug:dealer_slug>/csv/",
views.purchase_report_csv_export, path(
name="purchase-report-csv-export",
),
path(
"<slug:dealer_slug>/car-sale-report/", "<slug:dealer_slug>/car-sale-report/",
views.car_sale_report_view, views.car_sale_report_view,
name="car-sale-report", name="car-sale-report",
), ),
path( path('car-sale-report/<slug:dealer_slug>/csv/', views.car_sale_report_csv_export, name='car-sale-report-csv-export'),
"car-sale-report/<slug:dealer_slug>/csv/",
views.car_sale_report_csv_export, path('feature/recall/', views.RecallListView.as_view(), name='recall_list'),
name="car-sale-report-csv-export", path('feature/recall/filter/', views.RecallFilterView, name='recall_filter'),
), path('feature/recall/<int:pk>/view/', views.RecallDetailView.as_view(), name='recall_detail'),
path("feature/recall/", views.RecallListView.as_view(), name="recall_list"), path('feature/recall/create/', views.RecallCreateView.as_view(), name='recall_create'),
path("feature/recall/filter/", views.RecallFilterView, name="recall_filter"), path('feature/recall/success/', views.RecallSuccessView.as_view(), name='recall_success'),
path(
"feature/recall/<int:pk>/view/", path('<slug:dealer_slug>/schedules/calendar/', views.schedule_calendar, name='schedule_calendar'),
views.RecallDetailView.as_view(),
name="recall_detail",
),
path(
"feature/recall/create/", views.RecallCreateView.as_view(), name="recall_create"
),
path(
"feature/recall/success/",
views.RecallSuccessView.as_view(),
name="recall_success",
),
path(
"<slug:dealer_slug>/schedules/calendar/",
views.schedule_calendar,
name="schedule_calendar",
),
# staff profile # staff profile
path( path('<slug:dealer_slug>/staff/<slug:slug>detail/', views.StaffDetailView.as_view(), name='staff_detail'),
"<slug:dealer_slug>/staff/<slug:slug>detail/",
views.StaffDetailView.as_view(),
name="staff_detail",
),
# tickets # tickets
path("help_center/view/", views.help_center, name="help_center"), path('help_center/view/', views.help_center, name='help_center'),
path( path('<slug:dealer_slug>/help_center/tickets/', views.ticket_list, name='ticket_list'),
"<slug:dealer_slug>/help_center/tickets/", views.ticket_list, name="ticket_list" path('help_center/tickets/<slug:dealer_slug>/create/', views.create_ticket, name='create_ticket'),
), path('<slug:dealer_slug>/help_center/tickets/<int:ticket_id>/', views.ticket_detail, name='ticket_detail'),
path( path('help_center/tickets/<int:ticket_id>/update/', views.ticket_update, name='ticket_update'),
"help_center/tickets/<slug:dealer_slug>/create/",
views.create_ticket,
name="create_ticket",
),
path(
"<slug:dealer_slug>/help_center/tickets/<int:ticket_id>/",
views.ticket_detail,
name="ticket_detail",
),
path(
"help_center/tickets/<int:ticket_id>/update/",
views.ticket_update,
name="ticket_update",
),
# path('help_center/tickets/<int:ticket_id>/ticket_mark_resolved/', views.ticket_mark_resolved, name='ticket_mark_resolved'), # path('help_center/tickets/<int:ticket_id>/ticket_mark_resolved/', views.ticket_mark_resolved, name='ticket_mark_resolved'),
] ]
handler404 = "inventory.views.custom_page_not_found_view" handler404 = "inventory.views.custom_page_not_found_view"

View File

@ -362,24 +362,31 @@ def dealer_signup(request):
"account/signup-wizard.html", "account/signup-wizard.html",
) )
class HomeView(LoginRequiredMixin, TemplateView): # class HomeView(LoginRequiredMixin, TemplateView):
""" # """
HomeView class responsible for rendering the home page. # HomeView class responsible for rendering the home page.
This class ensures that only authenticated users can access the home page. # This class ensures that only authenticated users can access the home page.
Unauthenticated users are redirected to the welcome page. It is built on top of # Unauthenticated users are redirected to the welcome page. It is built on top of
Django's TemplateView and includes additional functionality by inheriting from # Django's TemplateView and includes additional functionality by inheriting from
LoginRequiredMixin. The purpose of this class is to control the accessibility # LoginRequiredMixin. The purpose of this class is to control the accessibility
of the main index page of the application and manage context data for frontend # of the main index page of the application and manage context data for frontend
rendering. # rendering.
:ivar template_name: The path to the template used for rendering the view's # :ivar template_name: The path to the template used for rendering the view's
output. # output.
:type template_name: str # :type template_name: str
""" # """
template_name = "index.html" # template_name = "index.html"
@login_required
def HomeView(request,dealer_slug=None):
dealer_slug=request.dealer.slug
if request.is_sales and not request.is_manager and not request.is_dealer:
return redirect('sales_dashboard', dealer_slug=dealer_slug)
else:
return redirect('general_dashboard',dealer_slug=dealer_slug)
class TestView(TemplateView): class TestView(TemplateView):
""" """
@ -6328,6 +6335,7 @@ def lead_create(request, dealer_slug):
qs = form.fields["id_car_make"].queryset.filter( qs = form.fields["id_car_make"].queryset.filter(
is_sa_import=True, pk__in=dealer_make_list is_sa_import=True, pk__in=dealer_make_list
) )
# print(qs)
form.fields["staff"].queryset = ( form.fields["staff"].queryset = (
form.fields["staff"] form.fields["staff"]
.queryset.select_related("user") .queryset.select_related("user")
@ -6346,10 +6354,12 @@ def lead_create(request, dealer_slug):
form.fields["staff"].queryset = models.Staff.objects.filter( form.fields["staff"].queryset = models.Staff.objects.filter(
dealer=dealer, pk=request.staff.pk dealer=dealer, pk=request.staff.pk
) )
qs = qs.order_by("name")
form.fields["id_car_make"].queryset = qs form.fields["id_car_make"].queryset = qs
form.fields["id_car_make"].choices = [ form.fields["id_car_make"].choices = [
(obj.id_car_make, obj.get_local_name()) for obj in qs (obj.id_car_make, obj.get_local_name()) for obj in qs
] ]
if first_make := qs.first(): if first_make := qs.first():
form.fields["id_car_model"].queryset = first_make.carmodel_set.all() form.fields["id_car_model"].queryset = first_make.carmodel_set.all()
@ -6505,34 +6515,6 @@ def update_lead_actions(request, dealer_slug):
# return JsonResponse({"success": False, "message": str(e)}, status=500) # return JsonResponse({"success": False, "message": str(e)}, status=500)
def lead_update(request,dealer_slug,slug):
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
lead = get_object_or_404(models.Lead, slug=slug)
form = forms.LeadForm(instance=lead)
if "HX-Request" in request.headers:
make_id = request.GET.get("id_car_make")
make = models.CarMake.objects.get(pk=make_id)
form.fields[
"id_car_model"
].queryset = make.carmodel_set.all()
else:
form.fields[
"id_car_model"
].queryset = form.instance.id_car_make.carmodel_set.all()
form.fields["staff"].queryset = (
form.fields["staff"]
.queryset.select_related("user")
.filter(
dealer=dealer,
user__groups__permissions__codename__contains="add_lead",
)
.distinct()
)
context = {
"form":form
}
return render(request,"crm/leads/lead_form.html",context)
class LeadUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView): class LeadUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
""" """
Handles the update view for Lead objects. Handles the update view for Lead objects.
@ -8463,7 +8445,7 @@ class FiscalYearIncomeStatementViewBase(
""" """
template_name = "ledger/reports/income_statement.html" template_name = "ledger/reports/income_statement.html"
permission_required = ["inventory.view_carfinance"] permission_required = ["django_ledger.view_ledgermodel"]
def get_login_url(self): def get_login_url(self):
return reverse("account_login") return reverse("account_login")
@ -8602,7 +8584,7 @@ class FiscalYearCashFlowStatementViewBase(
""" """
template_name = "ledger/reports/cash_flow_statement.html" template_name = "ledger/reports/cash_flow_statement.html"
permission_required = ["inventory.view_carfinance"] permission_required = ["django_ledger.view_ledgermodel"]
def get_login_url(self): def get_login_url(self):
return reverse("account_login") return reverse("account_login")
@ -8791,7 +8773,7 @@ class FiscalYearEntityModelDashboardView(
:type permission_required: list :type permission_required: list
""" """
permission_required = ["inventory.view_carfinance"] permission_required = ["django_ledger.view_ledgermodel"]
def get_login_url(self): def get_login_url(self):
return reverse("account_login") return reverse("account_login")
@ -11461,6 +11443,10 @@ def create_ticket(request,dealer_slug):
def ticket_list(request,dealer_slug): def ticket_list(request,dealer_slug):
dealer= get_object_or_404(models.Dealer, slug=dealer_slug) dealer= get_object_or_404(models.Dealer, slug=dealer_slug)
tickets = models.Ticket.objects.filter(dealer=dealer).order_by('-created_at') tickets = models.Ticket.objects.filter(dealer=dealer).order_by('-created_at')
query=request.GET.get('q')
if query:
tickets=tickets.filter(Q(id__icontains=query)| Q(subject__icontains=query))
return render(request, 'support/ticket_list.html', {'tickets': tickets}) return render(request, 'support/ticket_list.html', {'tickets': tickets})
@login_required @login_required

View File

@ -88,7 +88,7 @@
</div> </div>
<div id="main_content" <div id="main_content"
class="fade-me-in" class="fade-me-in"
hx-boost="false" hx-boost="true"
hx-target="#main_content" hx-target="#main_content"
hx-select="#main_content" hx-select="#main_content"
hx-swap="outerHTML transition:true" hx-swap="outerHTML transition:true"

View File

@ -12,7 +12,7 @@
<h5 class="fw-bold mb-0 text-dark">{% trans "Monthly Revenue & Profit" %}</h5> <h5 class="fw-bold mb-0 text-dark">{% trans "Monthly Revenue & Profit" %}</h5>
</div> </div>
<div class="card-body" style="height: 400px;"> <div class="card-body" style="height: 400px;">
<canvas id="revenueProfitChart"></canvas> <canvas id="revenueProfitChart" ></canvas>
</div> </div>
</div> </div>
</div> </div>

View File

@ -11,6 +11,7 @@
hx-swap="outerHTML" hx-swap="outerHTML"
hx-select-oob="#toast-container" hx-select-oob="#toast-container"
hx-indicator="#spinner"> hx-indicator="#spinner">
<li class="nav-item"> <li class="nav-item">
{% comment %} <p class="navbar-vertical-label text-primary fs-8 text-truncate">{{request.dealer|default:"Apps"}}</p> {% comment %} <p class="navbar-vertical-label text-primary fs-8 text-truncate">{{request.dealer|default:"Apps"}}</p>
<hr class="navbar-vertical-line"> {% endcomment %} <hr class="navbar-vertical-line"> {% endcomment %}
@ -439,25 +440,23 @@
</div> </div>
</a> </a>
</li> </li>
<li class="nav-item ">
<a class="nav-link" href="#">
<div class="d-flex align-items-center">
{% if user.is_authenticated %}
<span class="nav-link-icon"><span class="fa-solid fa-car"></span></span>
<span class="nav-link-text">{{ request.dealer.user.username }}</span>
{% endif %}
</div>
</a>
</li>
</ul> </ul>
</div> </div>
{% endif %} {% endif %}
</div> </div>
</div> </div>
<div class="navbar-vertical-footer"> <div class="navbar-vertical-footer">
<button class="btn navbar-vertical-toggle border-0 fw-semibold w-100 white-space-nowrap d-flex align-items-center"> <a class="nav-link ps-2" href="{% if request.is_dealer%}{% url 'ticket_list' request.dealer.slug %} {% else %}#{%endif%}">
<span class="fas fa-angle-double-left fs-8"></span><span class="fas fa-angle-double-right fs-8"></span><span class="navbar-vertical-footer-text ms-2">Collapsed View</span> <div class="d-flex align-items-center">
</button> {% if user.is_authenticated%}
<span class="nav-link-icon"><span class="fa-solid fa-gear me-1 fs-5"></span></span>
<span class="nav-link-text">{{ request.dealer.user.username }}</span>
{% endif %}
</div>
</a>
</div> </div>
</nav> </nav>
<nav class="navbar navbar-top fixed-top navbar-expand" id="navbarDefault"> <nav class="navbar navbar-top fixed-top navbar-expand" id="navbarDefault">
@ -626,10 +625,12 @@
href="{% url 'management' request.dealer.slug %}"> <span class="me-2 text-body align-bottom" data-feather="shield"></span>{{ _("Admin Managemnet") }}</a> href="{% url 'management' request.dealer.slug %}"> <span class="me-2 text-body align-bottom" data-feather="shield"></span>{{ _("Admin Managemnet") }}</a>
{% endif %} {% endif %}
</li> </li>
{% if request.is_dealer%}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link px-3 d-block" <a class="nav-link px-3 d-block"
href="{% url 'ticket_list' request.dealer.slug %}"> <span class="me-2 text-body align-bottom" data-feather="help-circle"></span>{{ _("Help Center") }}</a> href="{% url 'ticket_list' request.dealer.slug %}"> <span class="me-2 text-body align-bottom" data-feather="help-circle"></span>{{ _("Help Center") }}</a>
</li> </li>
{% endif %}
{% if request.is_staff %} {% if request.is_staff %}
<li class="nav-item"> <li class="nav-item">
<a hx-boost="false" <a hx-boost="false"

View File

@ -1,9 +1,16 @@
{% extends 'base.html' %}
{% comment %} {% extends 'base.html' %}
{% load i18n static custom_filters django_ledger %} {% load i18n static custom_filters django_ledger %}
{% block content %} {% block content %}
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
{% if request.is_sales and not request.is_manager and not request.is_dealer %}
{% url 'sales_dashboard' request.dealer.slug as dashboard_url %}
{% else %}
{% url 'general_dashboard' request.dealer.slug as dashboard_url %}
{% endif %}
<div id="dashboard-content" <div id="dashboard-content"
hx-get="{% if request.is_sales and not request.is_manager %} {% url 'sales_dashboard' request.dealer.slug %} {% else %} {% url 'general_dashboard' request.dealer.slug %} {% endif %}" hx-get="{{ dashboard_url }}"
hx-trigger="load" hx-trigger="load"
hx-target="#dashboard-content" hx-target="#dashboard-content"
hx-swap="innerHTML"> hx-swap="innerHTML">
@ -13,4 +20,6 @@
</div> </div>
</div> </div>
{% endif %} {% endif %}
{% endblock %}
{% endblock %} {% endcomment %}

View File

@ -77,15 +77,182 @@
<div class="row-fluid {% if car.status == 'sold' %}disabled{% endif %}"> <div class="row-fluid {% if car.status == 'sold' %}disabled{% endif %}">
<div class="row g-3 justify-content-between"> <div class="row g-3 justify-content-between">
<div class="col-md-6"> <div class="col-md-6">
<div class="row mb-2"> <div class="card mb-3 rounded shadow d-flex justify-content-center align-item-center{% if car.get_transfer %}disabled{% endif %}">
<div class="col-md-4"> <p class="card-header rounded-top fw-bold">{% trans 'Car Details' %}</p>
<div class="col-md-4 ms-4 mt-2">
<div class="avatar avatar-6xl mb-3"> <div class="avatar avatar-6xl mb-3">
<img class="rounded" <img class="rounded"
src="{% static 'images/car_images/' %}{{ car.get_hash }}.png" src="{% static 'images/car_images/' %}{{ car.get_hash }}.png"
alt="{{ car.vin }}" /> alt="{{ car.vin }}" />
</div> </div>
</div> </div>
<div class="col-md-8"> <div class="card-body">
<div class="table-responsive scrollbar mb-3">
<table class="table table-sm fs-9 mb-0 overflow-hidden">
<tr>
<th>{% trans "VIN" %}</th>
<td>{{ car.vin }}</td>
</tr>
<tr>
<th>{% trans "year"|capfirst %}</th>
<td>{{ car.year }}</td>
</tr>
<tr>
<th>{% trans "make"|capfirst %}</th>
<td>{{ car.id_car_make.get_local_name }}</td>
</tr>
<tr>
<th>{% trans "model"|capfirst %}</th>
<td>{{ car.id_car_model.get_local_name }}</td>
</tr>
<tr>
<th>{% trans "series"|capfirst %}</th>
<td>{{ car.id_car_serie.name }}</td>
</tr>
<tr>
<th>{% trans "trim"|capfirst %}</th>
<td>{{ car.id_car_trim.name }}</td>
</tr>
<tr>
<th>{% trans "Status"|capfirst %}</th>
<td>{{ car.get_status_display }}</td>
</tr>
<tr>
<th>{% trans "Stock Type"|capfirst %}</th>
<td>{{ car.get_stock_type_display }}</td>
</tr>
<tr>
<th>{% trans "Mileage"|capfirst %}</th>
<td>{{ car.mileage }}</td>
</tr>
<tr>
<th>{% trans "Receiving Date"|capfirst %}</th>
<td>{{ car.receiving_date|timesince }}</td>
</tr>
{% if car.vendor %}
<tr>
<th>{% trans "Vendor"|capfirst %}</th>
<td>{{ car.vendor.name }}</td>
</tr>
{% endif %}
<tr>
<th>{% trans "Remarks"|capfirst %}</th>
<td>{{ car.remarks }}</td>
</tr>
<tr>
<th>{% trans 'specifications'|capfirst %}</th>
<td>
<button type="button"
class="btn btn-phoenix-primary btn-sm"
id="specification-btn"
data-bs-toggle="modal"
data-bs-target="#specificationsModal">
{% trans 'view'|capfirst %}
</button>
</td>
</tr>
{% if car.custom_cards %}
<tr>
<th>{% trans "Custom Number"|capfirst %}</th>
<td>{{ car.custom_cards.custom_number }}</td>
</tr>
<tr>
<th>{% trans "Custom Date"|capfirst %}</th>
<td>{{ car.custom_cards.custom_date|date }}</td>
</tr>
{% else %}
<tr>
<th>{% trans "Custom Card" %}</th>
<td>
{% if perms.inventory.add_customcard %}
<button type="button"
class="btn btn-sm btn-phoenix-success"
data-bs-toggle="modal"
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>
{% endif %}
</td>
</tr>
{% endif %}
{% if car.registrations %}
<tr>
<th>{% trans "Registration"|capfirst %}</th>
<td>
{{ car.registrations.plate_number }} | {{ car.registrations.text1 }} {{ car.registrations.text2 }} {{ car.registrations.text3 }}
</td>
</tr>
<tr>
<th>{% trans "Registration Date"|capfirst %}</th>
<td>{{ car.registrations.registration_date|date }}</td>
</tr>
{% else %}
<tr>
<th>{% trans "Registration" %}</th>
<td>
{% if perms.inventory.add_carregistration %}
<button type="button"
class="btn btn-sm btn-phoenix-success"
data-bs-toggle="modal"
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>
{% endif %}
</td>
</tr>
{% endif %}
<tr>
<th>{% trans 'Location'|capfirst %}</th>
<td>
{% if car.marked_price and not car.get_transfer %}
{% if car.location %}
{% if car.location.is_owner_showroom %}
{% trans 'Our Showroom' %}
{% else %}
{{ car.location.showroom.get_local_name }}
{% endif %}
{% if perms.inventory.add_cartransfer %}
<a href="{% url 'update_car_location' car.slug car.location.pk %}"
class="btn btn-phoenix-danger btn-sm">
{% trans "transfer"|capfirst %}
</a>
{% endif %}
{% else %}
{% trans "No location available." %}
{% if perms.inventory.add_carlocation %}
<a href="{% url 'add_car_location' car.slug %}"
class="btn btn-phoenix-success btn-sm ms-2">{% trans "Add" %}</a>
{% endif %}
{% endif %}
{% endif %}
</td>
</tr>
</table>
</div>
<div>
{% if not car.get_transfer %}
{% if perms.inventory.change_car %}
<a href="{% url 'car_update' request.dealer.slug car.slug %}"
class="btn btn-phoenix-primary btn-sm mt-1 me-3 mb-3">{% trans "Edit" %}
<span class="fas fa-solid fa-pencil ms-1"></span>
</a>
<a href="{% url 'transfer' car.slug %}"
class="btn btn-phoenix-danger btn-sm">
{% trans "Sell to another dealer"|capfirst %}
</a>
{% endif %}
{% else %}
<span class="badge bg-danger">{% trans "Cannot Edit, Car in Transfer." %}</span>
{% endif %}
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="row mb-2">
<div class="col-md-12">
<div class="card rounded shadow d-flex align-content-center {% if car.get_transfer %}transfer{% endif %}"> <div class="card rounded shadow d-flex align-content-center {% if car.get_transfer %}transfer{% endif %}">
<p class="card-header rounded-top fw-bold">{% trans 'Financial Details' %}</p> <p class="card-header rounded-top fw-bold">{% trans 'Financial Details' %}</p>
<div class="card-body"> <div class="card-body">
@ -100,34 +267,7 @@
<th>{% trans "Marked Price"|capfirst %}</th> <th>{% trans "Marked Price"|capfirst %}</th>
<td>{{ car.marked_price|floatformat:2 }}</td> <td>{{ car.marked_price|floatformat:2 }}</td>
</tr> </tr>
{% comment %} <tr>
<th>{% trans "Selling Price"|capfirst %}</th>
<td>{{ car.finances.selling_price|floatformat:2 }}</td>
</tr>
<tr>
<th>{% trans "Discount Amount"|capfirst %}</th>
<td>{{ car.finances.discount_amount|floatformat:2 }}</td>
</tr>
<tr>
<th>{% trans "Additional Fee"|capfirst %}</th>
<td></td>
</tr>
{% if car.finances.additional_services.first.pk %}
{% for service in car.finances.additional_services.all %}
<tr>
<td>{{ service.name }}</td>
<td>{{ service.price_|floatformat:2 }}</td>
</tr>
{% endfor %}
{% endif %}
<tr>
<th>{% trans "VAT Amount"|capfirst %}</th>
<td>{{ car.finances.vat_amount|floatformat:2 }}</td>
</tr>
<tr>
<th>{% trans "Total"|capfirst %}</th>
<td>{{ car.finances.total_vat|floatformat:2 }}</td>
</tr> {% endcomment %}
<tr> <tr>
<td colspan="2"> <td colspan="2">
{% if not car.get_transfer %} {% if not car.get_transfer %}
@ -327,173 +467,7 @@
</div> </div>
{% endif %} {% endif %}
</div> </div>
<div class="col-md-6">
<div class="card mb-3 rounded shadow d-flex align-content-center {% if car.get_transfer %}disabled{% endif %}">
<p class="card-header rounded-top fw-bold">{% trans 'Car Details' %}</p>
<div class="card-body">
<div class="table-responsive scrollbar mb-3">
<table class="table table-sm fs-9 mb-0 overflow-hidden">
<tr>
<th>{% trans "VIN" %}</th>
<td>{{ car.vin }}</td>
</tr>
<tr>
<th>{% trans "year"|capfirst %}</th>
<td>{{ car.year }}</td>
</tr>
<tr>
<th>{% trans "make"|capfirst %}</th>
<td>{{ car.id_car_make.get_local_name }}</td>
</tr>
<tr>
<th>{% trans "model"|capfirst %}</th>
<td>{{ car.id_car_model.get_local_name }}</td>
</tr>
<tr>
<th>{% trans "series"|capfirst %}</th>
<td>{{ car.id_car_serie.name }}</td>
</tr>
<tr>
<th>{% trans "trim"|capfirst %}</th>
<td>{{ car.id_car_trim.name }}</td>
</tr>
<tr>
<th>{% trans "Status"|capfirst %}</th>
<td>{{ car.get_status_display }}</td>
</tr>
<tr>
<th>{% trans "Stock Type"|capfirst %}</th>
<td>{{ car.get_stock_type_display }}</td>
</tr>
<tr>
<th>{% trans "Mileage"|capfirst %}</th>
<td>{{ car.mileage }}</td>
</tr>
<tr>
<th>{% trans "Receiving Date"|capfirst %}</th>
<td>{{ car.receiving_date|timesince }}</td>
</tr>
{% if car.vendor %}
<tr>
<th>{% trans "Vendor"|capfirst %}</th>
<td>{{ car.vendor.name }}</td>
</tr>
{% endif %}
<tr>
<th>{% trans "Remarks"|capfirst %}</th>
<td>{{ car.remarks }}</td>
</tr>
<tr>
<th>{% trans 'specifications'|capfirst %}</th>
<td>
<button type="button"
class="btn btn-phoenix-primary btn-sm"
id="specification-btn"
data-bs-toggle="modal"
data-bs-target="#specificationsModal">
{% trans 'view'|capfirst %}
</button>
</td>
</tr>
{% if car.custom_cards %}
<tr>
<th>{% trans "Custom Number"|capfirst %}</th>
<td>{{ car.custom_cards.custom_number }}</td>
</tr>
<tr>
<th>{% trans "Custom Date"|capfirst %}</th>
<td>{{ car.custom_cards.custom_date|date }}</td>
</tr>
{% else %}
<tr>
<th>{% trans "Custom Card" %}</th>
<td>
{% if perms.inventory.add_customcard %}
<button type="button"
class="btn btn-sm btn-phoenix-success"
data-bs-toggle="modal"
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>
{% endif %}
</td>
</tr>
{% endif %}
{% if car.registrations %}
<tr>
<th>{% trans "Registration"|capfirst %}</th>
<td>
{{ car.registrations.plate_number }} | {{ car.registrations.text1 }} {{ car.registrations.text2 }} {{ car.registrations.text3 }}
</td>
</tr>
<tr>
<th>{% trans "Registration Date"|capfirst %}</th>
<td>{{ car.registrations.registration_date|date }}</td>
</tr>
{% else %}
<tr>
<th>{% trans "Registration" %}</th>
<td>
{% if perms.inventory.add_carregistration %}
<button type="button"
class="btn btn-sm btn-phoenix-success"
data-bs-toggle="modal"
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>
{% endif %}
</td>
</tr>
{% endif %}
<tr>
<th>{% trans 'Location'|capfirst %}</th>
<td>
{% if car.marked_price and not car.get_transfer %}
{% if car.location %}
{% if car.location.is_owner_showroom %}
{% trans 'Our Showroom' %}
{% else %}
{{ car.location.showroom.get_local_name }}
{% endif %}
{% if perms.inventory.add_cartransfer %}
<a href="{% url 'update_car_location' car.slug car.location.pk %}"
class="btn btn-phoenix-danger btn-sm">
{% trans "transfer"|capfirst %}
</a>
{% endif %}
{% else %}
{% trans "No location available." %}
{% if perms.inventory.add_carlocation %}
<a href="{% url 'add_car_location' car.slug %}"
class="btn btn-phoenix-success btn-sm ms-2">{% trans "Add" %}</a>
{% endif %}
{% endif %}
{% endif %}
</td>
</tr>
</table>
</div>
<div>
{% if not car.get_transfer %}
{% if perms.inventory.change_car %}
<a href="{% url 'car_update' request.dealer.slug car.slug %}"
class="btn btn-phoenix-primary btn-sm mt-1 me-3 mb-3">{% trans "Edit" %}
<span class="fas fa-solid fa-pencil ms-1"></span>
</a>
<a href="{% url 'transfer' car.slug %}"
class="btn btn-phoenix-danger btn-sm">
{% trans "Sell to another dealer"|capfirst %}
</a>
{% endif %}
{% else %}
<span class="badge bg-danger">{% trans "Cannot Edit, Car in Transfer." %}</span>
{% endif %}
</div>
</div>
</div>
</div>
</div> </div>
{% if car.status == 'sold' %} {% if car.status == 'sold' %}
<img class="car_status" <img class="car_status"

View File

@ -239,12 +239,12 @@
<span class="fs-10 fw-light me-2">{{ _("Inventory Ready") }}</span> <span class="fs-10 fw-light me-2">{{ _("Inventory Ready") }}</span>
{% if car.ready %} {% if car.ready %}
<span class="badge bg-success rounded-circle p-1 me-2"> <span class="badge bg-success rounded-circle p-1 me-2">
<span class="visually-hidden">Ready</span> <span class="visually-hidden">{% trans "Ready" %}</span>
</span> </span>
<span class="text-success fw-bold">{{ _("Yes") }}</span> <span class="text-success fw-bold">{{ _("Yes") }}</span>
{% else %} {% else %}
<span class="badge bg-danger rounded-circle p-1 me-2"> <span class="badge bg-danger rounded-circle p-1 me-2">
<span class="visually-hidden">Not Ready</span> <span class="visually-hidden">{% trans "Not Ready" %}</span>
</span> </span>
<span class="text-danger fw-bold">{{ _("No") }}</span> <span class="text-danger fw-bold">{{ _("No") }}</span>
{% endif %} {% endif %}
@ -306,3 +306,11 @@
{% include "empty-illustration-page.html" with value="car" url=create_car_url %} {% include "empty-illustration-page.html" with value="car" url=create_car_url %}
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block customJS%}
<script>
function toggle_filter() {
const filterContainer = document.querySelector('.filter');
filterContainer.classList.toggle('d-none');
}
</script>
{% endblock %}

View File

@ -5,6 +5,7 @@
{% endblock title %} {% endblock title %}
{% block content %} {% block content %}
{% if expenses or request.GET.q %} {% if expenses or request.GET.q %}
<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=""> <h3 class="">

View File

@ -1,68 +1,37 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load i18n crispy_forms_filters %} {% load i18n crispy_forms_filters %}
{% block title %} {% block title %}
{% trans 'Billing Information' %} {% trans 'Billing Information' %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% comment %} <div class="row mb-3">
<div class="col-sm-6">
<form action="{% url 'billing_info' %}{% if request.GET.next %}?next={{ request.GET.next }}{% endif %}" method="post" class="form">
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5">
<h3>{% trans "Provide billing data"|upper %}</h3> <div class="col-md-8">
{% csrf_token %} <div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
{{ form|crispy }} <div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
<button type="submit" class="btn btn-sm btn-phoenix-success me-2"> {% trans "Provide billing data"|upper %}
<i class="fa fa-save me-1"></i>{{ _("Save") }} <i class="fas fa-file-invoice-dollar ms-2"></i>
</button> </h3>
{% if object %} </div>
<a class="btn btn-sm btn-phoenix-danger " href="{% url 'billing_info_delete' %}"><i class="fa-solid fa-trash me-1"></i> {{ _("Delete") }}</a> <div class="card-body p-4 p-md-5">
{% endif %} <form action="{% url 'billing_info' %}{% if request.GET.next %}?next={{ request.GET.next }}{% endif %}"
method="post" class="needs-validation" novalidate>
</form> {% csrf_token %}
</div> {{ form|crispy }}
</div> {% endcomment %} <hr class="my-4">
<!----> <div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<div class="row justify-content-center mt-5 mb-3"> <button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<div class="col-lg-8 col-md-10"> <i class="fa-solid fa-floppy-disk me-1"></i>
<div class="card shadow-sm border-0 rounded-3"> {{ _("Save") }}
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3"> </button>
<h3 class="mb-0 fs-4 text-center"> <a href="{% url 'dealer_detail' request.dealer.slug %}"
{% trans "Provide billing data"|upper %}<span class="fas fa-file-invoice-dollar ms-2 text-primary"></span>
</h3>
{% trans 'Billing Information' %}
{% endblock %}
{% block content %}
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5">
<div class="col-md-8">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% trans "Provide billing data"|upper %}
<i class="fas fa-file-invoice-dollar ms-2"></i>
</h3>
</div>
<div class="card-body p-4 p-md-5">
<form action="{% url 'billing_info' %}{% if request.GET.next %}?next={{ request.GET.next }}{% endif %}"
method="post"
class="needs-validation"
novalidate>
{% csrf_token %}
{{ form|crispy }}
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{{ _("Save") }}
</button>
<a href="{% url 'dealer_detail' request.dealer.slug %}"
class="btn btn-lg btn-phoenix-secondary md-me-2" class="btn btn-lg btn-phoenix-secondary md-me-2"
type="submit"><i class="fa-solid fa-ban me-1"></i>{{ _("Cancel") }}</a> type="submit"><i class="fa-solid fa-ban me-1"></i>{{ _("Cancel") }}</a>
</div> </div>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</main> </main>
{% endblock %} {% endblock %}