This commit is contained in:
Marwan Alwali 2025-02-16 18:12:13 +03:00
parent ec6ca7dfd7
commit bb1fac8609
29 changed files with 156 additions and 158 deletions

View File

@ -94,9 +94,9 @@ urlpatterns = [
), ),
path("crm/leads/<int:pk>/delete/", views.LeadDeleteView, name="lead_delete"), path("crm/leads/<int:pk>/delete/", views.LeadDeleteView, name="lead_delete"),
path("crm/leads/<int:pk>/lead-convert/", views.lead_convert, name="lead_convert"), path("crm/leads/<int:pk>/lead-convert/", views.lead_convert, name="lead_convert"),
path("crm/leads/<int:pk>/add-note/", views.add_note_to_lead, name="add_note"), path("crm/leads/<int:pk>/add-note/", views.add_note_to_lead, name="add_note_to_lead"),
path('crm/leads/<int:pk>/update-note/', views.update_note, name='update_note'), path('crm/leads/<int:pk>/update-note/', views.update_note, name='update_note_to_lead'),
path("crm/leads/<int:pk>/delete-note/", views.delete_note, name="delete_note"), path("crm/leads/<int:pk>/delete-note/", views.delete_note, name="delete_note_to_lead"),
path( path(
"crm/leads/<int:pk>/add-activity/", "crm/leads/<int:pk>/add-activity/",
views.add_activity_to_lead, views.add_activity_to_lead,

View File

@ -652,9 +652,7 @@ class CarInventory(LoginRequiredMixin, ListView):
id_car_trim=trim_id, id_car_trim=trim_id,
).order_by("receiving_date") ).order_by("receiving_date")
if query: return apply_search_filters(cars, query)
cars = cars.filter(Q(vin__icontains=query))
return cars
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -1234,13 +1232,7 @@ class CustomerListView(LoginRequiredMixin, ListView):
customers = dealer.entity.get_customers().filter(additional_info__type="customer") customers = dealer.entity.get_customers().filter(additional_info__type="customer")
if query: return apply_search_filters(customers, query)
customers = customers.filter(
Q(first_name__icontains=query)
| Q(last_name__icontains=query)
| Q(additional_info__info__icontains=query)
)
return customers
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -1287,7 +1279,7 @@ def add_note_to_customer(request, pk):
return redirect("customer_detail", pk=pk) return redirect("customer_detail", pk=pk)
else: else:
form = forms.NoteForm() form = forms.NoteForm()
return render(request, "crm/add_note.html", {"form": form, "customer": customer}) return render(request, "crm/note_form.html", {"form": form, "customer": customer})
def add_activity_to_customer(request, pk): def add_activity_to_customer(request, pk):
@ -1421,10 +1413,11 @@ class VendorListView(LoginRequiredMixin, ListView):
ordering = ["-created"] ordering = ["-created"]
def get_queryset(self): def get_queryset(self):
query = self.request.GET.get("q")
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
# vendors = models.Vendor.objects.filter(dealer=dealer) vendors = dealer.entity.get_vendors().filter(active=True)
return dealer.entity.get_vendors().filter(active=True) return apply_search_filters(vendors, query)
# return vendors
# class VendorDetailView(LoginRequiredMixin, DetailView): # class VendorDetailView(LoginRequiredMixin, DetailView):
@ -1861,8 +1854,10 @@ class UserListView(LoginRequiredMixin, ListView):
template_name = "users/user_list.html" template_name = "users/user_list.html"
def get_queryset(self): def get_queryset(self):
query = self.request.GET.get("q")
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
return models.Staff.objects.filter(dealer=dealer).all() staff = models.Staff.objects.filter(dealer=dealer).all()
return apply_search_filters(staff, query)
class UserDetailView(LoginRequiredMixin, DetailView): class UserDetailView(LoginRequiredMixin, DetailView):
@ -1944,12 +1939,13 @@ class OrganizationListView(LoginRequiredMixin, ListView):
paginate_by = 10 paginate_by = 10
def get_queryset(self): def get_queryset(self):
query = self.request.GET.get("q")
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
return ( organization = dealer.entity.get_customers().filter(additional_info__type="organization", active=True)
dealer.entity.get_customers()
.filter(additional_info__type="organization", active=True) return apply_search_filters(organization, query)
.all()
)
class OrganizationDetailView(DetailView): class OrganizationDetailView(DetailView):
@ -2040,8 +2036,10 @@ class RepresentativeListView(LoginRequiredMixin, ListView):
paginate_by = 10 paginate_by = 10
def get_queryset(self): def get_queryset(self):
query = self.request.GET.get("q")
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
return models.Representative.objects.filter(dealer=dealer).all() representative = models.Representative.objects.filter(dealer=dealer)
return apply_search_filters(representative, query)
class RepresentativeDetailView(DetailView): class RepresentativeDetailView(DetailView):
@ -2266,8 +2264,10 @@ class BankAccountListView(LoginRequiredMixin, ListView):
paginate_by = 10 paginate_by = 10
def get_queryset(self): def get_queryset(self):
query = self.request.GET.get("q")
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
return BankAccountModel.objects.filter(entity_model=dealer.entity) bank_accounts = BankAccountModel.objects.filter(entity_model=dealer.entity)
return apply_search_filters(bank_accounts, query)
class BankAccountCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView): class BankAccountCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
@ -2337,9 +2337,10 @@ class AccountListView(LoginRequiredMixin, ListView):
paginate_by = 10 paginate_by = 10
def get_queryset(self): def get_queryset(self):
query = self.request.GET.get("q")
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
entity = dealer.entity accounts = dealer.entity.get_all_accounts()
return entity.get_all_accounts() return apply_search_filters(accounts, query)
class AccountCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView): class AccountCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
@ -2436,7 +2437,7 @@ def sales_list_view(request):
entity = dealer.entity entity = dealer.entity
transactions = ItemTransactionModel.objects.for_entity(entity_slug=entity.slug, user_model=dealer.user) transactions = ItemTransactionModel.objects.for_entity(entity_slug=entity.slug, user_model=dealer.user)
paginator = Paginator(transactions, 20) paginator = Paginator(transactions, 10)
page_number = request.GET.get('page') page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number) page_obj = paginator.get_page(page_number)
txs = get_item_transactions(page_obj) txs = get_item_transactions(page_obj)
@ -2803,9 +2804,10 @@ class InvoiceListView(LoginRequiredMixin, ListView):
paginate_by = 20 paginate_by = 20
def get_queryset(self): def get_queryset(self):
query = self.request.GET.get("q")
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
entity = dealer.entity invoices = dealer.entity.get_invoices()
return entity.get_invoices() return apply_search_filters(invoices, query)
class InvoiceDetailView(LoginRequiredMixin, DetailView): class InvoiceDetailView(LoginRequiredMixin, DetailView):
@ -4356,8 +4358,24 @@ class EmployeeCalendarView(ListView):
context_object_name = 'appointments' context_object_name = 'appointments'
def get_queryset(self): def get_queryset(self):
query = self.request.GET.get('q')
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
staff = self.request.user.staff staff = getattr(self.request, 'staff', None)
return Appointment.objects.filter(appointment_request__staff_member=staff).all() if staff:
appointments = Appointment.objects.filter(appointment_request__staff_member=staff, ppointment_request__date__gt=timezone.now())
appointments = Appointment.objects.filter(appointment_request__date__gt=timezone.now())
return apply_search_filters(appointments, query)
def apply_search_filters(queryset, query):
if not query:
return queryset
search_filters = Q()
model = queryset.model
for field in model._meta.get_fields():
if hasattr(field, 'attname') and field.get_internal_type() in ["CharField", "TextField", "EmailField"]:
search_filters |= Q(**{f"{field.name}__icontains": query})
return queryset.filter(search_filters).distinct()

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View File

