update
This commit is contained in:
parent
dbf4c6f91d
commit
692fa3f0ed
1
.idea/car_inventory.iml
generated
1
.idea/car_inventory.iml
generated
@ -33,6 +33,7 @@
|
|||||||
<orderEntry type="library" name="fullcalendar" level="application" />
|
<orderEntry type="library" name="fullcalendar" level="application" />
|
||||||
<orderEntry type="library" name="popper.js" level="application" />
|
<orderEntry type="library" name="popper.js" level="application" />
|
||||||
<orderEntry type="library" name="tempusdominus-bootstrap-4" level="application" />
|
<orderEntry type="library" name="tempusdominus-bootstrap-4" level="application" />
|
||||||
|
<orderEntry type="library" name="chart.js" level="application" />
|
||||||
</component>
|
</component>
|
||||||
<component name="TemplatesService">
|
<component name="TemplatesService">
|
||||||
<option name="TEMPLATE_CONFIGURATION" value="Django" />
|
<option name="TEMPLATE_CONFIGURATION" value="Django" />
|
||||||
|
|||||||
2
.idea/jsLibraryMappings.xml
generated
2
.idea/jsLibraryMappings.xml
generated
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="JavaScriptLibraryMappings">
|
<component name="JavaScriptLibraryMappings">
|
||||||
<file url="file://$PROJECT_DIR$" libraries="{@turf/turf, @zxing, apexcharts, bootstrap-icons, fullcalendar, jquery, jquery-3.5.1, line, moment-timezone, moment.js, popper.js, quagga, sweetalert2, tempusdominus-bootstrap-4, tesseract.js}" />
|
<file url="file://$PROJECT_DIR$" libraries="{@turf/turf, @zxing, apexcharts, bootstrap-icons, chart.js, fullcalendar, jquery, jquery-3.5.1, line, moment-timezone, moment.js, popper.js, quagga, sweetalert2, tempusdominus-bootstrap-4, tesseract.js}" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,6 +1,7 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from . import models
|
from . import models
|
||||||
from django_ledger import models as ledger_models
|
from django_ledger import models as ledger_models
|
||||||
|
from django_pdf_actions.actions import export_to_pdf_landscape, export_to_pdf_portrait
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(models.Dealer)
|
admin.site.register(models.Dealer)
|
||||||
@ -43,6 +44,7 @@ class CarMakeAdmin(admin.ModelAdmin):
|
|||||||
list_display = ('name', 'arabic_name', 'is_sa_import')
|
list_display = ('name', 'arabic_name', 'is_sa_import')
|
||||||
search_fields = ('name', 'arabic_name')
|
search_fields = ('name', 'arabic_name')
|
||||||
list_filter = ('is_sa_import', 'name',)
|
list_filter = ('is_sa_import', 'name',)
|
||||||
|
actions = [export_to_pdf_landscape, export_to_pdf_portrait]
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "Car Make"
|
verbose_name = "Car Make"
|
||||||
@ -115,3 +117,7 @@ class CarOptionAdmin(admin.ModelAdmin):
|
|||||||
# search_fields = ('user__username', 'action')
|
# search_fields = ('user__username', 'action')
|
||||||
# list_filter = ('timestamp',)
|
# list_filter = ('timestamp',)
|
||||||
|
|
||||||
|
@admin.register(ledger_models.ItemTransactionModel)
|
||||||
|
class ItemTransactionModelAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
|
actions = [export_to_pdf_landscape, export_to_pdf_portrait]
|
||||||
@ -35,8 +35,8 @@ def get_jwt_token():
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
data = {
|
data = {
|
||||||
"api_token": "f5204a00-6f31-4de2-96d8-ed998e0d230c",
|
"api_token": settings.CAR_API_TOKEN,
|
||||||
"api_secret": "8c11320781a5b8f4f327b6937e6f8241",
|
"api_secret": settings.CAR_API_SECRET,
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
response = requests.post(url, headers=headers, json=data)
|
response = requests.post(url, headers=headers, json=data)
|
||||||
@ -247,6 +247,7 @@ def get_financial_values(model):
|
|||||||
additional_services = []
|
additional_services = []
|
||||||
|
|
||||||
for i in data:
|
for i in data:
|
||||||
|
print(i)
|
||||||
if i.item_model.additional_info["additional_services"]:
|
if i.item_model.additional_info["additional_services"]:
|
||||||
additional_services.extend(
|
additional_services.extend(
|
||||||
[
|
[
|
||||||
|
|||||||
@ -3,6 +3,9 @@ from appointment.models import Appointment,AppointmentRequest,Service,StaffMembe
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from calendar import month_name
|
from calendar import month_name
|
||||||
from random import randint
|
from random import randint
|
||||||
|
|
||||||
|
from django_pdf_actions.actions import export_to_pdf_landscape
|
||||||
|
from reportlab.lib.pagesizes import landscape, A4
|
||||||
from rich import print
|
from rich import print
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
@ -139,6 +142,7 @@ from django_ledger.views.mixins import (
|
|||||||
BaseDateNavigationUrlMixIn,
|
BaseDateNavigationUrlMixIn,
|
||||||
PDFReportMixIn,
|
PDFReportMixIn,
|
||||||
)
|
)
|
||||||
|
from django_pdf_actions import actions
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -273,6 +277,7 @@ class HomeView(TemplateView):
|
|||||||
template_name = "index.html"
|
template_name = "index.html"
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
# Redirect unauthenticated users to the welcome page
|
||||||
if not request.user.is_authenticated:
|
if not request.user.is_authenticated:
|
||||||
return redirect("welcome")
|
return redirect("welcome")
|
||||||
return super().dispatch(request, *args, **kwargs)
|
return super().dispatch(request, *args, **kwargs)
|
||||||
@ -281,6 +286,8 @@ class HomeView(TemplateView):
|
|||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
dealer = get_user_type(self.request)
|
dealer = get_user_type(self.request)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Fetch car-related statistics
|
||||||
total_cars = models.Car.objects.filter(dealer=dealer).count()
|
total_cars = models.Car.objects.filter(dealer=dealer).count()
|
||||||
total_reservations = models.CarReservation.objects.filter(
|
total_reservations = models.CarReservation.objects.filter(
|
||||||
reserved_until__gte=timezone.now()
|
reserved_until__gte=timezone.now()
|
||||||
@ -289,24 +296,44 @@ class HomeView(TemplateView):
|
|||||||
owner=dealer,
|
owner=dealer,
|
||||||
).count()
|
).count()
|
||||||
cars_outside = total_cars - cars_in_house
|
cars_outside = total_cars - cars_in_house
|
||||||
|
|
||||||
|
# Fetch financial statistics
|
||||||
stats = models.CarFinance.objects.aggregate(
|
stats = models.CarFinance.objects.aggregate(
|
||||||
total_cost_price=Sum("cost_price"),
|
total_cost_price=Sum("cost_price"),
|
||||||
total_selling_price=Sum("selling_price"),
|
total_selling_price=Sum("selling_price"),
|
||||||
)
|
)
|
||||||
total_cost_price = stats["total_cost_price"] or 0
|
total_cost_price = stats.get("total_cost_price", 0) or 0
|
||||||
total_selling_price = stats["total_selling_price"] or 0
|
total_selling_price = stats.get("total_selling_price", 0) or 0
|
||||||
total_profit = total_selling_price - total_cost_price
|
total_profit = total_selling_price - total_cost_price
|
||||||
|
|
||||||
context["dealer"] = dealer
|
# Prepare context data
|
||||||
context["total_cars"] = total_cars
|
context.update({
|
||||||
context["cars_in_house"] = cars_in_house
|
"dealer": dealer,
|
||||||
context["cars_outside"] = cars_outside
|
"total_cars": total_cars,
|
||||||
context["total_reservations"] = total_reservations
|
"cars_in_house": cars_in_house,
|
||||||
context["total_cost_price"] = total_cost_price
|
"cars_outside": cars_outside,
|
||||||
context["total_selling_price"] = total_selling_price
|
"total_reservations": total_reservations,
|
||||||
context["total_profit"] = total_profit
|
"total_cost_price": total_cost_price,
|
||||||
return context
|
"total_selling_price": total_selling_price,
|
||||||
|
"total_profit": total_profit,
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
# Log the error (you can use Django's logging framework)
|
||||||
|
print(f"Error fetching data: {e}")
|
||||||
|
# Provide default values in case of an error
|
||||||
|
context.update({
|
||||||
|
"dealer": dealer,
|
||||||
|
"total_cars": 0,
|
||||||
|
"cars_in_house": 0,
|
||||||
|
"cars_outside": 0,
|
||||||
|
"total_reservations": 0,
|
||||||
|
"total_cost_price": 0,
|
||||||
|
"total_selling_price": 0,
|
||||||
|
"total_profit": 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
class TestView(TemplateView):
|
class TestView(TemplateView):
|
||||||
template_name = "test.html"
|
template_name = "test.html"
|
||||||
@ -663,7 +690,8 @@ class CarListView(LoginRequiredMixin, ListView):
|
|||||||
paginate_by = 10
|
paginate_by = 10
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
cars = models.Car.objects.all()
|
dealer = get_user_type(self.request)
|
||||||
|
cars = models.Car.objects.filter(dealer=dealer).order_by("receiving_date")
|
||||||
|
|
||||||
context["stats"] = {
|
context["stats"] = {
|
||||||
'all': cars.count(),
|
'all': cars.count(),
|
||||||
@ -672,16 +700,15 @@ class CarListView(LoginRequiredMixin, ListView):
|
|||||||
'sold':cars.filter(status='sold').count(),
|
'sold':cars.filter(status='sold').count(),
|
||||||
'transfer':cars.filter(status='transfer').count()
|
'transfer':cars.filter(status='transfer').count()
|
||||||
}
|
}
|
||||||
context['make'] = models.CarMake.objects.all()
|
context['make'] = models.CarMake.objects.filter(car__in=cars).distinct()
|
||||||
context['model'] = models.CarModel.objects.none()
|
context['model'] = models.CarModel.objects.none()
|
||||||
context['year'] = models.Car.objects.none()
|
context['year'] = models.Car.objects.none()
|
||||||
|
|
||||||
make = self.request.GET.get('make')
|
make = self.request.GET.get('make')
|
||||||
model = self.request.GET.get('model')
|
model = self.request.GET.get('model')
|
||||||
|
|
||||||
if make:
|
if make:
|
||||||
make_ = models.CarMake.objects.get(pk=int(make))
|
make_ = models.CarMake.objects.get(id_car_make=int(make))
|
||||||
context['model'] = make_.carmodel_set.all()
|
context['model'] = make_.carmodel_set.filter(car__in=cars).distinct()
|
||||||
if make and model:
|
if make and model:
|
||||||
make_ = models.CarMake.objects.get(id_car_make=int(make))
|
make_ = models.CarMake.objects.get(id_car_make=int(make))
|
||||||
model_ = models.CarModel.objects.get(id_car_model=int(model))
|
model_ = models.CarModel.objects.get(id_car_model=int(model))
|
||||||
@ -1205,9 +1232,7 @@ class CustomerListView(LoginRequiredMixin, ListView):
|
|||||||
query = self.request.GET.get("q")
|
query = self.request.GET.get("q")
|
||||||
dealer = get_user_type(self.request)
|
dealer = get_user_type(self.request)
|
||||||
|
|
||||||
customers = dealer.entity.get_customers().filter(
|
customers = dealer.entity.get_customers().filter(additional_info__type="customer")
|
||||||
active=True, additional_info__type="customer"
|
|
||||||
)
|
|
||||||
|
|
||||||
if query:
|
if query:
|
||||||
customers = customers.filter(
|
customers = customers.filter(
|
||||||
@ -1312,6 +1337,7 @@ def CustomerCreateView(request):
|
|||||||
"address_1": form.cleaned_data["address"],
|
"address_1": form.cleaned_data["address"],
|
||||||
"phone": form.cleaned_data["phone_number"],
|
"phone": form.cleaned_data["phone_number"],
|
||||||
"email": email,
|
"email": email,
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -2406,10 +2432,17 @@ def account_delete(request, pk):
|
|||||||
|
|
||||||
# Sales list
|
# Sales list
|
||||||
def sales_list_view(request):
|
def sales_list_view(request):
|
||||||
transactions = ItemTransactionModel.objects.all()[:10]
|
dealer = get_user_type(request)
|
||||||
txs = get_item_transactions(transactions)
|
entity = dealer.entity
|
||||||
context = {"txs":txs}
|
|
||||||
return render(request, "sales/sales_list.html",context)
|
transactions = ItemTransactionModel.objects.for_entity(entity_slug=entity.slug, user_model=dealer.user)
|
||||||
|
paginator = Paginator(transactions, 20)
|
||||||
|
page_number = request.GET.get('page')
|
||||||
|
page_obj = paginator.get_page(page_number)
|
||||||
|
txs = get_item_transactions(page_obj)
|
||||||
|
context = {"txs": txs, "page_obj": page_obj}
|
||||||
|
return render(request, "sales/sales_list.html", context)
|
||||||
|
|
||||||
|
|
||||||
# Estimates
|
# Estimates
|
||||||
class EstimateListView(LoginRequiredMixin, ListView):
|
class EstimateListView(LoginRequiredMixin, ListView):
|
||||||
@ -2428,6 +2461,10 @@ class EstimateListView(LoginRequiredMixin, ListView):
|
|||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# class EstimateCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
|
# class EstimateCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
|
||||||
# model = EstimateModel
|
# model = EstimateModel
|
||||||
# form_class = EstimateModelCreateForm
|
# form_class = EstimateModelCreateForm
|
||||||
@ -3106,7 +3143,11 @@ class LeadListView(ListView):
|
|||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
dealer = get_user_type(self.request)
|
dealer = get_user_type(self.request)
|
||||||
return models.Lead.objects.filter(dealer=dealer).all()
|
staff = getattr(self.request.user, "staff", None)
|
||||||
|
|
||||||
|
if staff:
|
||||||
|
return models.Lead.objects.filter(dealer=dealer, staff=staff)
|
||||||
|
return models.Lead.objects.filter(dealer=dealer)
|
||||||
|
|
||||||
|
|
||||||
class LeadDetailView(DetailView):
|
class LeadDetailView(DetailView):
|
||||||
@ -4314,9 +4355,9 @@ class EmployeeCalendarView(ListView):
|
|||||||
model = Appointment
|
model = Appointment
|
||||||
context_object_name = 'appointments'
|
context_object_name = 'appointments'
|
||||||
|
|
||||||
# def get_context_data(self):
|
def get_queryset(self):
|
||||||
# self.context['dealer'] = get_user_type(self.request)
|
dealer = get_user_type(self.request)
|
||||||
# dealer =
|
staff = self.request.user.staff
|
||||||
# return Appointment.objects.all()
|
return Appointment.objects.filter(appointment_request__staff_member=staff).all()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
89
ofx_sample.ofx
Normal file
89
ofx_sample.ofx
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
OFXHEADER:100
|
||||||
|
DATA:OFXSGML
|
||||||
|
VERSION:102
|
||||||
|
SECURITY:NONE
|
||||||
|
ENCODING:UTF-8
|
||||||
|
CHARSET:NONE
|
||||||
|
COMPRESSION:NONE
|
||||||
|
OLDFILEUID:NONE
|
||||||
|
NEWFILEUID:NONE
|
||||||
|
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<OFX>
|
||||||
|
<SIGNONMSGSRSV1>
|
||||||
|
<SONRS>
|
||||||
|
<STATUS>
|
||||||
|
<CODE>0</CODE>
|
||||||
|
<SEVERITY>INFO</SEVERITY>
|
||||||
|
</STATUS>
|
||||||
|
<DTSERVER>20250214000000</DTSERVER>
|
||||||
|
<LANGUAGE>ENG</LANGUAGE>
|
||||||
|
</SONRS>
|
||||||
|
</SIGNONMSGSRSV1>
|
||||||
|
<BANKMSGSRSV1>
|
||||||
|
<STMTTRNRS>
|
||||||
|
<TRNUID>1</TRNUID>
|
||||||
|
<STATUS>
|
||||||
|
<CODE>0</CODE>
|
||||||
|
<SEVERITY>INFO</SEVERITY>
|
||||||
|
</STATUS>
|
||||||
|
<STMTRS>
|
||||||
|
<CURDEF>USD</CURDEF>
|
||||||
|
<BANKACCTFROM>
|
||||||
|
<BANKID>123456789</BANKID>
|
||||||
|
<ACCTID>987654321</ACCTID>
|
||||||
|
<ACCTTYPE>CHECKING</ACCTTYPE>
|
||||||
|
</BANKACCTFROM>
|
||||||
|
<BANKTRANLIST>
|
||||||
|
<DTSTART>20240214000000</DTSTART>
|
||||||
|
<DTEND>20250213000000</DTEND>
|
||||||
|
|
||||||
|
<!-- Sample Transactions -->
|
||||||
|
<STMTTRN>
|
||||||
|
<TRNTYPE>DEP</TRNTYPE>
|
||||||
|
<DTPOSTED>20240301090000</DTPOSTED>
|
||||||
|
<TRNAMT>2500.00</TRNAMT>
|
||||||
|
<FITID>100001</FITID>
|
||||||
|
<NAME>PAYROLL DEPOSIT</NAME>
|
||||||
|
</STMTTRN>
|
||||||
|
|
||||||
|
<STMTTRN>
|
||||||
|
<TRNTYPE>POS</TRNTYPE>
|
||||||
|
<DTPOSTED>20240305120000</DTPOSTED>
|
||||||
|
<TRNAMT>-150.25</TRNAMT>
|
||||||
|
<FITID>100002</FITID>
|
||||||
|
<NAME>GROCERY STORE</NAME>
|
||||||
|
</STMTTRN>
|
||||||
|
|
||||||
|
<STMTTRN>
|
||||||
|
<TRNTYPE>ATM</TRNTYPE>
|
||||||
|
<DTPOSTED>20240310080000</DTPOSTED>
|
||||||
|
<TRNAMT>-100.00</TRNAMT>
|
||||||
|
<FITID>100003</FITID>
|
||||||
|
<NAME>ATM WITHDRAWAL</NAME>
|
||||||
|
</STMTTRN>
|
||||||
|
|
||||||
|
<STMTTRN>
|
||||||
|
<TRNTYPE>DEBIT</TRNTYPE>
|
||||||
|
<DTPOSTED>20240402070000</DTPOSTED>
|
||||||
|
<TRNAMT>-50.00</TRNAMT>
|
||||||
|
<FITID>100004</FITID>
|
||||||
|
<NAME>ONLINE SUBSCRIPTION</NAME>
|
||||||
|
</STMTTRN>
|
||||||
|
|
||||||
|
<STMTTRN>
|
||||||
|
<TRNTYPE>CHECK</TRNTYPE>
|
||||||
|
<DTPOSTED>20240415090000</DTPOSTED>
|
||||||
|
<TRNAMT>-500.00</TRNAMT>
|
||||||
|
<FITID>100005</FITID>
|
||||||
|
<NAME>RENT PAYMENT</NAME>
|
||||||
|
</STMTTRN>
|
||||||
|
</BANKTRANLIST>
|
||||||
|
<LEDGERBAL>
|
||||||
|
<BALAMT>7500.00</BALAMT>
|
||||||
|
<DTASOF>20250213000000</DTASOF>
|
||||||
|
</LEDGERBAL>
|
||||||
|
</STMTRS>
|
||||||
|
</STMTTRNRS>
|
||||||
|
</BANKMSGSRSV1>
|
||||||
|
</OFX>
|
||||||
@ -53,11 +53,13 @@ django-extensions==3.2.3
|
|||||||
django-filter==24.3
|
django-filter==24.3
|
||||||
django-formtools==2.5.1
|
django-formtools==2.5.1
|
||||||
django-ledger==0.7.4.1
|
django-ledger==0.7.4.1
|
||||||
|
django-model-utils==5.0.0
|
||||||
django-money==3.5.3
|
django-money==3.5.3
|
||||||
django-next-url-mixin==0.4.0
|
django-next-url-mixin==0.4.0
|
||||||
django-nine==0.2.7
|
django-nine==0.2.7
|
||||||
django-nonefield==0.4
|
django-nonefield==0.4
|
||||||
django-ordered-model==3.7.4
|
django-ordered-model==3.7.4
|
||||||
|
django-pdf-actions==0.1.38
|
||||||
django-phonenumber-field==8.0.0
|
django-phonenumber-field==8.0.0
|
||||||
django-picklefield==3.2
|
django-picklefield==3.2
|
||||||
django-plans==1.2.0
|
django-plans==1.2.0
|
||||||
|
|||||||
BIN
static/assets/fonts/DejaVuSans.ttf
Normal file
BIN
static/assets/fonts/DejaVuSans.ttf
Normal file
Binary file not shown.
BIN
static/assets/fonts/MarkaziText%5Bwght%5D.ttf
Normal file
BIN
static/assets/fonts/MarkaziText%5Bwght%5D.ttf
Normal file
Binary file not shown.
BIN
static/assets/fonts/Roboto%5Bwdth,wght%5D.ttf
Normal file
BIN
static/assets/fonts/Roboto%5Bwdth,wght%5D.ttf
Normal file
Binary file not shown.
BIN
static/images/export_pdf/logos/logo-d-pdf.png
Normal file
BIN
static/images/export_pdf/logos/logo-d-pdf.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
static/images/logos/users/Icon_Black4x_B0iEnf0.png
Normal file
BIN
static/images/logos/users/Icon_Black4x_B0iEnf0.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
@ -46,6 +46,9 @@
|
|||||||
<div class="text-start mt-1">
|
<div class="text-start mt-1">
|
||||||
<a class="fs-9" href="{% url 'account_reset_password' %}">{{ _("Forgot Password?")}}</a>
|
<a class="fs-9" href="{% url 'account_reset_password' %}">{{ _("Forgot Password?")}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% include 'partials/form_errors.html' %}
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
<div class="text-center my-3 fs-9">
|
<div class="text-center my-3 fs-9">
|
||||||
{% trans 'If you have not created an account yet, then please' %}
|
{% trans 'If you have not created an account yet, then please' %}
|
||||||
|
|||||||
@ -105,12 +105,10 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="row align-items-center justify-content-end py-4 pe-0 fs-9">
|
<div class="row align-items-center justify-content-end py-4 pe-0 fs-9">
|
||||||
|
|
||||||
<!-- Optional: Pagination -->
|
|
||||||
{% if is_paginated %}
|
{% if is_paginated %}
|
||||||
{% include 'partials/pagination.html' %}
|
{% include 'partials/pagination.html' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% include 'modal/delete_modal.html' %}
|
{% include 'modal/delete_modal.html' %}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
{% load i18n static %}
|
{% load i18n static %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<div class="px-3 mb-6">
|
<div class="px-3 mb-6">
|
||||||
<div class="row justify-content-between">
|
<div class="row justify-content-between">
|
||||||
@ -46,7 +48,7 @@
|
|||||||
<div class="border-translucent mb-sm-4">
|
<div class="border-translucent mb-sm-4">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<div class="d-flex align-items-center icon-wrapper-sm shadow-primary-100" style="transform: rotate(-7.45deg);">
|
<div class="d-flex align-items-center icon-wrapper-sm shadow-primary-100" style="transform: rotate(-7.45deg);">
|
||||||
<div class="icon icon-shape bg-gradient-info text-white rounded-circle shadow">MMMMMMMMMMMMMMM</div>
|
<div class="icon icon-shape bg-gradient-info text-white rounded-circle shadow"></div>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-body-tertiary fs-9 mb-0 ms-2 mt-3">Outgoing call</p>
|
<p class="text-body-tertiary fs-9 mb-0 ms-2 mt-3">Outgoing call</p>
|
||||||
</div>
|
</div>
|
||||||
@ -71,6 +73,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-sm-6 col-md-4 col-xl-3 col-xxl-4 align-content-center">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row g-3 mb-3">
|
||||||
|
<canvas id="pnlChart"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -103,4 +111,55 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script>
|
||||||
|
const url = "{% url 'django_ledger:entity-json-pnl' dealer.entity.slug %}"
|
||||||
|
async function fetchPnLData() {
|
||||||
|
try {
|
||||||
|
const response = await fetch(url); // Update with your API URL
|
||||||
|
const jsonResponse = await response.json();
|
||||||
|
const pnlData = jsonResponse.results.pnl_data;
|
||||||
|
console.log(pnlData);
|
||||||
|
|
||||||
|
const labels = Object.keys(pnlData);
|
||||||
|
const profits = labels.map(label => pnlData[label].GROUP_NET_PROFIT);
|
||||||
|
const sales = labels.map(label => pnlData[label].GROUP_NET_SALES);
|
||||||
|
|
||||||
|
renderChart(labels, profits, sales);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching PnL data:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderChart(labels, profits, sales) {
|
||||||
|
const ctx = document.getElementById("pnlChart").getContext("2d");
|
||||||
|
new Chart(ctx, {
|
||||||
|
type: "bar",
|
||||||
|
data: {
|
||||||
|
labels: labels,
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: "Net Profit",
|
||||||
|
data: profits,
|
||||||
|
backgroundColor: "green"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Net Sales",
|
||||||
|
data: sales,
|
||||||
|
backgroundColor: "blue"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
beginAtZero: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchPnLData();
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -38,7 +38,7 @@
|
|||||||
<li class="nav-item"><a class="nav-link px-2 py-1" href="{% url 'car_list' %}?status=reserved"><span>Reserved</span><span class="text-body-tertiary fw-semibold">({{stats.reserved}})</span></a></li>
|
<li class="nav-item"><a class="nav-link px-2 py-1" href="{% url 'car_list' %}?status=reserved"><span>Reserved</span><span class="text-body-tertiary fw-semibold">({{stats.reserved}})</span></a></li>
|
||||||
<li class="nav-item"><a class="nav-link px-2 py-1" href="{% url 'car_list' %}?status=transfer"><span>Transfer</span><span class="text-body-tertiary fw-semibold">({{stats.transfer}})</span></a></li>
|
<li class="nav-item"><a class="nav-link px-2 py-1" href="{% url 'car_list' %}?status=transfer"><span>Transfer</span><span class="text-body-tertiary fw-semibold">({{stats.transfer}})</span></a></li>
|
||||||
<li class="nav-item"><a class="nav-link px-2 py-1" href="{% url 'car_list' %}?status=sold"><span>Sold</span><span class="text-body-tertiary fw-semibold">({{stats.sold}})</span></a></li>
|
<li class="nav-item"><a class="nav-link px-2 py-1" href="{% url 'car_list' %}?status=sold"><span>Sold</span><span class="text-body-tertiary fw-semibold">({{stats.sold}})</span></a></li>
|
||||||
<li class="nav-item"><button hx-on:click="toggle_filter()" class="nav-link px-2 py-1"><span>Filter</span><span class="text-body-tertiary fw-semibold"></span></button></li>
|
<li class="nav-item"><button hx-on:click="toggle_filter()" class="btn btn-sm btn-primary px-2 py-1"><span>{{ _("Filter") }}</span><span class="fas fa-caret-down fs-9 ms-1 filter-icon"></span></button></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-sm-auto">
|
<div class="col-12 col-sm-auto">
|
||||||
@ -52,38 +52,20 @@
|
|||||||
/>
|
/>
|
||||||
<span class="fas fa-search search-box-icon"></span>
|
<span class="fas fa-search search-box-icon"></span>
|
||||||
</form>
|
</form>
|
||||||
</div><a class="btn btn-phoenix-primary px-3 me-1 border-0 text-body" href="#" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="List view"><span class="fa-solid fa-list fs-10"></span></a><a class="btn btn-phoenix-primary px-3 me-1" href="#" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Board view">
|
</div>
|
||||||
<svg width="9" height="9" viewbox="0 0 9 9" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M0 0.5C0 0.223857 0.223858 0 0.5 0H1.83333C2.10948 0 2.33333 0.223858 2.33333 0.5V1.83333C2.33333 2.10948 2.10948 2.33333 1.83333 2.33333H0.5C0.223857 2.33333 0 2.10948 0 1.83333V0.5Z" fill="currentColor"></path>
|
|
||||||
<path d="M3.33333 0.5C3.33333 0.223857 3.55719 0 3.83333 0H5.16667C5.44281 0 5.66667 0.223858 5.66667 0.5V1.83333C5.66667 2.10948 5.44281 2.33333 5.16667 2.33333H3.83333C3.55719 2.33333 3.33333 2.10948 3.33333 1.83333V0.5Z" fill="currentColor"></path>
|
|
||||||
<path d="M6.66667 0.5C6.66667 0.223857 6.89052 0 7.16667 0H8.5C8.77614 0 9 0.223858 9 0.5V1.83333C9 2.10948 8.77614 2.33333 8.5 2.33333H7.16667C6.89052 2.33333 6.66667 2.10948 6.66667 1.83333V0.5Z" fill="currentColor"></path>
|
|
||||||
<path d="M0 3.83333C0 3.55719 0.223858 3.33333 0.5 3.33333H1.83333C2.10948 3.33333 2.33333 3.55719 2.33333 3.83333V5.16667C2.33333 5.44281 2.10948 5.66667 1.83333 5.66667H0.5C0.223857 5.66667 0 5.44281 0 5.16667V3.83333Z" fill="currentColor"></path>
|
|
||||||
<path d="M3.33333 3.83333C3.33333 3.55719 3.55719 3.33333 3.83333 3.33333H5.16667C5.44281 3.33333 5.66667 3.55719 5.66667 3.83333V5.16667C5.66667 5.44281 5.44281 5.66667 5.16667 5.66667H3.83333C3.55719 5.66667 3.33333 5.44281 3.33333 5.16667V3.83333Z" fill="currentColor"></path>
|
|
||||||
<path d="M6.66667 3.83333C6.66667 3.55719 6.89052 3.33333 7.16667 3.33333H8.5C8.77614 3.33333 9 3.55719 9 3.83333V5.16667C9 5.44281 8.77614 5.66667 8.5 5.66667H7.16667C6.89052 5.66667 6.66667 5.44281 6.66667 5.16667V3.83333Z" fill="currentColor"></path>
|
|
||||||
<path d="M0 7.16667C0 6.89052 0.223858 6.66667 0.5 6.66667H1.83333C2.10948 6.66667 2.33333 6.89052 2.33333 7.16667V8.5C2.33333 8.77614 2.10948 9 1.83333 9H0.5C0.223857 9 0 8.77614 0 8.5V7.16667Z" fill="currentColor"></path>
|
|
||||||
<path d="M3.33333 7.16667C3.33333 6.89052 3.55719 6.66667 3.83333 6.66667H5.16667C5.44281 6.66667 5.66667 6.89052 5.66667 7.16667V8.5C5.66667 8.77614 5.44281 9 5.16667 9H3.83333C3.55719 9 3.33333 8.77614 3.33333 8.5V7.16667Z" fill="currentColor"></path>
|
|
||||||
<path d="M6.66667 7.16667C6.66667 6.89052 6.89052 6.66667 7.16667 6.66667H8.5C8.77614 6.66667 9 6.89052 9 7.16667V8.5C9 8.77614 8.77614 9 8.5 9H7.16667C6.89052 9 6.66667 8.77614 6.66667 8.5V7.16667Z" fill="currentColor"></path>
|
|
||||||
</svg></a><a class="btn btn-phoenix-primary px-3" href="#" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Card view">
|
|
||||||
<svg width="9" height="9" viewBox="0 0 9 9" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M0 0.5C0 0.223858 0.223858 0 0.5 0H3.5C3.77614 0 4 0.223858 4 0.5V3.5C4 3.77614 3.77614 4 3.5 4H0.5C0.223858 4 0 3.77614 0 3.5V0.5Z" fill="currentColor"></path>
|
|
||||||
<path d="M0 5.5C0 5.22386 0.223858 5 0.5 5H3.5C3.77614 5 4 5.22386 4 5.5V8.5C4 8.77614 3.77614 9 3.5 9H0.5C0.223858 9 0 8.77614 0 8.5V5.5Z" fill="currentColor"></path>
|
|
||||||
<path d="M5 0.5C5 0.223858 5.22386 0 5.5 0H8.5C8.77614 0 9 0.223858 9 0.5V3.5C9 3.77614 8.77614 4 8.5 4H5.5C5.22386 4 5 3.77614 5 3.5V0.5Z" fill="currentColor"></path>
|
|
||||||
<path d="M5 5.5C5 5.22386 5.22386 5 5.5 5H8.5C8.77614 5 9 5.22386 9 5.5V8.5C9 8.77614 8.77614 9 8.5 9H5.5C5.22386 9 5 8.77614 5 8.5V5.5Z" fill="currentColor"></path>
|
|
||||||
</svg></a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex align-items-center d-none filter">
|
<div class="d-flex align-items-center d-none filter">
|
||||||
<select hx-get="{% url 'car_list' %}" name="make" hx-target='.model-select' hx-select='.model-select' hx-swap="outerHTML show:window:top" hx-indicator=".htmx-indicator" class="form-select make" aria-label="Default select example"
|
<select hx-get="{% url 'car_list' %}" name="make" hx-target='.model-select' hx-select='.model-select' hx-swap="outerHTML show:window:top" hx-indicator=".htmx-indicator" class="form-select form-control-sm me-1 make" aria-label="Default select example"
|
||||||
hx-on::before-request="filter_before_request()"
|
hx-on::before-request="filter_before_request()"
|
||||||
hx-on::after-request="filter_after_request()"
|
hx-on::after-request="filter_after_request()">
|
||||||
>
|
|
||||||
<option selected="" value="" disabled>Select Make</option>
|
<option selected="" value="" disabled>Select Make</option>
|
||||||
{% for m in make %}
|
{% for m in make %}
|
||||||
<option value="{{ m.pk }}">{{ m.name }}</option>
|
<option value="{{ m.pk }}">{{ m.name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<select hx-get="{% url 'car_list' %}" hx-include=".make" name="model" hx-target='.year' hx-select='.year' hx-swap="outerHTML show:window:top" hx-indicator=".htmx-indicator" class="form-select model-select" aria-label="Default select example"
|
<select hx-get="{% url 'car_list' %}" hx-include=".make" name="model" hx-target='.year' hx-select='.year' hx-swap="outerHTML show:window:top" hx-indicator=".htmx-indicator" class="form-select form-control-sm me-1 model-select" aria-label="Default select example"
|
||||||
hx-on::before-request="filter_before_request()"
|
hx-on::before-request="filter_before_request()"
|
||||||
hx-on::after-request="filter_after_request()"
|
hx-on::after-request="filter_after_request()"
|
||||||
>
|
>
|
||||||
@ -92,24 +74,24 @@
|
|||||||
<option value="{{ m.pk }}">{{ m.name }}</option>
|
<option value="{{ m.pk }}">{{ m.name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<select class="form-select year" name="year" aria-label="Default select example">
|
<select class="form-select form-control-sm me-1 year" name="year" aria-label="Default select example">
|
||||||
<option selected="" value="" disabled>Select Year</option>
|
<option selected="" value="" disabled>Select Year</option>
|
||||||
{% for y in year %}
|
{% for y in year %}
|
||||||
<option value="{{ y.0 }}">{{ y.0 }}</option>
|
<option value="{{ y.0 }}">{{ y.0 }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<select class="form-select car_status" name="car_status" aria-label="Default select example">
|
<select class="form-select form-control-sm me-1 car_status" name="car_status" aria-label="Default select example">
|
||||||
<option selected="" value="">All</option>
|
<option selected="" value="">All</option>
|
||||||
<option value="available">Available</option>
|
<option value="available">Available</option>
|
||||||
<option value="reserved">Reserved</option>
|
<option value="reserved">Reserved</option>
|
||||||
<option value="sold">Sold</option>
|
<option value="sold">Sold</option>
|
||||||
<option value="transfer">Transfer</option>
|
<option value="transfer">Transfer</option>
|
||||||
</select>
|
</select>
|
||||||
<button id="search" hx-get="{% url 'car_list' %}" hx-include=".make,.model,.year,.car_status" hx-indicator=".htmx-indicator" hx-target='.table-responsive' hx-select='.table-responsive' hx-swap="outerHTML show:window:top" class="btn btn-sm btn-phoenix-primary"
|
<button id="search" hx-get="{% url 'car_list' %}" hx-include=".make,.model,.year,.car_status" hx-indicator=".htmx-indicator" hx-target='.table-responsive' hx-select='.table-responsive' hx-swap="outerHTML show:window:top" class="btn btn-sm btn-phoenix-primary ms-1"
|
||||||
hx-on::before-request="filter_before_request()"
|
hx-on::before-request="filter_before_request()"
|
||||||
hx-on::after-request="filter_after_request()">Search</button>
|
hx-on::after-request="filter_after_request()">{{ _("Search") }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row">
|
||||||
<div class="table-responsive scrollbar transition">
|
<div class="table-responsive scrollbar transition">
|
||||||
<div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9 border-bottom border-translucent">
|
<div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9 border-bottom border-translucent">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
@ -117,65 +99,62 @@
|
|||||||
<div class="d-flex" hx-boost="true" hx-push-url='false' hx-include=".make,.model,.year,.car_status" hx-target=".table-responsive" hx-select=".table-responsive" hx-swap="innerHTML show:window:top" hx-indicator=".htmx-indicator"
|
<div class="d-flex" hx-boost="true" hx-push-url='false' hx-include=".make,.model,.year,.car_status" hx-target=".table-responsive" hx-select=".table-responsive" hx-swap="innerHTML show:window:top" hx-indicator=".htmx-indicator"
|
||||||
hx-on::before-request="on_before_request()"
|
hx-on::before-request="on_before_request()"
|
||||||
hx-on::after-request="on_after_request()">
|
hx-on::after-request="on_after_request()">
|
||||||
{% if page_obj.has_previous %}
|
|
||||||
<a href="{% url '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>
|
|
||||||
<table class="table fs-9 mb-0 border-top border-translucent">
|
|
||||||
|
<table class="table table-sm fs-9 mb-0 border-top border-translucent">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="sort white-space-nowrap align-middle ps-0" scope="col" data-sort="projectName" style="width:10%;">Make</th>
|
<th class="sort white-space-nowrap align-middle ps-0" scope="col" data-sort="projectName" style="width:10%;">
|
||||||
<th class="sort align-middle ps-3" scope="col" data-sort="assignees" style="width:10%;">Model</th>
|
{{ _("Make") }}</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="assignees" style="width:10%;">{{ _("Model") }}</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="start" style="width:10%;">{{ _("Year") }}</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="deadline" style="width:15%;">{{ _("Trim") }}</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="task" style="width:12%;">{{ _("VIN") }}</th>
|
||||||
|
<th class="sort align-middle ps-3" scope="col" data-sort="task" style="width:12%;">{{ _("Age") }}</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" data-sort="statuses" style="width:10%;">{{ _("Status") }}</th>
|
||||||
<th class="sort align-middle text-end" scope="col" style="width:10%;"></th>
|
<th class="sort align-middle text-end" scope="col" style="width:10%;"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="list" id="project-list-table-body">
|
<tbody class="list" id="project-list-table-body">
|
||||||
{% for car in cars %}
|
{% for car in page_obj %}
|
||||||
<tr class="position-static">
|
<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 time white-space-nowrap ps-0 projectName"><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">
|
<td class="align-middle white-space-nowrap start">
|
||||||
<p class="mb-0 fs-9 text-body">{{car.id_car_model}}</p>
|
<p class="mb-0 fs-9 text-body">{{car.id_car_model}}</p>
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle white-space-nowrap deadline ps-3 py-4">
|
<td class="align-middle white-space-nowrap deadline">
|
||||||
<p class="mb-0 fs-9 text-body">{{car.year}}</p>
|
<p class="mb-0 fs-9 text-body">{{car.year}}</p>
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle white-space-nowrap task ps-3 py-4">
|
<td class="align-middle white-space-nowrap task">
|
||||||
<p class="fw-bo text-body fs-9 mb-0">{{car.id_car_trim}}</p>
|
<p class="fw-bo text-body fs-9 mb-0">{{car.id_car_trim}}</p>
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle white-space-nowrap task ps-3 py-4">
|
<td class="align-middle white-space-nowrap task">
|
||||||
<p class="fw-bo text-body fs-9 mb-0">{{car.vin}}</p>
|
<p class="fw-bo text-body fs-9 mb-0">{{car.vin}}</p>
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle white-space-nowrap task ps-3 py-4">
|
<td class="align-middle white-space-nowrap task">
|
||||||
<p class="fw-bo text-body fs-9 mb-0">{{car.receiving_date}}</p>
|
<p class="fw-bo text-body fs-9 mb-0">{{car.receiving_date|timesince}}</p>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="align-middle white-space-nowrap text-end statuses">
|
<td class="align-middle white-space-nowrap text-end statuses">
|
||||||
{% if car.status == "available" %}
|
{% if car.status == "available" %}
|
||||||
<span class="badge badge-phoenix fs-10 badge-phoenix-success">{{car.status}}</span>
|
<span class="badge badge-phoenix fs-11 badge-phoenix-success">{{car.status}}</span>
|
||||||
{% elif car.status == "reserved" %}
|
{% elif car.status == "reserved" %}
|
||||||
<span class="badge badge-phoenix fs-10 badge-phoenix-danger">{{car.status}}</span>
|
<span class="badge badge-phoenix fs-11 badge-phoenix-danger">{{car.status}}</span>
|
||||||
{% elif car.status == "sold" %}
|
{% elif car.status == "sold" %}
|
||||||
<span class="badge badge-phoenix fs-10 badge-phoenix-info">{{car.status}}</span>
|
<span class="badge badge-phoenix fs-11 badge-phoenix-info">{{car.status}}</span>
|
||||||
{% elif car.status == "transfer" %}
|
{% elif car.status == "transfer" %}
|
||||||
<span class="badge badge-phoenix fs-10 badge-phoenix-warning">{{car.status}}</span>
|
<span class="badge badge-phoenix fs-11 badge-phoenix-warning">{{car.status}}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle text-end white-space-nowrap pe-0 action">
|
<td class="align-middle text-end white-space-nowrap pe-0 action">
|
||||||
<div class="btn-reveal-trigger position-static">
|
<div class="btn-reveal-trigger position-static">
|
||||||
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
|
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
|
||||||
<div class="dropdown-menu dropdown-menu-end py-2"><a class="dropdown-item" href="#!">View</a><a class="dropdown-item" href="#!">Export</a>
|
<div class="dropdown-menu dropdown-menu-end py-2">
|
||||||
<div class="dropdown-divider"></div><a class="dropdown-item text-danger" href="#!">Remove</a>
|
<a class="dropdown-item" href="#!">{{ _("View") }}</a>
|
||||||
|
<a class="dropdown-item" href="#!">{{ _("Export") }}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@ -183,24 +162,21 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9 border-bottom border-translucent">
|
<div class="d-flex 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-include=".make,.model,.year,.car_status" hx-target=".table-responsive" hx-select=".table-responsive" hx-swap="innerHTML" hx-indicator=".htmx-indicator"
|
<div class="d-flex" hx-boost="true" hx-push-url='false' hx-include=".make,.model,.year,.car_status" hx-target=".table-responsive" hx-select=".table-responsive" hx-swap="innerHTML" hx-indicator=".htmx-indicator"
|
||||||
hx-on::before-request="on_before_request()"
|
hx-on::before-request="on_before_request()"
|
||||||
hx-on::after-request="on_after_request()">
|
hx-on::after-request="on_after_request()">
|
||||||
{% if page_obj.has_previous %}
|
|
||||||
<a href="{% url '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>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row d-flex justify-content-end align-items-center p-3">
|
||||||
|
{% if is_paginated %}
|
||||||
|
{% include 'partials/pagination.html' %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -226,6 +202,8 @@
|
|||||||
}
|
}
|
||||||
function toggle_filter(){
|
function toggle_filter(){
|
||||||
document.querySelector('.filter').classList.toggle('d-none')
|
document.querySelector('.filter').classList.toggle('d-none')
|
||||||
|
document.querySelector('.filter-icon').classList.toggle("fa-caret-down");
|
||||||
|
document.querySelector('.filter-icon').classList.toggle("fa-caret-up");
|
||||||
}
|
}
|
||||||
function filter_before_request(){
|
function filter_before_request(){
|
||||||
document.querySelector('.model-select').setAttribute('disabled', true)
|
document.querySelector('.model-select').setAttribute('disabled', true)
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<!-- Display Form Errors -->
|
<!-- Display Form Errors -->
|
||||||
{% if form.errors %}
|
{% if form.errors %}
|
||||||
<div class="alert alert-danger">
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||||
<ul>
|
<ul>
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
{% for error in field.errors %}
|
{% for error in field.errors %}
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
<table class="table fs-9 mb-0 border-top border-translucent">
|
<table class="table fs-9 mb-0 border-top border-translucent">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Estimate Number" %}</th>
|
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Quotation Number" %}</th>
|
||||||
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Customer" %}</th>
|
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Customer" %}</th>
|
||||||
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Status" %}</th>
|
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Status" %}</th>
|
||||||
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Status Date" %}</th>
|
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Status Date" %}</th>
|
||||||
@ -23,7 +23,7 @@
|
|||||||
{% for estimate in estimates %}
|
{% for estimate in estimates %}
|
||||||
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
||||||
<td class="align-middle product white-space-nowrap py-0">{{ estimate.estimate_number }}</td>
|
<td class="align-middle product white-space-nowrap py-0">{{ estimate.estimate_number }}</td>
|
||||||
<td class="align-middle product white-space-nowrap">{{ estimate.customer }}</td>
|
<td class="align-middle product white-space-nowrap">{{ estimate.customer.customer_name }}</td>
|
||||||
<td class="align-middle product white-space-nowrap">
|
<td class="align-middle product white-space-nowrap">
|
||||||
{% if estimate.status == 'draft' %}
|
{% if estimate.status == 'draft' %}
|
||||||
<span class="badge badge-phoenix badge-phoenix-warning">{% trans "Draft" %}</span>
|
<span class="badge badge-phoenix badge-phoenix-warning">{% trans "Draft" %}</span>
|
||||||
@ -48,6 +48,10 @@
|
|||||||
class="btn btn-sm btn-phoenix-success">
|
class="btn btn-sm btn-phoenix-success">
|
||||||
{% trans "view"|capfirst %}
|
{% trans "view"|capfirst %}
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{% url 'estimate_detail' estimate.pk %}"
|
||||||
|
class="btn btn-sm btn-phoenix-success">
|
||||||
|
{% trans "pdf"|capfirst %}
|
||||||
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
|
|||||||
@ -118,11 +118,11 @@
|
|||||||
hx-on::before-request="on_before_request()"
|
hx-on::before-request="on_before_request()"
|
||||||
hx-on::after-request="on_after_request()">
|
hx-on::after-request="on_after_request()">
|
||||||
{% if page_obj.has_previous %}
|
{% 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>
|
<a href="{% url 'sales_list' %}?page={{page_obj.previous_page_number}}" class="page-link" data-list-pagination="prev"><span class="fas fa-chevron-left"></span></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<ul class="mb-0 pagination">Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</ul>
|
<ul class="mb-0 pagination">Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</ul>
|
||||||
{% if page_obj.has_next %}
|
{% 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>
|
<a href="{% url 'sales_list' %}?page={{page_obj.next_page_number}}" class="page-link pe-0" data-list-pagination="next"><span class="fas fa-chevron-right"></span></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
39
test.json
Normal file
39
test.json
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
{
|
||||||
|
"type": "customer",
|
||||||
|
"customer_info":
|
||||||
|
{
|
||||||
|
"first_name": "firstNameT",
|
||||||
|
"first_name_arabic": "firstName",
|
||||||
|
"middle_name": "fatherNameT",
|
||||||
|
"middle_name_arabic": "fatherName",
|
||||||
|
"last_name": "familyNameT",
|
||||||
|
"last_name_arabic": "familyName",
|
||||||
|
"national_id": "id",
|
||||||
|
"birth_date": "birthDate",
|
||||||
|
"nationality": "nationalityDescEn"
|
||||||
|
},
|
||||||
|
|
||||||
|
"elm":
|
||||||
|
{
|
||||||
|
"birthDate": "1985-12-20",
|
||||||
|
"familyName": "العنزي",
|
||||||
|
"familyNameT": "Alenazi",
|
||||||
|
"fatherName": "الراوي",
|
||||||
|
"fatherNameT": "Alrawi",
|
||||||
|
"firstName": "هليل",
|
||||||
|
"firstNameT": "Hilayel",
|
||||||
|
"grandFatherName": "عثمان",
|
||||||
|
"grandFatherNameT": "Othman",
|
||||||
|
"hasIdExpired": 2,
|
||||||
|
"id": 1020060808,
|
||||||
|
"idExpirationDate": "2029-01-15",
|
||||||
|
"nationalityCode": 100,
|
||||||
|
"nationalityDescAr": "سعودي",
|
||||||
|
"nationalityDescEn": "Saudi",
|
||||||
|
"sexCode": 1,
|
||||||
|
"sexDescAr": "ذكر",
|
||||||
|
"sexDescEn": "Male"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user