add car list view
This commit is contained in:
parent
f4111803bb
commit
8d19c15f73
@ -413,11 +413,28 @@ class Car(models.Model):
|
|||||||
return f"{self.id_car_make.get_local_name} {self.id_car_model.get_local_name}"
|
return f"{self.id_car_make.get_local_name} {self.id_car_model.get_local_name}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def get_hash(self):
|
def get_hash(self):
|
||||||
hash_object = hashlib.sha256()
|
hash_object = hashlib.sha256()
|
||||||
hash_object.update(f"{self.id_car_make.name}{self.id_car_model.name}".encode('utf-8'))
|
color = ""
|
||||||
|
try:
|
||||||
|
color = self.colors.first().exterior.name if self.colors.exists() else ""
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
hash_object.update(f"{self.id_car_make.name}{self.id_car_model.name}{self.year}{self.id_car_serie.name}{self.id_car_trim.name}{color}".encode('utf-8'))
|
||||||
return hash_object.hexdigest()
|
return hash_object.hexdigest()
|
||||||
|
|
||||||
|
def mark_as_sold(self):
|
||||||
|
self.cancel_reservation()
|
||||||
|
self.status = CarStatusChoices.SOLD
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
def cancel_reservation(self):
|
||||||
|
if self.reservations.exists():
|
||||||
|
self.reservations.all().delete()
|
||||||
|
def cancel_transfer(self):
|
||||||
|
if self.transfer_logs.exists():
|
||||||
|
self.transfer_logs.all().delete()
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return {
|
return {
|
||||||
"vin": self.vin,
|
"vin": self.vin,
|
||||||
|
|||||||
@ -723,6 +723,10 @@ def update_item_model_cost(sender, instance, created, **kwargs):
|
|||||||
# quotation.status = 'pending'
|
# quotation.status = 'pending'
|
||||||
# quotation.save()
|
# quotation.save()
|
||||||
|
|
||||||
|
@receiver(post_save, sender=models.CarColors)
|
||||||
|
def update_car_when_color_changed(sender, instance, **kwargs):
|
||||||
|
car = instance.car
|
||||||
|
car.save()
|
||||||
|
|
||||||
@receiver(post_save, sender=models.Opportunity)
|
@receiver(post_save, sender=models.Opportunity)
|
||||||
def notify_staff_on_deal_stage_change(sender, instance, **kwargs):
|
def notify_staff_on_deal_stage_change(sender, instance, **kwargs):
|
||||||
|
|||||||
@ -181,6 +181,7 @@ urlpatterns = [
|
|||||||
name="car_inventory",
|
name="car_inventory",
|
||||||
),
|
),
|
||||||
path("cars/inventory/stats", views.inventory_stats_view, name="inventory_stats"),
|
path("cars/inventory/stats", views.inventory_stats_view, name="inventory_stats"),
|
||||||
|
path("cars/inventory/list", views.CarListView.as_view(), name="car_list"),
|
||||||
path("cars/<int:pk>/", views.CarDetailView.as_view(), name="car_detail"),
|
path("cars/<int:pk>/", views.CarDetailView.as_view(), name="car_detail"),
|
||||||
path("cars/<int:pk>/update/", views.CarUpdateView.as_view(), name="car_update"),
|
path("cars/<int:pk>/update/", views.CarUpdateView.as_view(), name="car_update"),
|
||||||
path("cars/<int:pk>/delete/", views.CarDeleteView.as_view(), name="car_delete"),
|
path("cars/<int:pk>/delete/", views.CarDeleteView.as_view(), name="car_delete"),
|
||||||
|
|||||||
@ -615,7 +615,7 @@ class CarColorCreate(LoginRequiredMixin, CreateView):
|
|||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
car = get_object_or_404(models.Car, pk=self.kwargs["car_pk"])
|
car = get_object_or_404(models.Car, pk=self.kwargs["car_pk"])
|
||||||
form.instance.car = car
|
form.instance.car = car
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
@ -626,6 +626,34 @@ class CarColorCreate(LoginRequiredMixin, CreateView):
|
|||||||
context["car"] = get_object_or_404(models.Car, pk=self.kwargs["car_pk"])
|
context["car"] = get_object_or_404(models.Car, pk=self.kwargs["car_pk"])
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
class CarListView(LoginRequiredMixin, ListView):
|
||||||
|
model = models.Car
|
||||||
|
template_name = "inventory/car_list_view.html"
|
||||||
|
context_object_name = "cars"
|
||||||
|
paginate_by = 10
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
cars = models.Car.objects.all()
|
||||||
|
|
||||||
|
context["stats"] = {
|
||||||
|
'all': cars.count(),
|
||||||
|
'available':cars.filter(status='available').count(),
|
||||||
|
'reserved':cars.filter(status='reserved').count(),
|
||||||
|
'sold':cars.filter(status='sold').count(),
|
||||||
|
'transfer':cars.filter(status='transfer').count()
|
||||||
|
}
|
||||||
|
return context
|
||||||
|
def get_queryset(self):
|
||||||
|
qs = super().get_queryset()
|
||||||
|
status = self.request.GET.get('status')
|
||||||
|
search = self.request.GET.get('search')
|
||||||
|
print(status)
|
||||||
|
if status:
|
||||||
|
qs=qs.filter(status=status)
|
||||||
|
if search:
|
||||||
|
query = Q(vin__icontains=search)|Q(id_car_make__name__icontains=search)|Q(id_car_model__name__icontains=search)|Q(id_car_trim__name__icontains=search)|Q(vin=search)
|
||||||
|
qs=qs.filter(query)
|
||||||
|
return qs
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def inventory_stats_view(request):
|
def inventory_stats_view(request):
|
||||||
@ -2365,12 +2393,12 @@ def create_estimate(request):
|
|||||||
)
|
)
|
||||||
if isinstance(items, list):
|
if isinstance(items, list):
|
||||||
for item, quantity in zip(items, quantities):
|
for item, quantity in zip(items, quantities):
|
||||||
if int(quantity) > models.Car.objects.filter(hash=item).count():
|
if int(quantity) > models.Car.objects.filter(hash=item,status='available').count():
|
||||||
return JsonResponse(
|
return JsonResponse(
|
||||||
{"status": "error", "message": "Quantity must be less than or equal to the number of cars in stock"},
|
{"status": "error", "message": "Quantity must be less than or equal to the number of cars in stock"},
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if int(quantities) > models.Car.objects.filter(hash=item).count():
|
if int(quantities) > models.Car.objects.filter(hash=items,status='available').count():
|
||||||
return JsonResponse(
|
return JsonResponse(
|
||||||
{"status": "error", "message": "Quantity must be less than or equal to the number of cars in stock"},
|
{"status": "error", "message": "Quantity must be less than or equal to the number of cars in stock"},
|
||||||
)
|
)
|
||||||
@ -2438,7 +2466,7 @@ def create_estimate(request):
|
|||||||
if isinstance(items, list):
|
if isinstance(items, list):
|
||||||
for item in estimate_itemtxs.keys():
|
for item in estimate_itemtxs.keys():
|
||||||
item_instance = ItemModel.objects.get(item_number=item)
|
item_instance = ItemModel.objects.get(item_number=item)
|
||||||
instance = models.Car.objects.get(name=item_instance.name)
|
instance = models.Car.objects.get(vin=item_instance.name)
|
||||||
reserve_car(instance, request)
|
reserve_car(instance, request)
|
||||||
# for item in items:
|
# for item in items:
|
||||||
# item_instance = ItemModel.objects.filter(additioinal_info__car_info__hash=item).first()
|
# item_instance = ItemModel.objects.filter(additioinal_info__car_info__hash=item).first()
|
||||||
@ -2463,16 +2491,18 @@ def create_estimate(request):
|
|||||||
entity_slug=entity.slug, user_model=entity.admin
|
entity_slug=entity.slug, user_model=entity.admin
|
||||||
)
|
)
|
||||||
form.fields["customer"].queryset = entity.get_customers().filter(active=True)
|
form.fields["customer"].queryset = entity.get_customers().filter(active=True)
|
||||||
car_list = models.Car.objects.filter(dealer=dealer).exclude(status="reserved").values_list(
|
car_list = models.Car.objects.filter(dealer=dealer).exclude(status="reserved").annotate(color=F('colors__exterior__name')).values_list(
|
||||||
'id_car_make__name', 'id_car_model__name','hash').distinct()
|
'id_car_make__name', 'id_car_model__name','id_car_serie__name','id_car_trim__name','color','hash').distinct()
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
"form": form,
|
"form": form,
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
'make':x[0],
|
'make':x[0],
|
||||||
'model':x[1],
|
'model':x[1],
|
||||||
'hash': x[2]
|
'serie':x[2],
|
||||||
|
'trim':x[3],
|
||||||
|
'color':x[4],
|
||||||
|
'hash': x[5]
|
||||||
}
|
}
|
||||||
for x in car_list
|
for x in car_list
|
||||||
],
|
],
|
||||||
@ -2510,7 +2540,16 @@ def create_sale_order(request, pk):
|
|||||||
if not estimate.is_approved():
|
if not estimate.is_approved():
|
||||||
estimate.mark_as_approved()
|
estimate.mark_as_approved()
|
||||||
estimate.save()
|
estimate.save()
|
||||||
messages.success(request, "Sale Order created successfully")
|
for item in estimate.get_itemtxs_data()[0].all():
|
||||||
|
try:
|
||||||
|
item.item_model.additional_info['car_info']['status'] = 'sold'
|
||||||
|
item.item_model.save()
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
models.Car.objects.get(vin=item.item_model.name).mark_as_sold()
|
||||||
|
|
||||||
|
messages.success(request, "Sale Order created successfully")
|
||||||
return redirect("estimate_detail", pk=pk)
|
return redirect("estimate_detail", pk=pk)
|
||||||
|
|
||||||
form = forms.SaleOrderForm()
|
form = forms.SaleOrderForm()
|
||||||
@ -2843,10 +2882,17 @@ def PaymentCreateView(request, pk):
|
|||||||
|
|
||||||
if not model.is_approved():
|
if not model.is_approved():
|
||||||
model.mark_as_approved(user_model=entity.admin)
|
model.mark_as_approved(user_model=entity.admin)
|
||||||
|
if model.amount_paid == model.amount_due:
|
||||||
|
messages.error(request,"fully paid")
|
||||||
|
return redirect(redirect_url, pk=model.pk)
|
||||||
|
if model.amount_paid + amount > model.amount_due:
|
||||||
|
messages.error(request,"Amount exceeds due amount")
|
||||||
|
return redirect(redirect_url, pk=model.pk)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if invoice:
|
if invoice:
|
||||||
set_invoice_payment(dealer, entity, invoice, amount, payment_method)
|
set_invoice_payment(dealer, entity, invoice, amount, payment_method)
|
||||||
elif bill:
|
elif bill:
|
||||||
set_bill_payment(dealer, entity, bill, amount, payment_method)
|
set_bill_payment(dealer, entity, bill, amount, payment_method)
|
||||||
messages.success(request, "Payment created successfully!")
|
messages.success(request, "Payment created successfully!")
|
||||||
return redirect(redirect_url, pk=model.pk)
|
return redirect(redirect_url, pk=model.pk)
|
||||||
|
|||||||
59
scripts/generate.py
Normal file
59
scripts/generate.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
from inventory.models import *
|
||||||
|
from rich import print
|
||||||
|
import random
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from inventory.services import decodevin
|
||||||
|
|
||||||
|
|
||||||
|
def run():
|
||||||
|
# car = Car.objects.filter(vin='2C3HD46R4WH170267')
|
||||||
|
vin_list = [
|
||||||
|
"1B3ES56C13D120225",
|
||||||
|
"1GB4KYC86FF131536",
|
||||||
|
"1HSHXAHR15J136217",
|
||||||
|
"1G1ZT52845F231124",
|
||||||
|
"1J4GK48K43W721617",
|
||||||
|
"JTDBE32K430163717",
|
||||||
|
"1J4FA69S05P331572",
|
||||||
|
"2FMGK5D86EBD28496",
|
||||||
|
"KNADE243696530337",
|
||||||
|
"1N4AL21EX8N499928",
|
||||||
|
"1N4AL21E49N400571",
|
||||||
|
"1G2NW12E54C145398",
|
||||||
|
]
|
||||||
|
for vin in vin_list:
|
||||||
|
try:
|
||||||
|
for _ in range(15):
|
||||||
|
dealer = Dealer.objects.get(user__email="ismail.mosa.ibrahim@gmail.com")
|
||||||
|
vin = f"{vin[:-4]}{random.randint(0, 9)}{random.randint(0, 9)}{random.randint(0, 9)}{random.randint(0, 9)}"
|
||||||
|
result = decodevin(vin)
|
||||||
|
make = CarMake.objects.get(name=result["maker"])
|
||||||
|
model = make.carmodel_set.filter(name__contains=result["model"]).first()
|
||||||
|
if not model or model == "":
|
||||||
|
model = random.choice(make.carmodel_set.all())
|
||||||
|
year = result["modelYear"]
|
||||||
|
serie = random.choice(model.carserie_set.all())
|
||||||
|
trim = random.choice(serie.cartrim_set.all())
|
||||||
|
|
||||||
|
car = Car.objects.create(
|
||||||
|
vin=vin,
|
||||||
|
id_car_make=make,
|
||||||
|
id_car_model=model,
|
||||||
|
id_car_serie=serie,
|
||||||
|
id_car_trim=trim,
|
||||||
|
year=(int(year) or 2025),
|
||||||
|
receiving_date=datetime.datetime.now(),
|
||||||
|
dealer=dealer,
|
||||||
|
)
|
||||||
|
car_finance = CarFinance.objects.create(
|
||||||
|
car=car, cost_price=10000, selling_price=20000
|
||||||
|
)
|
||||||
|
car_color = CarColors.objects.create(
|
||||||
|
car=car,
|
||||||
|
interior=random.choice(InteriorColors.objects.all()),
|
||||||
|
exterior=random.choice(ExteriorColors.objects.all()),
|
||||||
|
)
|
||||||
|
print(make, model, serie, trim)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
192
templates/inventory/car_list_view.html
Normal file
192
templates/inventory/car_list_view.html
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load custom_filters %}
|
||||||
|
|
||||||
|
{% block customCSS %}
|
||||||
|
<style>
|
||||||
|
.htmx-indicator{
|
||||||
|
opacity:0;
|
||||||
|
transition: opacity 500ms ease-in;
|
||||||
|
}
|
||||||
|
.htmx-request .htmx-indicator{
|
||||||
|
opacity:1;
|
||||||
|
}
|
||||||
|
.htmx-request.htmx-indicator{
|
||||||
|
opacity:1;
|
||||||
|
}
|
||||||
|
.on-before-request{
|
||||||
|
opacity: 0.5;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.transition {
|
||||||
|
transition: all ease-in 1s ;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock customCSS %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="mb-9">
|
||||||
|
<div id="projectSummary">
|
||||||
|
<div class="row g-3 justify-content-between align-items-end mb-4">
|
||||||
|
<div class="col-12 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' %}"><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' %}?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' %}?status=reserved"><span>Reserved</span><span class="text-body-tertiary fw-semibold">({{stats.reserved}})</span></a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link px-2 py-1" href="{% url 'car_list' %}?status=transfer"><span>Transfer</span><span class="text-body-tertiary fw-semibold">({{stats.transfer}})</span></a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link px-2 py-1" href="{% url 'car_list' %}?status=sold"><span>Sold</span><span class="text-body-tertiary fw-semibold">({{stats.sold}})</span></a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 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' %}" 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><a class="btn btn-phoenix-primary px-3 me-1 border-0 text-body" href="../../apps/project-management/project-list-view.html" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="List view"><span class="fa-solid fa-list fs-10"></span></a><a class="btn btn-phoenix-primary px-3 me-1" href="../../apps/project-management/project-board-view.html" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Board view">
|
||||||
|
<svg width="9" height="9" viewbox="0 0 9 9" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 0.5C0 0.223857 0.223858 0 0.5 0H1.83333C2.10948 0 2.33333 0.223858 2.33333 0.5V1.83333C2.33333 2.10948 2.10948 2.33333 1.83333 2.33333H0.5C0.223857 2.33333 0 2.10948 0 1.83333V0.5Z" fill="currentColor"></path>
|
||||||
|
<path d="M3.33333 0.5C3.33333 0.223857 3.55719 0 3.83333 0H5.16667C5.44281 0 5.66667 0.223858 5.66667 0.5V1.83333C5.66667 2.10948 5.44281 2.33333 5.16667 2.33333H3.83333C3.55719 2.33333 3.33333 2.10948 3.33333 1.83333V0.5Z" fill="currentColor"></path>
|
||||||
|
<path d="M6.66667 0.5C6.66667 0.223857 6.89052 0 7.16667 0H8.5C8.77614 0 9 0.223858 9 0.5V1.83333C9 2.10948 8.77614 2.33333 8.5 2.33333H7.16667C6.89052 2.33333 6.66667 2.10948 6.66667 1.83333V0.5Z" fill="currentColor"></path>
|
||||||
|
<path d="M0 3.83333C0 3.55719 0.223858 3.33333 0.5 3.33333H1.83333C2.10948 3.33333 2.33333 3.55719 2.33333 3.83333V5.16667C2.33333 5.44281 2.10948 5.66667 1.83333 5.66667H0.5C0.223857 5.66667 0 5.44281 0 5.16667V3.83333Z" fill="currentColor"></path>
|
||||||
|
<path d="M3.33333 3.83333C3.33333 3.55719 3.55719 3.33333 3.83333 3.33333H5.16667C5.44281 3.33333 5.66667 3.55719 5.66667 3.83333V5.16667C5.66667 5.44281 5.44281 5.66667 5.16667 5.66667H3.83333C3.55719 5.66667 3.33333 5.44281 3.33333 5.16667V3.83333Z" fill="currentColor"></path>
|
||||||
|
<path d="M6.66667 3.83333C6.66667 3.55719 6.89052 3.33333 7.16667 3.33333H8.5C8.77614 3.33333 9 3.55719 9 3.83333V5.16667C9 5.44281 8.77614 5.66667 8.5 5.66667H7.16667C6.89052 5.66667 6.66667 5.44281 6.66667 5.16667V3.83333Z" fill="currentColor"></path>
|
||||||
|
<path d="M0 7.16667C0 6.89052 0.223858 6.66667 0.5 6.66667H1.83333C2.10948 6.66667 2.33333 6.89052 2.33333 7.16667V8.5C2.33333 8.77614 2.10948 9 1.83333 9H0.5C0.223857 9 0 8.77614 0 8.5V7.16667Z" fill="currentColor"></path>
|
||||||
|
<path d="M3.33333 7.16667C3.33333 6.89052 3.55719 6.66667 3.83333 6.66667H5.16667C5.44281 6.66667 5.66667 6.89052 5.66667 7.16667V8.5C5.66667 8.77614 5.44281 9 5.16667 9H3.83333C3.55719 9 3.33333 8.77614 3.33333 8.5V7.16667Z" fill="currentColor"></path>
|
||||||
|
<path d="M6.66667 7.16667C6.66667 6.89052 6.89052 6.66667 7.16667 6.66667H8.5C8.77614 6.66667 9 6.89052 9 7.16667V8.5C9 8.77614 8.77614 9 8.5 9H7.16667C6.89052 9 6.66667 8.77614 6.66667 8.5V7.16667Z" fill="currentColor"></path>
|
||||||
|
</svg></a><a class="btn btn-phoenix-primary px-3" href="../../apps/project-management/project-card-view.html" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Card view">
|
||||||
|
<svg width="9" height="9" viewBox="0 0 9 9" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 0.5C0 0.223858 0.223858 0 0.5 0H3.5C3.77614 0 4 0.223858 4 0.5V3.5C4 3.77614 3.77614 4 3.5 4H0.5C0.223858 4 0 3.77614 0 3.5V0.5Z" fill="currentColor"></path>
|
||||||
|
<path d="M0 5.5C0 5.22386 0.223858 5 0.5 5H3.5C3.77614 5 4 5.22386 4 5.5V8.5C4 8.77614 3.77614 9 3.5 9H0.5C0.223858 9 0 8.77614 0 8.5V5.5Z" fill="currentColor"></path>
|
||||||
|
<path d="M5 0.5C5 0.223858 5.22386 0 5.5 0H8.5C8.77614 0 9 0.223858 9 0.5V3.5C9 3.77614 8.77614 4 8.5 4H5.5C5.22386 4 5 3.77614 5 3.5V0.5Z" fill="currentColor"></path>
|
||||||
|
<path d="M5 5.5C5 5.22386 5.22386 5 5.5 5H8.5C8.77614 5 9 5.22386 9 5.5V8.5C9 8.77614 8.77614 9 8.5 9H5.5C5.22386 9 5 8.77614 5 8.5V5.5Z" fill="currentColor"></path>
|
||||||
|
</svg></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive scrollbar transition">
|
||||||
|
<div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9 border-bottom border-translucent">
|
||||||
|
<div class="d-flex">
|
||||||
|
</div>
|
||||||
|
<div class="d-flex" 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()">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<a href="{% url 'car_list' %}?page={{page_obj.previous_page_number}}" class="page-link" data-list-pagination="prev"><span class="fas fa-chevron-left"></span></a>
|
||||||
|
{% endif %}
|
||||||
|
<ul class="mb-0 pagination">Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</ul>
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<a href="{% url 'car_list' %}?page={{page_obj.next_page_number}}" class="page-link pe-0" data-list-pagination="next"><span class="fas fa-chevron-right"></span></a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table class="table fs-9 mb-0 border-top border-translucent">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sort white-space-nowrap align-middle ps-0" scope="col" data-sort="projectName" style="width:10%;">Make</th>
|
||||||
|
<th class="sort align-middle ps-3" scope="col" data-sort="assignees" style="width:10%;">Model</th>
|
||||||
|
<th class="sort align-middle ps-3" scope="col" data-sort="start" style="width:10%;">Year</th>
|
||||||
|
<th class="sort align-middle ps-3" scope="col" data-sort="deadline" style="width:15%;">Trim</th>
|
||||||
|
<th class="sort align-middle ps-3" scope="col" data-sort="task" style="width:12%;">VIN</th>
|
||||||
|
<th class="sort align-middle ps-3" scope="col" data-sort="task" style="width:12%;">Receiving Date</th>
|
||||||
|
<th class="sort align-middle ps-3" scope="col" data-sort="projectprogress" style="width:5%;">PROGRESS</th>
|
||||||
|
<th class="sort align-middle text-end" scope="col" data-sort="statuses" style="width:10%;">STATUS</th>
|
||||||
|
<th class="sort align-middle text-end" scope="col" style="width:10%;"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="list" id="project-list-table-body">
|
||||||
|
{% for car in cars %}
|
||||||
|
<tr class="position-static">
|
||||||
|
<td class="align-middle time white-space-nowrap ps-0 projectName py-4"><a class="fw-bold fs-8" href="{% url 'car_detail' car.pk %}">{{car.id_car_make}}</a></td>
|
||||||
|
<td class="align-middle white-space-nowrap start ps-3 py-4">
|
||||||
|
<p class="mb-0 fs-9 text-body">{{car.id_car_model}}</p>
|
||||||
|
</td>
|
||||||
|
<td class="align-middle white-space-nowrap deadline ps-3 py-4">
|
||||||
|
<p class="mb-0 fs-9 text-body">{{car.year}}</p>
|
||||||
|
</td>
|
||||||
|
<td class="align-middle white-space-nowrap task ps-3 py-4">
|
||||||
|
<p class="fw-bo text-body fs-9 mb-0">{{car.id_car_trim}}</p>
|
||||||
|
</td>
|
||||||
|
<td class="align-middle white-space-nowrap task ps-3 py-4">
|
||||||
|
<p class="fw-bo text-body fs-9 mb-0">{{car.vin}}</p>
|
||||||
|
</td>
|
||||||
|
<td class="align-middle white-space-nowrap task ps-3 py-4">
|
||||||
|
<p class="fw-bo text-body fs-9 mb-0">{{car.receiving_date}}</p>
|
||||||
|
</td>
|
||||||
|
<td class="align-middle white-space-nowrap ps-3 projectprogress">
|
||||||
|
<p class="text-body-secondary fs-10 mb-0">145 / 145</p>
|
||||||
|
<div class="progress" style="height:3px;">
|
||||||
|
<div class="progress-bar bg-success" style="width: 100%" role="progressbar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100"></div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="align-middle white-space-nowrap text-end statuses">
|
||||||
|
{% if car.status == "available" %}
|
||||||
|
<span class="badge badge-phoenix fs-10 badge-phoenix-success">{{car.status}}</span>
|
||||||
|
{% elif car.status == "reserved" %}
|
||||||
|
<span class="badge badge-phoenix fs-10 badge-phoenix-danger">{{car.status}}</span>
|
||||||
|
{% elif car.status == "sold" %}
|
||||||
|
<span class="badge badge-phoenix fs-10 badge-phoenix-info">{{car.status}}</span>
|
||||||
|
{% elif car.status == "transfer" %}
|
||||||
|
<span class="badge badge-phoenix fs-10 badge-phoenix-warning">{{car.status}}</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td class="align-middle text-end white-space-nowrap pe-0 action">
|
||||||
|
<div class="btn-reveal-trigger position-static">
|
||||||
|
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
|
||||||
|
<div class="dropdown-menu dropdown-menu-end py-2"><a class="dropdown-item" href="#!">View</a><a class="dropdown-item" href="#!">Export</a>
|
||||||
|
<div class="dropdown-divider"></div><a class="dropdown-item text-danger" href="#!">Remove</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9 border-bottom border-translucent">
|
||||||
|
<div class="d-flex">
|
||||||
|
<p class="mb-0 d-none d-sm-block me-3 fw-semibold text-body" data-list-info="data-list-info"></p><a class="fw-semibold" href="#!" data-list-view="*">View all<span class="fas fa-angle-right ms-1" data-fa-transform="down-1"></span></a><a class="fw-semibold d-none" href="#!" data-list-view="less">View Less<span class="fas fa-angle-right ms-1" data-fa-transform="down-1"></span></a>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex" hx-boost="true" hx-push-url='false' hx-target=".table-responsive" hx-select=".table-responsive" hx-swap="innerHTML" hx-indicator=".htmx-indicator"
|
||||||
|
hx-on::before-request="on_before_request()"
|
||||||
|
hx-on::after-request="on_after_request()">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<a href="{% url 'car_list' %}?page={{page_obj.previous_page_number}}" class="page-link" data-list-pagination="prev"><span class="fas fa-chevron-left"></span></a>
|
||||||
|
{% endif %}
|
||||||
|
<ul class="mb-0 pagination">Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</ul>
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<a href="{% url 'car_list' %}?page={{page_obj.next_page_number}}" class="page-link pe-0" data-list-pagination="next"><span class="fas fa-chevron-right"></span></a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block customJS %}
|
||||||
|
<script>
|
||||||
|
links = document.querySelectorAll('.nav-link')
|
||||||
|
links.forEach(link => {
|
||||||
|
link.addEventListener('click', () => {
|
||||||
|
links.forEach(link => {
|
||||||
|
link.classList.remove('active')
|
||||||
|
})
|
||||||
|
link.classList.add('active')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
function on_before_request() {
|
||||||
|
document.querySelector('.table').classList.add('on-before-request')
|
||||||
|
}
|
||||||
|
function on_after_request() {
|
||||||
|
document.querySelector('.table').classList.remove('on-before-request')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% endblock customJS %}
|
||||||
@ -119,12 +119,13 @@
|
|||||||
<thead class="bg-body-secondary">
|
<thead class="bg-body-secondary">
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col" style="width: 24px;">#</th>
|
<th scope="col" style="width: 24px;">#</th>
|
||||||
<th scope="col" style="min-width: 260px;">{% trans "Make" %}</th>
|
<th scope="col" style="min-width: 100px;">{% trans "Make" %}</th>
|
||||||
<th scope="col" style="min-width: 260px;">{% trans "Model" %}</th>
|
<th scope="col" style="min-width: 100px;">{% trans "Model" %}</th>
|
||||||
<th scope="col" style="min-width: 260px;">{% trans "Year" %}</th>
|
<th scope="col" style="min-width: 100px;">{% trans "Year" %}</th>
|
||||||
<th scope="col" style="min-width: 60px;">{% trans "Quantity" %}</th>
|
<th scope="col" style="min-width: 100px;">{% trans "VIN" %}</th>
|
||||||
<th scope="col" style="min-width: 60px;">{% trans "Unit Price" %}</th>
|
<th scope="col" style="min-width: 100px;">{% trans "Quantity" %}</th>
|
||||||
<th scope="col" style="min-width: 60px;">{% trans "Total" %}</th>
|
<th scope="col" style="min-width: 100px;">{% trans "Unit Price" %}</th>
|
||||||
|
<th scope="col" style="min-width: 100px;">{% trans "Total" %}</th>
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -135,25 +136,26 @@
|
|||||||
<td class="align-middle">{{item.make}}</td>
|
<td class="align-middle">{{item.make}}</td>
|
||||||
<td class="align-middle">{{item.model}}</td>
|
<td class="align-middle">{{item.model}}</td>
|
||||||
<td class="align-middle">{{item.year}}</td>
|
<td class="align-middle">{{item.year}}</td>
|
||||||
|
<td class="align-middle">{{item.vin}}</td>
|
||||||
<td class="align-middle">{{item.quantity}}</td>
|
<td class="align-middle">{{item.quantity}}</td>
|
||||||
<td class="align-middle ps-5">{{item.unit_price}}</td>
|
<td class="align-middle ps-5">{{item.unit_price}}</td>
|
||||||
<td class="align-middle text-body-tertiary fw-semibold">{{item.total}}</td>
|
<td class="align-middle text-body-tertiary fw-semibold">{{item.total}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<tr class="bg-body-secondary total-sum">
|
<tr class="bg-body-secondary total-sum">
|
||||||
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="6">{% trans "Vat" %} ({{data.vat}}%)</td>
|
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="7">{% trans "Vat" %} ({{data.vat}}%)</td>
|
||||||
<td class="align-middle text-start fw-semibold">
|
<td class="align-middle text-start fw-semibold">
|
||||||
<span id="grand-total">+ {{data.total_vat_amount}}</span>
|
<span id="grand-total">+ {{data.total_vat_amount}}</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="bg-body-secondary total-sum">
|
<tr class="bg-body-secondary total-sum">
|
||||||
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="6">{% trans "Discount Amount" %}</td>
|
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="7">{% trans "Discount Amount" %}</td>
|
||||||
<td class="align-middle text-start text-danger fw-semibold ">
|
<td class="align-middle text-start text-danger fw-semibold ">
|
||||||
<span id="grand-total">- {{data.total_discount}}</span>
|
<span id="grand-total">- {{data.total_discount}}</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="bg-body-secondary total-sum">
|
<tr class="bg-body-secondary total-sum">
|
||||||
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="6">{% trans "Additional Services" %}</td>
|
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="7">{% trans "Additional Services" %}</td>
|
||||||
<td class="align-middle text-start fw-semibold">
|
<td class="align-middle text-start fw-semibold">
|
||||||
{% for service in data.additionals %}
|
{% for service in data.additionals %}
|
||||||
<small><span class="fw-semibold">+ {{service.name}} - {{service.total}}</span></small><br>
|
<small><span class="fw-semibold">+ {{service.name}} - {{service.total}}</span></small><br>
|
||||||
@ -161,7 +163,7 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="bg-body-secondary total-sum">
|
<tr class="bg-body-secondary total-sum">
|
||||||
<td class="align-middle ps-4 fw-bolder text-body-highlight" colspan="6">{% trans "Grand Total" %}</td>
|
<td class="align-middle ps-4 fw-bolder text-body-highlight" colspan="7">{% trans "Grand Total" %}</td>
|
||||||
<td class="align-middle text-start fw-bolder">
|
<td class="align-middle text-start fw-bolder">
|
||||||
<span id="grand-total">{{data.grand_total}}</span>
|
<span id="grand-total">{{data.grand_total}}</span>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@ -15,10 +15,10 @@
|
|||||||
<div id="formrow">
|
<div id="formrow">
|
||||||
<h3 class="text-start">{{ _("Cars") }}</h3>
|
<h3 class="text-start">{{ _("Cars") }}</h3>
|
||||||
<div class="form-row row g-3 mb-3 mt-5">
|
<div class="form-row row g-3 mb-3 mt-5">
|
||||||
<div class="mb-2 col-sm-2">
|
<div class="mb-2 col-sm-4">
|
||||||
<select class="form-control item" name="item[]" required>
|
<select class="form-control item" name="item[]" required>
|
||||||
{% for item in items %}
|
{% for item in items %}
|
||||||
<option value="{{ item.hash }}">{{ item.make }} {{item.model}}</option>
|
<option value="{{ item.hash }}">{{ item.make }} {{item.model}} {{item.serie}} {{item.trim}}-{{item.color}}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@ -68,7 +68,7 @@
|
|||||||
<div class="mb-2 col-sm-2">
|
<div class="mb-2 col-sm-2">
|
||||||
<select class="form-control item" name="item[]" required>
|
<select class="form-control item" name="item[]" required>
|
||||||
{% for item in items %}
|
{% for item in items %}
|
||||||
<option value="{{ item.product.pk }}">{{ item.car.id_car_model }}</option>
|
<option value="{{ item.hash }}">{{ item.make }} {{item.model}} {{item.serie}} {{item.trim}} {{item.color}}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -212,12 +212,13 @@
|
|||||||
<thead class="bg-body-secondary">
|
<thead class="bg-body-secondary">
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col" style="width: 24px;">#</th>
|
<th scope="col" style="width: 24px;">#</th>
|
||||||
<th scope="col" style="min-width: 260px;">{% trans "Make" %}</th>
|
<th scope="col" style="min-width: 100px;">{% trans "Make" %}</th>
|
||||||
<th scope="col" style="min-width: 260px;">{% trans "Model" %}</th>
|
<th scope="col" style="min-width: 100px;">{% trans "Model" %}</th>
|
||||||
<th scope="col" style="min-width: 260px;">{% trans "Year" %}</th>
|
<th scope="col" style="min-width: 100px;">{% trans "Year" %}</th>
|
||||||
<th scope="col" style="min-width: 60px;">{% trans "Quantity" %}</th>
|
<th scope="col" style="min-width: 100px;">{% trans "VIN" %}</th>
|
||||||
<th scope="col" style="min-width: 60px;">{% trans "Unit Price" %}</th>
|
<th scope="col" style="min-width: 100px;">{% trans "Quantity" %}</th>
|
||||||
<th scope="col" style="min-width: 60px;">{% trans "Total" %}</th>
|
<th scope="col" style="min-width: 100px;">{% trans "Unit Price" %}</th>
|
||||||
|
<th scope="col" style="min-width: 100px;">{% trans "Total" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -227,25 +228,26 @@
|
|||||||
<td class="align-middle">{{item.make}}</td>
|
<td class="align-middle">{{item.make}}</td>
|
||||||
<td class="align-middle">{{item.model}}</td>
|
<td class="align-middle">{{item.model}}</td>
|
||||||
<td class="align-middle">{{item.year}}</td>
|
<td class="align-middle">{{item.year}}</td>
|
||||||
|
<td class="align-middle">{{item.vin}}</td>
|
||||||
<td class="align-middle">{{item.quantity}}</td>
|
<td class="align-middle">{{item.quantity}}</td>
|
||||||
<td class="align-middle ps-5">{{item.total}}</td>
|
<td class="align-middle ps-5">{{item.total}}</td>
|
||||||
<td class="align-middle text-body-tertiary fw-semibold">{{item.total}}</td>
|
<td class="align-middle text-body-tertiary fw-semibold">{{item.total}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<tr class="bg-body-secondary total-sum">
|
<tr class="bg-body-secondary total-sum">
|
||||||
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="6">{% trans "Discount Amount" %}</td>
|
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="7">{% trans "Discount Amount" %}</td>
|
||||||
<td class="align-middle text-start fw-semibold">
|
<td class="align-middle text-start fw-semibold">
|
||||||
<span id="grand-total">- {{data.total_discount}}</span>
|
<span id="grand-total">- {{data.total_discount}}</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="bg-body-secondary total-sum">
|
<tr class="bg-body-secondary total-sum">
|
||||||
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="6">{% trans "VAT" %} ({{data.vat}}%)</td>
|
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="7">{% trans "VAT" %} ({{data.vat}}%)</td>
|
||||||
<td class="align-middle text-start fw-semibold">
|
<td class="align-middle text-start fw-semibold">
|
||||||
<span id="grand-total">+ {{data.total_vat_amount}}</span>
|
<span id="grand-total">+ {{data.total_vat_amount}}</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="bg-body-secondary total-sum">
|
<tr class="bg-body-secondary total-sum">
|
||||||
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="6">{% trans "Additional Services" %}</td>
|
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="7">{% trans "Additional Services" %}</td>
|
||||||
<td class="align-middle text-start fw-bold">
|
<td class="align-middle text-start fw-bold">
|
||||||
{% for service in data.additionals %}
|
{% for service in data.additionals %}
|
||||||
<small><span class="fw-bold">+ {{service.name}} - {{service.price}}</span></small><br>
|
<small><span class="fw-bold">+ {{service.name}} - {{service.price}}</span></small><br>
|
||||||
@ -253,7 +255,7 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="bg-body-secondary total-sum">
|
<tr class="bg-body-secondary total-sum">
|
||||||
<td class="align-middle ps-4 fw-bolder text-body-highlight" colspan="6">{% trans "Grand Total" %}</td>
|
<td class="align-middle ps-4 fw-bolder text-body-highlight" colspan="7">{% trans "Grand Total" %}</td>
|
||||||
<td class="align-middle text-start fw-bolder">
|
<td class="align-middle text-start fw-bolder">
|
||||||
<span id="grand-total">{{data.grand_total}}</span>
|
<span id="grand-total">{{data.grand_total}}</span>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@ -201,7 +201,10 @@
|
|||||||
<table class="table table-bordered">
|
<table class="table table-bordered">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th><small class="fs-10">Item</small><br><small class="fs-10">الصنف</small></th>
|
<th><small class="fs-10">Make</small><br><small class="fs-10">الصنف</small></th>
|
||||||
|
<th><small class="fs-10">Model</small><br><small class="fs-10">الموديل</small></th>
|
||||||
|
<th><small class="fs-10">Year</small><br><small class="fs-10">السنة</small></th>
|
||||||
|
<th><small class="fs-10">VIN</small><br><small class="fs-10">رقم الهيكل</small></th>
|
||||||
<th><small class="fs-10">Quantity</small><br><small class="fs-10">العدد</small></th>
|
<th><small class="fs-10">Quantity</small><br><small class="fs-10">العدد</small></th>
|
||||||
<th><small class="fs-10">Unit Price</small><br><small class="fs-10">سعر الوحدة</small></th>
|
<th><small class="fs-10">Unit Price</small><br><small class="fs-10">سعر الوحدة</small></th>
|
||||||
<th><small class="fs-10">Total</small><br><small class="fs-10">الإجمالي</small></th>
|
<th><small class="fs-10">Total</small><br><small class="fs-10">الإجمالي</small></th>
|
||||||
@ -211,6 +214,9 @@
|
|||||||
{% for item in data.cars %}
|
{% for item in data.cars %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="">{{item.make}}</td>
|
<td class="">{{item.make}}</td>
|
||||||
|
<td class="">{{item.model}}</td>
|
||||||
|
<td class="">{{item.year}}</td>
|
||||||
|
<td class="">{{item.vin}}</td>
|
||||||
<td class="align-middle">{{item.quantity}}</td>
|
<td class="align-middle">{{item.quantity}}</td>
|
||||||
<td class="align-middle ps-5">{{item.selling_price}}</td>
|
<td class="align-middle ps-5">{{item.selling_price}}</td>
|
||||||
<td class="align-middle text-body-tertiary fw-semibold">{{item.total}}</td>
|
<td class="align-middle text-body-tertiary fw-semibold">{{item.total}}</td>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user