@ -1,22 +1,38 @@
<!-- crm/employee_calendar.html --> {% extends 'base.html' %}
<h1>Upcoming Test Drives</h1> {% load static %}
<table> {% block content %}
<div class="row">
<div class="table-responsive border-translucent">
<table class="table table-sm fs-9">
<thead> <thead>
<tr> <tr>
<th>Customer</th> <th>Customer</th>
<th>Vehicle</th> <th>Service</th>
<th>Date/Time</th> <th>Date</th>
<th>Start Time</th>
<th>End Time</th>
<th>Staff</th> <th>Staff</th>
<th>Status</th>
<th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for appointment in appointments %} {% for appointment in appointments %}
<tr> <tr>
<td>{{ appointment.client.name }}</td> <td>{{ appointment.get_client_name }}</td>
<td>{{ appointment.service.name }}</td> <td>{{ appointment.get_service }}</td>
<td>{{ appointment.start_time|date:"M j, Y H:i" }}</td> <td>{{ appointment.appointment_request.date|date:"Y-m-d" }}</td>
<td>{{ appointment.staff.user.get_full_name }}</td> <td>{{ appointment.appointment_request.start_time }}</td>
<td>{{ appointment.appointment_request.end_time }}</td>
<td>{{ appointment.get_staff_member_name }}</td>
<td></td>
<td>
<a href="{% url 'appointment:display_appointment' appointment.id %}">view</a>
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div>
</div>
{% endblock %}

