update
This commit is contained in:
commit
4f0b199dae
3
.idea/car_inventory.iml
generated
3
.idea/car_inventory.iml
generated
@ -14,9 +14,10 @@
|
||||
</component>
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.11 (car_inventory)" jdkType="Python SDK" />
|
||||
<orderEntry type="jdk" jdkName="uv (car_inventory)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="jquery-3.5.1" level="application" />
|
||||
<orderEntry type="library" name="sweetalert2" level="application" />
|
||||
|
||||
5
.idea/misc.xml
generated
5
.idea/misc.xml
generated
@ -3,8 +3,5 @@
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.11 (car_inventory)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11 (car_inventory)" project-jdk-type="Python SDK" />
|
||||
<component name="PyPackaging">
|
||||
<option name="earlyReleasesAsUpgrades" value="true" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="uv (car_inventory)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
@ -1,31 +0,0 @@
|
||||
# Generated by Django 5.2.1 on 2025-05-25 23:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="CarVIN",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("vin", models.CharField(max_length=17, verbose_name="VIN")),
|
||||
(
|
||||
"created",
|
||||
models.DateTimeField(auto_now_add=True, verbose_name="created"),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
@ -1,8 +1,5 @@
|
||||
from django.conf import settings
|
||||
|
||||
from inventory.utils import get_user_type
|
||||
|
||||
|
||||
def currency_context(request):
|
||||
"""
|
||||
Provides a context dictionary containing the currency setting. This is typically
|
||||
|
||||
@ -114,6 +114,7 @@ class InjectDealerMiddleware:
|
||||
# if request.user.is_authenticated and not request.session.get('otp_verified', False):
|
||||
# return redirect(reverse('verify_otp'))
|
||||
# return self.get_response(request)
|
||||
|
||||
class DealerSlugMiddleware:
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
@ -971,7 +971,7 @@ def sale_order_created_notification(sender, instance, created, **kwargs):
|
||||
user=recipient,
|
||||
message=f"""
|
||||
New Sale Order has been added for estimate:{instance.estimate}.
|
||||
<a href="{reverse('estimate_detail',kwargs={'dealer_slug':instance.dealer.slug,'pk':instance.pk})}" target="_blank">View</a>
|
||||
<a href="{reverse('estimate_detail',kwargs={'dealer_slug':instance.dealer.slug,'pk':instance.estimate.pk})}" target="_blank">View</a>
|
||||
""",
|
||||
)
|
||||
@receiver(post_save, sender=models.Lead)
|
||||
|
||||
@ -41,7 +41,7 @@ urlpatterns = [
|
||||
path("dashboards/sales/", views.SalesDashboard.as_view(), name="sales_dashboard"),
|
||||
path("test/", views.TestView.as_view(), name="test"),
|
||||
path("cars/inventory/table/", views.CarListViewTable.as_view(), name="car_table"),
|
||||
path("export/format/", TableExport, name="export"),
|
||||
path("export/format/", TableExport.export, name="export"),
|
||||
# Dealer URLs
|
||||
path(
|
||||
"<slug:slug>/dealers/", views.DealerDetailView.as_view(), name="dealer_detail"
|
||||
@ -440,63 +440,23 @@ urlpatterns = [
|
||||
path("<slug:dealer_slug>/user/create/", views.UserCreateView.as_view(), name="user_create"),
|
||||
path("<slug:dealer_slug>/user/<slug:slug>/", views.UserDetailView.as_view(), name="user_detail"),
|
||||
path("<slug:dealer_slug>/user/<slug:slug>/groups/", views.UserGroupView, name="user_groups"),
|
||||
path(
|
||||
"<slug:dealer_slug>/user/<slug:slug>/update/", views.UserUpdateView.as_view(), name="user_update"
|
||||
),
|
||||
path("<slug:dealer_slug>/user/<slug:slug>/update/", views.UserUpdateView.as_view(), name="user_update"),
|
||||
path("<slug:dealer_slug>/user/<slug:slug>/confirm/", views.UserDeleteview, name="user_delete"),
|
||||
# Group URLs
|
||||
path("<slug:dealer_slug>/group/create/", views.GroupCreateView.as_view(), name="group_create"),
|
||||
path(
|
||||
"<slug:dealer_slug>/group/<int:pk>/update/", views.GroupUpdateView.as_view(), name="group_update"
|
||||
),
|
||||
path("<slug:dealer_slug>/group/<int:pk>/update/", views.GroupUpdateView.as_view(), name="group_update"),
|
||||
path("<slug:dealer_slug>/group/<int:pk>/", views.GroupDetailView.as_view(), name="group_detail"),
|
||||
path("<slug:dealer_slug>/group/", views.GroupListView.as_view(), name="group_list"),
|
||||
path("<slug:dealer_slug>/group/<int:pk>/confirm/", views.GroupDeleteview, name="group_delete"),
|
||||
path(
|
||||
"<slug:dealer_slug>/group/<int:pk>/permission/", views.GroupPermissionView, name="group_permission"
|
||||
),
|
||||
# Organization URLs
|
||||
path(
|
||||
"<slug:dealer_slug>/organizations/create/",
|
||||
views.OrganizationCreateView.as_view(),
|
||||
name="organization_create",
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/organizations/", views.OrganizationListView.as_view(), name="organization_list"
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/organizations/<slug:slug>/",
|
||||
views.OrganizationDetailView.as_view(),
|
||||
name="organization_detail",
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/organizations/<slug:slug>/update/",
|
||||
views.OrganizationUpdateView.as_view(),
|
||||
name="organization_update",
|
||||
),
|
||||
path(
|
||||
"<slug:dealer_slug>/organizations/<slug:slug>/delete/",
|
||||
views.OrganizationDeleteView,
|
||||
name="organization_delete",
|
||||
),
|
||||
# Representative URLs
|
||||
path(
|
||||
"representatives/",
|
||||
views.RepresentativeListView.as_view(),
|
||||
name="representative_list",
|
||||
),
|
||||
path(
|
||||
"representatives/<int:pk>/",
|
||||
views.RepresentativeDetailView.as_view(),
|
||||
name="representative_detail",
|
||||
),
|
||||
path(
|
||||
"representatives/create/",
|
||||
views.RepresentativeCreateView.as_view(),
|
||||
name="representative_create",
|
||||
),
|
||||
path(
|
||||
"representatives/<int:pk>/update/",
|
||||
path("<slug:dealer_slug>/group/<int:pk>/permission/", views.GroupPermissionView, name="group_permission"),
|
||||
path("<slug:dealer_slug>/organizations/create/", views.OrganizationCreateView.as_view(), name="organization_create"),
|
||||
path("<slug:dealer_slug>/organizations/", views.OrganizationListView.as_view(), name="organization_list"),
|
||||
path("<slug:dealer_slug>/organizations/<slug:slug>/", views.OrganizationDetailView.as_view(), name="organization_detail"),
|
||||
path("<slug:dealer_slug>/organizations/<slug:slug>/update/", views.OrganizationUpdateView.as_view(), name="organization_update"),
|
||||
path("<slug:dealer_slug>/organizations/<slug:slug>/delete/", views.OrganizationDeleteView, name="organization_delete"),
|
||||
path("representatives/", views.RepresentativeListView.as_view(), name="representative_list"),
|
||||
path("representatives/<int:pk>/", views.RepresentativeDetailView.as_view(), name="representative_detail"),
|
||||
path("representatives/create/", views.RepresentativeCreateView.as_view(),name="representative_create"),
|
||||
path("representatives/<int:pk>/update/",
|
||||
views.RepresentativeUpdateView.as_view(),
|
||||
name="representative_update",
|
||||
),
|
||||
@ -505,9 +465,6 @@ urlpatterns = [
|
||||
views.RepresentativeDeleteView.as_view(),
|
||||
name="representative_delete",
|
||||
),
|
||||
#####################################################################
|
||||
# Ledger
|
||||
#####################################################################
|
||||
path("<slug:dealer_slug>/ledgers/", views.LedgerModelListView.as_view(), name="ledger_list"),
|
||||
path(
|
||||
"<slug:dealer_slug>/ledgers/create/", views.LedgerModelCreateView.as_view(), name="ledger_create"
|
||||
@ -613,9 +570,6 @@ urlpatterns = [
|
||||
views.LedgerModelDeleteView.as_view(),
|
||||
name="ledger-delete",
|
||||
),
|
||||
##############################################################
|
||||
# Bank Account
|
||||
##############################################################
|
||||
path(
|
||||
"<slug:dealer_slug>/bank_accounts/",
|
||||
views.BankAccountListView.as_view(),
|
||||
@ -641,7 +595,6 @@ urlpatterns = [
|
||||
views.bank_account_delete,
|
||||
name="bank_account_delete",
|
||||
),
|
||||
# Account
|
||||
path(
|
||||
"<slug:dealer_slug>/coa_accounts/",
|
||||
views.AccountListView.as_view(),
|
||||
|
||||
@ -1005,6 +1005,7 @@ class CarFinanceCalculator:
|
||||
car_finance = self._get_nested_value(item, self.CAR_FINANCE_KEY)
|
||||
car_info = self._get_nested_value(item, self.CAR_INFO_KEY)
|
||||
unit_price = Decimal(car_finance.get("selling_price", 0))
|
||||
print(item.item_model.car.finances)
|
||||
return {
|
||||
"item_number": item.item_model.item_number,
|
||||
"vin": car_info.get("vin"),
|
||||
|
||||
@ -27,7 +27,7 @@ from django.views.decorators.http import require_http_methods
|
||||
from django.db.models.deletion import RestrictedError
|
||||
from django.http.response import StreamingHttpResponse
|
||||
from django.core.exceptions import ImproperlyConfigured, ValidationError
|
||||
|
||||
from django.core.exceptions import PermissionDenied
|
||||
# Django
|
||||
from django.db.models import Q
|
||||
from django.conf import settings
|
||||
@ -624,8 +624,9 @@ class CarCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
|
||||
return super().form_valid(form)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
dealer = get_user_type(self.request)
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["vendor_exists"] = self.request.dealer.vendors.exists()
|
||||
context["vendor_exists"] = dealer.vendors.exists()
|
||||
return context
|
||||
|
||||
|
||||
@ -3636,7 +3637,7 @@ class BankAccountListView(LoginRequiredMixin, PermissionRequiredMixin, ListView)
|
||||
template_name = "ledger/bank_accounts/bank_account_list.html"
|
||||
context_object_name = "bank_accounts"
|
||||
paginate_by = 30
|
||||
permission_required = ["inventory.view_carfinance"]
|
||||
permission_required = ["django_ledger.view_bankaccountmodel"]
|
||||
|
||||
def get_queryset(self):
|
||||
query = self.request.GET.get("q")
|
||||
@ -4275,7 +4276,12 @@ def create_estimate(request, dealer_slug, slug=None):
|
||||
# }
|
||||
# )
|
||||
car_instance = models.Car.objects.filter(
|
||||
hash=item.get("item_id"), finances__is_sold=False
|
||||
hash=item.get("item_id"),
|
||||
finances__is_sold=False,
|
||||
colors__isnull=False,
|
||||
finances__isnull=False,
|
||||
finances__selling_price__gt=1,
|
||||
status="available",
|
||||
).all()
|
||||
|
||||
for i in car_instance[: int(quantities[0])]:
|
||||
@ -4372,7 +4378,7 @@ def create_estimate(request, dealer_slug, slug=None):
|
||||
dealer=dealer,
|
||||
colors__isnull=False,
|
||||
finances__isnull=False,
|
||||
finances__selling_price__gt=0,
|
||||
finances__selling_price__gt=1,
|
||||
status="available",
|
||||
)
|
||||
.annotate(
|
||||
@ -4443,6 +4449,7 @@ class EstimateDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
|
||||
if estimate.get_itemtxs_data():
|
||||
calculator = CarFinanceCalculator(estimate)
|
||||
finance_data = calculator.get_finance_data()
|
||||
print(finance_data)
|
||||
invoice_obj = InvoiceModel.objects.all().filter(ce_model=estimate).first()
|
||||
kwargs["data"] = finance_data
|
||||
kwargs["invoice"] = invoice_obj
|
||||
@ -4643,7 +4650,6 @@ class EstimatePreviewView(LoginRequiredMixin, PermissionRequiredMixin, DetailVie
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("django_ledger.change_estimatemodel", raise_exception=True)
|
||||
def estimate_mark_as(request, dealer_slug, pk):
|
||||
"""
|
||||
Marks an estimate with a specified status based on the requested action and
|
||||
@ -4660,6 +4666,11 @@ def estimate_mark_as(request, dealer_slug, pk):
|
||||
:return: A redirect response to the estimate detail view.
|
||||
:rtype: HttpResponseRedirect
|
||||
"""
|
||||
if not (
|
||||
request.user.has_perm("django_ledger.can_approve_estimatemodel") or
|
||||
request.user.has_perm("django_ledger.change_estimatemodel")
|
||||
):
|
||||
raise PermissionDenied
|
||||
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
|
||||
estimate = get_object_or_404(EstimateModel, pk=pk)
|
||||
mark = request.GET.get("mark")
|
||||
@ -4680,6 +4691,9 @@ def estimate_mark_as(request, dealer_slug, pk):
|
||||
)
|
||||
estimate.mark_as_approved()
|
||||
messages.success(request, _("Quotation approved successfully"))
|
||||
return redirect(
|
||||
"estimate_list", dealer_slug=dealer.slug
|
||||
)
|
||||
elif mark == "rejected":
|
||||
if not estimate.can_cancel():
|
||||
messages.error(request, _("Quotation is not ready for rejection"))
|
||||
@ -5518,8 +5532,10 @@ def lead_create(request,dealer_slug):
|
||||
is_sa_import=True, pk__in=dealer_make_list
|
||||
)
|
||||
form.fields["staff"].queryset = form.fields["staff"].queryset.filter(
|
||||
dealer=dealer, staff_type="sales"
|
||||
)
|
||||
dealer=dealer,staff_member__user__groups__name__contains="Sales")
|
||||
# form.fields["staff"].queryset = form.fields["staff"].queryset.filter(
|
||||
# dealer=dealer
|
||||
# )
|
||||
|
||||
if hasattr(request.user.staffmember, "staff"):
|
||||
form.initial["staff"] = request.user.staffmember.staff
|
||||
|
||||
357
pyproject.toml
Normal file
357
pyproject.toml
Normal file
@ -0,0 +1,357 @@
|
||||
[project]
|
||||
name = "car-inventory"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"aiohappyeyeballs>=2.6.1",
|
||||
"aiohttp>=3.12.13",
|
||||
"aiohttp-retry>=2.9.1",
|
||||
"aiosignal>=1.3.2",
|
||||
"alabaster>=1.0.0",
|
||||
"albucore>=0.0.24",
|
||||
"albumentations>=2.0.8",
|
||||
"annotated-types>=0.7.0",
|
||||
"anthropic>=0.55.0",
|
||||
"anyio>=4.9.0",
|
||||
"arabic-reshaper>=3.0.0",
|
||||
"argcomplete>=3.6.2",
|
||||
"arrow>=1.3.0",
|
||||
"asgiref>=3.8.1",
|
||||
"astor>=0.8.1",
|
||||
"astroid>=3.3.10",
|
||||
"attrs>=25.3.0",
|
||||
"autopep8>=2.3.2",
|
||||
"babel>=2.17.0",
|
||||
"beautifulsoup4>=4.13.4",
|
||||
"bleach>=6.2.0",
|
||||
"blessed>=1.21.0",
|
||||
"blinker>=1.9.0",
|
||||
"boto3>=1.38.44",
|
||||
"botocore>=1.38.44",
|
||||
"brotli>=1.1.0",
|
||||
"cachetools>=5.5.2",
|
||||
"cattrs>=25.1.1",
|
||||
"certifi>=2025.6.15",
|
||||
"cffi>=1.17.1",
|
||||
"chardet>=5.2.0",
|
||||
"charset-normalizer>=3.4.2",
|
||||
"click>=7.1.2",
|
||||
"cohere>=5.15.0",
|
||||
"colorama>=0.4.6",
|
||||
"commonmark>=0.9.1",
|
||||
"contourpy>=1.3.2",
|
||||
"crispy-bootstrap5>=2025.6",
|
||||
"cryptography>=45.0.4",
|
||||
"cssselect2>=0.8.0",
|
||||
"ctranslate2>=4.6.0",
|
||||
"cycler>=0.12.1",
|
||||
"cython>=3.1.2",
|
||||
"dataclasses-json>=0.6.7",
|
||||
"decorator>=5.2.1",
|
||||
"defusedxml>=0.7.1",
|
||||
"desert>=2020.11.18",
|
||||
"diff-match-patch>=20241021",
|
||||
"dill>=0.4.0",
|
||||
"distro>=1.9.0",
|
||||
"dj-rest-auth>=7.0.1",
|
||||
"django>=5.2.3",
|
||||
"django-allauth>=65.9.0",
|
||||
"django-appointment>=3.6.0",
|
||||
"django-autoslug>=1.9.9",
|
||||
"django-background-tasks>=1.2.8",
|
||||
"django-bootstrap5>=25.1",
|
||||
"django-ckeditor>=6.7.3",
|
||||
"django-classy-tags>=4.1.0",
|
||||
"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-formtools>=2.5.1",
|
||||
"django-import-export>=4.3.8",
|
||||
"django-js-asset>=3.1.2",
|
||||
"django-ledger==0.7.8",
|
||||
"django-model-utils>=5.0.0",
|
||||
"django-money>=3.5.4",
|
||||
"django-next-url-mixin>=0.4.0",
|
||||
"django-nine>=0.2.7",
|
||||
"django-nonefield>=0.4",
|
||||
"django-ordered-model>=3.7.4",
|
||||
"django-pdf-actions>=0.1.52",
|
||||
"django-phonenumber-field>=8.1.0",
|
||||
"django-picklefield>=3.3",
|
||||
"django-plans>=2.0.0",
|
||||
"django-prometheus>=2.4.1",
|
||||
"django-q2>=1.8.0",
|
||||
"django-schema-graph>=3.1.0",
|
||||
"django-sekizai>=4.1.0",
|
||||
"django-sequences>=3.0",
|
||||
"django-silk>=5.4.0",
|
||||
"django-simple-history>=3.10.1",
|
||||
"django-sms>=0.7.0",
|
||||
"django-sslserver-v2>=1.0",
|
||||
"django-tables2>=2.7.5",
|
||||
"django-treebeard>=4.7.1",
|
||||
"django-view-breadcrumbs>=2.5.1",
|
||||
"django-widget-tweaks>=1.5.0",
|
||||
"djangocms-admin-style>=3.3.1",
|
||||
"djangorestframework>=3.16.0",
|
||||
"djangorestframework-simplejwt>=5.5.0",
|
||||
"djangoviz>=0.1.1",
|
||||
"djhtml>=3.0.8",
|
||||
"docopt>=0.6.2",
|
||||
"docutils>=0.21.2",
|
||||
"easy-thumbnails>=2.10",
|
||||
"emoji>=2.14.1",
|
||||
"et-xmlfile>=2.0.0",
|
||||
"eval-type-backport>=0.2.2",
|
||||
"executing>=2.2.0",
|
||||
"faker>=37.4.0",
|
||||
"fasta2a>=0.3.4",
|
||||
"fastavro>=1.11.1",
|
||||
"filelock>=3.18.0",
|
||||
"fire>=0.7.0",
|
||||
"fonttools>=4.58.4",
|
||||
"fpdf>=1.7.2",
|
||||
"fpdf2>=2.8.3",
|
||||
"frozenlist>=1.7.0",
|
||||
"fsspec>=2025.5.1",
|
||||
"google-auth>=2.40.3",
|
||||
"google-genai>=1.22.0",
|
||||
"googleapis-common-protos>=1.70.0",
|
||||
"gprof2dot>=2025.4.14",
|
||||
"graphqlclient>=0.2.4",
|
||||
"greenlet>=3.2.3",
|
||||
"griffe>=1.7.3",
|
||||
"groq>=0.29.0",
|
||||
"h11>=0.16.0",
|
||||
"h2>=4.2.0",
|
||||
"hf-xet>=1.1.5",
|
||||
"hpack>=4.1.0",
|
||||
"hstspreload>=2025.1.1",
|
||||
"httpcore>=1.0.9",
|
||||
"httpx>=0.28.1",
|
||||
"httpx-sse>=0.4.0",
|
||||
"huggingface-hub>=0.33.1",
|
||||
"hyperframe>=6.1.0",
|
||||
"icalendar>=6.3.1",
|
||||
"idna>=3.10",
|
||||
"imageio>=2.37.0",
|
||||
"imagesize>=1.4.1",
|
||||
"imgaug>=0.4.0",
|
||||
"importlib-metadata>=8.7.0",
|
||||
"iso4217>=1.14.20250512",
|
||||
"isodate>=0.7.2",
|
||||
"isort>=6.0.1",
|
||||
"itsdangerous>=2.2.0",
|
||||
"jinja2>=3.1.6",
|
||||
"jiter>=0.10.0",
|
||||
"jmespath>=1.0.1",
|
||||
"joblib>=1.5.1",
|
||||
"jsonpatch>=1.33",
|
||||
"jsonpointer>=3.0.0",
|
||||
"jwt>=1.4.0",
|
||||
"kiwisolver>=1.4.8",
|
||||
"langchain>=0.3.26",
|
||||
"langchain-community>=0.3.26",
|
||||
"langchain-core>=0.3.66",
|
||||
"langchain-ollama>=0.3.3",
|
||||
"langchain-text-splitters>=0.3.8",
|
||||
"langsmith>=0.4.2",
|
||||
"lazy-loader>=0.4",
|
||||
"ledger>=1.0.1",
|
||||
"libretranslatepy>=2.1.4",
|
||||
"lmdb>=1.6.2",
|
||||
"logfire>=3.21.1",
|
||||
"logfire-api>=3.21.1",
|
||||
"luhnchecker>=0.0.12",
|
||||
"lxml>=5.4.0",
|
||||
"markdown>=3.8.2",
|
||||
"markdown-it-py>=3.0.0",
|
||||
"markupsafe>=3.0.2",
|
||||
"marshmallow>=3.26.1",
|
||||
"matplotlib>=3.10.3",
|
||||
"mccabe>=0.7.0",
|
||||
"mcp>=1.9.4",
|
||||
"mdurl>=0.1.2",
|
||||
"mistralai>=1.8.2",
|
||||
"mouseinfo>=0.1.3",
|
||||
"mpmath>=1.3.0",
|
||||
"multidict>=6.5.1",
|
||||
"mypy-extensions>=1.1.0",
|
||||
"networkx>=3.5",
|
||||
"newrelic>=10.14.0",
|
||||
"nltk>=3.9.1",
|
||||
"num2words>=0.5.14",
|
||||
"numpy>=2.3.1",
|
||||
"oauthlib>=3.3.1",
|
||||
"ofxtools>=0.9.5",
|
||||
"ollama>=0.5.1",
|
||||
"openai>=1.91.0",
|
||||
"opencv-contrib-python>=4.11.0.86",
|
||||
"opencv-python>=4.11.0.86",
|
||||
"opencv-python-headless>=4.11.0.86",
|
||||
"openpyxl>=3.1.5",
|
||||
"opentelemetry-api>=1.34.1",
|
||||
"opentelemetry-exporter-otlp-proto-common>=1.34.1",
|
||||
"opentelemetry-exporter-otlp-proto-http>=1.34.1",
|
||||
"opentelemetry-instrumentation>=0.55b1",
|
||||
"opentelemetry-proto>=1.34.1",
|
||||
"opentelemetry-sdk>=1.34.1",
|
||||
"opentelemetry-semantic-conventions>=0.55b1",
|
||||
"opt-einsum>=3.4.0",
|
||||
"orjson>=3.10.18",
|
||||
"outcome>=1.3.0.post0",
|
||||
"packaging>=24.2",
|
||||
"pandas>=2.3.0",
|
||||
"pango>=0.0.1",
|
||||
"pdfkit>=1.0.0",
|
||||
"phonenumbers>=9.0.8",
|
||||
"pillow>=11.2.1",
|
||||
"platformdirs>=4.3.8",
|
||||
"prometheus-client>=0.22.1",
|
||||
"prompt-toolkit>=3.0.51",
|
||||
"propcache>=0.3.2",
|
||||
"protobuf>=5.29.5",
|
||||
"psycopg>=3.2.9",
|
||||
"psycopg-binary>=3.2.9",
|
||||
"psycopg-c>=3.2.9",
|
||||
"psycopg2-binary>=2.9.10",
|
||||
"py-moneyed>=3.0",
|
||||
"pyasn1>=0.6.1",
|
||||
"pyasn1-modules>=0.4.2",
|
||||
"pyautogui>=0.9.54",
|
||||
"pyclipper>=1.3.0.post6",
|
||||
"pycodestyle>=2.14.0",
|
||||
"pycparser>=2.22",
|
||||
"pydantic>=2.11.7",
|
||||
"pydantic-ai>=0.3.4",
|
||||
"pydantic-ai-slim>=0.3.4",
|
||||
"pydantic-core>=2.33.2",
|
||||
"pydantic-evals>=0.3.4",
|
||||
"pydantic-graph>=0.3.4",
|
||||
"pydantic-settings>=2.10.1",
|
||||
"pydotplus>=2.0.2",
|
||||
"pydyf>=0.11.0",
|
||||
"pygetwindow>=0.0.9",
|
||||
"pygments>=2.19.2",
|
||||
"pyjwt>=2.9.0",
|
||||
"pylint>=3.3.7",
|
||||
"pymsgbox>=1.0.9",
|
||||
"pymysql>=1.1.1",
|
||||
"pyobjc-core>=11.1",
|
||||
"pyobjc-framework-cocoa>=11.1",
|
||||
"pyobjc-framework-quartz>=11.1",
|
||||
"pyparsing>=3.2.3",
|
||||
"pypdf>=5.6.1",
|
||||
"pyperclip>=1.9.0",
|
||||
"pyphen>=0.17.2",
|
||||
"pypng>=0.20220715.0",
|
||||
"pyrect>=0.2.0",
|
||||
"pyscreeze>=1.0.1",
|
||||
"pyserial>=3.5",
|
||||
"pysocks>=1.7.1",
|
||||
"python-bidi>=0.6.6",
|
||||
"python-dateutil>=2.9.0.post0",
|
||||
"python-docx>=1.2.0",
|
||||
"python-dotenv>=1.1.1",
|
||||
"python-multipart>=0.0.20",
|
||||
"python-openid>=2.2.5",
|
||||
"python-slugify>=8.0.4",
|
||||
"python-stdnum>=2.1",
|
||||
"python3-saml>=1.16.0",
|
||||
"pytweening>=1.2.0",
|
||||
"pytz>=2025.2",
|
||||
"pyvin>=0.0.2",
|
||||
"pywa>=2.11.0",
|
||||
"pywhat>=1.0.0",
|
||||
"pywhatkit>=5.4",
|
||||
"pyyaml>=6.0.2",
|
||||
"pyzbar>=0.1.9",
|
||||
"qrcode>=8.2",
|
||||
"rapidfuzz>=3.13.0",
|
||||
"redis>=6.2.0",
|
||||
"regex>=2024.11.6",
|
||||
"reportlab>=4.4.2",
|
||||
"requests>=2.32.4",
|
||||
"requests-oauthlib>=2.0.0",
|
||||
"requests-toolbelt>=1.0.0",
|
||||
"rfc3986>=2.0.0",
|
||||
"rich>=14.0.0",
|
||||
"rsa>=4.9.1",
|
||||
"rubicon-objc>=0.5.1",
|
||||
"s3transfer>=0.13.0",
|
||||
"sacremoses>=0.1.1",
|
||||
"safetensors>=0.5.3",
|
||||
"scikit-image>=0.25.2",
|
||||
"scikit-learn>=1.7.0",
|
||||
"scipy>=1.16.0",
|
||||
"selenium>=4.32.0",
|
||||
"sentence-transformers>=4.1.0",
|
||||
"sentencepiece>=0.2.0",
|
||||
"shapely>=2.1.1",
|
||||
"simsimd>=6.4.9",
|
||||
"six>=1.17.0",
|
||||
"slugify>=0.0.1",
|
||||
"sniffio>=1.3.1",
|
||||
"snowballstemmer>=3.0.1",
|
||||
"sortedcontainers>=2.4.0",
|
||||
"soupsieve>=2.7",
|
||||
"sqlalchemy>=2.0.41",
|
||||
"sqlparse>=0.5.3",
|
||||
"sse-starlette>=2.3.6",
|
||||
"stanza>=1.10.1",
|
||||
"starlette>=0.47.1",
|
||||
"stringzilla>=3.12.5",
|
||||
"suds>=1.2.0",
|
||||
"swapper>=1.3.0",
|
||||
"sympy>=1.14.0",
|
||||
"tablib>=3.8.0",
|
||||
"tenacity>=8.5.0",
|
||||
"termcolor>=3.1.0",
|
||||
"text-unidecode>=1.3",
|
||||
"threadpoolctl>=3.6.0",
|
||||
"tifffile>=2025.6.11",
|
||||
"tinycss2>=1.4.0",
|
||||
"tinyhtml5>=2.0.0",
|
||||
"tokenizers>=0.21.2",
|
||||
"tomli>=2.2.1",
|
||||
"tomlkit>=0.13.3",
|
||||
"torch>=2.7.1",
|
||||
"tqdm>=4.67.1",
|
||||
"transformers>=4.52.4",
|
||||
"trio>=0.30.0",
|
||||
"trio-websocket>=0.12.2",
|
||||
"twilio>=9.6.3",
|
||||
"types-python-dateutil>=2.9.0.20250516",
|
||||
"types-requests>=2.32.4.20250611",
|
||||
"typing-extensions>=4.14.0",
|
||||
"typing-inspect>=0.9.0",
|
||||
"typing-inspection>=0.4.1",
|
||||
"tzdata>=2025.2",
|
||||
"unidecode>=1.4.0",
|
||||
"upgrade-requirements>=1.7.0",
|
||||
"urllib3>=2.5.0",
|
||||
"uvicorn>=0.34.3",
|
||||
"vin>=0.6.2",
|
||||
"vininfo>=1.9.1",
|
||||
"vishap>=0.1.5",
|
||||
"vpic-api>=0.7.4",
|
||||
"wcwidth>=0.2.13",
|
||||
"weasyprint>=65.1",
|
||||
"webencodings>=0.5.1",
|
||||
"websocket-client>=1.8.0",
|
||||
"websockets>=15.0.1",
|
||||
"werkzeug>=3.1.3",
|
||||
"wikipedia>=1.4.0",
|
||||
"wrapt>=1.17.2",
|
||||
"wsproto>=1.2.0",
|
||||
"xmlsec>=1.3.15",
|
||||
"yarl>=1.20.1",
|
||||
"zipp>=3.23.0",
|
||||
"zopfli>=0.2.3.post1",
|
||||
"zstandard>=0.23.0",
|
||||
]
|
||||
700
requirements.txt
700
requirements.txt
@ -1,350 +1,350 @@
|
||||
aiohappyeyeballs==2.6.1
|
||||
aiohttp==3.12.0
|
||||
aiohttp-retry==2.9.1
|
||||
aiosignal==1.3.2
|
||||
alabaster==1.0.0
|
||||
albucore==0.0.24
|
||||
albumentations==2.0.7
|
||||
annotated-types==0.7.0
|
||||
anthropic==0.52.2
|
||||
anyio==4.9.0
|
||||
arabic-reshaper==3.0.0
|
||||
argcomplete==3.6.2
|
||||
arrow==1.3.0
|
||||
asgiref==3.8.1
|
||||
astor==0.8.1
|
||||
astroid==3.3.10
|
||||
attrs==25.3.0
|
||||
autopep8==2.3.2
|
||||
Babel==2.15.0
|
||||
beautifulsoup4==4.13.4
|
||||
bleach==6.2.0
|
||||
blessed==1.21.0
|
||||
blinker==1.9.0
|
||||
boto3==1.38.29
|
||||
botocore==1.38.29
|
||||
Brotli==1.1.0
|
||||
cachetools==5.5.2
|
||||
cattrs==24.1.3
|
||||
certifi==2025.4.26
|
||||
cffi==1.17.1
|
||||
chardet==5.2.0
|
||||
charset-normalizer==3.4.2
|
||||
click==8.2.1
|
||||
cohere==5.15.0
|
||||
colorama==0.4.6
|
||||
commonmark==0.9.1
|
||||
contourpy==1.3.2
|
||||
crispy-bootstrap5==2025.4
|
||||
cryptography==45.0.3
|
||||
cssselect2==0.8.0
|
||||
ctranslate2==4.6.0
|
||||
cycler==0.12.1
|
||||
Cython==3.1.1
|
||||
dataclasses-json==0.6.7
|
||||
decorator==5.2.1
|
||||
defusedxml==0.7.1
|
||||
desert==2020.11.18
|
||||
diff-match-patch==20241021
|
||||
dill==0.4.0
|
||||
distro==1.9.0
|
||||
dj-rest-auth==7.0.1
|
||||
Django==5.2.1
|
||||
django-allauth==65.8.1
|
||||
django-appointment==3.8.0
|
||||
django-autoslug==1.9.9
|
||||
django-background-tasks==1.2.8
|
||||
django-bootstrap5==25.1
|
||||
django-ckeditor==6.7.2
|
||||
django-classy-tags==4.1.0
|
||||
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-formtools==2.5.1
|
||||
django-import-export==4.3.7
|
||||
django-js-asset==3.1.2
|
||||
django-ledger==0.7.7
|
||||
django-model-utils==5.0.0
|
||||
django-money==3.5.4
|
||||
django-next-url-mixin==0.4.0
|
||||
django-nine==0.2.7
|
||||
django-nonefield==0.4
|
||||
django-ordered-model==3.7.4
|
||||
django-pdf-actions==0.1.49
|
||||
django-phonenumber-field==8.0.0
|
||||
django-picklefield==3.3
|
||||
django-plans==2.0.0
|
||||
django-prometheus==2.3.1
|
||||
django-q2==1.8.0
|
||||
django-schema-graph==3.1.0
|
||||
django-sekizai==4.1.0
|
||||
django-sequences==3.0
|
||||
django-silk==5.3.2
|
||||
django-simple-history==3.8.0
|
||||
django-sms==0.7.0
|
||||
django-sslserver==0.22
|
||||
django-tables2==2.7.5
|
||||
django-treebeard==4.7.1
|
||||
django-view-breadcrumbs==2.5.1
|
||||
django-widget-tweaks==1.5.0
|
||||
djangocms-admin-style==3.3.1
|
||||
djangorestframework==3.16.0
|
||||
djangorestframework_simplejwt==5.5.0
|
||||
djangoviz==0.1.1
|
||||
djhtml==3.0.8
|
||||
docopt==0.6.2
|
||||
docutils==0.21.2
|
||||
easy-thumbnails==2.10
|
||||
emoji==2.14.1
|
||||
et_xmlfile==2.0.0
|
||||
eval_type_backport==0.2.2
|
||||
executing==2.2.0
|
||||
Faker==37.3.0
|
||||
fasta2a==0.2.14
|
||||
fastavro==1.11.1
|
||||
filelock==3.18.0
|
||||
fire==0.7.0
|
||||
fonttools==4.58.0
|
||||
fpdf==1.7.2
|
||||
fpdf2==2.8.3
|
||||
frozenlist==1.6.0
|
||||
fsspec==2025.5.1
|
||||
google-auth==2.40.2
|
||||
google-genai==1.18.0
|
||||
googleapis-common-protos==1.70.0
|
||||
gprof2dot==2025.4.14
|
||||
graphqlclient==0.2.4
|
||||
greenlet==3.2.2
|
||||
griffe==1.7.3
|
||||
groq==0.26.0
|
||||
h11==0.16.0
|
||||
h2==4.2.0
|
||||
hf-xet==1.1.3
|
||||
hpack==4.1.0
|
||||
hstspreload==2025.1.1
|
||||
httpcore==1.0.9
|
||||
httpx==0.28.1
|
||||
httpx-sse==0.4.0
|
||||
huggingface-hub==0.32.4
|
||||
hyperframe==6.1.0
|
||||
icalendar==6.3.1
|
||||
idna==3.10
|
||||
imageio==2.37.0
|
||||
imagesize==1.4.1
|
||||
imgaug==0.4.0
|
||||
importlib_metadata==8.7.0
|
||||
iso4217==1.12.20240625
|
||||
isodate==0.7.2
|
||||
isort==6.0.1
|
||||
itsdangerous==2.2.0
|
||||
Jinja2==3.1.6
|
||||
jiter==0.10.0
|
||||
jmespath==1.0.1
|
||||
joblib==1.5.1
|
||||
jsonpatch==1.33
|
||||
jsonpointer==3.0.0
|
||||
jwt==1.3.1
|
||||
kiwisolver==1.4.8
|
||||
langchain==0.3.25
|
||||
langchain-community==0.3.24
|
||||
langchain-core==0.3.61
|
||||
langchain-ollama==0.3.3
|
||||
langchain-text-splitters==0.3.8
|
||||
langsmith==0.3.42
|
||||
lazy_loader==0.4
|
||||
ledger==1.0.1
|
||||
libretranslatepy==2.1.4
|
||||
lmdb==1.6.2
|
||||
logfire==3.18.0
|
||||
logfire-api==3.17.0
|
||||
luhnchecker==0.0.12
|
||||
lxml==5.4.0
|
||||
Markdown==3.8
|
||||
markdown-it-py==3.0.0
|
||||
MarkupSafe==3.0.2
|
||||
marshmallow==3.26.1
|
||||
matplotlib==3.10.3
|
||||
mccabe==0.7.0
|
||||
mcp==1.9.2
|
||||
mdurl==0.1.2
|
||||
mistralai==1.8.1
|
||||
MouseInfo==0.1.3
|
||||
mpmath==1.3.0
|
||||
multidict==6.4.4
|
||||
mypy_extensions==1.1.0
|
||||
networkx==3.4.2
|
||||
newrelic==10.12.0
|
||||
nltk==3.9.1
|
||||
num2words==0.5.14
|
||||
numpy==2.2.6
|
||||
oauthlib==3.2.2
|
||||
ofxtools==0.9.5
|
||||
ollama==0.4.8
|
||||
openai==1.82.0
|
||||
opencv-contrib-python==4.11.0.86
|
||||
opencv-python==4.11.0.86
|
||||
opencv-python-headless==4.11.0.86
|
||||
openpyxl==3.1.5
|
||||
opentelemetry-api==1.34.0
|
||||
opentelemetry-exporter-otlp-proto-common==1.34.0
|
||||
opentelemetry-exporter-otlp-proto-http==1.34.0
|
||||
opentelemetry-instrumentation==0.55b0
|
||||
opentelemetry-proto==1.34.0
|
||||
opentelemetry-sdk==1.34.0
|
||||
opentelemetry-semantic-conventions==0.55b0
|
||||
opt_einsum==3.4.0
|
||||
orjson==3.10.18
|
||||
outcome==1.3.0.post0
|
||||
packaging==24.2
|
||||
pandas==2.2.3
|
||||
pango==0.0.1
|
||||
pdfkit==1.0.0
|
||||
phonenumbers==8.13.42
|
||||
pillow==10.4.0
|
||||
platformdirs==4.3.8
|
||||
prometheus_client==0.22.0
|
||||
prompt_toolkit==3.0.51
|
||||
propcache==0.3.1
|
||||
protobuf==5.29.5
|
||||
psycopg==3.2.9
|
||||
psycopg-binary==3.2.9
|
||||
psycopg-c==3.2.9
|
||||
psycopg2-binary==2.9.10
|
||||
py-moneyed==3.0
|
||||
pyasn1==0.6.1
|
||||
pyasn1_modules==0.4.2
|
||||
PyAutoGUI==0.9.54
|
||||
pyclipper==1.3.0.post6
|
||||
pycodestyle==2.13.0
|
||||
pycparser==2.22
|
||||
pydantic==2.11.5
|
||||
pydantic-ai==0.2.14
|
||||
pydantic-ai-slim==0.2.14
|
||||
pydantic-evals==0.2.14
|
||||
pydantic-graph==0.2.14
|
||||
pydantic-settings==2.9.1
|
||||
pydantic_core==2.33.2
|
||||
pydotplus==2.0.2
|
||||
pydyf==0.11.0
|
||||
PyGetWindow==0.0.9
|
||||
Pygments==2.19.1
|
||||
PyJWT==2.10.1
|
||||
pylint==3.3.7
|
||||
PyMsgBox==1.0.9
|
||||
PyMySQL==1.1.1
|
||||
pyobjc-core==11.0
|
||||
pyobjc-framework-Cocoa==11.0
|
||||
pyobjc-framework-Quartz==11.0
|
||||
pyparsing==3.2.3
|
||||
pypdf==5.5.0
|
||||
pyperclip==1.9.0
|
||||
pyphen==0.17.2
|
||||
pypng==0.20220715.0
|
||||
PyRect==0.2.0
|
||||
PyScreeze==1.0.1
|
||||
pyserial==3.5
|
||||
PySocks==1.7.1
|
||||
python-bidi==0.6.6
|
||||
python-dateutil==2.9.0.post0
|
||||
python-docx==1.1.2
|
||||
python-dotenv==1.1.0
|
||||
python-multipart==0.0.20
|
||||
python-openid==2.2.5
|
||||
python-slugify==8.0.4
|
||||
python-stdnum==2.1
|
||||
python3-saml==1.16.0
|
||||
pytweening==1.2.0
|
||||
pytz==2025.2
|
||||
pyvin==0.0.2
|
||||
pywa==2.10.0
|
||||
pywhat==5.1.0
|
||||
pywhatkit==5.4
|
||||
PyYAML==6.0.2
|
||||
pyzbar==0.1.9
|
||||
qrcode==8.2
|
||||
RapidFuzz==3.13.0
|
||||
redis==6.1.0
|
||||
regex==2024.11.6
|
||||
reportlab==4.4.1
|
||||
requests==2.32.3
|
||||
requests-oauthlib==2.0.0
|
||||
requests-toolbelt==1.0.0
|
||||
rfc3986==2.0.0
|
||||
rich==14.0.0
|
||||
rsa==4.9.1
|
||||
rubicon-objc==0.5.0
|
||||
s3transfer==0.13.0
|
||||
sacremoses==0.1.1
|
||||
safetensors==0.5.3
|
||||
scikit-image==0.25.2
|
||||
scikit-learn==1.6.1
|
||||
scipy==1.15.3
|
||||
selenium==4.33.0
|
||||
sentence-transformers==4.1.0
|
||||
sentencepiece==0.2.0
|
||||
shapely==2.1.1
|
||||
simsimd==6.2.1
|
||||
six==1.17.0
|
||||
slugify==0.0.1
|
||||
sniffio==1.3.1
|
||||
snowballstemmer==3.0.1
|
||||
sortedcontainers==2.4.0
|
||||
soupsieve==2.7
|
||||
SQLAlchemy==2.0.41
|
||||
sqlparse==0.5.3
|
||||
sse-starlette==2.3.6
|
||||
stanza==1.10.1
|
||||
starlette==0.47.0
|
||||
stringzilla==3.12.5
|
||||
suds==1.2.0
|
||||
swapper==1.3.0
|
||||
sympy==1.14.0
|
||||
tablib==3.8.0
|
||||
tenacity==9.1.2
|
||||
termcolor==3.1.0
|
||||
text-unidecode==1.3
|
||||
threadpoolctl==3.6.0
|
||||
tifffile==2025.5.24
|
||||
tinycss2==1.4.0
|
||||
tinyhtml5==2.0.0
|
||||
tokenizers==0.21.1
|
||||
tomli==2.2.1
|
||||
tomlkit==0.13.2
|
||||
torch==2.7.0
|
||||
tqdm==4.67.1
|
||||
transformers==4.52.4
|
||||
trio==0.30.0
|
||||
trio-websocket==0.12.2
|
||||
twilio==9.6.1
|
||||
types-python-dateutil==2.9.0.20250516
|
||||
types-requests==2.32.0.20250602
|
||||
typing-inspect==0.9.0
|
||||
typing-inspection==0.4.1
|
||||
typing_extensions==4.13.2
|
||||
tzdata==2025.2
|
||||
Unidecode==1.4.0
|
||||
upgrade-requirements==1.7.0
|
||||
urllib3==2.4.0
|
||||
uvicorn==0.34.3
|
||||
vin==0.6.2
|
||||
vininfo==1.8.0
|
||||
vishap==0.1.5
|
||||
vpic-api==0.7.4
|
||||
wcwidth==0.2.13
|
||||
weasyprint==65.1
|
||||
webencodings==0.5.1
|
||||
websocket-client==1.8.0
|
||||
websockets==15.0.1
|
||||
Werkzeug==3.1.3
|
||||
wikipedia==1.4.0
|
||||
wrapt==1.17.2
|
||||
wsproto==1.2.0
|
||||
xmlsec==1.3.15
|
||||
yarl==1.20.0
|
||||
zipp==3.22.0
|
||||
zopfli==0.2.3.post1
|
||||
zstandard==0.23.0
|
||||
aiohappyeyeballs
|
||||
aiohttp
|
||||
aiohttp-retry
|
||||
aiosignal
|
||||
alabaster
|
||||
albucore
|
||||
albumentations
|
||||
annotated-types
|
||||
anthropic
|
||||
anyio
|
||||
arabic-reshaper
|
||||
argcomplete
|
||||
arrow
|
||||
asgiref
|
||||
astor
|
||||
astroid
|
||||
attrs
|
||||
autopep8
|
||||
Babel
|
||||
beautifulsoup4
|
||||
bleach
|
||||
blessed
|
||||
blinker
|
||||
boto3
|
||||
botocore
|
||||
Brotli
|
||||
cachetools
|
||||
cattrs
|
||||
certifi
|
||||
cffi
|
||||
chardet
|
||||
charset-normalizer
|
||||
click
|
||||
cohere
|
||||
colorama
|
||||
commonmark
|
||||
contourpy
|
||||
crispy-bootstrap5
|
||||
cryptography
|
||||
cssselect2
|
||||
ctranslate2
|
||||
cycler
|
||||
Cython
|
||||
dataclasses-json
|
||||
decorator
|
||||
defusedxml
|
||||
desert
|
||||
diff-match-patch
|
||||
dill
|
||||
distro
|
||||
dj-rest-auth
|
||||
Django
|
||||
django-allauth
|
||||
django-appointment
|
||||
django-autoslug
|
||||
django-background-tasks
|
||||
django-bootstrap5
|
||||
django-ckeditor
|
||||
django-classy-tags
|
||||
django-cors-headers
|
||||
django-countries
|
||||
django-crispy-forms
|
||||
django-debug-toolbar
|
||||
django-easy-audit
|
||||
django-extensions
|
||||
django-filter
|
||||
django-formtools
|
||||
django-import-export
|
||||
django-js-asset
|
||||
django-ledger
|
||||
django-model-utils
|
||||
django-money
|
||||
django-next-url-mixin
|
||||
django-nine
|
||||
django-nonefield
|
||||
django-ordered-model
|
||||
django-pdf-actions
|
||||
django-phonenumber-field
|
||||
django-picklefield
|
||||
django-plans
|
||||
django-prometheus
|
||||
django-q2
|
||||
django-schema-graph
|
||||
django-sekizai
|
||||
django-sequences
|
||||
django-silk
|
||||
django-simple-history
|
||||
django-sms
|
||||
django-sslserver
|
||||
django-tables2
|
||||
django-treebeard
|
||||
django-view-breadcrumbs
|
||||
django-widget-tweaks
|
||||
djangocms-admin-style
|
||||
djangorestframework
|
||||
djangorestframework_simplejwt
|
||||
djangoviz
|
||||
djhtml
|
||||
docopt
|
||||
docutils
|
||||
easy-thumbnails
|
||||
emoji
|
||||
et_xmlfile
|
||||
eval_type_backport
|
||||
executing
|
||||
Faker
|
||||
fasta2a
|
||||
fastavro
|
||||
filelock
|
||||
fire
|
||||
fonttools
|
||||
fpdf
|
||||
fpdf2
|
||||
frozenlist
|
||||
fsspec
|
||||
google-auth
|
||||
google-genai
|
||||
googleapis-common-protos
|
||||
gprof2dot
|
||||
graphqlclient
|
||||
greenlet
|
||||
griffe
|
||||
groq
|
||||
h11
|
||||
h2
|
||||
hf-xet
|
||||
hpack
|
||||
hstspreload
|
||||
httpcore
|
||||
httpx
|
||||
httpx-sse
|
||||
huggingface-hub
|
||||
hyperframe
|
||||
icalendar
|
||||
idna
|
||||
imageio
|
||||
imagesize
|
||||
imgaug
|
||||
importlib_metadata
|
||||
iso4217
|
||||
isodate
|
||||
isort
|
||||
itsdangerous
|
||||
Jinja2
|
||||
jiter
|
||||
jmespath
|
||||
joblib
|
||||
jsonpatch
|
||||
jsonpointer
|
||||
jwt
|
||||
kiwisolver
|
||||
langchain
|
||||
langchain-community
|
||||
langchain-core
|
||||
langchain-ollama
|
||||
langchain-text-splitters
|
||||
langsmith
|
||||
lazy_loader
|
||||
ledger
|
||||
libretranslatepy
|
||||
lmdb
|
||||
logfire
|
||||
logfire-api
|
||||
luhnchecker
|
||||
lxml
|
||||
Markdown
|
||||
markdown-it-py
|
||||
MarkupSafe
|
||||
marshmallow
|
||||
matplotlib
|
||||
mccabe
|
||||
mcp
|
||||
mdurl
|
||||
mistralai
|
||||
MouseInfo
|
||||
mpmath
|
||||
multidict
|
||||
mypy_extensions
|
||||
networkx
|
||||
newrelic
|
||||
nltk
|
||||
num2words
|
||||
numpy
|
||||
oauthlib
|
||||
ofxtools
|
||||
ollama
|
||||
openai
|
||||
opencv-contrib-python
|
||||
opencv-python
|
||||
opencv-python-headless
|
||||
openpyxl
|
||||
opentelemetry-api
|
||||
opentelemetry-exporter-otlp-proto-common
|
||||
opentelemetry-exporter-otlp-proto-http
|
||||
opentelemetry-instrumentation
|
||||
opentelemetry-proto
|
||||
opentelemetry-sdk
|
||||
opentelemetry-semantic-conventions
|
||||
opt_einsum
|
||||
orjson
|
||||
outcome
|
||||
packaging
|
||||
pandas
|
||||
pango
|
||||
pdfkit
|
||||
phonenumbers
|
||||
pillow
|
||||
platformdirs
|
||||
prometheus_client
|
||||
prompt_toolkit
|
||||
propcache
|
||||
protobuf
|
||||
psycopg
|
||||
psycopg-binary
|
||||
psycopg-c
|
||||
psycopg2-binary
|
||||
py-moneyed
|
||||
pyasn1
|
||||
pyasn1_modules
|
||||
PyAutoGUI
|
||||
pyclipper
|
||||
pycodestyle
|
||||
pycparser
|
||||
pydantic
|
||||
pydantic-ai
|
||||
pydantic-ai-slim
|
||||
pydantic-evals
|
||||
pydantic-graph
|
||||
pydantic-settings
|
||||
pydantic_core
|
||||
pydotplus
|
||||
pydyf
|
||||
PyGetWindow
|
||||
Pygments
|
||||
PyJWT
|
||||
pylint
|
||||
PyMsgBox
|
||||
PyMySQL
|
||||
pyobjc-core
|
||||
pyobjc-framework-Cocoa
|
||||
pyobjc-framework-Quartz
|
||||
pyparsing
|
||||
pypdf
|
||||
pyperclip
|
||||
pyphen
|
||||
pypng
|
||||
PyRect
|
||||
PyScreeze
|
||||
pyserial
|
||||
PySocks
|
||||
python-bidi
|
||||
python-dateutil
|
||||
python-docx
|
||||
python-dotenv
|
||||
python-multipart
|
||||
python-openid
|
||||
python-slugify
|
||||
python-stdnum
|
||||
python3-saml
|
||||
pytweening
|
||||
pytz
|
||||
pyvin
|
||||
pywa
|
||||
pywhat
|
||||
pywhatkit
|
||||
PyYAML
|
||||
pyzbar
|
||||
qrcode
|
||||
RapidFuzz
|
||||
redis
|
||||
regex
|
||||
reportlab
|
||||
requests
|
||||
requests-oauthlib
|
||||
requests-toolbelt
|
||||
rfc3986
|
||||
rich
|
||||
rsa
|
||||
rubicon-objc
|
||||
s3transfer
|
||||
sacremoses
|
||||
safetensors
|
||||
scikit-image
|
||||
scikit-learn
|
||||
scipy
|
||||
selenium
|
||||
sentence-transformers
|
||||
sentencepiece
|
||||
shapely
|
||||
simsimd
|
||||
six
|
||||
slugify
|
||||
sniffio
|
||||
snowballstemmer
|
||||
sortedcontainers
|
||||
soupsieve
|
||||
SQLAlchemy
|
||||
sqlparse
|
||||
sse-starlette
|
||||
stanza
|
||||
starlette
|
||||
stringzilla
|
||||
suds
|
||||
swapper
|
||||
sympy
|
||||
tablib
|
||||
tenacity
|
||||
termcolor
|
||||
text-unidecode
|
||||
threadpoolctl
|
||||
tifffile
|
||||
tinycss2
|
||||
tinyhtml5
|
||||
tokenizers
|
||||
tomli
|
||||
tomlkit
|
||||
torch
|
||||
tqdm
|
||||
transformers
|
||||
trio
|
||||
trio-websocket
|
||||
twilio
|
||||
types-python-dateutil
|
||||
types-requests
|
||||
typing-inspect
|
||||
typing-inspection
|
||||
typing_extensions
|
||||
tzdata
|
||||
Unidecode
|
||||
upgrade-requirements
|
||||
urllib3
|
||||
uvicorn
|
||||
vin
|
||||
vininfo
|
||||
vishap
|
||||
vpic-api
|
||||
wcwidth
|
||||
weasyprint
|
||||
webencodings
|
||||
websocket-client
|
||||
websockets
|
||||
Werkzeug
|
||||
wikipedia
|
||||
wrapt
|
||||
wsproto
|
||||
xmlsec
|
||||
yarl
|
||||
zipp
|
||||
zopfli
|
||||
zstandard
|
||||
|
||||
BIN
static/.DS_Store
vendored
BIN
static/.DS_Store
vendored
Binary file not shown.
BIN
static/images/.DS_Store
vendored
BIN
static/images/.DS_Store
vendored
Binary file not shown.
BIN
static/images/cars/.DS_Store
vendored
BIN
static/images/cars/.DS_Store
vendored
Binary file not shown.
@ -19,6 +19,3 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,90 +1,64 @@
|
||||
{% load i18n static %}
|
||||
<div class="d-flex justify-content-between align-items-center mt-4 mb-3">
|
||||
<div class="text-body-secondary">
|
||||
{{ _("Showing") }} {{ page_obj.start_index }} {{ _("to") }} {{ page_obj.end_index }}
|
||||
{{ _("of") }} {{ page_obj.paginator.count }} {{ _("results") }}
|
||||
</div>
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination mb-0">
|
||||
<div class="text-body-secondary fw-bold fs-10">
|
||||
{{ _("Showing") }} {{ page_obj.start_index }} {{ _("to") }} {{ page_obj.end_index }}
|
||||
{{ _("of") }} {{ page_obj.paginator.count }} {{ _("results") }}
|
||||
</div>
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination mb-0">
|
||||
{# First Page Link #}
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item rounded-md overflow-hidden">
|
||||
<a class="page-link px-3 py-2 border border-gray-300 bg-white text-blue-600 hover:bg-gray-100 transition-colors duration-200" href="?page=1{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'First' %}">
|
||||
<span class="fas fa-angle-double-left" aria-hidden="true"></span>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled rounded-md overflow-hidden">
|
||||
<span class="page-link px-3 py-2 border border-gray-200 bg-gray-50 text-gray-400 cursor-not-allowed">
|
||||
<span class="fas fa-angle-double-left" aria-hidden="true"></span>
|
||||
|
||||
</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page=1{% if q %}&q={{q}}{% endif %}">
|
||||
<span class="fas fa-angle-double-{% if LANGUAGE_CODE == 'ar' %}right{% else %}left{% endif %}"> </span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item">
|
||||
<span class="page-link">
|
||||
<span class="fas fa-chevron-{% if LANGUAGE_CODE == 'ar' %}right{% else %}left{% endif %}"> </span>
|
||||
</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{# Previous Page Link #}
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item rounded-md overflow-hidden">
|
||||
<a class="page-link px-3 py-2 border border-gray-300 bg-white text-blue-600 hover:bg-gray-100 transition-colors duration-200" href="?page={{ page_obj.previous_page_number }}{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'Previous' %}">
|
||||
<span class="fas fa-chevron-left" aria-hidden="true"></span>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled rounded-md overflow-hidden">
|
||||
<span class="page-link px-3 py-2 border border-gray-200 bg-gray-50 text-gray-400 cursor-not-allowed">
|
||||
<span class="fas fa-chevron-left" aria-hidden="true"></span>
|
||||
|
||||
</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if q %}&q={{q}}{% endif %}">
|
||||
<span class="fas fa-chevron-{% if LANGUAGE_CODE == 'ar' %}right{% else %}left{% endif %}"></span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{# Page Numbers #}
|
||||
{% for num in page_obj.paginator.page_range %}
|
||||
{% if num == 1 or num == page_obj.paginator.num_pages or num >= page_obj.number|add:-2 and num <= page_obj.number|add:2 %}
|
||||
<li class="page-item {% if num == page_obj.number %}active{% endif %}">
|
||||
<a class="page-link" {% if num == page_obj.number %}aria-current="page"{% endif %}
|
||||
href="?page={{ num }}{% if q %}&q={{q}}{% endif %}">
|
||||
{{ num }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for num in page_obj.paginator.page_range %}
|
||||
{% if num == 1 or num == page_obj.paginator.num_pages or num >= page_obj.number|add:-2 and num <= page_obj.number|add:2 %}
|
||||
<li class="page-item {% if num == page_obj.number %}active{% endif %}">
|
||||
<a class="page-link" {% if num == page_obj.number %}aria-current="page"{% endif %}
|
||||
href="?page={{ num }}{% if q %}&q={{q}}{% endif %}">
|
||||
{{ num }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{# Next Page Link #}
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item rounded-md overflow-hidden">
|
||||
<a class="page-link px-3 py-2 border border-gray-300 bg-white text-blue-600 hover:bg-gray-100 transition-colors duration-200" href="?page={{ page_obj.next_page_number }}{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'Next' %}">
|
||||
<span class="fas fa-chevron-right" aria-hidden="true"></span>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled rounded-md overflow-hidden">
|
||||
<span class="page-link px-3 py-2 border border-gray-200 bg-gray-50 text-gray-400 cursor-not-allowed">
|
||||
<span class="fas fa-chevron-right" aria-hidden="true"></span>
|
||||
|
||||
</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if q %}&q={{q}}{% endif %}">
|
||||
<span class="fas fa-chevron-{% if LANGUAGE_CODE == 'ar' %}left{% else %}right{% endif %}"></span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{# Last Page Link #}
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item rounded-md overflow-hidden">
|
||||
<a class="page-link px-3 py-2 border border-gray-300 bg-white text-blue-600 hover:bg-gray-100 transition-colors duration-200" href="?page={{ page_obj.paginator.num_pages }}{% if q %}&q={{q}}{% endif %}" aria-label="{% trans 'Last' %}">
|
||||
<span class="fas fa-angle-double-right" aria-hidden="true"></span>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled rounded-md overflow-hidden">
|
||||
<span class="page-link px-3 py-2 border border-gray-200 bg-gray-50 text-gray-400 cursor-not-allowed">
|
||||
<span class="fas fa-angle-double-right" aria-hidden="true"></span>
|
||||
|
||||
</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}{% if q %}&q={{q}}{% endif %}">
|
||||
<span class="fas fa-angle-double-{% if LANGUAGE_CODE == 'ar' %}left{% else %}right{% endif %}"></span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
@ -76,14 +76,16 @@
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
|
||||
{% if estimate.status == 'draft' %}
|
||||
<a href="{% url 'send_email' request.dealer.slug estimate.pk %}" class="btn btn-phoenix-primary me-2"><span class="fa-regular fa-paper-plane me-sm-2"></span><span class="d-none d-sm-inline-block">{% trans 'Send Quotation' %}</span></a>
|
||||
<button id="mark_as_sent_estimate" class="btn btn-phoenix-secondary" onclick="setFormAction('review')" data-bs-toggle="modal" data-bs-target="#confirmModal"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-check-double"></i> {% trans 'Mark As Sent' %}</span></button>
|
||||
{% elif estimate.status == 'in_review' %}
|
||||
{% if perms.django_ledger.can_approve_estimate %}
|
||||
<button id="accept_estimate" onclick="setFormAction('approved')" class="btn btn-phoenix-secondary" data-bs-toggle="modal" data-bs-target="#confirmModal"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-check-double"></i> {% trans 'Mark As Accept' %}</span></button>
|
||||
{% endif %}
|
||||
{% if estimate.status == 'draft' %}
|
||||
{% if perms.django_ledger.change_estimatemodel %}
|
||||
<button id="mark_as_sent_estimate" class="btn btn-phoenix-secondary" onclick="setFormAction('review')" data-bs-toggle="modal" data-bs-target="#confirmModal"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-check-double"></i> {% trans 'Mark As Review' %}</span></button>
|
||||
{% endif %}
|
||||
{% elif estimate.status == 'in_review' %}
|
||||
{% if perms.django_ledger.can_approve_estimatemodel %}
|
||||
<button id="accept_estimate" onclick="setFormAction('approved')" class="btn btn-phoenix-secondary" data-bs-toggle="modal" data-bs-target="#confirmModal"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-check-double"></i> {% trans 'Mark As Accept' %}</span></button>
|
||||
{% endif %}
|
||||
{% elif estimate.status == 'approved' %}
|
||||
<a href="{% url 'send_email' request.dealer.slug estimate.pk %}" class="btn btn-phoenix-primary me-2"><span class="fa-regular fa-paper-plane me-sm-2"></span><span class="d-none d-sm-inline-block">{% trans 'Send Quotation' %}</span></a>
|
||||
|
||||
{% if estimate.sale_orders.first %}
|
||||
<!--if sale order exist-->
|
||||
@ -99,9 +101,9 @@
|
||||
|
||||
|
||||
{% elif estimate.status == 'completed' %}
|
||||
<a href="{% url 'order_detail' request.dealer.slug estimate.sale_orders.first.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{{ _("Preview Sale Order") }}</span></a>
|
||||
<a href="{% url 'invoice_detail' request.dealer.slug estimate.invoicemodel_set.first.pk %}" class="btn btn-phoenix-primary btn-sm" type="button"><i class="fa-solid fa-receipt"></i>
|
||||
{{ _("View Invoice")}}</a>
|
||||
<a href="{% url 'order_detail' request.dealer.slug estimate.sale_orders.first.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{{ _("Preview Sale Order") }}</span></a>
|
||||
<a href="{% url 'invoice_detail' request.dealer.slug estimate.invoicemodel_set.first.pk %}" class="btn btn-phoenix-primary btn-sm" type="button"><i class="fa-solid fa-receipt"></i>
|
||||
{{ _("View Invoice")}}</a>
|
||||
{% endif %}
|
||||
|
||||
{% if estimate.can_cancel %}
|
||||
|
||||
@ -2,5 +2,5 @@ from django.contrib import admin
|
||||
from . import models
|
||||
|
||||
# Register your models here.
|
||||
admin.site.register(models.Tour)
|
||||
admin.site.register(models.TourCompletion)
|
||||
# admin.site.register(models.Tour)
|
||||
# admin.site.register(models.TourCompletion)
|
||||
|
||||
@ -1,66 +0,0 @@
|
||||
# Generated by Django 5.2.1 on 2025-06-06 14:05
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Tour",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=100)),
|
||||
("description", models.TextField(blank=True)),
|
||||
("slug", models.SlugField(unique=True)),
|
||||
("tour_file", models.CharField(max_length=255)),
|
||||
("is_active", models.BooleanField(default=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TourCompletion",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("completed_on", models.DateTimeField(auto_now_add=True)),
|
||||
(
|
||||
"tour",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to="tours.tour"
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"unique_together": {("tour", "user")},
|
||||
},
|
||||
),
|
||||
]
|
||||
@ -1,21 +1,21 @@
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Tour(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
description = models.TextField(blank=True)
|
||||
slug = models.SlugField(unique=True)
|
||||
tour_file = models.CharField(max_length=255)
|
||||
is_active = models.BooleanField(default=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class TourCompletion(models.Model):
|
||||
tour = models.ForeignKey(Tour, on_delete=models.CASCADE)
|
||||
user = models.ForeignKey("auth.User", on_delete=models.CASCADE)
|
||||
completed_on = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
unique_together = ("tour", "user")
|
||||
# class Tour(models.Model):
|
||||
# name = models.CharField(max_length=100)
|
||||
# description = models.TextField(blank=True)
|
||||
# slug = models.SlugField(unique=True)
|
||||
# tour_file = models.CharField(max_length=255)
|
||||
# is_active = models.BooleanField(default=True)
|
||||
#
|
||||
# def __str__(self):
|
||||
# return self.name
|
||||
#
|
||||
#
|
||||
# class TourCompletion(models.Model):
|
||||
# tour = models.ForeignKey(Tour, on_delete=models.CASCADE)
|
||||
# user = models.ForeignKey("auth.User", on_delete=models.CASCADE)
|
||||
# completed_on = models.DateTimeField(auto_now_add=True)
|
||||
#
|
||||
# class Meta:
|
||||
# unique_together = ("tour", "user")
|
||||
|
||||
@ -2,8 +2,8 @@ from django.urls import path
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path("", views.tour_list, name="tour_list"),
|
||||
path("data/<slug:slug>/", views.get_tour_data, name="get_tour_data"),
|
||||
path("complete/<slug:slug>/", views.mark_tour_completed, name="mark_tour_complete"),
|
||||
path("start/<slug:slug>/", views.start_tour_view, name="start_tour"),
|
||||
# path("", views.tour_list, name="tour_list"),
|
||||
# path("data/<slug:slug>/", views.get_tour_data, name="get_tour_data"),
|
||||
# path("complete/<slug:slug>/", views.mark_tour_completed, name="mark_tour_complete"),
|
||||
# path("start/<slug:slug>/", views.start_tour_view, name="start_tour"),
|
||||
]
|
||||
|
||||
108
tours/views.py
108
tours/views.py
@ -1,54 +1,54 @@
|
||||
import os
|
||||
import json
|
||||
from django.shortcuts import render, get_object_or_404
|
||||
from django.http import JsonResponse
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.conf import settings
|
||||
from .models import Tour, TourCompletion
|
||||
|
||||
|
||||
@login_required
|
||||
def tour_list(request):
|
||||
tours = Tour.objects.filter(is_active=True)
|
||||
return render(request, "tours/tour_list.html", {"tours": tours})
|
||||
|
||||
|
||||
@login_required
|
||||
def get_tour_data(request, slug):
|
||||
tour = get_object_or_404(Tour, slug=slug, is_active=True)
|
||||
|
||||
# Check if user has already completed this tour
|
||||
completed = TourCompletion.objects.filter(tour=tour, user=request.user).exists()
|
||||
|
||||
# Load the tour data from JSON file
|
||||
tour_file_path = os.path.join(
|
||||
settings.BASE_DIR, "static", "js", "tours", tour.tour_file
|
||||
)
|
||||
|
||||
try:
|
||||
with open(tour_file_path, "r") as f:
|
||||
tour_data = json.load(f)
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
return JsonResponse({"error": "Tour data not found or invalid"}, status=404)
|
||||
|
||||
return JsonResponse({"tour": tour_data, "completed": completed})
|
||||
|
||||
|
||||
@login_required
|
||||
def mark_tour_completed(request, slug):
|
||||
if request.method != "POST":
|
||||
return JsonResponse({"error": "Method not allowed"}, status=405)
|
||||
|
||||
tour = get_object_or_404(Tour, slug=slug, is_active=True)
|
||||
|
||||
# Mark the tour as completed for this user
|
||||
TourCompletion.objects.get_or_create(tour=tour, user=request.user)
|
||||
|
||||
return JsonResponse({"status": "success"})
|
||||
|
||||
|
||||
@login_required
|
||||
def start_tour_view(request, slug):
|
||||
tour = get_object_or_404(Tour, slug=slug, is_active=True)
|
||||
# Redirect to the page where the tour should start
|
||||
return render(request, "tours/start_tour.html", {"tour": tour})
|
||||
# import os
|
||||
# import json
|
||||
# from django.shortcuts import render, get_object_or_404
|
||||
# from django.http import JsonResponse
|
||||
# from django.contrib.auth.decorators import login_required
|
||||
# from django.conf import settings
|
||||
# from .models import Tour, TourCompletion
|
||||
#
|
||||
#
|
||||
# @login_required
|
||||
# def tour_list(request):
|
||||
# tours = Tour.objects.filter(is_active=True)
|
||||
# return render(request, "tours/tour_list.html", {"tours": tours})
|
||||
#
|
||||
#
|
||||
# @login_required
|
||||
# def get_tour_data(request, slug):
|
||||
# tour = get_object_or_404(Tour, slug=slug, is_active=True)
|
||||
#
|
||||
# # Check if user has already completed this tour
|
||||
# completed = TourCompletion.objects.filter(tour=tour, user=request.user).exists()
|
||||
#
|
||||
# # Load the tour data from JSON file
|
||||
# tour_file_path = os.path.join(
|
||||
# settings.BASE_DIR, "static", "js", "tours", tour.tour_file
|
||||
# )
|
||||
#
|
||||
# try:
|
||||
# with open(tour_file_path, "r") as f:
|
||||
# tour_data = json.load(f)
|
||||
# except (FileNotFoundError, json.JSONDecodeError):
|
||||
# return JsonResponse({"error": "Tour data not found or invalid"}, status=404)
|
||||
#
|
||||
# return JsonResponse({"tour": tour_data, "completed": completed})
|
||||
#
|
||||
#
|
||||
# @login_required
|
||||
# def mark_tour_completed(request, slug):
|
||||
# if request.method != "POST":
|
||||
# return JsonResponse({"error": "Method not allowed"}, status=405)
|
||||
#
|
||||
# tour = get_object_or_404(Tour, slug=slug, is_active=True)
|
||||
#
|
||||
# # Mark the tour as completed for this user
|
||||
# TourCompletion.objects.get_or_create(tour=tour, user=request.user)
|
||||
#
|
||||
# return JsonResponse({"status": "success"})
|
||||
#
|
||||
#
|
||||
# @login_required
|
||||
# def start_tour_view(request, slug):
|
||||
# tour = get_object_or_404(Tour, slug=slug, is_active=True)
|
||||
# # Redirect to the page where the tour should start
|
||||
# return render(request, "tours/start_tour.html", {"tour": tour})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user