Compare commits

...

6 Commits

Author SHA1 Message Date
92a2fd7067 check 2025-09-01 10:57:49 +03:00
cc1c70a19e plan and sale_report 2025-09-01 10:56:17 +03:00
d3dcb85fa3 update 2025-09-01 09:42:32 +03:00
f4f0e842b8 test stage 2025-09-01 09:02:27 +03:00
f51ce25790 small update 2025-08-31 19:33:16 +03:00
5416a9f90b Merge pull request 'charts , phonenumber and profile picture fix' (#212) from frontend into main
Reviewed-on: #212
2025-08-31 19:33:14 +03:00
15 changed files with 300 additions and 128 deletions

View File

@ -12,12 +12,9 @@ find ./haikalbot -type d -iname "__pycache__"|xargs rm -rf
echo "Apply Base Migrate" echo "Apply Base Migrate"
python3 manage.py migrate python3 manage.py migrate
echo "Apply makemigrations"
python3 manage.py makemigrations python3 manage.py makemigrations
echo "Apply Appointment Migratinos"
python3 manage.py makemigrations appointment
echo "Apply Final Migrate" echo "Apply Final Migrate"
python3 manage.py migrate python3 manage.py migrate

View File

@ -2,7 +2,7 @@ from django.core.cache import cache
from datetime import datetime from datetime import datetime
from luhnchecker.luhn import Luhn from luhnchecker.luhn import Luhn
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from appointment.models import Service # from appointment.models import Service
from django.core.validators import MinLengthValidator from django.core.validators import MinLengthValidator
from django import forms from django import forms
from plans.models import PlanPricing from plans.models import PlanPricing
@ -121,12 +121,12 @@ class StaffForm(forms.ModelForm):
widget=forms.EmailInput(attrs={"class": "form-control form-control-sm"}), widget=forms.EmailInput(attrs={"class": "form-control form-control-sm"}),
) )
service_offered = forms.ModelMultipleChoiceField( # service_offered = forms.ModelMultipleChoiceField(
label=_("Services Offered"), # label=_("Services Offered"),
widget=forms.CheckboxSelectMultiple(attrs={"class": "form-check-input"}), # widget=forms.CheckboxSelectMultiple(attrs={"class": "form-check-input"}),
queryset=Service.objects.all(), # # queryset=Service.objects.all(),
required=False, # required=False,
) # )
# phone_number = SaudiPhoneNumberField( # phone_number = SaudiPhoneNumberField(
# required=False, # required=False,
# widget=forms.TextInput( # widget=forms.TextInput(

View File

@ -47,3 +47,4 @@ class Command(BaseCommand):
codename="can_approve_estimatemodel", codename="can_approve_estimatemodel",
content_type=ContentType.objects.get_for_model(EstimateModel), content_type=ContentType.objects.get_for_model(EstimateModel),
) )

View File

@ -43,31 +43,31 @@ class Command(BaseCommand):
) )
# Assign quotas to plans # Assign quotas to plans
PlanQuota.objects.create(plan=basic_plan, quota=users_quota, value=4) PlanQuota.objects.create(plan=basic_plan, quota=users_quota, value=99999)
PlanQuota.objects.create(plan=basic_plan, quota=cars_quota, value=4) PlanQuota.objects.create(plan=basic_plan, quota=cars_quota, value=99999)
PlanQuota.objects.create(plan=pro_plan, quota=users_quota, value=5) PlanQuota.objects.create(plan=pro_plan, quota=users_quota, value=99999)
PlanQuota.objects.create(plan=pro_plan, quota=cars_quota, value=5) PlanQuota.objects.create(plan=pro_plan, quota=cars_quota, value=99999)
PlanQuota.objects.create(plan=enterprise_plan, quota=users_quota, value=10) PlanQuota.objects.create(plan=enterprise_plan, quota=users_quota, value=99999)
PlanQuota.objects.create(plan=enterprise_plan, quota=cars_quota, value=10) PlanQuota.objects.create(plan=enterprise_plan, quota=cars_quota, value=99999)
# PlanQuota.objects.create(plan=pro_plan, quota=project_quota, value=50) # PlanQuota.objects.create(plan=pro_plan, quota=project_quota, value=50)
# PlanQuota.objects.create(plan=pro_plan, quota=storage_quota, value=100) # PlanQuota.objects.create(plan=pro_plan, quota=storage_quota, value=100)
# Define pricing # Define pricing
basic_pricing = Pricing.objects.create(name="Monthly", period=30) basic_pricing = Pricing.objects.create(name="3 Months", period=90)
pro_pricing = Pricing.objects.create(name="Monthly", period=30) pro_pricing = Pricing.objects.create(name="6 Months", period=180)
enterprise_pricing = Pricing.objects.create(name="Monthly", period=30) enterprise_pricing = Pricing.objects.create(name="1 Year", period=365)
PlanPricing.objects.create( PlanPricing.objects.create(
plan=basic_plan, pricing=basic_pricing, price=Decimal("9.99") plan=basic_plan, pricing=basic_pricing, price=Decimal("2500.00")
) )
PlanPricing.objects.create( PlanPricing.objects.create(
plan=pro_plan, pricing=pro_pricing, price=Decimal("19.99") plan=pro_plan, pricing=pro_pricing, price=Decimal("4500.00")
) )
PlanPricing.objects.create( PlanPricing.objects.create(
plan=enterprise_plan, pricing=enterprise_pricing, price=Decimal("29.99") plan=enterprise_plan, pricing=enterprise_pricing, price=Decimal("8500.00")
) )
# # Create quotas # # Create quotas