View File

@ -181,7 +181,7 @@
<h3 class="mb-4" id="scrollspyNotes">{{ _("Notes") }}</h3> <h3 class="mb-4" id="scrollspyNotes">{{ _("Notes") }}</h3>
</div> </div>
<div class="d-flex align-items-center justify-content-start"> <div class="d-flex align-items-center justify-content-start">
<a id="addBtn" href="#" class="btn btn-sm btn-phoenix-primary mb-3" data-url="{% url 'add_note' lead.pk %}" data-bs-toggle="modal" data-bs-target="#noteModal" data-note-title="{{ _("Add") }}<i class='fa fa-plus-circle text-success ms-2'></i>"> <a id="addBtn" href="#" class="btn btn-sm btn-phoenix-primary mb-3" data-url="{% url 'add_note_to_lead' lead.pk %}" data-bs-toggle="modal" data-bs-target="#noteModal" data-note-title="{{ _("Add") }}<i class='fa fa-plus-circle text-success ms-2'></i>">
<span class="fas fa-plus me-1"></span> <span class="fas fa-plus me-1"></span>
{% trans 'Add Note' %} {% trans 'Add Note' %}
</a> </a>
@ -197,7 +197,7 @@
<th class="align-middle pe-0 text-end" scope="col" style="width:10%;"> </th> <th class="align-middle pe-0 text-end" scope="col" style="width:10%;"> </th>
</tr> </tr>
</thead> </thead>
<tbody class="list" id="lead-details-table-body"> <tbody >
{% for note in notes %} {% for note in notes %}
<tr class="hover-actions-trigger btn-reveal-trigger position-static"> <tr class="hover-actions-trigger btn-reveal-trigger position-static">
@ -205,17 +205,17 @@
{% if note.created_by.staff %} {% if note.created_by.staff %}
<td class="align-middle white-space-nowrap text-start white-space-nowrap">{{ note.created_by.staff.name }}</td> <td class="align-middle white-space-nowrap text-start white-space-nowrap">{{ note.created_by.staff.name }}</td>
{% else %} {% else %}
<td class="align-middle white-space-nowrap text-start white-space-nowrap">{{ note.created_by.dealer.get_local_name }}</td> <td class="align-middle white-space-nowrap text-start white-space-nowrap">{{ note.created_by.dealer.get_local_name|default:note.created_by.dealer.name }}</td>
{% endif %} {% endif %}
<td class="align-middle text-body-tertiary text-start white-space-nowrap">{{ note.created }}</td> <td class="align-middle text-body-tertiary text-start white-space-nowrap">{{ note.created }}</td>
<td class="align-middle text-end white-space-nowrap pe-0 action py-2"> <td class="align-middle text-end white-space-nowrap pe-0 action py-2">
{% if note.created_by == request.user %} {% if note.created_by == request.user %}
<a id="updateBtn" href="#" class="btn btn-sm btn-phoenix-primary me-2" data-url="{% url 'update_note' note.pk %}" data-bs-toggle="modal" data-bs-target="#noteModal" data-note-title="{{ _("Update") }}<i class='fas fa-pen-square text-primary ms-2'></i>"> <a id="updateBtn" href="#" class="btn btn-sm btn-phoenix-primary me-2" data-url="{% url 'update_note_to_lead' note.pk %}" data-bs-toggle="modal" data-bs-target="#noteModal" data-note-title="{{ _("Update") }}<i class='fas fa-pen-square text-primary ms-2'></i>">
<i class="fas fa-pen"></i> <i class="fas fa-pen"></i>
</a> </a>
<button class="btn btn-phoenix-danger btn-sm delete-btn" <button class="btn btn-phoenix-danger btn-sm delete-btn"
data-url="{% url 'delete_note' note.pk %}" data-url="{% url 'delete_note_to_lead' note.pk %}"
data-message="Are you sure you want to delete this note?" data-message="Are you sure you want to delete this note?"
data-bs-toggle="modal" data-bs-target="#deleteModal"> data-bs-toggle="modal" data-bs-target="#deleteModal">
<i class="fas fa-trash"></i> <i class="fas fa-trash"></i>

View File

