This commit is contained in:
Faheedkhan 2025-09-01 10:57:49 +03:00
commit 92a2fd7067
13 changed files with 218 additions and 66 deletions

View File

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

View File

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

View File

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

View File

@ -43,31 +43,31 @@ class Command(BaseCommand):
)
# Assign quotas to plans
PlanQuota.objects.create(plan=basic_plan, quota=users_quota, value=4)
PlanQuota.objects.create(plan=basic_plan, quota=cars_quota, value=4)
PlanQuota.objects.create(plan=basic_plan, quota=users_quota, value=99999)
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=cars_quota, value=5)
PlanQuota.objects.create(plan=pro_plan, quota=users_quota, value=99999)
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=cars_quota, value=10)
PlanQuota.objects.create(plan=enterprise_plan, quota=users_quota, value=99999)
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=storage_quota, value=100)
# Define pricing
basic_pricing = Pricing.objects.create(name="Monthly", period=30)
pro_pricing = Pricing.objects.create(name="Monthly", period=30)
enterprise_pricing = Pricing.objects.create(name="Monthly", period=30)
basic_pricing = Pricing.objects.create(name="3 Months", period=90)
pro_pricing = Pricing.objects.create(name="6 Months", period=180)
enterprise_pricing = Pricing.objects.create(name="1 Year", period=365)
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(
plan=pro_plan, pricing=pro_pricing, price=Decimal("19.99")
plan=pro_plan, pricing=pro_pricing, price=Decimal("4500.00")
)
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

View File

@ -5,7 +5,7 @@ from django.urls import reverse
from django.contrib.auth.models import Group
from django.db.models.signals import post_save, post_delete
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.contrib.contenttypes.models import ContentType
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
#######################################################

View File

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

View File

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

Binary file not shown.

View File

@ -9305,10 +9305,8 @@ msgstr "سعر البيع"
#: inventory/models.py:705 templates/inventory/car_detail.html:267
#: templates/ledger/reports/car_sale_report.html:237
#, fuzzy
#| msgid "Agreed Price"
msgid "Marked Price"
msgstr "السعر المتفق عليه"
msgstr "سعر العرض"
#: inventory/models.py:711 templates/ledger/reports/car_sale_report.html:238
#: 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();
const data = await response.json();
if (response.ok) {
<<<<<<< HEAD
notify("success","{% trans 'Account created successfully'%}");
=======
notify("success","Account created successfully");
>>>>>>> d3dcb85fa378e156b77550e8ab833ad10ffad51f
setTimeout(() => {
window.location.href = "{% url 'account_login' %}";
}, 1000);

View File

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