update and formatting
This commit is contained in:
parent
3ce318317e
commit
a930acfae5
1
.gitignore
vendored
1
.gitignore
vendored
@ -43,6 +43,7 @@ Makefile
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
**/migrations/
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
|
||||
@ -42,4 +42,4 @@ def breadcrumbs(request):
|
||||
for i in range(len(path)):
|
||||
url = "/" + "/".join(path[: i + 1]) + "/"
|
||||
breadcrumbs.append({"name": path[i].capitalize(), "url": url})
|
||||
return {"breadcrumbs": breadcrumbs}
|
||||
return {"breadcrumbs": breadcrumbs}
|
||||
|
||||
@ -124,10 +124,8 @@ class DealerSlugMiddleware:
|
||||
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:
|
||||
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
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
# 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,
|
||||
),
|
||||
]
|
||||
@ -1,17 +0,0 @@
|
||||
# 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',
|
||||
),
|
||||
]
|
||||
@ -69,10 +69,8 @@ class LocalizedNameMixin:
|
||||
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:
|
||||
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)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
@ -2482,16 +2482,22 @@ class SaleOrder(models.Model):
|
||||
item_data = self.invoice.get_itemtxs_data()
|
||||
if item_data:
|
||||
return item_data
|
||||
return [] # Return an empty list if no invoice or no item data
|
||||
|
||||
return [] # Return an empty list if no invoice or no item data
|
||||
|
||||
@property
|
||||
def cars(self):
|
||||
# Check if self.items is not empty before trying to iterate
|
||||
if self.items.exists() if hasattr(self.items, 'exists') else self.items: # Handle both QuerySet and list
|
||||
if (
|
||||
self.items.exists() if hasattr(self.items, "exists") else self.items
|
||||
): # Handle both QuerySet and list
|
||||
# Ensure x is an *instance* of ItemTransactionModel
|
||||
# item_model should be a ForeignKey to your CarModel within ItemTransactionModel
|
||||
return [x.item_model.car for x in self.items if hasattr(x, 'item_model') and hasattr(x.item_model, 'car')]
|
||||
return [] # Return an empty list if no items or no associated cars
|
||||
return [
|
||||
x.item_model.car
|
||||
for x in self.items
|
||||
if hasattr(x, "item_model") and hasattr(x.item_model, "car")
|
||||
]
|
||||
return [] # Return an empty list if no items or no associated cars
|
||||
|
||||
|
||||
class CustomGroup(models.Model):
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
from typing import Union
|
||||
from random import randint
|
||||
from django import template
|
||||
@ -493,15 +492,15 @@ def transactions_table(
|
||||
qs = object_type.get_transaction_queryset(annotated=True)
|
||||
transaction_model_qs = qs.annotate(
|
||||
debit_credit_sort_order=Case(
|
||||
When(tx_type='debit', then=Value(0)), # Debits will get sort order 0
|
||||
When(tx_type='credit', then=Value(1)), # Credits will get sort order 1
|
||||
default=Value(2), # Fallback for any other tx_type, if applicable
|
||||
output_field=IntegerField()
|
||||
When(tx_type="debit", then=Value(0)), # Debits will get sort order 0
|
||||
When(tx_type="credit", then=Value(1)), # Credits will get sort order 1
|
||||
default=Value(2), # Fallback for any other tx_type, if applicable
|
||||
output_field=IntegerField(),
|
||||
)
|
||||
).order_by(
|
||||
'-timestamp', # Primary sort: chronological (oldest first)
|
||||
'-debit_credit_sort_order', # Secondary sort: Debits (0) before Credits (1)
|
||||
'pk' # Optional: Tie-breaker for consistent order
|
||||
"-timestamp", # Primary sort: chronological (oldest first)
|
||||
"-debit_credit_sort_order", # Secondary sort: Debits (0) before Credits (1)
|
||||
"pk", # Optional: Tie-breaker for consistent order
|
||||
)
|
||||
elif isinstance(object_type, InvoiceModel):
|
||||
transaction_model_qs = object_type.get_transaction_queryset(
|
||||
|
||||
@ -280,20 +280,48 @@ urlpatterns = [
|
||||
),
|
||||
# Car URLs
|
||||
path("<slug:dealer_slug>/cars/upload_cars/", views.upload_cars, name="upload_cars"),
|
||||
path("<slug:dealer_slug>/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("<slug:dealer_slug>/cars/add/", views.CarCreateView.as_view(), name="car_add"),
|
||||
path("<slug:dealer_slug>/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(
|
||||
"<slug:dealer_slug>/cars/inventory/<slug:make_id>/<slug:model_id>/<slug:trim_id>/",
|
||||
views.CarInventory.as_view(),
|
||||
name="car_inventory",
|
||||
),
|
||||
path("<slug:dealer_slug>/cars/inventory/stats", views.inventory_stats_view, name="inventory_stats"),
|
||||
path("<slug:dealer_slug>/cars/inventory/list", views.CarListView.as_view(), name="car_list"),
|
||||
path("<slug:dealer_slug>/cars/<slug:slug>/", views.CarDetailView.as_view(), name="car_detail"),
|
||||
path(
|
||||
"<slug:dealer_slug>/cars/inventory/stats",
|
||||
views.inventory_stats_view,
|
||||
name="inventory_stats",
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/cars/inventory/list",
|
||||
views.CarListView.as_view(),
|
||||
name="car_list",
|
||||
),
|
||||
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("<slug:dealer_slug>/cars/<slug:slug>/update/", views.CarUpdateView.as_view(), name="car_update"),
|
||||
path("<slug:dealer_slug>/cars/<slug:slug>/delete/", views.CarDeleteView.as_view(), name="car_delete"),
|
||||
path(
|
||||
"<slug:dealer_slug>/cars/<slug:slug>/update/",
|
||||
views.CarUpdateView.as_view(),
|
||||
name="car_update",
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/cars/<slug:slug>/delete/",
|
||||
views.CarDeleteView.as_view(),
|
||||
name="car_delete",
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/cars/<slug:slug>/finance/create/",
|
||||
views.CarFinanceCreateView.as_view(),
|
||||
@ -309,9 +337,13 @@ urlpatterns = [
|
||||
views.bulk_update_car_price,
|
||||
name="bulk_update_car_price",
|
||||
),
|
||||
path("<slug:dealer_slug>/ajax/", views.AjaxHandlerView.as_view(), name="ajax_handler"),
|
||||
path(
|
||||
"<slug:dealer_slug>/cars/<slug:slug>/add-color/", views.CarColorCreate.as_view(), name="add_color"
|
||||
"<slug:dealer_slug>/ajax/", views.AjaxHandlerView.as_view(), name="ajax_handler"
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/cars/<slug:slug>/add-color/",
|
||||
views.CarColorCreate.as_view(),
|
||||
name="add_color",
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/car/colors/<slug:slug>/update/",
|
||||
@ -355,7 +387,11 @@ urlpatterns = [
|
||||
),
|
||||
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("<slug:dealer_slug>/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(
|
||||
"<slug:dealer_slug>/reservations/<int:reservation_id>/",
|
||||
views.manage_reservation,
|
||||
@ -373,17 +409,17 @@ urlpatterns = [
|
||||
),
|
||||
# sales list
|
||||
path(
|
||||
"sales/list/",
|
||||
"<slug:dealer_slug>/sales/list/",
|
||||
views.sales_list_view,
|
||||
name="sales_list",
|
||||
),
|
||||
path(
|
||||
"sale_orders/<int:pk>/",
|
||||
"<slug:dealer_slug>/sale_orders/<int:pk>/",
|
||||
views.SaleOrderDetailView.as_view(),
|
||||
name="order_detail",
|
||||
),
|
||||
path(
|
||||
"inventory/<slug:entity_slug>/list/",
|
||||
"<slug:dealer_slug>/inventory/<slug:entity_slug>/list/",
|
||||
views.InventoryListView.as_view(),
|
||||
name="inventort_list",
|
||||
),
|
||||
@ -614,7 +650,9 @@ urlpatterns = [
|
||||
),
|
||||
# Bank Account
|
||||
path(
|
||||
"<slug:dealer_slug>/bank_accounts/", views.BankAccountListView.as_view(), name="bank_account_list"
|
||||
"<slug:dealer_slug>/bank_accounts/",
|
||||
views.BankAccountListView.as_view(),
|
||||
name="bank_account_list",
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/bank_accounts/<uuid:pk>/",
|
||||
@ -637,31 +675,49 @@ urlpatterns = [
|
||||
name="bank_account_delete",
|
||||
),
|
||||
# Account
|
||||
path("<slug:dealer_slug>/coa_accounts/", views.AccountListView.as_view(), name="account_list"),
|
||||
path(
|
||||
"<slug:dealer_slug>/coa_accounts/",
|
||||
views.AccountListView.as_view(),
|
||||
name="account_list",
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/coa_accounts/<uuid:pk>/",
|
||||
views.AccountDetailView.as_view(),
|
||||
name="account_detail",
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/coa_accounts/create/", views.AccountCreateView.as_view(), name="account_create"
|
||||
"<slug:dealer_slug>/coa_accounts/create/",
|
||||
views.AccountCreateView.as_view(),
|
||||
name="account_create",
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/coa_accounts/<uuid:pk>/update/",
|
||||
views.AccountUpdateView.as_view(),
|
||||
name="account_update",
|
||||
),
|
||||
path("<slug:dealer_slug>/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
|
||||
#################################################
|
||||
path("<slug:dealer_slug>/sales/estimates/", views.EstimateListView.as_view(), name="estimate_list"),
|
||||
path(
|
||||
"<slug:dealer_slug>/sales/estimates/",
|
||||
views.EstimateListView.as_view(),
|
||||
name="estimate_list",
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/sales/estimates/<uuid:pk>/",
|
||||
views.EstimateDetailView.as_view(),
|
||||
name="estimate_detail",
|
||||
),
|
||||
path("<slug:dealer_slug>/sales/estimates/create/", views.create_estimate, name="estimate_create"),
|
||||
path(
|
||||
"<slug:dealer_slug>/sales/estimates/create/",
|
||||
views.create_estimate,
|
||||
name="estimate_create",
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/sales/estimates/create/<slug:slug>/",
|
||||
views.create_estimate,
|
||||
@ -683,7 +739,9 @@ urlpatterns = [
|
||||
name="payment_request",
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/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(
|
||||
"<slug:dealer_slug>/sales/estimates/<uuid:pk>/sale_order/",
|
||||
@ -703,9 +761,15 @@ urlpatterns = [
|
||||
###############################################
|
||||
# Invoice
|
||||
###############################################
|
||||
path("<slug:dealer_slug>/sales/invoices/", views.InvoiceListView.as_view(), name="invoice_list"),
|
||||
path(
|
||||
"<slug:dealer_slug>/sales/invoices/<uuid:pk>/create/", views.invoice_create, name="invoice_create"
|
||||
"<slug:dealer_slug>/sales/invoices/",
|
||||
views.InvoiceListView.as_view(),
|
||||
name="invoice_list",
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/sales/invoices/<uuid:pk>/create/",
|
||||
views.invoice_create,
|
||||
name="invoice_create",
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/sales/invoices/<uuid:pk>/",
|
||||
@ -740,7 +804,9 @@ urlpatterns = [
|
||||
# path('sales/estimates/<uuid:pk>/preview/', views.EstimatePreviewView.as_view(), name='estimate_preview'),
|
||||
# path('send_email/<uuid:pk>', views.send_email, name='send_email'),
|
||||
# Payment
|
||||
path("<slug:dealer_slug>/sales/payments/", views.PaymentListView, name="payment_list"),
|
||||
path(
|
||||
"<slug:dealer_slug>/sales/payments/", views.PaymentListView, name="payment_list"
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/sales/payments/<uuid:pk>/create/",
|
||||
views.PaymentCreateView,
|
||||
@ -793,7 +859,11 @@ urlpatterns = [
|
||||
name="item_expense_update",
|
||||
),
|
||||
# Bills
|
||||
path("<slug:dealer_slug>/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(
|
||||
"<slug:dealer_slug>/items/bills/<slug:entity_slug>/create/",
|
||||
@ -1121,7 +1191,6 @@ urlpatterns = [
|
||||
views.PurchaseOrderMarkAsVoidView.as_view(),
|
||||
name="po-action-mark-as-void",
|
||||
),
|
||||
|
||||
]
|
||||
|
||||
handler404 = "inventory.views.custom_page_not_found_view"
|
||||
|
||||
@ -349,7 +349,7 @@ class HomeView(LoginRequiredMixin, TemplateView):
|
||||
|
||||
template_name = "index.html"
|
||||
|
||||
def dispatch(self, request,*args, **kwargs):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
# Redirect unauthenticated users to the welcome page
|
||||
if not request.user.is_authenticated:
|
||||
return redirect("welcome")
|
||||
@ -620,8 +620,12 @@ class CarCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
|
||||
def get_success_url(self):
|
||||
"""Determine the redirect URL based on user choice."""
|
||||
if self.request.POST.get("add_another"):
|
||||
return reverse("car_add", kwargs={"dealer_slug": self.kwargs["dealer_slug"]})
|
||||
return reverse("inventory_stats", kwargs={"dealer_slug": self.kwargs["dealer_slug"]})
|
||||
return reverse(
|
||||
"car_add", kwargs={"dealer_slug": self.kwargs["dealer_slug"]}
|
||||
)
|
||||
return reverse(
|
||||
"inventory_stats", kwargs={"dealer_slug": self.kwargs["dealer_slug"]}
|
||||
)
|
||||
|
||||
def form_valid(self, form):
|
||||
dealer = get_user_type(self.request)
|
||||
@ -675,7 +679,7 @@ class AjaxHandlerView(LoginRequiredMixin, View):
|
||||
:ivar request: Django request object containing HTTP request details.
|
||||
"""
|
||||
|
||||
def get(self, request,dealer_slug, *args, **kwargs):
|
||||
def get(self, request, dealer_slug, *args, **kwargs):
|
||||
action = request.GET.get("action")
|
||||
handlers = {
|
||||
"decode_vin": self.decode_vin,
|
||||
@ -988,7 +992,13 @@ class CarColorCreate(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
|
||||
return super().form_valid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("car_detail", kwargs={"dealer_slug":self.request.dealer.slug,"slug": self.kwargs["slug"]})
|
||||
return reverse_lazy(
|
||||
"car_detail",
|
||||
kwargs={
|
||||
"dealer_slug": self.request.dealer.slug,
|
||||
"slug": self.kwargs["slug"],
|
||||
},
|
||||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
@ -1027,7 +1037,13 @@ class CarColorsUpdateView(
|
||||
"""
|
||||
# self.object refers to the CarColors instance that was just updated.
|
||||
# self.object.car then refers to the associated Car instance.
|
||||
return reverse("car_detail", kwargs={"dealer_slug":self.request.dealer.slug,"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):
|
||||
"""
|
||||
@ -1140,7 +1156,7 @@ class CarListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
||||
|
||||
|
||||
@login_required
|
||||
def inventory_stats_view(request,dealer_slug):
|
||||
def inventory_stats_view(request, dealer_slug):
|
||||
"""
|
||||
Handle the inventory stats view for a dealer, displaying detailed information
|
||||
about the cars, including counts grouped by make, model, and trim.
|
||||
@ -1245,7 +1261,6 @@ def inventory_stats_view(request,dealer_slug):
|
||||
return render(request, "inventory/inventory_stats.html", {"inventory": result})
|
||||
|
||||
|
||||
|
||||
# @login_required
|
||||
# def inventory_stats_view(request):
|
||||
# """
|
||||
@ -1362,7 +1377,6 @@ def inventory_stats_view(request,dealer_slug):
|
||||
# return render(request, "inventory/inventory_stats.html", context)
|
||||
|
||||
|
||||
|
||||
class CarDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
||||
"""
|
||||
Provides a detailed view of a single car instance.
|
||||
@ -1427,7 +1441,10 @@ class CarFinanceCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateVi
|
||||
return super().form_valid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse("car_detail", kwargs={"dealer_slug":self.request.dealer.slug,"slug": self.car.slug})
|
||||
return reverse(
|
||||
"car_detail",
|
||||
kwargs={"dealer_slug": self.request.dealer.slug, "slug": self.car.slug},
|
||||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
@ -1474,7 +1491,13 @@ class CarFinanceUpdateView(
|
||||
permission_required = ["inventory.change_carfinance"]
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse("car_detail", kwargs={"dealer_slug":self.request.dealer.slug,"slug": self.object.car.slug})
|
||||
return reverse(
|
||||
"car_detail",
|
||||
kwargs={
|
||||
"dealer_slug": self.request.dealer.slug,
|
||||
"slug": self.object.car.slug,
|
||||
},
|
||||
)
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
@ -1871,7 +1894,13 @@ class CustomCardCreateView(LoginRequiredMixin, CreateView):
|
||||
|
||||
def get_success_url(self):
|
||||
messages.success(self.request, _("Custom Card added successfully"))
|
||||
return reverse_lazy("car_detail", kwargs={"dealer_slug":self.request.dealer.slug,"slug": self.kwargs["slug"]})
|
||||
return reverse_lazy(
|
||||
"car_detail",
|
||||
kwargs={
|
||||
"dealer_slug": self.request.dealer.slug,
|
||||
"slug": self.kwargs["slug"],
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class CarRegistrationCreateView(LoginRequiredMixin, CreateView):
|
||||
@ -1913,11 +1942,17 @@ class CarRegistrationCreateView(LoginRequiredMixin, CreateView):
|
||||
|
||||
def get_success_url(self):
|
||||
messages.success(self.request, _("Registration added successfully"))
|
||||
return reverse_lazy("car_detail", kwargs={"dealer_slug":self.request.dealer.slug,"slug": self.kwargs["slug"]})
|
||||
return reverse_lazy(
|
||||
"car_detail",
|
||||
kwargs={
|
||||
"dealer_slug": self.request.dealer.slug,
|
||||
"slug": self.kwargs["slug"],
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@login_required()
|
||||
def reserve_car_view(request, dealer_slug,slug):
|
||||
def reserve_car_view(request, dealer_slug, slug):
|
||||
"""
|
||||
Handles car reservation requests. This view requires the user to be logged in
|
||||
and processes only POST requests. When invoked, it checks if the specified car
|
||||
@ -1945,7 +1980,7 @@ def reserve_car_view(request, dealer_slug,slug):
|
||||
|
||||
|
||||
@login_required
|
||||
def manage_reservation(request,dealer_slug, reservation_id):
|
||||
def manage_reservation(request, dealer_slug, reservation_id):
|
||||
"""
|
||||
Handles the management of a car reservation, providing options to renew or
|
||||
cancel an existing reservation associated with the logged-in user.
|
||||
@ -1974,7 +2009,9 @@ def manage_reservation(request,dealer_slug, reservation_id):
|
||||
reservation.reserved_until = timezone.now() + timezone.timedelta(hours=24)
|
||||
reservation.save()
|
||||
messages.success(request, _("Reservation renewed successfully"))
|
||||
return redirect("car_detail",dealer_slug=request.dealer.slug, slug=reservation.car.slug)
|
||||
return redirect(
|
||||
"car_detail", dealer_slug=request.dealer.slug, slug=reservation.car.slug
|
||||
)
|
||||
|
||||
elif action == "cancel":
|
||||
car = reservation.car
|
||||
@ -1982,7 +2019,9 @@ def manage_reservation(request,dealer_slug, reservation_id):
|
||||
car.status = models.CarStatusChoices.AVAILABLE
|
||||
car.save()
|
||||
messages.success(request, _("Reservation canceled successfully"))
|
||||
return redirect("car_detail",dealer_slug=request.dealer.slug, slug=reservation.car.slug)
|
||||
return redirect(
|
||||
"car_detail", dealer_slug=request.dealer.slug, slug=reservation.car.slug
|
||||
)
|
||||
|
||||
else:
|
||||
return JsonResponse(
|
||||
@ -3454,10 +3493,16 @@ class BankAccountUpdateView(
|
||||
kwargs["entity_slug"] = entity.slug # Get entity_slug from URL
|
||||
kwargs["user_model"] = entity.admin # Get user_model from the request
|
||||
return kwargs
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("bank_account_detail", kwargs={"dealer_slug": self.kwargs["dealer_slug"], "pk": self.object.pk})
|
||||
return reverse_lazy(
|
||||
"bank_account_detail",
|
||||
kwargs={"dealer_slug": self.kwargs["dealer_slug"], "pk": self.object.pk},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
def bank_account_delete(request,dealer_slug, pk):
|
||||
def bank_account_delete(request, dealer_slug, pk):
|
||||
"""
|
||||
Delete a bank account entry from the database.
|
||||
|
||||
@ -3590,8 +3635,11 @@ class AccountCreateView(
|
||||
entity = get_user_type(self.request).entity
|
||||
form.initial["coa_model"] = entity.get_default_coa()
|
||||
return form
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse("account_list", kwargs={"dealer_slug":self.kwargs["dealer_slug"]})
|
||||
return reverse(
|
||||
"account_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"]}
|
||||
)
|
||||
|
||||
|
||||
class AccountDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
||||
@ -3691,12 +3739,16 @@ class AccountUpdateView(
|
||||
form.fields["_ref_node_id"].widget = HiddenInput()
|
||||
form.fields["_position"].widget = HiddenInput()
|
||||
return form
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("account_list", kwargs={"dealer_slug":self.kwargs["dealer_slug"]})
|
||||
return reverse_lazy(
|
||||
"account_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"]}
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("inventory.view_carfinance")
|
||||
def account_delete(request, dealer_slug,pk):
|
||||
def account_delete(request, dealer_slug, pk):
|
||||
"""
|
||||
Handles the deletion of an account object identified by its primary key (pk). Ensures
|
||||
that the user has the necessary permissions to perform the deletion. Successfully
|
||||
@ -3715,13 +3767,13 @@ def account_delete(request, dealer_slug,pk):
|
||||
|
||||
account.delete()
|
||||
messages.success(request, _("Account deleted successfully"))
|
||||
return redirect("account_list",dealer_slug=dealer_slug)
|
||||
return redirect("account_list", dealer_slug=dealer_slug)
|
||||
|
||||
|
||||
# Sales list
|
||||
@login_required
|
||||
@permission_required("inventory.view_lead", raise_exception=True)
|
||||
def sales_list_view(request):
|
||||
def sales_list_view(request, dealer_slug):
|
||||
"""
|
||||
Handles the retrieval and presentation of a paginated list of item transactions for
|
||||
sales, specific to the logged-in user's entity. Requires the user to have appropriate
|
||||
@ -3735,7 +3787,7 @@ def sales_list_view(request):
|
||||
item transactions specific to the user's entity.
|
||||
:rtype: HttpResponse
|
||||
"""
|
||||
dealer = get_user_type(request)
|
||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||
entity = dealer.entity
|
||||
|
||||
sale_orders = models.SaleOrder.objects.filter(
|
||||
@ -3812,7 +3864,7 @@ class EstimateListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
||||
# @csrf_exempt
|
||||
@login_required
|
||||
@permission_required("django_ledger.add_estimatemodel", raise_exception=True)
|
||||
def create_estimate(request, dealer_slug,slug=None):
|
||||
def create_estimate(request, dealer_slug, slug=None):
|
||||
"""
|
||||
Creates a new estimate based on the provided data and saves it. This function processes
|
||||
a POST request and expects a JSON payload containing details of the estimate such as
|
||||
@ -4005,7 +4057,9 @@ def create_estimate(request, dealer_slug,slug=None):
|
||||
opportunity.estimate = estimate
|
||||
opportunity.save()
|
||||
|
||||
url = reverse("estimate_detail", kwargs={"dealer_slug": dealer.slug,"pk": estimate.pk})
|
||||
url = reverse(
|
||||
"estimate_detail", kwargs={"dealer_slug": dealer.slug, "pk": estimate.pk}
|
||||
)
|
||||
return JsonResponse(
|
||||
{
|
||||
"status": "success",
|
||||
@ -4111,7 +4165,7 @@ class EstimateDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
|
||||
|
||||
@login_required
|
||||
@permission_required("inventory.add_saleorder", raise_exception=True)
|
||||
def create_sale_order(request,dealer_slug, pk):
|
||||
def create_sale_order(request, dealer_slug, pk):
|
||||
"""
|
||||
Creates a sale order for a given estimate and updates associated item and car data.
|
||||
|
||||
@ -4204,7 +4258,7 @@ class SaleOrderDetail(DetailView):
|
||||
|
||||
|
||||
@login_required
|
||||
def preview_sale_order(request, dealer_slug,pk):
|
||||
def preview_sale_order(request, dealer_slug, pk):
|
||||
"""
|
||||
Handles rendering of the sale order preview page for a specific estimate.
|
||||
|
||||
@ -4304,7 +4358,7 @@ class EstimatePreviewView(LoginRequiredMixin, PermissionRequiredMixin, DetailVie
|
||||
|
||||
@login_required
|
||||
@permission_required("django_ledger.change_estimatemodel", raise_exception=True)
|
||||
def estimate_mark_as(request,dealer_slug, pk):
|
||||
def estimate_mark_as(request, dealer_slug, pk):
|
||||
"""
|
||||
Marks an estimate with a specified status based on the requested action and
|
||||
permissions. The marking possibilities include review, approval, rejection,
|
||||
@ -4327,29 +4381,39 @@ def estimate_mark_as(request,dealer_slug, pk):
|
||||
if mark == "review":
|
||||
if not estimate.can_review():
|
||||
messages.error(request, _("Quotation is not ready for review"))
|
||||
return redirect("estimate_detail",dealer_slug=dealer.slug, pk=estimate.pk)
|
||||
return redirect(
|
||||
"estimate_detail", dealer_slug=dealer.slug, pk=estimate.pk
|
||||
)
|
||||
estimate.mark_as_review()
|
||||
|
||||
elif mark == "approved":
|
||||
if not estimate.can_approve():
|
||||
messages.error(request, _("Quotation is not ready for approval"))
|
||||
return redirect("estimate_detail",dealer_slug=dealer.slug, pk=estimate.pk)
|
||||
return redirect(
|
||||
"estimate_detail", dealer_slug=dealer.slug, pk=estimate.pk
|
||||
)
|
||||
estimate.mark_as_approved()
|
||||
messages.success(request, _("Quotation approved successfully"))
|
||||
elif mark == "rejected":
|
||||
if not estimate.can_cancel():
|
||||
messages.error(request, _("Quotation is not ready for rejection"))
|
||||
return redirect("estimate_detail",dealer_slug=dealer.slug, pk=estimate.pk)
|
||||
return redirect(
|
||||
"estimate_detail", dealer_slug=dealer.slug, pk=estimate.pk
|
||||
)
|
||||
estimate.mark_as_canceled()
|
||||
messages.success(request, _("Quotation canceled successfully"))
|
||||
elif mark == "completed":
|
||||
if not estimate.can_complete():
|
||||
messages.error(request, _("Quotation is not ready for completion"))
|
||||
return redirect("estimate_detail",dealer_slug=dealer.slug, pk=estimate.pk)
|
||||
return redirect(
|
||||
"estimate_detail", dealer_slug=dealer.slug, pk=estimate.pk
|
||||
)
|
||||
elif mark == "canceled":
|
||||
if not estimate.can_cancel():
|
||||
messages.error(request, _("Quotation is not ready for cancellation"))
|
||||
return redirect("estimate_detail", dealer_slug=dealer.slug, pk=estimate.pk)
|
||||
return redirect(
|
||||
"estimate_detail", dealer_slug=dealer.slug, pk=estimate.pk
|
||||
)
|
||||
estimate.mark_as_canceled()
|
||||
try:
|
||||
car = models.Car.objects.get(
|
||||
@ -4526,7 +4590,10 @@ class ApprovedInvoiceModelUpdateFormView(
|
||||
return kwargs
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("invoice_detail", kwargs={"dealer_slug":self.kwargs["dealer_slug"],"pk": self.object.pk})
|
||||
return reverse_lazy(
|
||||
"invoice_detail",
|
||||
kwargs={"dealer_slug": self.kwargs["dealer_slug"], "pk": self.object.pk},
|
||||
)
|
||||
|
||||
|
||||
class PaidInvoiceModelUpdateFormView(
|
||||
@ -4571,7 +4638,10 @@ class PaidInvoiceModelUpdateFormView(
|
||||
return kwargs
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("invoice_detail", kwargs={"dealer_slug":self.kwargs["dealer_slug"],"pk": self.object.pk})
|
||||
return reverse_lazy(
|
||||
"invoice_detail",
|
||||
kwargs={"dealer_slug": self.kwargs["dealer_slug"], "pk": self.object.pk},
|
||||
)
|
||||
|
||||
def form_valid(self, form):
|
||||
invoice = form.save()
|
||||
@ -4587,7 +4657,7 @@ class PaidInvoiceModelUpdateFormView(
|
||||
|
||||
@login_required
|
||||
@permission_required("django_ledger.change_invoicemodel", raise_exception=True)
|
||||
def invoice_mark_as(request,dealer_slug, pk):
|
||||
def invoice_mark_as(request, dealer_slug, pk):
|
||||
"""
|
||||
Marks an invoice as approved if it meets the required conditions.
|
||||
|
||||
@ -4610,17 +4680,17 @@ def invoice_mark_as(request,dealer_slug, pk):
|
||||
if mark and mark == "accept":
|
||||
if not invoice.can_approve():
|
||||
messages.error(request, "invoice is not ready for approval")
|
||||
return redirect("invoice_detail",dealer_slug=dealer_slug, pk=invoice.pk)
|
||||
return redirect("invoice_detail", dealer_slug=dealer_slug, pk=invoice.pk)
|
||||
invoice.mark_as_approved(
|
||||
entity_slug=dealer.entity.slug, user_model=dealer.entity.admin
|
||||
)
|
||||
invoice.save()
|
||||
return redirect("invoice_detail",dealer_slug=dealer_slug, pk=invoice.pk)
|
||||
return redirect("invoice_detail", dealer_slug=dealer_slug, pk=invoice.pk)
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("django_ledger.add_invoicemodel", raise_exception=True)
|
||||
def invoice_create(request,dealer_slug, pk):
|
||||
def invoice_create(request, dealer_slug, pk):
|
||||
"""
|
||||
Handles the creation of a new invoice associated with a given estimate. It validates
|
||||
the submitted data through a form, processes the invoice, updates related models, and
|
||||
@ -4636,7 +4706,7 @@ def invoice_create(request,dealer_slug, pk):
|
||||
creation or renders the invoice creation form template otherwise.
|
||||
:rtype: HttpResponse
|
||||
"""
|
||||
dealer = get_object_or_404(models.Dealer,slug=dealer_slug)
|
||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||
estimate = get_object_or_404(EstimateModel, pk=pk)
|
||||
entity = dealer.entity
|
||||
|
||||
@ -4678,7 +4748,7 @@ def invoice_create(request,dealer_slug, pk):
|
||||
estimate.save()
|
||||
invoice.save()
|
||||
messages.success(request, "Invoice created successfully")
|
||||
return redirect("invoice_detail", dealer_slug=dealer.slug,pk=invoice.pk)
|
||||
return redirect("invoice_detail", dealer_slug=dealer.slug, pk=invoice.pk)
|
||||
else:
|
||||
print(form.errors)
|
||||
form = forms.InvoiceModelCreateForm(
|
||||
@ -4726,7 +4796,7 @@ class InvoicePreviewView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
|
||||
permission_required = ["django_ledger.view_invoicemodel"]
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
dealer = get_object_or_404(models.Dealer,slug=self.kwargs["dealer_slug"])
|
||||
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
||||
invoice = kwargs.get("object")
|
||||
if invoice.get_itemtxs_data():
|
||||
calculator = CarFinanceCalculator(invoice)
|
||||
@ -4741,7 +4811,7 @@ class InvoicePreviewView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
|
||||
|
||||
@login_required
|
||||
@permission_required("django_ledger.add_journalentrymodel", raise_exception=True)
|
||||
def PaymentCreateView(request,dealer_slug, pk):
|
||||
def PaymentCreateView(request, dealer_slug, pk):
|
||||
"""
|
||||
Handles the creation of a payment entry associated with an invoice or bill. Validates
|
||||
the payment data against the model's current state and reflects the changes in
|
||||
@ -4764,7 +4834,7 @@ def PaymentCreateView(request,dealer_slug, pk):
|
||||
redirect to the detail view of the processed invoice or bill, re-render the
|
||||
payment form with error messages or indicate success in payment creation.
|
||||
"""
|
||||
dealer = get_object_or_404(models.Dealer,slug=dealer_slug)
|
||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||
invoice = InvoiceModel.objects.filter(pk=pk).first()
|
||||
bill = BillModel.objects.filter(pk=pk).first()
|
||||
model = invoice if invoice else bill
|
||||
@ -4784,7 +4854,7 @@ def PaymentCreateView(request,dealer_slug, pk):
|
||||
model.mark_as_approved(user_model=entity.admin)
|
||||
if model.amount_paid == model.amount_due:
|
||||
messages.error(request, _("fully paid"))
|
||||
return redirect(redirect_url, dealer_slug=dealer.slug,pk=model.pk)
|
||||
return redirect(redirect_url, dealer_slug=dealer.slug, pk=model.pk)
|
||||
if model.amount_paid + amount > model.amount_due:
|
||||
messages.error(request, _("Amount exceeds due amount"))
|
||||
return redirect(redirect_url, dealer_slug=dealer.slug, pk=model.pk)
|
||||
@ -4816,7 +4886,7 @@ def PaymentCreateView(request,dealer_slug, pk):
|
||||
|
||||
@login_required
|
||||
@permission_required("django_ledger.view_journalentrymodel", raise_exception=True)
|
||||
def PaymentListView(request,dealer_slug):
|
||||
def PaymentListView(request, dealer_slug):
|
||||
"""
|
||||
Handles the view for listing payment information associated with the journals of a specific
|
||||
entity. This view is protected to ensure only authenticated and authorized users can
|
||||
@ -4832,7 +4902,7 @@ def PaymentListView(request,dealer_slug):
|
||||
:return: The rendered HTML response displaying the list of payments.
|
||||
:rtype: HttpResponse
|
||||
"""
|
||||
dealer = get_object_or_404(models.Dealer,slug=dealer_slug)
|
||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||
entity = dealer.entity
|
||||
|
||||
journals = JournalEntryModel.objects.filter(ledger__entity=entity).all()
|
||||
@ -4846,7 +4916,7 @@ def PaymentListView(request,dealer_slug):
|
||||
|
||||
@login_required
|
||||
@permission_required("django_ledger.view_journalentrymodel", raise_exception=True)
|
||||
def PaymentDetailView(request,dealer_slug, pk):
|
||||
def PaymentDetailView(request, dealer_slug, pk):
|
||||
"""
|
||||
This function handles the detail view for a payment by fetching a journal entry
|
||||
and its associated transactions. It ensures that the request is authenticated
|
||||
@ -4860,7 +4930,7 @@ def PaymentDetailView(request,dealer_slug, pk):
|
||||
entry and its associated transactions.
|
||||
:rtype: HttpResponse
|
||||
"""
|
||||
dealer = get_object_or_404(models.Dealer,slug=dealer_slug)
|
||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||
journal = JournalEntryModel.objects.filter(pk=pk).first()
|
||||
transactions = (
|
||||
TransactionModel.objects.filter(journal_entry=journal)
|
||||
@ -4876,7 +4946,7 @@ def PaymentDetailView(request,dealer_slug, pk):
|
||||
|
||||
@login_required
|
||||
@permission_required("django_ledger.change_journalentrymodel", raise_exception=True)
|
||||
def payment_mark_as_paid(request, dealer_slug,pk):
|
||||
def payment_mark_as_paid(request, dealer_slug, pk):
|
||||
"""
|
||||
Marks an invoice as paid if it meets the conditions of being fully paid and eligible
|
||||
for payment. Also ensures that related ledger journal entries are locked and posted
|
||||
@ -4895,7 +4965,7 @@ def payment_mark_as_paid(request, dealer_slug,pk):
|
||||
:raises: In case of an exception during the process, an error message is
|
||||
displayed to the user through Django's messaging framework.
|
||||
"""
|
||||
dealer = get_object_or_404(models.Dealer,slug=dealer_slug)
|
||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||
invoice = get_object_or_404(InvoiceModel, pk=pk)
|
||||
if request.method == "POST":
|
||||
try:
|
||||
@ -4920,7 +4990,7 @@ def payment_mark_as_paid(request, dealer_slug,pk):
|
||||
)
|
||||
except Exception as e:
|
||||
messages.error(request, f"Error: {str(e)}")
|
||||
return redirect("invoice_detail",dealer_slug=dealer_slug, pk=invoice.pk)
|
||||
return redirect("invoice_detail", dealer_slug=dealer_slug, pk=invoice.pk)
|
||||
|
||||
|
||||
# activity log
|
||||
@ -6651,8 +6721,8 @@ class BillModelCreateView(CreateView):
|
||||
for_purchase_order = False
|
||||
for_estimate = False
|
||||
|
||||
def get(self, request, dealer_slug,**kwargs):
|
||||
dealer = get_object_or_404(models.Dealer,slug=dealer_slug)
|
||||
def get(self, request, dealer_slug, **kwargs):
|
||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||
if not request.user.is_authenticated:
|
||||
return HttpResponseForbidden()
|
||||
|
||||
@ -6665,7 +6735,7 @@ class BillModelCreateView(CreateView):
|
||||
)
|
||||
if not estimate_model.can_bind():
|
||||
return HttpResponseNotFound("404 Not Found")
|
||||
return super(BillModelCreateView, self).get(request,dealer_slug, **kwargs)
|
||||
return super(BillModelCreateView, self).get(request, dealer_slug, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(BillModelCreateView, self).get_context_data(**kwargs)
|
||||
@ -6797,17 +6867,29 @@ class BillModelCreateView(CreateView):
|
||||
po_pk = self.kwargs["po_pk"]
|
||||
return reverse(
|
||||
"purchase_order_update",
|
||||
kwargs={"dealer_slug": self.kwargs["dealer_slug"],"entity_slug": entity_slug, "po_pk": po_pk},
|
||||
kwargs={
|
||||
"dealer_slug": self.kwargs["dealer_slug"],
|
||||
"entity_slug": entity_slug,
|
||||
"po_pk": po_pk,
|
||||
},
|
||||
)
|
||||
elif self.for_estimate:
|
||||
return reverse(
|
||||
"customer-estimate-detail",
|
||||
kwargs={"dealer_slug": self.kwargs["dealer_slug"],"entity_slug": entity_slug, "ce_pk": self.kwargs["ce_pk"]},
|
||||
kwargs={
|
||||
"dealer_slug": self.kwargs["dealer_slug"],
|
||||
"entity_slug": entity_slug,
|
||||
"ce_pk": self.kwargs["ce_pk"],
|
||||
},
|
||||
)
|
||||
bill_model: BillModel = self.object
|
||||
return reverse(
|
||||
"bill-detail",
|
||||
kwargs={"dealer_slug": self.kwargs["dealer_slug"],"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,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@ -6823,7 +6905,7 @@ class BillModelDetailViewView(BillModelDetailView):
|
||||
class BillModelUpdateViewView(BillModelUpdateView):
|
||||
template_name = "bill/bill_update.html"
|
||||
|
||||
def post(self, request, dealer_slug,entity_slug,bill_pk, *args, **kwargs):
|
||||
def post(self, request, dealer_slug, entity_slug, bill_pk, *args, **kwargs):
|
||||
if self.action_update_items:
|
||||
if not request.user.is_authenticated:
|
||||
return HttpResponseForbidden()
|
||||
@ -6888,7 +6970,9 @@ class BillModelUpdateViewView(BillModelUpdateView):
|
||||
)
|
||||
context = self.get_context_data(itemtxs_formset=itemtxs_formset)
|
||||
return self.render_to_response(context=context)
|
||||
return super(BillModelUpdateViewView, self).post(request,dealer_slug,entity_slug,bill_pk, **kwargs)
|
||||
return super(BillModelUpdateViewView, self).post(
|
||||
request, dealer_slug, entity_slug, bill_pk, **kwargs
|
||||
)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse(
|
||||
@ -7091,7 +7175,7 @@ class OrderListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
||||
# email
|
||||
@login_required
|
||||
@permission_required("django_ledger.view_estimatemodel", raise_exception=True)
|
||||
def send_email_view(request,dealer_slug, pk):
|
||||
def send_email_view(request, dealer_slug, pk):
|
||||
"""
|
||||
View function to send an email for an estimate. This function allows authenticated and
|
||||
authorized users to send an email containing the estimate details to the customer.
|
||||
@ -7112,10 +7196,12 @@ def send_email_view(request,dealer_slug, pk):
|
||||
|
||||
if not estimate.get_itemtxs_data()[0]:
|
||||
messages.error(request, _("Quotation has no items"))
|
||||
return redirect("estimate_detail", dealer_slug=dealer_slug,pk=estimate.pk)
|
||||
return redirect("estimate_detail", dealer_slug=dealer_slug, pk=estimate.pk)
|
||||
|
||||
link = request.build_absolute_uri(
|
||||
reverse_lazy("estimate_preview", kwargs={"dealer_slug":dealer_slug,"pk": estimate.pk})
|
||||
reverse_lazy(
|
||||
"estimate_preview", kwargs={"dealer_slug": dealer_slug, "pk": estimate.pk}
|
||||
)
|
||||
)
|
||||
|
||||
msg = f"""
|
||||
@ -7152,7 +7238,7 @@ def send_email_view(request,dealer_slug, pk):
|
||||
estimate.mark_as_review()
|
||||
messages.success(request, _("Email sent successfully"))
|
||||
|
||||
return redirect("estimate_detail", dealer_slug=dealer.slug,pk=estimate.pk)
|
||||
return redirect("estimate_detail", dealer_slug=dealer.slug, pk=estimate.pk)
|
||||
|
||||
|
||||
# errors
|
||||
@ -8342,7 +8428,7 @@ class JournalEntryListView(LoginRequiredMixin, ListView):
|
||||
model = JournalEntryModel
|
||||
context_object_name = "journal_entries"
|
||||
template_name = "ledger/journal_entry/journal_entry_list.html"
|
||||
ordering=['-timestamp']
|
||||
ordering = ["-timestamp"]
|
||||
|
||||
def get_queryset(self):
|
||||
qs = super().get_queryset()
|
||||
@ -8454,12 +8540,14 @@ def JournalEntryTransactionsView(request, pk):
|
||||
# .order_by("account__code")
|
||||
# .all()
|
||||
# )
|
||||
qs=TransactionModel.objects.filter(journal_entry=journal).all()
|
||||
transactions=qs.annotate(
|
||||
debit_credit_sort_order=Case(When(tx_type='debit',then=Value(0)),
|
||||
When(tx_type='credit',then=Value(1)),
|
||||
output_field=IntegerField())
|
||||
).order_by('debit_credit_sort_order')
|
||||
qs = TransactionModel.objects.filter(journal_entry=journal).all()
|
||||
transactions = qs.annotate(
|
||||
debit_credit_sort_order=Case(
|
||||
When(tx_type="debit", then=Value(0)),
|
||||
When(tx_type="credit", then=Value(1)),
|
||||
output_field=IntegerField(),
|
||||
)
|
||||
).order_by("debit_credit_sort_order")
|
||||
return render(
|
||||
request,
|
||||
"ledger/journal_entry/journal_entry_transactions.html",
|
||||
@ -9074,7 +9162,7 @@ def PurchaseOrderCreateView(request, dealer_slug):
|
||||
return render(request, "purchase_orders/po_form.html", {"form": form})
|
||||
|
||||
|
||||
def InventoryItemCreateView(request,dealer_slug):
|
||||
def InventoryItemCreateView(request, dealer_slug):
|
||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||
for_po = request.GET.get("for_po")
|
||||
entity = dealer.entity
|
||||
@ -9115,7 +9203,10 @@ def InventoryItemCreateView(request,dealer_slug):
|
||||
.first()
|
||||
):
|
||||
messages.error(request, _("Inventory item already exists"))
|
||||
return redirect(f"{reverse('inventory_item_create')}?for_po={for_po}", dealer_slug=dealer.slug)
|
||||
return redirect(
|
||||
f"{reverse('inventory_item_create')}?for_po={for_po}",
|
||||
dealer_slug=dealer.slug,
|
||||
)
|
||||
uom = entity.get_uom_all().get(name="Unit")
|
||||
entity.create_item_inventory(
|
||||
name=inventory_name,
|
||||
@ -9147,7 +9238,7 @@ def InventoryItemCreateView(request,dealer_slug):
|
||||
)
|
||||
|
||||
|
||||
def inventory_items_filter(request,dealer_slug):
|
||||
def inventory_items_filter(request, dealer_slug):
|
||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||
make = request.GET.get("make")
|
||||
model = request.GET.get("model")
|
||||
@ -9253,7 +9344,11 @@ class PurchaseOrderUpdateView(PurchaseOrderModelUpdateViewBase):
|
||||
return HttpResponseRedirect(
|
||||
redirect_to=reverse(
|
||||
"purchase_order_update",
|
||||
kwargs={"dealer_slug": dealer_slug,"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(
|
||||
@ -9318,7 +9413,7 @@ class PurchaseOrderUpdateView(PurchaseOrderModelUpdateViewBase):
|
||||
context=self.get_context_data(itemtxs_formset=itemtxs_formset)
|
||||
)
|
||||
return super(PurchaseOrderUpdateView, self).post(
|
||||
request,dealer_slug, entity_slug, *args, **kwargs
|
||||
request, dealer_slug, entity_slug, *args, **kwargs
|
||||
)
|
||||
|
||||
def get_form(self, form_class=None):
|
||||
@ -9349,19 +9444,24 @@ class PurchaseOrderUpdateView(PurchaseOrderModelUpdateViewBase):
|
||||
|
||||
|
||||
class BasePurchaseOrderActionActionView(BasePurchaseOrderActionActionViewBase):
|
||||
def get_redirect_url(self,dealer_slug, entity_slug, po_pk, *args, **kwargs):
|
||||
def get_redirect_url(self, dealer_slug, entity_slug, po_pk, *args, **kwargs):
|
||||
return reverse(
|
||||
"purchase_order_update", kwargs={"dealer_slug":dealer_slug,"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,dealer_slug, entity_slug, po_pk, *args, **kwargs):
|
||||
def get(self, request, dealer_slug, entity_slug, po_pk, *args, **kwargs):
|
||||
# kwargs["user_model"] = self.request.user
|
||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||
kwargs["user_model"] = dealer.entity.admin
|
||||
if not self.action_name:
|
||||
raise ImproperlyConfigured("View attribute action_name is required.")
|
||||
response = super(BasePurchaseOrderActionActionView, self).get(
|
||||
request,dealer_slug,entity_slug,po_pk, *args, **kwargs
|
||||
request, dealer_slug, entity_slug, po_pk, *args, **kwargs
|
||||
)
|
||||
po_model: PurchaseOrderModel = self.get_object()
|
||||
|
||||
@ -9386,7 +9486,9 @@ class PurchaseOrderModelDeleteView(PurchaseOrderModelDeleteViewBase):
|
||||
message="PO deleted successfully.",
|
||||
level=messages.SUCCESS,
|
||||
)
|
||||
return reverse("purchase_order_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"]})
|
||||
return reverse(
|
||||
"purchase_order_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"]}
|
||||
)
|
||||
|
||||
|
||||
class PurchaseOrderMarkAsDraftView(BasePurchaseOrderActionActionView):
|
||||
@ -9415,9 +9517,14 @@ class PurchaseOrderMarkAsVoidView(BasePurchaseOrderActionActionView):
|
||||
|
||||
##############################bil
|
||||
class BaseBillActionView(BaseBillActionViewBase):
|
||||
def get_redirect_url(self,dealer_slug, entity_slug, bill_pk, *args, **kwargs):
|
||||
def get_redirect_url(self, dealer_slug, entity_slug, bill_pk, *args, **kwargs):
|
||||
return reverse(
|
||||
"bill-update", kwargs={"dealer_slug": self.kwargs["dealer_slug"],"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,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@ -9465,14 +9572,14 @@ class BillModelActionForceMigrateView(BaseBillActionView):
|
||||
###############################################################
|
||||
|
||||
|
||||
def view_items_inventory(request,dealer_slug, entity_slug, po_pk):
|
||||
def view_items_inventory(request, dealer_slug, entity_slug, po_pk):
|
||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||
po = PurchaseOrderModel.objects.get(pk=po_pk)
|
||||
items = po.get_itemtxs_data()[0]
|
||||
items_per_page = 30
|
||||
items_per_page = 30
|
||||
paginator = Paginator(items, items_per_page)
|
||||
|
||||
page_number = request.GET.get('page')
|
||||
page_number = request.GET.get("page")
|
||||
try:
|
||||
page_obj = paginator.get_page(page_number)
|
||||
except PageNotAnInteger:
|
||||
@ -9482,21 +9589,26 @@ def view_items_inventory(request,dealer_slug, entity_slug, po_pk):
|
||||
# If page is out of range (e.g. 9999), deliver last page of results.
|
||||
page_obj = paginator.get_page(paginator.num_pages)
|
||||
return render(
|
||||
request, "purchase_orders/po_upload_cars.html", {"po": po, "items": items,"page_obj":page_obj}
|
||||
request,
|
||||
"purchase_orders/po_upload_cars.html",
|
||||
{"po": po, "items": items, "page_obj": page_obj},
|
||||
)
|
||||
|
||||
|
||||
def upload_cars(request,dealer_slug, pk=None):
|
||||
def upload_cars(request, dealer_slug, pk=None):
|
||||
item = None
|
||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||
response = redirect("upload_cars",dealer_slug=dealer_slug)
|
||||
response = redirect("upload_cars", dealer_slug=dealer_slug)
|
||||
if pk:
|
||||
item = get_object_or_404(ItemTransactionModel, pk=pk)
|
||||
response = redirect("upload_cars", dealer_slug=dealer_slug,pk=pk)
|
||||
response = redirect("upload_cars", dealer_slug=dealer_slug, pk=pk)
|
||||
if item.item_model.additional_info.get("uploaded"):
|
||||
messages.add_message(request, messages.ERROR, "Item already uploaded.")
|
||||
return redirect(
|
||||
"view_items_inventory",dealer_slug=dealer_slug, entity_slug=dealer.entity.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":
|
||||
@ -9506,7 +9618,9 @@ def upload_cars(request,dealer_slug, pk=None):
|
||||
if item:
|
||||
item = ItemTransactionModel.objects.get(pk=pk)
|
||||
data = [x.strip() for x in item.item_model.name.split("||")]
|
||||
make = models.CarMake.objects.filter(is_sa_import=True).get(name=data[0])
|
||||
make = models.CarMake.objects.filter(is_sa_import=True).get(
|
||||
name=data[0]
|
||||
)
|
||||
model = make.carmodel_set.get(name=data[1])
|
||||
trim = models.CarTrim.objects.filter(
|
||||
name=data[3], id_car_serie__id_car_model=model.id_car_model
|
||||
@ -9541,7 +9655,7 @@ def upload_cars(request,dealer_slug, pk=None):
|
||||
|
||||
if not csv_file.name.endswith(".csv"):
|
||||
messages.error(request, "Please upload a CSV file")
|
||||
return redirect("upload_cars",dealer_slug=dealer_slug)
|
||||
return redirect("upload_cars", dealer_slug=dealer_slug)
|
||||
try:
|
||||
# Read the file content
|
||||
file_content = csv_file.read().decode("utf-8")
|
||||
@ -9644,5 +9758,3 @@ class InventoryListView(InventoryListViewBase):
|
||||
entity_slug=dealer.entity.slug,
|
||||
)
|
||||
return super().get_queryset()
|
||||
|
||||
|
||||
|
||||
@ -63,7 +63,7 @@
|
||||
{% include 'header.html' %}
|
||||
|
||||
<div class="content">
|
||||
|
||||
|
||||
{% include "plans/expiration_messages.html" %}
|
||||
{% block period_navigation %}
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="fs-9">
|
||||
|
||||
|
||||
{% for transaction_model in transaction_model_qs %}
|
||||
|
||||
<tr>
|
||||
|
||||
@ -231,27 +231,27 @@
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="6" class="text-center">{% trans "No Lead Yet" %}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="6" class="text-center">{% trans "No Lead Yet" %}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@ -90,14 +90,14 @@
|
||||
<div id="opportunities-grid" class="row g-4 px-2 px-lg-4 mt-1">
|
||||
{% include 'crm/opportunities/partials/opportunity_grid.html' %}
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@ -109,15 +109,15 @@
|
||||
</tbody>
|
||||
{% endif %}
|
||||
</table>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% include 'modal/delete_modal.html' %}
|
||||
{% endblock %}
|
||||
@ -46,13 +46,13 @@
|
||||
</table>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@ -98,7 +98,7 @@
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if perms.django_ledger.view_invoicemodel %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'invoice_list' request.dealer.slug %}">
|
||||
@ -118,7 +118,7 @@
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'sales_list' %}">
|
||||
<a class="nav-link" href="{% url 'sales_list' request.dealer.slug %}">
|
||||
<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 "Sales Orders"|capfirst %}</span>
|
||||
</div>
|
||||
@ -270,7 +270,7 @@
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -163,14 +163,14 @@
|
||||
<tr>
|
||||
<th>{% trans "Custom Card" %}</th>
|
||||
<td>
|
||||
<button type="button"
|
||||
<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>
|
||||
>{% trans 'Add' %}</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
@ -196,7 +196,7 @@
|
||||
hx-get="{% url 'add_registration' request.dealer.slug car.slug %}"
|
||||
hx-target=".main-modal-body"
|
||||
hx-swap="innerHTML"
|
||||
>{% trans 'Add' %}</button>
|
||||
>{% trans 'Add' %}</button>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@ -25,83 +25,83 @@
|
||||
{% endblock customCSS %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid" id="projectSummary">
|
||||
<div class="container-fluid" id="projectSummary">
|
||||
<div class="row g-3 justify-content-between align-items-end mb-4">
|
||||
<div class="col-12 col-sm-auto">
|
||||
<h2 class="text-body-emphasis fw-bold mb-0">{{ _("Inventory") }}</h2>
|
||||
</div>
|
||||
<div class="col-12 col-sm-auto">
|
||||
<h2 class="text-body-emphasis fw-bold mb-0">{{ _("Inventory") }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-3 justify-content-between align-items-end mb-2">
|
||||
<div class="col-4 col-sm-auto">
|
||||
<ul
|
||||
class="nav nav-links mx-n2"
|
||||
hx-boost="true"
|
||||
hx-push-url="false"
|
||||
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::after-request="on_after_request()">
|
||||
<li class="nav-item">
|
||||
<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 class="nav-item">
|
||||
<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 class="nav-item">
|
||||
<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 class="nav-item">
|
||||
<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 class="nav-item">
|
||||
<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 class="nav-item">
|
||||
<button hx-on:click="toggle_filter()" class="btn btn-sm btn-phoenix-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>
|
||||
</div>
|
||||
<div class="col-4 col-sm-auto">
|
||||
<form hx-boost="true" action="{% url 'bulk_update_car_price' %}" method="post" hx-include=".car-checkbox" class="update-price-form d-flex flex-row align-items-center ms-auto d-none" style="float: right;">
|
||||
{% csrf_token %}
|
||||
<div class="input-group">
|
||||
<input class="form-control" type="number" placeholder='{{ _("Price") }}' name="price" aria-label="Price" id="price" />
|
||||
<button class="btn btn-sm btn-phoenix-primary" type="submit">{{ _("Update") }}</button>
|
||||
</div>
|
||||
<div class="col-4 col-sm-auto">
|
||||
<ul
|
||||
class="nav nav-links mx-n2"
|
||||
hx-boost="true"
|
||||
hx-push-url="false"
|
||||
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::after-request="on_after_request()">
|
||||
<li class="nav-item">
|
||||
<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 class="nav-item">
|
||||
<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 class="nav-item">
|
||||
<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 class="nav-item">
|
||||
<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 class="nav-item">
|
||||
<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 class="nav-item">
|
||||
<button hx-on:click="toggle_filter()" class="btn btn-sm btn-phoenix-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>
|
||||
</div>
|
||||
<div class="col-4 col-sm-auto">
|
||||
<form hx-boost="true" action="{% url 'bulk_update_car_price' %}" method="post" hx-include=".car-checkbox" class="update-price-form d-flex flex-row align-items-center ms-auto d-none" style="float: right;">
|
||||
{% csrf_token %}
|
||||
<div class="input-group">
|
||||
<input class="form-control" type="number" placeholder='{{ _("Price") }}' name="price" aria-label="Price" id="price" />
|
||||
<button class="btn btn-sm btn-phoenix-primary" type="submit">{{ _("Update") }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-4 col-sm-auto">
|
||||
<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="search-box me-3">
|
||||
<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' 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::after-request="on_after_request()"
|
||||
/>
|
||||
<span class="fas fa-search search-box-icon"></span>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-4 col-sm-auto">
|
||||
<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="search-box me-3">
|
||||
<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' 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::after-request="on_after_request()"
|
||||
/>
|
||||
<span class="fas fa-search search-box-icon"></span>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="d-flex align-items-center d-none filter">
|
||||
@ -165,147 +165,147 @@
|
||||
{{ _("Search") }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="table-responsive scrollbar">
|
||||
<div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9">
|
||||
<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::after-request="on_after_request()"></div>
|
||||
<div class="w-100 list table-responsive" >
|
||||
<div class="form-check">
|
||||
<input class="form-check-input ms-4" type="checkbox" id="select-all" /> <span class="ms-1 text-body-tertiary">{{ _("Select All") }}</span>
|
||||
</div>
|
||||
{% for car in cars %}
|
||||
<div class="card border mb-3 py-0 px-0" id="project-list-table-body">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input car-checkbox" type="checkbox" name="car" value="{{ car.pk }}" id="car-{{car.pk}}" />
|
||||
</div>
|
||||
<div class="table-responsive scrollbar">
|
||||
<div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9">
|
||||
<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::after-request="on_after_request()"></div>
|
||||
<div class="w-100 list table-responsive" >
|
||||
<div class="form-check">
|
||||
<input class="form-check-input ms-4" type="checkbox" id="select-all" /> <span class="ms-1 text-body-tertiary">{{ _("Select All") }}</span>
|
||||
</div>
|
||||
{% for car in cars %}
|
||||
<div class="card border mb-3 py-0 px-0" id="project-list-table-body">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input car-checkbox" type="checkbox" name="car" value="{{ car.pk }}" id="car-{{car.pk}}" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- Vehicle Image/Icon -->
|
||||
<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 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">
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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 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 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>
|
||||
{% 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>
|
||||
{% 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>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block customJS %}
|
||||
|
||||
@ -86,15 +86,15 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if is_paginated %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@ -13,12 +13,12 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
|
||||
{% for i in inventory_list %}
|
||||
|
||||
|
||||
<tr class="hover-actions-trigger">
|
||||
|
||||
<td class="ps-2 fw-medium">{{ i.item_model__name }}</td>
|
||||
|
||||
<td class="ps-2 fw-medium">{{ i.item_model__name }}</td>
|
||||
<td class="ps-2 fw-medium">{{ i.item_model__name }}</td>
|
||||
<td class="text-center">{{ i.item_model__uom__name }}</td>
|
||||
<td class="text-end pe-3">{{ i.total_quantity | floatformat:3 }}</td>
|
||||
|
||||
@ -61,16 +61,16 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -62,16 +62,16 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -52,14 +52,14 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
@ -96,16 +96,16 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</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">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@ -113,16 +113,16 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
<!--test-->
|
||||
|
||||
@ -42,14 +42,14 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@ -121,15 +121,15 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -24,9 +24,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="d-flex">
|
||||
{% include 'partials/search_box.html' %}
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
{% include 'partials/search_box.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -123,16 +123,16 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
@ -1,90 +1,90 @@
|
||||
{% load i18n static %}
|
||||
<div class="d-flex justify-content-between align-items-center mt-4">
|
||||
<div class="text-body-secondary">
|
||||
{{ _("Showing") }} {{ page_obj.start_index }} {{ _("to") }} {{ page_obj.end_index }}
|
||||
{{ _("of") }} {{ page_obj.paginator.count }} {{ _("results") }}
|
||||
</div>
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination mb-0">
|
||||
<div class="text-body-secondary">
|
||||
{{ _("Showing") }} {{ page_obj.start_index }} {{ _("to") }} {{ page_obj.end_index }}
|
||||
{{ _("of") }} {{ page_obj.paginator.count }} {{ _("results") }}
|
||||
</div>
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination mb-0">
|
||||
{# First Page Link #}
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item rounded-md overflow-hidden">
|
||||
<a class="page-link px-3 py-2 border border-gray-300 bg-white text-blue-600 hover:bg-gray-100 transition-colors duration-200" href="?page=1{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'First' %}">
|
||||
<span class="fas fa-angle-double-left" aria-hidden="true"></span>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled rounded-md overflow-hidden">
|
||||
<span class="page-link px-3 py-2 border border-gray-200 bg-gray-50 text-gray-400 cursor-not-allowed">
|
||||
<span class="fas fa-angle-double-left" aria-hidden="true"></span>
|
||||
|
||||
</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item rounded-md overflow-hidden">
|
||||
<a class="page-link px-3 py-2 border border-gray-300 bg-white text-blue-600 hover:bg-gray-100 transition-colors duration-200" href="?page=1{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'First' %}">
|
||||
<span class="fas fa-angle-double-left" aria-hidden="true"></span>
|
||||
|
||||
{# Previous Page Link #}
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item rounded-md overflow-hidden">
|
||||
<a class="page-link px-3 py-2 border border-gray-300 bg-white text-blue-600 hover:bg-gray-100 transition-colors duration-200" href="?page={{ page_obj.previous_page_number }}{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'Previous' %}">
|
||||
<span class="fas fa-chevron-left" aria-hidden="true"></span>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled rounded-md overflow-hidden">
|
||||
<span class="page-link px-3 py-2 border border-gray-200 bg-gray-50 text-gray-400 cursor-not-allowed">
|
||||
<span class="fas fa-chevron-left" aria-hidden="true"></span>
|
||||
|
||||
</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{# Page Numbers #}
|
||||
{% for num in page_obj.paginator.page_range %}
|
||||
{% if num == 1 or num == page_obj.paginator.num_pages or num >= page_obj.number|add:-2 and num <= page_obj.number|add:2 %}
|
||||
<li class="page-item {% if num == page_obj.number %}active{% endif %}">
|
||||
<a class="page-link" {% if num == page_obj.number %}aria-current="page"{% endif %}
|
||||
href="?page={{ num }}{% if q %}&q={{q}}{% endif %}">
|
||||
{{ num }}
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled rounded-md overflow-hidden">
|
||||
<span class="page-link px-3 py-2 border border-gray-200 bg-gray-50 text-gray-400 cursor-not-allowed">
|
||||
<span class="fas fa-angle-double-left" aria-hidden="true"></span>
|
||||
|
||||
</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{# Previous Page Link #}
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item rounded-md overflow-hidden">
|
||||
<a class="page-link px-3 py-2 border border-gray-300 bg-white text-blue-600 hover:bg-gray-100 transition-colors duration-200" href="?page={{ page_obj.previous_page_number }}{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'Previous' %}">
|
||||
<span class="fas fa-chevron-left" aria-hidden="true"></span>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled rounded-md overflow-hidden">
|
||||
<span class="page-link px-3 py-2 border border-gray-200 bg-gray-50 text-gray-400 cursor-not-allowed">
|
||||
<span class="fas fa-chevron-left" aria-hidden="true"></span>
|
||||
|
||||
</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{# Page Numbers #}
|
||||
{% for num in page_obj.paginator.page_range %}
|
||||
{% if num == 1 or num == page_obj.paginator.num_pages or num >= page_obj.number|add:-2 and num <= page_obj.number|add:2 %}
|
||||
<li class="page-item {% if num == page_obj.number %}active{% endif %}">
|
||||
<a class="page-link" {% if num == page_obj.number %}aria-current="page"{% endif %}
|
||||
href="?page={{ num }}{% if q %}&q={{q}}{% endif %}">
|
||||
{{ num }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{# Next Page Link #}
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item rounded-md overflow-hidden">
|
||||
<a class="page-link px-3 py-2 border border-gray-300 bg-white text-blue-600 hover:bg-gray-100 transition-colors duration-200" href="?page={{ page_obj.next_page_number }}{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'Next' %}">
|
||||
<span class="fas fa-chevron-right" aria-hidden="true"></span>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled rounded-md overflow-hidden">
|
||||
<span class="page-link px-3 py-2 border border-gray-200 bg-gray-50 text-gray-400 cursor-not-allowed">
|
||||
<span class="fas fa-chevron-right" aria-hidden="true"></span>
|
||||
|
||||
</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item rounded-md overflow-hidden">
|
||||
<a class="page-link px-3 py-2 border border-gray-300 bg-white text-blue-600 hover:bg-gray-100 transition-colors duration-200" href="?page={{ page_obj.next_page_number }}{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'Next' %}">
|
||||
<span class="fas fa-chevron-right" aria-hidden="true"></span>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled rounded-md overflow-hidden">
|
||||
<span class="page-link px-3 py-2 border border-gray-200 bg-gray-50 text-gray-400 cursor-not-allowed">
|
||||
<span class="fas fa-chevron-right" aria-hidden="true"></span>
|
||||
|
||||
</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{# Last Page Link #}
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item rounded-md overflow-hidden">
|
||||
<a class="page-link px-3 py-2 border border-gray-300 bg-white text-blue-600 hover:bg-gray-100 transition-colors duration-200" href="?page={{ page_obj.paginator.num_pages }}{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'Last' %}">
|
||||
<span class="fas fa-angle-double-right" aria-hidden="true"></span>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled rounded-md overflow-hidden">
|
||||
<span class="page-link px-3 py-2 border border-gray-200 bg-gray-50 text-gray-400 cursor-not-allowed">
|
||||
<span class="fas fa-angle-double-right" aria-hidden="true"></span>
|
||||
|
||||
</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item rounded-md overflow-hidden">
|
||||
<a class="page-link px-3 py-2 border border-gray-300 bg-white text-blue-600 hover:bg-gray-100 transition-colors duration-200" href="?page={{ page_obj.paginator.num_pages }}{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'Last' %}">
|
||||
<span class="fas fa-angle-double-right" aria-hidden="true"></span>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled rounded-md overflow-hidden">
|
||||
<span class="page-link px-3 py-2 border border-gray-200 bg-gray-50 text-gray-400 cursor-not-allowed">
|
||||
<span class="fas fa-angle-double-right" aria-hidden="true"></span>
|
||||
|
||||
</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
@ -11,11 +11,11 @@
|
||||
<h3>{% trans "Provide billing data"|upper %}</h3>
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
|
||||
|
||||
<button type="submit" class="btn btn-sm btn-phoenix-success me-2">
|
||||
<i class="fa fa-save me-1"></i>{{ _("Save") }}
|
||||
</button>
|
||||
{% if object %}
|
||||
{% if object %}
|
||||
<a class="btn btn-sm btn-phoenix-danger " href="{% url 'billing_info_delete' %}"><i class="fa-solid fa-trash me-1"></i> {{ _("Delete") }}</a>
|
||||
{% endif %}
|
||||
|
||||
|
||||
@ -50,29 +50,29 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-12">
|
||||
<!-- PO Details -->
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="h4 fw-light mb-2">{{ po_model.po_title }}</h3>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="h4 fw-light mb-2">{{ po_model.po_title }}</h3>
|
||||
|
||||
<!-- PO Items Table -->
|
||||
<div class="table-responsive">
|
||||
{% po_item_table1 po_items %}
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
{% po_item_table1 po_items %}
|
||||
</div>
|
||||
</div>
|
||||
<!--POS list-->
|
||||
<a class="btn btn-phoenix-primary w-100 py-2 mt-2"
|
||||
href="{% url 'purchase_order_list' %}">
|
||||
<i class="fas fa-list me-2"></i>{% trans 'PO List' %}
|
||||
</a>
|
||||
</div>
|
||||
<!--POS list-->
|
||||
<a class="btn btn-phoenix-primary w-100 py-2 mt-2"
|
||||
href="{% url 'purchase_order_list' %}">
|
||||
<i class="fas fa-list me-2"></i>{% trans 'PO List' %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include "purchase_orders/includes/mark_as.html" %}
|
||||
{% endblock %}
|
||||
|
||||
@ -82,16 +82,16 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</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">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% include 'modal/delete_modal.html' %}
|
||||
{% endblock %}
|
||||
@ -57,14 +57,14 @@
|
||||
</table>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
<div>
|
||||
{% endblock content %}
|
||||
@ -105,40 +105,40 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="container bg-body dark__bg-gray-1100 p-4 mb-4 rounded-2">
|
||||
<div class="row">
|
||||
<div class="col mb-2">
|
||||
<h6><i class="fa-solid fa-hashtag"></i> {% trans 'Quotation Number' %}:</h6>
|
||||
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{estimate.estimate_number}}</p>
|
||||
</div>
|
||||
<div class="col mb-2">
|
||||
<h6><i class="fa-solid fa-calendar-days"></i> {% trans 'Quotation Date' %}:</h6>
|
||||
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{estimate.created}}</p>
|
||||
</div>
|
||||
<div class="col mb-2">
|
||||
<h6><i class="fa-solid fa-user"></i> {% trans 'Customer' %}:</h6>
|
||||
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{estimate.customer.customer_name}}</p>
|
||||
</div>
|
||||
<div class="col mb-2">
|
||||
<h6><i class="fa-solid fa-envelope"></i> {% trans 'Email' %}:</h6>
|
||||
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{estimate.customer.email}}</p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h6><i class="fa-solid fa-list"></i> {% trans "Quotation Status" %}:</h6>
|
||||
<div class="fs-9 text-body-secondary fw-semibold mb-0">
|
||||
{% if estimate.status == 'draft' %}
|
||||
<span class="badge text-bg-warning">{% trans "Draft" %}</span>
|
||||
{% elif estimate.status == 'in_review' %}
|
||||
<span class="badge text-bg-info">{% trans "In Review" %}</span>
|
||||
{% elif estimate.status == 'approved' %}
|
||||
<span class="badge text-bg-success">{% trans "Approved" %}</span>
|
||||
{% elif estimate.status == 'completed' %}
|
||||
<span class="badge text-bg-success">{% trans "Completed" %}</span>
|
||||
{% elif estimate.status == 'canceled' %}
|
||||
<span class="badge text-bg-danger">{% trans "Canceled" %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col mb-2">
|
||||
<h6><i class="fa-solid fa-hashtag"></i> {% trans 'Quotation Number' %}:</h6>
|
||||
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{estimate.estimate_number}}</p>
|
||||
</div>
|
||||
<div class="col mb-2">
|
||||
<h6><i class="fa-solid fa-calendar-days"></i> {% trans 'Quotation Date' %}:</h6>
|
||||
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{estimate.created}}</p>
|
||||
</div>
|
||||
<div class="col mb-2">
|
||||
<h6><i class="fa-solid fa-user"></i> {% trans 'Customer' %}:</h6>
|
||||
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{estimate.customer.customer_name}}</p>
|
||||
</div>
|
||||
<div class="col mb-2">
|
||||
<h6><i class="fa-solid fa-envelope"></i> {% trans 'Email' %}:</h6>
|
||||
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{estimate.customer.email}}</p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h6><i class="fa-solid fa-list"></i> {% trans "Quotation Status" %}:</h6>
|
||||
<div class="fs-9 text-body-secondary fw-semibold mb-0">
|
||||
{% if estimate.status == 'draft' %}
|
||||
<span class="badge text-bg-warning">{% trans "Draft" %}</span>
|
||||
{% elif estimate.status == 'in_review' %}
|
||||
<span class="badge text-bg-info">{% trans "In Review" %}</span>
|
||||
{% elif estimate.status == 'approved' %}
|
||||
<span class="badge text-bg-success">{% trans "Approved" %}</span>
|
||||
{% elif estimate.status == 'completed' %}
|
||||
<span class="badge text-bg-success">{% trans "Completed" %}</span>
|
||||
{% elif estimate.status == 'canceled' %}
|
||||
<span class="badge text-bg-danger">{% trans "Canceled" %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="px-0">
|
||||
|
||||
@ -60,11 +60,11 @@
|
||||
</table>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -172,41 +172,41 @@
|
||||
<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="col mb-2">
|
||||
<h6 class="mb-0 me-3"><i class="fa-solid fa-hashtag"></i> {% trans "Invoice Number" %} :</h6>
|
||||
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{invoice.invoice_number}}</p>
|
||||
</div>
|
||||
<div class="col mb-2">
|
||||
<h6 class="me-3"><i class="fa-solid fa-calendar-days"></i> {% trans "Invoice Date" %} :</h6>
|
||||
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{invoice.created}}</p>
|
||||
</div>
|
||||
<div class="col mb-2">
|
||||
<h6 class="mb-2 me-3"><i class="fa-solid fa-user"></i> {% trans "Customer Name" %} :</h6>
|
||||
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{invoice.customer.customer_name}}</p>
|
||||
</div>
|
||||
<div class="col mb-2">
|
||||
<h6 class="mb-2"><i class="fa-solid fa-envelope"></i> {% trans "Customer Email" %} :</h6>
|
||||
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{invoice.customer.email}}</p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h6 class="mb-2"><i class="fa-solid fa-list"></i> {% trans "Invoice Status" %} :</h6>
|
||||
<div class="fs-9 text-body-secondary fw-semibold mb-0">
|
||||
{% if invoice.invoice_status == 'draft' %}
|
||||
<span class="badge text-bg-warning">{% trans "Draft" %}</span>
|
||||
{% elif invoice.invoice_status == 'in_review' %}
|
||||
<span class="badge text-bg-info">{% trans "In Review" %}</span>
|
||||
{% elif invoice.invoice_status == 'approved' %}
|
||||
<span class="badge text-bg-info">{% trans "Approved" %}</span>
|
||||
{% elif invoice.invoice_status == 'declined' %}
|
||||
<span class="badge text-bg-danger">{% trans "Declined" %}</span>
|
||||
{% elif invoice.invoice_status == 'paid' %}
|
||||
<span class="badge text-bg-success">{% trans "Paid" %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col mb-2">
|
||||
<h6 class="mb-0 me-3"><i class="fa-solid fa-hashtag"></i> {% trans "Invoice Number" %} :</h6>
|
||||
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{invoice.invoice_number}}</p>
|
||||
</div>
|
||||
<div class="col mb-2">
|
||||
<h6 class="me-3"><i class="fa-solid fa-calendar-days"></i> {% trans "Invoice Date" %} :</h6>
|
||||
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{invoice.created}}</p>
|
||||
</div>
|
||||
<div class="col mb-2">
|
||||
<h6 class="mb-2 me-3"><i class="fa-solid fa-user"></i> {% trans "Customer Name" %} :</h6>
|
||||
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{invoice.customer.customer_name}}</p>
|
||||
</div>
|
||||
<div class="col mb-2">
|
||||
<h6 class="mb-2"><i class="fa-solid fa-envelope"></i> {% trans "Customer Email" %} :</h6>
|
||||
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{invoice.customer.email}}</p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h6 class="mb-2"><i class="fa-solid fa-list"></i> {% trans "Invoice Status" %} :</h6>
|
||||
<div class="fs-9 text-body-secondary fw-semibold mb-0">
|
||||
{% if invoice.invoice_status == 'draft' %}
|
||||
<span class="badge text-bg-warning">{% trans "Draft" %}</span>
|
||||
{% elif invoice.invoice_status == 'in_review' %}
|
||||
<span class="badge text-bg-info">{% trans "In Review" %}</span>
|
||||
{% elif invoice.invoice_status == 'approved' %}
|
||||
<span class="badge text-bg-info">{% trans "Approved" %}</span>
|
||||
{% elif invoice.invoice_status == 'declined' %}
|
||||
<span class="badge text-bg-danger">{% trans "Declined" %}</span>
|
||||
{% elif invoice.invoice_status == 'paid' %}
|
||||
<span class="badge text-bg-success">{% trans "Paid" %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-0 {% if invoice.is_review %}disabled{% endif %}">
|
||||
<div class="table-responsive scrollbar">
|
||||
|
||||
@ -70,12 +70,12 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -44,11 +44,11 @@
|
||||
</table>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1%}
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -53,11 +53,11 @@
|
||||
</table>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1%}
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
@ -54,11 +54,11 @@
|
||||
</table>
|
||||
</div>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-end mt-3">
|
||||
<div class="d-flex">
|
||||
{% include 'partials/pagination.html'%}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -247,7 +247,7 @@
|
||||
</div>
|
||||
|
||||
<div class="card-footer text-end">
|
||||
<a href="{% url 'sales_list' %}" class="btn btn-phoenix-secondary">
|
||||
<a href="{% url 'sales_list' request.dealer.slug %}" class="btn btn-phoenix-secondary">
|
||||
{% trans "Back to List" %}
|
||||
</a>
|
||||
|
||||
|
||||
@ -204,7 +204,7 @@
|
||||
<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 text-success-dark" href="{% url 'order_detail' tx.pk %}">{{ _("View Sales Order Detail") }}</a>
|
||||
<div class="dropdown-menu dropdown-menu-end py-2"><a class="dropdown-item text-success-dark" href="{% url 'order_detail' request.dealer.slug tx.pk %}">{{ _("View Sales Order Detail") }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user