@ -121,8 +121,7 @@
</div> </div>
<tr class="hover-actions-trigger btn-reveal-trigger position-static"> <tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="name align-middle white-space-nowrap ps-0"> <td class="name align-middle white-space-nowrap ps-0">
<div class="d-flex align-items-center"><a href="#!"> <div class="d-flex align-items-center">
</a>
<div><a class="fs-8 fw-bold" href="{% url 'lead_detail' lead.pk %}">{{lead.full_name}}</a> <div><a class="fs-8 fw-bold" href="{% url 'lead_detail' lead.pk %}">{{lead.full_name}}</a>
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<p class="mb-0 text-body-highlight fw-semibold fs-9 me-2"></p> <p class="mb-0 text-body-highlight fw-semibold fs-9 me-2"></p>

View File

@ -1,9 +1,9 @@
{% load i18n static crispy_forms_filters %} {% load i18n static crispy_forms_filters %}
{% if form.instance.pk %} {% if form.instance.pk %}
<form method="post" action="{% url 'update_note' note.pk %}" enctype="multipart/form-data"> <form method="post" action="{% url 'update_note_to_lead' note.pk %}" enctype="multipart/form-data">
{% else %} {% else %}
<form method="post" action="{% url 'add_note' lead.pk %}" enctype="multipart/form-data"> <form method="post" action="{% url 'add_note_to_lead' lead.pk %}" enctype="multipart/form-data">
{% endif %} {% endif %}
{% csrf_token %} {% csrf_token %}

View File

@ -6,7 +6,7 @@
{% block content %} {% block content %}
<div class="row"> <div class="row">
<h2 class="mb-4">{{ _("Customers")|capfirst }}</h2> <h4 class="mb-4">{{ _("Customers")|capfirst }}</h4>
<div class="row g-3 justify-content-between mb-4"> <div class="row g-3 justify-content-between mb-4">
<div class="col-auto"> <div class="col-auto">
<div class="d-md-flex justify-content-between"> <div class="d-md-flex justify-content-between">
@ -17,25 +17,15 @@
</div> </div>
<div class="col-auto"> <div class="col-auto">
<div class="d-flex"> <div class="d-flex">
<div class="search-box me-2"> {% include 'partials/search_box.html' %}
<form method="get" class="d-inline-block position-relative">
<div class="input-group">
<button type="submit" class="btn btn-phoenix-primary"><span class="fas fa-search search-box-icon"></span></button>
<input name="q" class="form-control search-input search" type="search" placeholder="{{ _('Enter customer name') }}" value="{{ request.GET.q }}"/>
{% if request.GET.q %}
<a href="{% url request.resolver_match.view_name %}" class="btn btn-close"></a>
</div>
{% endif %}
</form>
</div>
</div> </div>
</div> </div>
</div> </div>
{% if page_obj.object_list %} {% if page_obj.object_list %}
<div class="table-responsive scrollbar mx-n1 px-1"> <div class="table-responsive scrollbar transition">
<table class="table fs-9 mb-0 border-top border-translucent"> <table class="table table-sm fs-9 mb-0 border-translucent">
<thead> <thead>
<tr> <tr>
<th></th> <th></th>
@ -104,11 +94,9 @@
{% endif %} {% endif %}
</table> </table>
</div> </div>
<div class="row align-items-center justify-content-end py-4 pe-0 fs-9">
{% if is_paginated %}
{% include 'partials/pagination.html' %} {% include 'partials/pagination.html' %}
{% endif %}
</div>
</div> </div>
{% include 'modal/delete_modal.html' %} {% include 'modal/delete_modal.html' %}

View File