View File

@ -5,7 +5,7 @@ from django.urls import reverse
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.db.models.signals import post_save, post_delete from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver from django.dispatch import receiver
from appointment.models import Service # from appointment.models import Service
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model

View File

@ -276,7 +276,7 @@ urlpatterns = [
), ),
# ####################### # #######################
# ####################### # #######################
path("crm/calender/", views.EmployeeCalendarView.as_view(), name="calendar_list"), # path("crm/calender/", views.EmployeeCalendarView.as_view(), name="calendar_list"),
####################################################### #######################################################
# Vendor URLs # Vendor URLs
####################################################### #######################################################

View File

@ -196,7 +196,7 @@ from django_ledger.views.mixins import (
from . import models, forms, tables from . import models, forms, tables
from django_tables2 import SingleTableView from django_tables2 import SingleTableView
from django_tables2.export.views import ExportMixin from django_tables2.export.views import ExportMixin
from appointment.models import Appointment, AppointmentRequest, Service, StaffMember # from appointment.models import Appointment, AppointmentRequest, Service, StaffMember
from .services import ( from .services import (
decodevin, decodevin,
get_make, get_make,
@ -3734,7 +3734,6 @@ class UserUpdateView(
# self.object.staff_member.services_offered.add(service) # self.object.staff_member.services_offered.add(service)
staff = form.save(commit=False) staff = form.save(commit=False)
print(form.cleaned_data)
# staff.name = form.cleaned_data["name"] # staff.name = form.cleaned_data["name"]
staff.arabic_name = form.cleaned_data["arabic_name"] staff.arabic_name = form.cleaned_data["arabic_name"]
staff.phone_number = form.cleaned_data["phone_number"] staff.phone_number = form.cleaned_data["phone_number"]
@ -9012,40 +9011,40 @@ class PnLAPIView(DjangoLedgerSecurityMixIn, EntityUnitMixIn, View):
return JsonResponse({"message": _("Unauthorized")}, status=401) return JsonResponse({"message": _("Unauthorized")}, status=401)
class EmployeeCalendarView(LoginRequiredMixin, ListView): # class EmployeeCalendarView(LoginRequiredMixin, ListView):
""" # """
Provides a view for displaying the employee's calendar in a list format. # Provides a view for displaying the employee's calendar in a list format.
Displays a list of appointments for logged-in users. This view ensures that # Displays a list of appointments for logged-in users. This view ensures that
only appointments relevant to the logged-in user as a dealer or staff member # only appointments relevant to the logged-in user as a dealer or staff member
are displayed. Supports search functionality to filter displayed appointments # are displayed. Supports search functionality to filter displayed appointments
based on provided query parameters. # based on provided query parameters.
:ivar template_name: Path to the HTML template used to render the view. # :ivar template_name: Path to the HTML template used to render the view.
:type template_name: str # :type template_name: str
:ivar model: Model object to interact with appointments data. # :ivar model: Model object to interact with appointments data.
:type model: Appointment # :type model: Appointment
:ivar context_object_name: Name of the context variable that contains the # :ivar context_object_name: Name of the context variable that contains the
list of appointments in the template. # list of appointments in the template.
:type context_object_name: str # :type context_object_name: str
""" # """
template_name = "crm/employee_calendar.html" # template_name = "crm/employee_calendar.html"
model = Appointment # model = Appointment
context_object_name = "appointments" # context_object_name = "appointments"
def get_queryset(self): # def get_queryset(self):
query = self.request.GET.get("q") # query = self.request.GET.get("q")
staff = getattr(self.request, "staff", None) # staff = getattr(self.request, "staff", None)
if staff: # if staff:
appointments = Appointment.objects.filter( # appointments = Appointment.objects.filter(
appointment_request__staff_member=staff, # appointment_request__staff_member=staff,
ppointment_request__date__gt=timezone.now(), # ppointment_request__date__gt=timezone.now(),
) # )
appointments = Appointment.objects.filter( # appointments = Appointment.objects.filter(
appointment_request__date__gt=timezone.now() # appointment_request__date__gt=timezone.now()
) # )
return apply_search_filters(appointments, query) # return apply_search_filters(appointments, query)
def apply_search_filters(queryset, query): def apply_search_filters(queryset, query):
@ -9809,7 +9808,7 @@ def payment_callback(request, dealer_slug):
UserPlan.objects.create( UserPlan.objects.create(
user=order.user, user=order.user,
plan=order.plan, plan=order.plan,
expire=datetime.now().date() + timedelta(days=order.get_plan_pricing().pricing.period) expire=datetime.now().date() + timedelta(days=order.get_plan_pricing().pricing.period + 30)
) )
logger.info(f"Created new UserPlan for user {order.user} with plan {order.plan}.") logger.info(f"Created new UserPlan for user {order.user} with plan {order.plan}.")
else: else:

View File

@ -26,6 +26,4 @@ python3 manage.py tenhal_plan
python3 manage.py set_custom_permissions python3 manage.py set_custom_permissions
python3 manage.py initial_services_offered
echo "Done" echo "Done"

Binary file not shown.

View File

@ -9305,10 +9305,8 @@ msgstr "سعر البيع"
#: inventory/models.py:705 templates/inventory/car_detail.html:267 #: inventory/models.py:705 templates/inventory/car_detail.html:267
#: templates/ledger/reports/car_sale_report.html:237 #: templates/ledger/reports/car_sale_report.html:237
#, fuzzy
#| msgid "Agreed Price"
msgid "Marked Price" msgid "Marked Price"
msgstr "السعر المتفق عليه" msgstr "سعر العرض"
#: inventory/models.py:711 templates/ledger/reports/car_sale_report.html:238 #: inventory/models.py:711 templates/ledger/reports/car_sale_report.html:238
#: templates/sales/estimates/estimate_detail.html:259 #: templates/sales/estimates/estimate_detail.html:259

155
requirements_dev1.txt Normal file
View File

@ -0,0 +1,155 @@
annotated-types==0.7.0
anyio==4.9.0
arrow==1.3.0
asgiref==3.9.1
attrs==25.3.0
autobahn==24.4.2
Automat==25.4.16
Babel==2.15.0
beautifulsoup4==4.13.4
blessed==1.21.0
cattrs==25.1.1
certifi==2025.7.9
cffi==1.17.1
channels==4.2.2
charset-normalizer==3.4.2
click==8.2.1
colorama==0.4.6
constantly==23.10.4
crispy-bootstrap5==2025.6
cryptography==45.0.5
cssbeautifier==1.15.4
daphne==4.2.1
defusedxml==0.7.1
diff-match-patch==20241021
distro==1.9.0
Django==5.2.4
django-allauth==65.10.0
django-appconf==1.1.0
django-appointment==3.8.0
django-background-tasks==1.2.8
django-bootstrap5==25.1
django-ckeditor==6.7.3
django-cors-headers==4.7.0
django-countries==7.6.1
django-crispy-forms==2.4
django-debug-toolbar==5.2.0
django-easy-audit==1.3.7
django-extensions==4.1
django-filter==25.1
django-imagekit==5.0.0
django-import-export==4.3.8
django-js-asset==3.1.2
django-ledger==0.7.6.1
django-manager-utils==3.1.5
django-next-url-mixin==0.4.0
django-ordered-model==3.7.4
django-phonenumber-field==8.0.0
django-picklefield==3.3
django-plans==2.0.0
django-prometheus==2.4.1
django-q2==1.8.0
django-query-builder==3.2.0
django-schema-graph==3.1.0
django-sequences==3.0
django-tables2==2.7.5
django-treebeard==4.7.1
django-widget-tweaks==1.5.0
djangorestframework==3.16.0
djhtml==3.0.8
djlint==1.36.4
docopt==0.6.2
EditorConfig==0.17.1
Faker==37.4.0
fleming==0.7.0
fonttools==4.58.5
fpdf==1.7.2
fpdf2==2.8.3
greenlet==3.2.3
gunicorn==23.0.0
h11==0.16.0
h2==4.2.0
hpack==4.1.0
httpcore==1.0.9
httpx==0.28.1
hyperframe==6.1.0
hyperlink==21.0.0
icalendar==6.3.1
idna==3.10
incremental==24.7.2
jiter==0.10.0
jsbeautifier==1.15.4
json5==0.12.0
jsonpatch==1.33
jsonpointer==3.0.0
jwt==1.4.0
langchain==0.3.26
langchain-core==0.3.68
langchain-ollama==0.3.4
langchain-text-splitters==0.3.8
langsmith==0.4.4
luhnchecker==0.0.12
Markdown==3.8.2
markdown-it-py==3.0.0
mdurl==0.1.2
num2words==0.5.14
numpy==2.3.1
ofxtools==0.9.5
ollama==0.5.1
openai==1.93.3
opencv-python==4.11.0.86
orjson==3.10.18
packaging==24.2
pandas==2.3.1
pathspec==0.12.1
phonenumbers==8.13.42
pilkit==3.0
pillow==10.4.0
priority==1.3.0
prometheus_client==0.22.1
psycopg2-binary==2.9.10
pyasn1==0.6.1
pyasn1_modules==0.4.2
pycparser==2.22
pydantic==2.11.7
pydantic_core==2.33.2
Pygments==2.19.2
pyOpenSSL==25.1.0
python-dateutil==2.9.0.post0
python-slugify==8.0.4
python-stdnum==2.1
pytz==2025.2
pyvin==0.0.2
PyYAML==6.0.2
pyzbar==0.1.9
redis==6.2.0
regex==2024.11.6
requests==2.32.4
requests-toolbelt==1.0.0
rich==14.0.0
ruff==0.12.2
service-identity==24.2.0
setuptools==80.9.0
six==1.17.0
sniffio==1.3.1
soupsieve==2.7
SQLAlchemy==2.0.41
sqlparse==0.5.3
suds==1.2.0
swapper==1.3.0
tablib==3.8.0
tenacity==9.1.2
text-unidecode==1.3
tqdm==4.67.1
Twisted==25.5.0
txaio==25.6.1
types-python-dateutil==2.9.0.20250708
typing-inspection==0.4.1
typing_extensions==4.14.1
tzdata==2025.2
urllib3==2.5.0
uvicorn==0.35.0
uvicorn-worker==0.3.0
wcwidth==0.2.13
zope.interface==7.2
zstandard==0.23.0

View File

@ -372,7 +372,11 @@
hideLoading(); hideLoading();
const data = await response.json(); const data = await response.json();
if (response.ok) { if (response.ok) {
notify("success","{% trans'Account created successfully'%}"); <<<<<<< HEAD
notify("success","{% trans 'Account created successfully'%}");
=======
notify("success","Account created successfully");
>>>>>>> d3dcb85fa378e156b77550e8ab833ad10ffad51f
setTimeout(() => { setTimeout(() => {
window.location.href = "{% url 'account_login' %}"; window.location.href = "{% url 'account_login' %}";
}, 1000); }, 1000);

View File

@ -68,7 +68,7 @@
<div class="col-12 col-sm-auto d-flex align-items-center justify-content-around flex-wrap mt-3 mt-sm-0"> <div class="col-12 col-sm-auto d-flex align-items-center justify-content-around flex-wrap mt-3 mt-sm-0">
<div class="text-center mx-3 mb-2 mb-sm-0"> <div class="text-center mx-3 mb-2 mb-sm-0">
<h6 class="mb-2 text-body-secondary">{% trans 'Total users'|capfirst %}</h6> <h6 class="mb-2 text-body-secondary">{% trans 'Total users'|capfirst %}</h6>
<h4 class="fs-7 text-body-highlight mb-2">{{ dealer.staff_count }} / {{ allowed_users }}</h4> <h4 class="fs-7 text-body-highlight mb-2">{{ dealer.staff_count }}</h4>
<div class="progress" style="height: 5px; width: 100px;"> <div class="progress" style="height: 5px; width: 100px;">
<div class="progress-bar bg-success" <div class="progress-bar bg-success"
role="progressbar" role="progressbar"
@ -80,7 +80,7 @@
</div> </div>
<div class="text-center mx-3 mb-2 mb-sm-0"> <div class="text-center mx-3 mb-2 mb-sm-0">
<h6 class="mb-2 text-body-secondary">{% trans 'Total cars'|capfirst %}</h6> <h6 class="mb-2 text-body-secondary">{% trans 'Total cars'|capfirst %}</h6>
<h4 class="fs-7 text-body-highlight mb-2">{{ cars_count }} / {{ allowed_cars }}</h4> <h4 class="fs-7 text-body-highlight mb-2">{{ cars_count }}</h4>
<div class="progress" style="height: 5px; width: 100px;"> <div class="progress" style="height: 5px; width: 100px;">
<div class="progress-bar bg-info" <div class="progress-bar bg-info"
role="progressbar" role="progressbar"
@ -150,56 +150,56 @@
<div class="d-flex align-items-center justify-content-between mb-3"> <div class="d-flex align-items-center justify-content-between mb-3">
<h3 class="mb-0">{{ dealer.user.userplan.plan|capfirst }}</h3> <h3 class="mb-0">{{ dealer.user.userplan.plan|capfirst }}</h3>
{% if dealer.user.userplan and not dealer.user.userplan.is_expired %} {% if dealer.user.userplan and not dealer.user.userplan.is_expired %}
<span class="badge bg-success-subtle text-success">{{ _("Active") }}</span> <span class="badge bg-success-subtle text-success">{{ _("Active") }}</span>
{% elif dealer.user.userplan and dealer.user.userplan.is_expired %} {% elif dealer.user.userplan and dealer.user.userplan.is_expired %}
<span class="badge bg-danger-subtle text-danger">{{ _("Expired") }}</span> <span class="badge bg-danger-subtle text-danger">{{ _("Expired") }}</span>
{% else %} {% else %}
<span class="badge bg-warning-subtle text-warning">{{ _("No Active Plan") }}</span> <span class="badge bg-warning-subtle text-warning">{{ _("No Active Plan") }}</span>
{% endif %} {% endif %}
</div> </div>
<p class="fs-9 text-body-secondary"> <p class="fs-9 text-body-secondary">
{% if dealer.user.userplan and not dealer.user.userplan.is_expired %} {% if dealer.user.userplan and not dealer.user.userplan.is_expired %}
{% trans 'Active until' %}: {{ dealer.user.userplan.expire }} &nbsp; <small>{% trans 'Days left' %}: {{ dealer.user.userplan.days_left }}</small> {% trans 'Active until' %}: {{ dealer.user.userplan.expire }} &nbsp; <small>{% trans 'Days left' %}: {{ dealer.user.userplan.days_left }}</small>
{% else %} {% else %}
{% trans 'Please subscribe or renew your plan to continue using our services.' %} {% trans 'Please subscribe or renew your plan to continue using our services.' %}
{% endif %} {% endif %}
</p> </p>
<div class="d-flex align-items-end mb-3"> <div class="d-flex align-items-end mb-3">
<h4 class="fw-bolder me-1"> <h4 class="fw-bolder me-1">
{{ dealer.user.userplan.plan.planpricing_set.first.price }} <span class="icon-saudi_riyal"></span> {{ dealer.user.userplan.plan.planpricing_set.first.price }} <span class="icon-saudi_riyal"></span>
</h4> </h4>
<h5 class="fs-9 fw-normal text-body-tertiary ms-1">{{ _("Per month") }}</h5> <h5 class="fs-9 fw-normal text-body-tertiary ms-1">{{ _("Per month") }}</h5>
</div> </div>
<ul class="list-unstyled mb-4"> <ul class="list-unstyled mb-4">
{% for line in dealer.user.userplan.plan.description|splitlines %} {% for line in dealer.user.userplan.plan.description|splitlines %}
<li class="d-flex align-items-center mb-1"> <li class="d-flex align-items-center mb-1">
<span class="uil uil-check-circle text-success me-2"></span> <span class="uil uil-check-circle text-success me-2"></span>
<span class="text-body-secondary">{{ line }}</span> <span class="text-body-secondary">{{ line }}</span>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
{% comment %} <div class="d-flex justify-content-end gap-2"> {% comment %} <div class="d-flex justify-content-end gap-2">
{% if dealer.user.userplan.is_expired %} {% if dealer.user.userplan.is_expired %}
<a href="{% url 'pricing_page' request.dealer.slug %}" class="btn btn-warning"><span class="fas fa-redo-alt me-2"></span>{{ _("Renew") }}</a> <a href="{% url 'pricing_page' request.dealer.slug %}" class="btn btn-warning"><span class="fas fa-redo-alt me-2"></span>{{ _("Renew") }}</a>
{% endif %} {% endif %}
{% if dealer.user.userplan.plan.name != "Enterprise" %} {% if dealer.user.userplan.plan.name != "Enterprise" %}
<a href="{% url 'pricing_page' request.dealer.slug %}" class="btn btn-primary"><span class="fas fa-rocket me-2"></span>{{ _("Upgrade Plan") }}</a> <a href="{% url 'pricing_page' request.dealer.slug %}" class="btn btn-primary"><span class="fas fa-rocket me-2"></span>{{ _("Upgrade Plan") }}</a>
{% endif %} {% endif %}
{% if not dealer.user.userplan %} {% if not dealer.user.userplan %}
<a href="{% url 'pricing_page' request.dealer.slug %}" class="btn btn-success"><span class="fas fa-cart-plus me-2"></span>{{ _("Subscribe Now") }}</a> <a href="{% url 'pricing_page' request.dealer.slug %}" class="btn btn-success"><span class="fas fa-cart-plus me-2"></span>{{ _("Subscribe Now") }}</a>
{% endif %} {% endif %}
</div> {% endcomment %} </div> {% endcomment %}
<div class="d-flex justify-content-end gap-2"> <div class="d-flex justify-content-end gap-2">
{% if not dealer.user.userplan %} {% if not dealer.user.userplan %}
<a href="{% url 'pricing_page' request.dealer.slug %}" <a href="{% url 'pricing_page' request.dealer.slug %}"
class="btn btn-outline-primary"><span class="fas fa-cart-plus me-2"></span>{{ _("Subscribe Now") }}</a> class="btn btn-outline-primary"><span class="fas fa-cart-plus me-2"></span>{{ _("Subscribe Now") }}</a>
{% elif dealer.user.userplan.is_expired %} {% elif dealer.user.userplan.is_expired %}
<a href="{% url 'pricing_page' request.dealer.slug %}" <a href="{% url 'pricing_page' request.dealer.slug %}"
class="btn btn-outline-warning"><span class="fas fa-redo-alt me-2"></span>{{ _("Renew") }}</a> class="btn btn-outline-warning"><span class="fas fa-redo-alt me-2"></span>{{ _("Renew") }}</a>
{% elif dealer.user.userplan.plan.name != "Enterprise" %} {% elif dealer.user.userplan.plan.name != "Enterprise" %}
<a href="{% url 'pricing_page' request.dealer.slug %}" <a href="{% url 'pricing_page' request.dealer.slug %}"
class="btn btn-outline-primary"><span class="fas fa-rocket me-2"></span>{{ _("Upgrade Plan") }}</a> class="btn btn-outline-primary"><span class="fas fa-rocket me-2"></span>{{ _("Upgrade Plan") }}</a>
{% endif %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
@ -221,8 +221,8 @@
aria-valuemax="100"></div> aria-valuemax="100"></div>
</div> </div>
<div class="d-flex justify-content-between text-body-secondary fs-9 mt-2"> <div class="d-flex justify-content-between text-body-secondary fs-9 mt-2">
<span>{{ _("Used") }}: {{ dealer.staff_count }}</span> <span>{{ _("Used") }}: {{ dealer.staff_count }}</span>
<span>{{ _("Limit") }}: {{ allowed_users }}</span>
</div> </div>
</div> </div>
<div class="mb-4"> <div class="mb-4">
@ -236,8 +236,8 @@
aria-valuemax="100"></div> aria-valuemax="100"></div>
</div> </div>
<div class="d-flex justify-content-between text-body-secondary fs-9 mt-2"> <div class="d-flex justify-content-between text-body-secondary fs-9 mt-2">
<span>{{ _("Used") }}: {{ cars_count }}</span> <span>{{ _("Used") }}: {{ cars_count }}</span>
<span>{{ _("Limit") }}: {{ allowed_cars }}</span>
</div> </div>
</div> </div>
<small class="text-body-secondary mt-auto">{{ _("Contact support to increase your limits") }}</small> <small class="text-body-secondary mt-auto">{{ _("Contact support to increase your limits") }}</small>
@ -258,22 +258,22 @@
<div class="d-flex align-items-center mb-3"> <div class="d-flex align-items-center mb-3">
<span class="fas fa-location-dot me-3 text-primary"></span> <span class="fas fa-location-dot me-3 text-primary"></span>
<div> <div>
<h6 class="mb-0">{% trans 'Address' %}</h6> <h6 class="mb-0">{% trans 'Address' %}</h6>
<p class="mb-0 text-body-secondary">{{ dealer.address }}</p> <p class="mb-0 text-body-secondary">{{ dealer.address }}</p>
</div> </div>
</div> </div>
<div class="d-flex align-items-center mb-3"> <div class="d-flex align-items-center mb-3">
<span class="fas fa-envelope me-3 text-info"></span> <span class="fas fa-envelope me-3 text-info"></span>
<div> <div>
<h6 class="mb-0">{% trans 'Email' %}</h6> <h6 class="mb-0">{% trans 'Email' %}</h6>
<p class="mb-0 text-body-secondary">{{ dealer.user.email }}</p> <p class="mb-0 text-body-secondary">{{ dealer.user.email }}</p>
</div> </div>
</div> </div>
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<span class="fas fa-phone me-3 text-success"></span> <span class="fas fa-phone me-3 text-success"></span>
<div> <div>
<h6 class="mb-0">{% trans 'Phone' %}</h6> <h6 class="mb-0">{% trans 'Phone' %}</h6>
<p class="mb-0 text-body-secondary" dir="ltr">{{ dealer.phone_number }}</p> <p class="mb-0 text-body-secondary" dir="ltr">{{ dealer.phone_number }}</p>
</div> </div>
</div> </div>
</div> </div>
@ -285,11 +285,11 @@
<h5 class="mb-3">{{ _("VAT Information") }}</h5> <h5 class="mb-3">{{ _("VAT Information") }}</h5>
<form action="{% url 'dealer_vat_rate_update' request.dealer.slug %}" <form action="{% url 'dealer_vat_rate_update' request.dealer.slug %}"
method="post"> method="post">
{% csrf_token %} {% csrf_token %}
{{ vatform|crispy }} {{ vatform|crispy }}
<button class="btn btn-phoenix-primary mt-3" type="submit"> <button class="btn btn-phoenix-primary mt-3" type="submit">
<i class="fa-solid fa-pen-to-square me-1"></i>{% trans 'Update VAT' %} <i class="fa-solid fa-pen-to-square me-1"></i>{% trans 'Update VAT' %}
</button> </button>
</form> </form>
</div> </div>
</div> </div>
@ -304,21 +304,21 @@
<div class="card-body"> <div class="card-body">
<h5 class="mb-4">{{ _("Makes you are selling") }}</h5> <h5 class="mb-4">{{ _("Makes you are selling") }}</h5>
<div class="d-flex flex-wrap gap-3 mb-4"> <div class="d-flex flex-wrap gap-3 mb-4">
{% for make in car_makes %} {% for make in car_makes %}
<div class="text-center p-2 border rounded-3"> <div class="text-center p-2 border rounded-3">
{% if make.logo %} {% if make.logo %}
<img src="{{ make.logo.url }}" <img src="{{ make.logo.url }}"
alt="{{ make.get_local_name }}" alt="{{ make.get_local_name }}"
class="rounded" class="rounded"
style="height: 48px; style="height: 48px;
width: auto; width: auto;
background-color:white" /> background-color:white" />
{% endif %} {% endif %}
<p class="fs-8 text-body-secondary mt-1 mb-0">{{ make.get_local_name }}</p> <p class="fs-8 text-body-secondary mt-1 mb-0">{{ make.get_local_name }}</p>
</div> </div>
{% empty %} {% empty %}
<p class="text-body-secondary">{{ _("No car makes selected.") }}</p> <p class="text-body-secondary">{{ _("No car makes selected.") }}</p>
{% endfor %} {% endfor %}
</div> </div>
<a class="btn btn-phoenix-warning" <a class="btn btn-phoenix-warning"
href="{% url 'assign_car_makes' request.dealer.slug %}"><span class="fas fa-plus me-2"></span>{{ _("Select Makes") }}</a> href="{% url 'assign_car_makes' request.dealer.slug %}"><span class="fas fa-plus me-2"></span>{{ _("Select Makes") }}</a>
@ -331,4 +331,4 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -238,10 +238,10 @@
class="btn btn-phoenix-primary btn-sm mt-1 me-3 mb-3">{% trans "Edit" %} class="btn btn-phoenix-primary btn-sm mt-1 me-3 mb-3">{% trans "Edit" %}
<span class="fas fa-solid fa-pencil ms-1"></span> <span class="fas fa-solid fa-pencil ms-1"></span>
</a> </a>
<a href="{% url 'transfer' car.slug %}" {% comment %} <a href="{% url 'transfer' car.slug %}"
class="btn btn-phoenix-danger btn-sm"> class="btn btn-phoenix-danger btn-sm">
{% trans "Sell to another dealer"|capfirst %} {% trans "Sell to another dealer"|capfirst %}
</a> </a> TODO: for future {% endcomment %}
{% endif %} {% endif %}
{% else %} {% else %}
<span class="badge bg-danger">{% trans "Cannot Edit, Car in Transfer." %}</span> <span class="badge bg-danger">{% trans "Cannot Edit, Car in Transfer." %}</span>
@ -267,7 +267,7 @@
<th>{% trans "Marked Price"|capfirst %}</th> <th>{% trans "Marked Price"|capfirst %}</th>
<td>{{ car.marked_price|floatformat:2 }}</td> <td>{{ car.marked_price|floatformat:2 }}</td>
</tr> </tr>
<tr> <tr>
<td colspan="2"> <td colspan="2">
{% if not car.get_transfer %} {% if not car.get_transfer %}

View File

@ -47,7 +47,7 @@
<p class="text-muted">{% trans 'Report Date' %}: {{ current_time }}</p> <p class="text-muted">{% trans 'Report Date' %}: {{ current_time }}</p>
</header> </header>
<main> <main>
<section id="filters" class="mb-5 p-4 rounded border border-primary"> <section id="filters" class="mb-5 p-4 rounded border border-primary">
<h2 class="section-heading mb-4"> <h2 class="section-heading mb-4">
{% trans 'Filters' %} <i class="fas fa-sliders-h ms-2"></i> {% trans 'Filters' %} <i class="fas fa-sliders-h ms-2"></i>
</h2> </h2>
@ -58,7 +58,8 @@
<option value="">{% trans 'All Makes' %}</option> <option value="">{% trans 'All Makes' %}</option>
{% for make in makes %} {% for make in makes %}
<option value="{{ make }}" {% if make == selected_make %}selected{% endif %}>{{ make }}</option> <option value="{{ make }}" {% if make == selected_make %}selected{% endif %}>{{ make }}</option>
{% endfor %} {% endfor %}
</select>
</div> </div>
<div class="col-md-2"> <div class="col-md-2">
<label for="model-select" class="form-label">{% trans 'Model' %}</label> <label for="model-select" class="form-label">{% trans 'Model' %}</label>
@ -111,7 +112,26 @@
</div> </div>
</form> </form>
</section> </section>
<!---->
{% comment %} 'cars_sold': cars_sold,
'current_time': current_time,
'dealer': dealer,
'total_revenue_from_cars': total_revenue_from_cars,
'total_revenue_from_additonals':total_revenue_from_additonals,
'total_revenue_collected': total_revenue_collected,
'total_vat_on_cars':total_vat_on_cars,
'total_vat_from_additonals':total_vat_from_additonals,
'total_vat_collected':total_vat_collected,
'total_discount': total_discount,
'makes': makes,
'models': models_qs,
'series': series,
'years': years,
'selected_make': selected_make,
'selected_model': selected_model,
'selected_serie': selected_serie,
'selected_year': selected_year, {% endcomment %}
<!---->
<section id="summary" class="mb-5"> <section id="summary" class="mb-5">
<h2 class="section-heading mb-4 border-start border-5 border-primary p-2">{% trans 'Report Summary' %}</h2> <h2 class="section-heading mb-4 border-start border-5 border-primary p-2">{% trans 'Report Summary' %}</h2>
<div class="row g-4"> <div class="row g-4">
@ -267,13 +287,13 @@
<span>{{ car.discount }} <span class="icon-saudi_riyal"></span></span> <span>{{ car.discount }} <span class="icon-saudi_riyal"></span></span>
</td> </td>
<td class="fs-9 text-nowrap"> <td class="fs-9 text-nowrap">
<span >{{ car.final_price }} <span class="icon-saudi_riyal"></span></span> <span>{{ car.final_price }} <span class="icon-saudi_riyal"></span></span>
</td> </td>
<td class="fs-9 text-nowrap"> <td class="fs-9 text-nowrap">
<span>{{ car.vat_amount|floatformat:2 }} <span class="icon-saudi_riyal"></span></span> <span>{{ car.vat_amount|floatformat:2 }} <span class="icon-saudi_riyal"></span></span>
</td> </td>
<td class="fs-9 text-nowrap"> <td class="fs-9 text-nowrap">
<span >{{ car.get_additional_services.total|floatformat:2 }} <span class="icon-saudi_riyal"></span></span> <span>{{ car.get_additional_services.total|floatformat:2 }} <span class="icon-saudi_riyal"></span></span>
</td> </td>
<td class="fs-9 text-nowrap"> <td class="fs-9 text-nowrap">
<span>{{ car.get_additional_services.services_vat|floatformat:2 }}<span class="icon-saudi_riyal"></span></span> <span>{{ car.get_additional_services.services_vat|floatformat:2 }}<span class="icon-saudi_riyal"></span></span>