@ -106,7 +106,10 @@
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<div class="d-flex align-items-center justify-content-end"> <div class="d-flex align-items-center justify-content-end">
<a class="fw-bold fs-9 mb-0 text-end" href="{% url 'add_note_to_customer' customer.pk %}"><span class="fas fa-plus me-1"></span>{{ _("Add Note")}}</a> <a id="addBtn" href="#" class="btn btn-sm btn-phoenix-primary mb-3" data-url="{% url 'add_note_to_customer' customer.pk %}" data-bs-toggle="modal" data-bs-target="#noteModal" data-note-title="{{ _("Add") }}<i class='fa fa-plus-circle text-success ms-2'></i>">
<span class="fas fa-plus me-1"></span>
{% trans 'Add Note' %}
</a>
</div> </div>
<table class="table fs-9 mb-0 table-responsive"> <table class="table fs-9 mb-0 table-responsive">
<thead> <thead>
@ -214,21 +217,13 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="row align-items-center justify-content-between py-2 pe-0 fs-9"> {% include 'partials/pagination.html' %}
<div class="col-auto d-flex">
<p class="mb-0 d-none d-sm-block me-3 fw-semibold text-body" data-list-info="data-list-info"></p><a class="fw-semibold" href="#!" data-list-view="*">View all<span class="fas fa-angle-right ms-1" data-fa-transform="down-1"></span></a><a class="fw-semibold d-none" href="#!" data-list-view="less">View Less<span class="fas fa-angle-right ms-1" data-fa-transform="down-1"></span></a>
</div>
<div class="col-auto d-flex">
<button class="page-link" data-list-pagination="prev"><span class="fas fa-chevron-left"></span></button>
<ul class="mb-0 pagination"></ul>
<button class="page-link pe-0" data-list-pagination="next"><span class="fas fa-chevron-right"></span></button>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{% include 'partials/notes.html' %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -436,15 +436,17 @@
</li> </li>
{% else %} {% else %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link px-3 d-block" href="{% url 'user_detail' user.staff.pk %}"> <span class="me-2 text-body align-bottom" data-feather="user"></span><span>{% translate 'profile'|capfirst %}</span></a> <a class="nav-link px-3 d-block" href="{% url 'appointment:user_profile' request.user.id %}"> <span class="me-2 text-body align-bottom" data-feather="user"></span><span>{% translate 'profile'|capfirst %}</span></a>
</li> </li>
{% endif %} {% endif %}
{% if user.dealer %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link px-3 d-block" href="{% url 'user_list' %}"><span class="me-2 text-body align-bottom" data-feather="users"></span>{{ _("Staff") }}</a> <a class="nav-link px-3 d-block" href="{% url 'user_list' %}"><span class="me-2 text-body align-bottom" data-feather="users"></span>{{ _("Staff") }}</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link px-3 d-block" href="{% url 'dealer_activity' %}"> <span class="me-2 text-body align-bottom" data-feather="lock"></span>{{ _("Activity") }}</a> <a class="nav-link px-3 d-block" href="{% url 'dealer_activity' %}"> <span class="me-2 text-body align-bottom" data-feather="lock"></span>{{ _("Activity") }}</a>
</li> </li>
{% endif %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link px-3 d-block" href=""> <span class="me-2 text-body align-bottom" data-feather="settings"></span>Settings &amp; Privacy </a> <a class="nav-link px-3 d-block" href=""> <span class="me-2 text-body align-bottom" data-feather="settings"></span>Settings &amp; Privacy </a>
</li> </li>

View File

@ -38,20 +38,20 @@
<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></li> <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></li>
<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></li> <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></li>
<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></li> <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></li>
<li class="nav-item"><button hx-on:click="toggle_filter()" class="btn btn-sm btn-primary px-2 py-1"><span>{{ _("Filter") }}</span><span class="fas fa-caret-down fs-9 ms-1 filter-icon"></span></button></li> <li class="nav-item"><button hx-on:click="toggle_filter()" class="btn btn-sm btn-primary px-2 py-1"><span><span class="fa fa-filter me-1"></span>{{ _("Filter") }}</span><span class="fas fa-caret-down fs-9 ms-1 filter-icon"></span></button></li>
</ul> </ul>
</div> </div>
<div class="col-12 col-sm-auto"> <div class="col-12 col-sm-auto">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<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' %}" 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()"
/> />
<span class="fas fa-search search-box-icon"></span> <span class="fas fa-search search-box-icon"></span>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
@ -94,8 +94,6 @@
<div class="row"> <div class="row">
<div class="table-responsive scrollbar transition"> <div class="table-responsive scrollbar transition">
<div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9"> <div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9">
<div class="d-flex">
</div>
<div class="d-flex" hx-boost="true" hx-push-url='false' hx-include=".make,.model,.year,.car_status" hx-target=".table-responsive" hx-select=".table-responsive" hx-swap="innerHTML show:window:top" hx-indicator=".htmx-indicator" <div class="d-flex" hx-boost="true" hx-push-url='false' hx-include=".make,.model,.year,.car_status" 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()">
@ -164,17 +162,13 @@
</table> </table>
</div> </div>
<div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9 "> {% include 'partials/pagination.html' %}
<div class="d-flex" hx-boost="true" hx-push-url='false' hx-include=".make,.model,.year,.car_status" hx-target=".table-responsive" hx-select=".table-responsive" hx-swap="innerHTML" hx-indicator=".htmx-indicator"
hx-on::before-request="on_before_request()"
hx-on::after-request="on_after_request()">
</div>
</div>
</div> </div>
{% if is_paginated %}
{% include 'partials/pagination.html' %}
{% endif %}
</div> </div>
</div> </div>

View File

@ -7,7 +7,7 @@
<div class="row"> <div class="row">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-8"> <div class="col-md-8">
<div class="card"> <div class="card bg-body">
<div class="card-header"> <div class="card-header">
{% if service.pk %} {% if service.pk %}
{{ _("Update Service") }} {{ _("Update Service") }}
@ -19,7 +19,7 @@
<form method="post" action=""> <form method="post" action="">
{% csrf_token %} {% csrf_token %}
{{ form|crispy }} {{ form|crispy }}
<button type="submit" class="btn btn-primary">{% trans 'Save' %}</button> <button type="submit" class="btn btn-sm btn-primary">{% trans 'Save' %}</button>
</form> </form>
</div> </div>
</div> </div>

View File

@ -4,16 +4,16 @@
{% block title %}{{ _("Expenses") }}{% endblock title %} {% block title %}{{ _("Expenses") }}{% endblock title %}
{% block content %} {% block content %}
<div class="row mt-4 mx-4"> <div class="row">
<div class="d-flex justify-content-between mb-2 p-6"> <div class="d-flex justify-content-between">
<span></span>
<h3 class="text-center">{% trans "Services" %}</h3> <h3 class="mb-2">{% trans "Services" %}</h3>
<a href="{% url 'item_service_create' %}" class="btn btn-sm btn-success ">{% trans "Add Service" %}</a> <a href="{% url 'item_service_create' %}" class="btn btn-sm btn-phoenix-primary ">{% trans "Add Service" %}</a>
</div> </div>
<div class="mx-n4 px-4 mx-lg-n6 px-lg-6 bg-body-emphasis pt-7 border-y">
<div class="table-responsive mx-n1 px-1 scrollbar"> <div class="table-responsive scrollbar transition">
<table class="table fs-9 mb-0 border-top border-translucent"> <table class="table table-sm fs-9 mb-0 border-translucent">
<thead> <thead>
<tr> <tr>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Item Number" %}</th> <th class="sort white-space-nowrap align-middle" scope="col">{% trans "Item Number" %}</th>
@ -56,5 +56,4 @@
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
</div> </div>
</div> </div>
</div>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,15 @@
<div class="search-box me-2">
<form class="position-relative justify-content-between">
<input name="q" class="form-control form-control-sm search-input search" type="search" aria-label="Search" placeholder="{{ _('Search') }}" value="{{ request.GET.q }}"/>
<span class="fa fa-magnifying-glass search-box-icon"></span>
</form>
<div class="position-absolute top-50 start-50 translate-middle ">
{% if request.GET.q %}
<a href="{% url request.resolver_match.view_name %}" class="btn p-0"><span class="fas fa-times text-danger "></span></a>
{% endif %}
</div>
</div>

View File

@ -52,24 +52,7 @@
/> />
<span class="fas fa-search search-box-icon"></span> <span class="fas fa-search search-box-icon"></span>
</form> </form>
</div><a class="btn btn-phoenix-primary px-3 me-1 border-0 text-body" href="#" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="List view"><span class="fa-solid fa-list fs-10"></span></a><a class="btn btn-phoenix-primary px-3 me-1" href="#" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Board view"> </div>
<svg width="9" height="9" viewbox="0 0 9 9" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0.5C0 0.223857 0.223858 0 0.5 0H1.83333C2.10948 0 2.33333 0.223858 2.33333 0.5V1.83333C2.33333 2.10948 2.10948 2.33333 1.83333 2.33333H0.5C0.223857 2.33333 0 2.10948 0 1.83333V0.5Z" fill="currentColor"></path>
<path d="M3.33333 0.5C3.33333 0.223857 3.55719 0 3.83333 0H5.16667C5.44281 0 5.66667 0.223858 5.66667 0.5V1.83333C5.66667 2.10948 5.44281 2.33333 5.16667 2.33333H3.83333C3.55719 2.33333 3.33333 2.10948 3.33333 1.83333V0.5Z" fill="currentColor"></path>
<path d="M6.66667 0.5C6.66667 0.223857 6.89052 0 7.16667 0H8.5C8.77614 0 9 0.223858 9 0.5V1.83333C9 2.10948 8.77614 2.33333 8.5 2.33333H7.16667C6.89052 2.33333 6.66667 2.10948 6.66667 1.83333V0.5Z" fill="currentColor"></path>
<path d="M0 3.83333C0 3.55719 0.223858 3.33333 0.5 3.33333H1.83333C2.10948 3.33333 2.33333 3.55719 2.33333 3.83333V5.16667C2.33333 5.44281 2.10948 5.66667 1.83333 5.66667H0.5C0.223857 5.66667 0 5.44281 0 5.16667V3.83333Z" fill="currentColor"></path>
<path d="M3.33333 3.83333C3.33333 3.55719 3.55719 3.33333 3.83333 3.33333H5.16667C5.44281 3.33333 5.66667 3.55719 5.66667 3.83333V5.16667C5.66667 5.44281 5.44281 5.66667 5.16667 5.66667H3.83333C3.55719 5.66667 3.33333 5.44281 3.33333 5.16667V3.83333Z" fill="currentColor"></path>
<path d="M6.66667 3.83333C6.66667 3.55719 6.89052 3.33333 7.16667 3.33333H8.5C8.77614 3.33333 9 3.55719 9 3.83333V5.16667C9 5.44281 8.77614 5.66667 8.5 5.66667H7.16667C6.89052 5.66667 6.66667 5.44281 6.66667 5.16667V3.83333Z" fill="currentColor"></path>
<path d="M0 7.16667C0 6.89052 0.223858 6.66667 0.5 6.66667H1.83333C2.10948 6.66667 2.33333 6.89052 2.33333 7.16667V8.5C2.33333 8.77614 2.10948 9 1.83333 9H0.5C0.223857 9 0 8.77614 0 8.5V7.16667Z" fill="currentColor"></path>
<path d="M3.33333 7.16667C3.33333 6.89052 3.55719 6.66667 3.83333 6.66667H5.16667C5.44281 6.66667 5.66667 6.89052 5.66667 7.16667V8.5C5.66667 8.77614 5.44281 9 5.16667 9H3.83333C3.55719 9 3.33333 8.77614 3.33333 8.5V7.16667Z" fill="currentColor"></path>
<path d="M6.66667 7.16667C6.66667 6.89052 6.89052 6.66667 7.16667 6.66667H8.5C8.77614 6.66667 9 6.89052 9 7.16667V8.5C9 8.77614 8.77614 9 8.5 9H7.16667C6.89052 9 6.66667 8.77614 6.66667 8.5V7.16667Z" fill="currentColor"></path>
</svg></a><a class="btn btn-phoenix-primary px-3" href="#" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Card view">
<svg width="9" height="9" viewBox="0 0 9 9" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0.5C0 0.223858 0.223858 0 0.5 0H3.5C3.77614 0 4 0.223858 4 0.5V3.5C4 3.77614 3.77614 4 3.5 4H0.5C0.223858 4 0 3.77614 0 3.5V0.5Z" fill="currentColor"></path>
<path d="M0 5.5C0 5.22386 0.223858 5 0.5 5H3.5C3.77614 5 4 5.22386 4 5.5V8.5C4 8.77614 3.77614 9 3.5 9H0.5C0.223858 9 0 8.77614 0 8.5V5.5Z" fill="currentColor"></path>
<path d="M5 0.5C5 0.223858 5.22386 0 5.5 0H8.5C8.77614 0 9 0.223858 9 0.5V3.5C9 3.77614 8.77614 4 8.5 4H5.5C5.22386 4 5 3.77614 5 3.5V0.5Z" fill="currentColor"></path>
<path d="M5 5.5C5 5.22386 5.22386 5 5.5 5H8.5C8.77614 5 9 5.22386 9 5.5V8.5C9 8.77614 8.77614 9 8.5 9H5.5C5.22386 9 5 8.77614 5 8.5V5.5Z" fill="currentColor"></path>
</svg></a>
</div> </div>
</div> </div>
</div> </div>
@ -109,24 +92,16 @@
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>
<div class="row">
<div class="table-responsive scrollbar transition"> <div class="table-responsive scrollbar transition">
<div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9 border-bottom border-translucent"> <div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9">
<div class="d-flex">
</div>
<div class="d-flex" hx-boost="true" hx-push-url='false' hx-include=".make,.model,.year,.car_status" hx-target=".table-responsive" hx-select=".table-responsive" hx-swap="innerHTML show:window:top" hx-indicator=".htmx-indicator" <div class="d-flex" hx-boost="true" hx-push-url='false' hx-include=".make,.model,.year,.car_status" 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()">
{% if page_obj.has_previous %}
<a href="{% url 'sales_list' %}?page={{page_obj.previous_page_number}}" class="page-link" data-list-pagination="prev"><span class="fas fa-chevron-left"></span></a>
{% endif %}
<ul class="mb-0 pagination">Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</ul>
{% if page_obj.has_next %}
<a href="{% url 'sales_list' %}?page={{page_obj.next_page_number}}" class="page-link pe-0" data-list-pagination="next"><span class="fas fa-chevron-right"></span></a>
{% endif %}
</div> </div>
</div>
<table class="table fs-9 mb-0 border-top border-translucent"> <table class="table table-sm fs-9 mb-0 border-translucent">
<thead> <thead>
<tr> <tr>
<th class="sort white-space-nowrap align-middle ps-0" scope="col" data-sort="projectName" style="width:10%;"> <th class="sort white-space-nowrap align-middle ps-0" scope="col" data-sort="projectName" style="width:10%;">
@ -147,29 +122,29 @@
<tbody class="list" id="project-list-table-body"> <tbody class="list" id="project-list-table-body">
{% for tx in txs %} {% for tx in txs %}
<tr class="position-static"> <tr class="position-static">
<td class="align-middle white-space-nowrap deadline ps-3 py-4"> <td class="align-middle white-space-nowrap deadline">
<p class="mb-0 fs-9 text-body">{{tx.customer.customer_name}}</p> <p class="mb-0 fs-9 text-body">{{tx.customer.customer_name}}</p>
</td> </td>
<td class="align-middle white-space-nowrap deadline ps-3 py-4"> <td class="align-middle white-space-nowrap deadline">
<p class="mb-0 fs-9 text-body">{{tx.customer.address_1}}</p> <p class="mb-0 fs-9 text-body">{{tx.customer.address_1}}</p>
</td> </td>
<td class="align-middle white-space-nowrap deadline ps-3 py-4"> <td class="align-middle white-space-nowrap deadline">
<p class="mb-0 fs-9 text-body">{{tx.customer.phone}}</p> <p class="mb-0 fs-9 text-body">{{tx.customer.phone}}</p>
</td> </td>
<td class="align-middle time white-space-nowrap ps-0 projectName py-4">{{tx.info.make}}</td> <td class="align-middle time white-space-nowrap projectName">{{tx.info.make}}</td>
<td class="align-middle white-space-nowrap start ps-3 py-4"> <td class="align-middle white-space-nowrap start">
<p class="mb-0 fs-9 text-body">{{tx.info.model}}</p> <p class="mb-0 fs-9 text-body">{{tx.info.model}}</p>
</td> </td>
<td class="align-middle white-space-nowrap deadline ps-3 py-4"> <td class="align-middle white-space-nowrap deadline">
<p class="mb-0 fs-9 text-body">{{tx.info.vin}}</p> <p class="mb-0 fs-9 text-body">{{tx.info.vin}}</p>
</td> </td>
<td class="align-middle white-space-nowrap task ps-3 py-4"> <td class="align-middle white-space-nowrap task">
<p class="fw-bo text-body fs-9 mb-0">{{tx.info.trim}}</p> <p class="fw-bo text-body fs-9 mb-0">{{tx.info.trim}}</p>
</td> </td>
<td class="align-middle white-space-nowrap task ps-3 py-4"> <td class="align-middle white-space-nowrap task">
<p class="fw-bo text-body fs-9 mb-0">{{tx.finance.total}}</p> <p class="fw-bo text-body fs-9 mb-0">{{tx.finance.total}}</p>
</td> </td>
<td class="align-middle white-space-nowrap task ps-3 py-4"> <td class="align-middle white-space-nowrap task">
{% if tx.has_estimate %} {% if tx.has_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' tx.estimate.uuid %}">
@ -187,7 +162,7 @@
</p> </p>
{% endif %} {% endif %}
</td> </td>
<td class="align-middle white-space-nowrap task ps-3 py-4"> <td class="align-middle white-space-nowrap task">
{% if tx.has_invoice %} {% if tx.has_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' tx.invoice.uuid %}">
@ -235,18 +210,15 @@
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div>
<div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9 border-bottom border-translucent">
<div class="d-flex">
{% if is_paginated %}
{% include 'partials/pagination.html' %}
{% endif %}
</div>
</div> </div>
</div>
</div> </div>
</div> </div>
</div>
{% endblock %} {% endblock %}
{% block customJS %} {% block customJS %}