add admin management+more fixes to the overall logic + lint and formating + more

This commit is contained in:
ismail 2025-05-21 19:26:41 +03:00
parent 41feca462d
commit 8e6d62273d
68 changed files with 1401 additions and 848 deletions

View File

@ -1,5 +1,3 @@
import hashlib
import json
import requests import requests

View File

@ -1,3 +1,2 @@
from django.test import TestCase
# Create your tests here. # Create your tests here.

View File

@ -1,17 +1,15 @@
from django.core.paginator import Paginator from django.core.paginator import Paginator
from django.http import JsonResponse from django.http import JsonResponse
from rest_framework import permissions, status, viewsets, generics from rest_framework import permissions, status, viewsets
from inventory.utils import get_user_type from inventory.utils import get_user_type
from . import models, serializers from . import models, serializers
from .services import get_car_data from .services import get_car_data
from inventory import models as inventory_models from inventory import models as inventory_models
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework import status
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from inventory import models as inventory_models from inventory.services import decodevin
from inventory.services import get_make, get_model, decodevin
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@ -1,3 +1,2 @@
from django.contrib import admin
# Register your models here. # Register your models here.

View File

@ -1,3 +1,2 @@
from django.test import TestCase
# Create your tests here. # Create your tests here.

View File

@ -7,7 +7,6 @@ from django_ledger import models as ledger_models
from import_export.admin import ExportMixin from import_export.admin import ExportMixin
from import_export.resources import ModelResource from import_export.resources import ModelResource
from .models import Car
# # Define resource class # # Define resource class
# class CarSerieResource(ModelResource): # class CarSerieResource(ModelResource):

View File

@ -5,7 +5,7 @@ class InventoryConfig(AppConfig):
name = 'inventory' name = 'inventory'
def ready(self): def ready(self):
import inventory.signals pass
#from decimal import Decimal #from decimal import Decimal
#from inventory.models import VatRate #from inventory.models import VatRate
#VatRate.objects.get_or_create(rate=Decimal('0.15'), is_active=True) #VatRate.objects.get_or_create(rate=Decimal('0.15'), is_active=True)

View File

@ -1,11 +1,8 @@
import re
from django.core.cache import cache 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.core.validators import RegexValidator
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 phonenumber_field.formfields import PhoneNumberField
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
@ -17,9 +14,6 @@ from .mixins import AddClassMixin
from django_ledger.forms.invoice import ( from django_ledger.forms.invoice import (
InvoiceModelCreateForm as InvoiceModelCreateFormBase, InvoiceModelCreateForm as InvoiceModelCreateFormBase,
) )
from django_ledger.forms.estimate import (
EstimateModelCreateForm as EstimateModelCreateFormBase,
)
from django_ledger.forms.bill import BillModelCreateForm as BillModelCreateFormBase from django_ledger.forms.bill import BillModelCreateForm as BillModelCreateFormBase
from django_ledger.forms.journal_entry import JournalEntryModelCreateForm as JournalEntryModelCreateFormBase from django_ledger.forms.journal_entry import JournalEntryModelCreateForm as JournalEntryModelCreateFormBase
@ -1062,6 +1056,7 @@ class LeadForm(forms.ModelForm):
"crn", "crn",
"vrn", "vrn",
"year", "year",
"salary",
"source", "source",
"channel", "channel",
"staff", "staff",

View File

@ -1,7 +1,4 @@
import re import re
from itertools import cycle
from datetime import datetime
from typing import List
def vin_year(vin_char: str) -> int: def vin_year(vin_char: str) -> int:
@ -1830,7 +1827,7 @@ def decode_vin_haikalna(vin):
pattern = r"^[A-HJ-NPR-Z0-9]{17}$" pattern = r"^[A-HJ-NPR-Z0-9]{17}$"
if not re.match(pattern, vin): if not re.match(pattern, vin):
raise Exception(f"VIN number must only contain alphanumeric symbols except 'I', 'O', and 'Q' ") raise Exception("VIN number must only contain alphanumeric symbols except 'I', 'O', and 'Q' ")
vin = vin.upper() vin = vin.upper()

View File

@ -1,11 +1,9 @@
import os
import json import json
import pymysql import pymysql
import pandas as pd import pandas as pd
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from sqlalchemy import create_engine from sqlalchemy import create_engine
from tqdm import tqdm # Progress bar support from tqdm import tqdm # Progress bar support
from django.conf import settings
# Database connection details # Database connection details
db_config = { db_config = {

View File

@ -11,19 +11,19 @@ class Command(BaseCommand):
def handle(self, *args, **kwargs): def handle(self, *args, **kwargs):
vin,description = self.generate_vin() vin,description = self.generate_vin()
result = decodevin(vin) result = decodevin(vin)
self.stdout.write(self.style.SUCCESS(f'####################################################################################################')) self.stdout.write(self.style.SUCCESS('####################################################################################################'))
self.stdout.write(self.style.SUCCESS(f'####################################################################################################')) self.stdout.write(self.style.SUCCESS('####################################################################################################'))
self.stdout.write(self.style.SUCCESS(f'Generated VIN: {vin}')) self.stdout.write(self.style.SUCCESS(f'Generated VIN: {vin}'))
self.stdout.write(self.style.SUCCESS(f'Description: {description}')) self.stdout.write(self.style.SUCCESS(f'Description: {description}'))
self.stdout.write(self.style.SUCCESS(f'####################################################################################################')) self.stdout.write(self.style.SUCCESS('####################################################################################################'))
self.stdout.write(self.style.SUCCESS(f'####################################################################################################')) self.stdout.write(self.style.SUCCESS('####################################################################################################'))
self.stdout.write(self.style.SUCCESS(f'Decoded VIN: {result}')) self.stdout.write(self.style.SUCCESS(f'Decoded VIN: {result}'))
make,model,year_model = result.values() make,model,year_model = result.values()
self.stdout.write(self.style.SUCCESS(f'VIN: {vin} - Make {make} - Model {model} - Model Year {year_model}')) self.stdout.write(self.style.SUCCESS(f'VIN: {vin} - Make {make} - Model {model} - Model Year {year_model}'))
m = get_model(model) m = get_model(model)
self.stdout.write(self.style.SUCCESS(f'Make: {m.id_car_make} - Model: {m}')) self.stdout.write(self.style.SUCCESS(f'Make: {m.id_car_make} - Model: {m}'))
self.stdout.write(self.style.SUCCESS(f'####################################################################################################')) self.stdout.write(self.style.SUCCESS('####################################################################################################'))
self.stdout.write(self.style.SUCCESS(f'####################################################################################################')) self.stdout.write(self.style.SUCCESS('####################################################################################################'))

View File

@ -1,6 +1,6 @@
# management/commands/create_plans.py # management/commands/create_plans.py
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from plans.models import Plan, Quota, PlanQuota, Pricing, PlanPricing from plans.models import Plan, Quota, Pricing, PlanPricing
from decimal import Decimal from decimal import Decimal
from django.db.models import Q from django.db.models import Q

View File

@ -1,12 +1,7 @@
# management/commands/create_plans.py # management/commands/create_plans.py
from decimal import Decimal from decimal import Decimal
from datetime import timedelta
from django.db.models import Q
from django.utils import timezone
from plans.quota import get_user_quota
from django.contrib.auth.models import User
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from plans.models import Plan, Quota, PlanQuota, Pricing, PlanPricing,UserPlan,Order,BillingInfo,AbstractOrder from plans.models import Plan, Quota, PlanQuota, Pricing, PlanPricing
class Command(BaseCommand): class Command(BaseCommand):
help = 'Create basic subscription plans structure' help = 'Create basic subscription plans structure'

View File

@ -1,9 +1,5 @@
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.core.mail import send_mail
from allauth.account.models import EmailConfirmation
from inventory.tasks import send_email
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
import re
from inventory.tasks import create_coa_accounts from inventory.tasks import create_coa_accounts
from inventory.models import Dealer from inventory.models import Dealer

View File

@ -1,12 +1,6 @@
import logging import logging
from django.conf import settings
from inventory import models from inventory import models
from django.utils import timezone from django.utils import timezone
from django.shortcuts import redirect
from django.urls import reverse
from django.utils.deprecation import MiddlewareMixin
from fpdf import FPDF
import os
from inventory.utils import get_user_type from inventory.utils import get_user_type
@ -67,7 +61,7 @@ class InjectParamsMiddleware:
try: try:
# request.entity = request.user.dealer.entity # request.entity = request.user.dealer.entity
request.dealer = get_user_type(request) request.dealer = get_user_type(request)
except Exception as e: except Exception:
pass pass
response = self.get_response(request) response = self.get_response(request)
return response return response
@ -98,7 +92,7 @@ class InjectDealerMiddleware:
request.is_dealer = True request.is_dealer = True
if hasattr(request.user, "staffmember"): if hasattr(request.user, "staffmember"):
request.is_staff = True request.is_staff = True
except Exception as e: except Exception:
pass pass
response = self.get_response(request) response = self.get_response(request)
return response return response

View File

@ -0,0 +1,18 @@
# Generated by Django 5.1.7 on 2025-05-21 10:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0005_notes_dealer'),
]
operations = [
migrations.AddField(
model_name='organization',
name='slug',
field=models.SlugField(blank=True, editable=False, max_length=255, null=True, unique=True),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 5.1.7 on 2025-05-21 13:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0006_organization_slug'),
]
operations = [
migrations.AddField(
model_name='staff',
name='active',
field=models.BooleanField(default=True, verbose_name='Active'),
),
migrations.AddField(
model_name='staff',
name='slug',
field=models.SlugField(blank=True, editable=False, max_length=255, null=True, unique=True),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 5.1.7 on 2025-05-21 15:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0007_staff_active_staff_slug'),
]
operations = [
migrations.AddField(
model_name='lead',
name='salary',
field=models.PositiveIntegerField(blank=True, null=True, verbose_name='Salary'),
),
]

View File

@ -1,6 +1,4 @@
from django import forms
from django.utils.translation import get_language from django.utils.translation import get_language
from django.urls import reverse, reverse_lazy
class AddClassMixin: class AddClassMixin:
""" """

View File

@ -3,7 +3,7 @@ from django.contrib.auth.models import Permission
from decimal import Decimal from decimal import Decimal
from django.utils.text import slugify from django.utils.text import slugify
from django.utils import timezone from django.utils import timezone
from django.core.validators import MinValueValidator, MaxValueValidator from django.core.validators import MinValueValidator
import hashlib import hashlib
from django.db import models from django.db import models
from datetime import timedelta from datetime import timedelta
@ -23,12 +23,12 @@ from django.contrib.auth.models import Group
from inventory.utils import get_user_type, to_dict from inventory.utils import get_user_type, to_dict
from .mixins import LocalizedNameMixin from .mixins import LocalizedNameMixin
from django_ledger.models import EntityModel, ItemModel,EstimateModel,InvoiceModel,AccountModel,EntityManagementModel from django_ledger.models import EstimateModel,InvoiceModel,AccountModel,EntityManagementModel
from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from appointment.models import StaffMember from appointment.models import StaffMember
from plans.quota import get_user_quota from plans.quota import get_user_quota
from plans.models import UserPlan,Quota,PlanQuota from plans.models import UserPlan
# from plans.models import AbstractPlan # from plans.models import AbstractPlan
# from simple_history.models import HistoricalRecords # from simple_history.models import HistoricalRecords
@ -548,7 +548,7 @@ class Car(Base):
def ready(self): def ready(self):
try: try:
return all([self.colors ,self.finances,]) return all([self.colors ,self.finances,])
except Exception as e: except Exception:
return False return False
def get_transfer(self): def get_transfer(self):
return self.transfer_logs.filter(active=True).first() return self.transfer_logs.filter(active=True).first()
@ -1000,11 +1000,37 @@ class Staff(models.Model, LocalizedNameMixin):
arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name")) arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number")) phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number"))
staff_type = models.CharField(choices=StaffTypes.choices, max_length=255, verbose_name=_("Staff Type")) staff_type = models.CharField(choices=StaffTypes.choices, max_length=255, verbose_name=_("Staff Type"))
active = models.BooleanField(default=True, verbose_name=_("Active"))
created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created")) created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created"))
updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated")) updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated"))
slug = models.SlugField(max_length=255, unique=True, editable=False, null=True, blank=True)
def save(self, *args, **kwargs):
if not self.slug:
base_slug = slugify(f"{self.name}")
self.slug = base_slug
counter = 1
while self.__class__.objects.filter(slug=self.slug).exclude(pk=self.pk).exists():
self.slug = f"{base_slug}-{counter}"
counter += 1
super().save(*args, **kwargs)
objects = StaffUserManager() objects = StaffUserManager()
def deactivate_account(self):
self.active = False
self.user.is_active = False
self.user.save()
self.save()
def activate_account(self):
self.active = True
self.user.is_active = True
self.user.save()
self.save()
def permenant_delete(self):
# self.user.delete()
self.staff_member.delete()
self.delete()
@property @property
def email(self): def email(self):
return self.staff_member.user.email return self.staff_member.user.email
@ -1256,7 +1282,17 @@ class Customer(models.Model):
self.customer_model.save() self.customer_model.save()
self.user.save() self.user.save()
self.save() self.save()
def activate_account(self):
self.active = True
self.customer_model.active = True
self.user.is_active = True
self.customer_model.save()
self.user.save()
self.save()
def permenant_delete(self):
self.customer_model.delete()
self.user.delete()
self.delete()
class Organization(models.Model, LocalizedNameMixin): class Organization(models.Model, LocalizedNameMixin):
dealer = models.ForeignKey( dealer = models.ForeignKey(
Dealer, on_delete=models.CASCADE, related_name="organizations" Dealer, on_delete=models.CASCADE, related_name="organizations"
@ -1282,6 +1318,18 @@ class Organization(models.Model, LocalizedNameMixin):
active = models.BooleanField(default=True, verbose_name=_("Active")) active = models.BooleanField(default=True, verbose_name=_("Active"))
created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created")) created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created"))
updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated")) updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated"))
slug = models.SlugField(max_length=255, unique=True, editable=False, null=True, blank=True)
def save(self, *args, **kwargs):
if not self.slug:
base_slug = slugify(f"{self.name}")
self.slug = base_slug
counter = 1
while self.__class__.objects.filter(slug=self.slug).exclude(pk=self.pk).exists():
self.slug = f"{base_slug}-{counter}"
counter += 1
super().save(*args, **kwargs)
class Meta: class Meta:
verbose_name = _("Organization") verbose_name = _("Organization")
@ -1348,6 +1396,17 @@ class Organization(models.Model, LocalizedNameMixin):
self.user.save() self.user.save()
self.customer_model.save() self.customer_model.save()
self.save() self.save()
def activate_account(self):
self.active = True
self.customer_model.active = True
self.user.is_active = True
self.customer_model.save()
self.user.save()
self.save()
def permenant_delete(self):
self.user.delete()
self.customer_model.delete()
self.delete()
class Representative(models.Model, LocalizedNameMixin): class Representative(models.Model, LocalizedNameMixin):
dealer = models.ForeignKey( dealer = models.ForeignKey(
@ -1447,7 +1506,6 @@ class Lead(models.Model):
blank=True, blank=True,
null=True null=True
) )
next_action_date = models.DateTimeField( next_action_date = models.DateTimeField(
verbose_name=_("Next Action Date"), verbose_name=_("Next Action Date"),
blank=True, blank=True,
@ -1455,6 +1513,7 @@ class Lead(models.Model):
) )
is_converted = models.BooleanField(default=False) is_converted = models.BooleanField(default=False)
converted_at = models.DateTimeField(null=True, blank=True) converted_at = models.DateTimeField(null=True, blank=True)
salary = models.PositiveIntegerField(verbose_name=_("Salary"), blank=True, null=True)
created = models.DateTimeField( created = models.DateTimeField(
auto_now_add=True, verbose_name=_("Created"), db_index=True auto_now_add=True, verbose_name=_("Created"), db_index=True
) )
@ -1548,7 +1607,6 @@ class Lead(models.Model):
return Activity.objects.filter(dealer=self.dealer,content_type__model="lead", object_id=self.pk).order_by('-updated').first() return Activity.objects.filter(dealer=self.dealer,content_type__model="lead", object_id=self.pk).order_by('-updated').first()
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
self.status = self.get_status()
if not self.slug: if not self.slug:
base_slug = slugify(f"{self.last_name} {self.first_name}") base_slug = slugify(f"{self.last_name} {self.first_name}")
self.slug = base_slug self.slug = base_slug
@ -1882,7 +1940,13 @@ class Vendor(models.Model, LocalizedNameMixin):
balance_type="credit", balance_type="credit",
active=True active=True
) )
def activate_account(self):
self.active = True
self.vendor_model.active = True
self.save()
def permenant_delete(self):
self.vendor_model.delete()
self.delete()
class Payment(models.Model): class Payment(models.Model):
METHOD_CHOICES = [ METHOD_CHOICES = [
("cash", _("cash")), ("cash", _("cash")),
@ -2034,7 +2098,7 @@ class CustomGroup(models.Model):
try: try:
for perm in Permission.objects.filter(content_type__app_label="inventory"): for perm in Permission.objects.filter(content_type__app_label="inventory"):
self.add_permission(perm) self.add_permission(perm)
except Exception as e: except Exception:
pass pass
def set_default_permissions(self): def set_default_permissions(self):

View File

@ -5,14 +5,10 @@ Services module
import requests import requests
import json import json
from django_ledger.models import EntityModel
from inventory.utils import get_jwt_token, get_user_type
from pyvin import VIN from pyvin import VIN
from django.conf import settings from django.conf import settings
from openai import OpenAI from .models import CarMake
from .models import Car,CarMake,CarModel
from inventory.haikalna import decode_vin_haikalna
def get_make(item): def get_make(item):

View File

@ -1,33 +1,20 @@
from inventory.tasks import create_coa_accounts,create_accounts_for_make,create_settings from inventory.tasks import create_coa_accounts
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from decimal import Decimal from django.db.models.signals import post_save, post_delete
from django.db.models.signals import post_save, post_delete, pre_delete, pre_save
from inventory.models import VatRate
from plans.quota import get_user_quota
from .utils import to_dict
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django_ledger.io import roles from django_ledger.io import roles
from django_ledger.models import ( from django_ledger.models import (
EntityModel, EntityModel,
AccountModel,
ItemModel, ItemModel,
ItemModelAbstract,
UnitOfMeasureModel,
VendorModel,
EstimateModel,
CustomerModel,
JournalEntryModel, JournalEntryModel,
TransactionModel, TransactionModel,
LedgerModel, LedgerModel
BillModel,
ItemTransactionModel
) )
from . import models from . import models
from django.utils.timezone import now from django.utils.timezone import now
from django.db import transaction from django.db import transaction
from django.core.exceptions import ValidationError
User = get_user_model() User = get_user_model()

View File

@ -2,7 +2,7 @@ from django.conf import settings
from django.utils.timesince import timesince from django.utils.timesince import timesince
import django_tables2 as tables import django_tables2 as tables
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from .models import Car, CarFinance, ExteriorColors, InteriorColors, CarColors from .models import Car
from .utils import get_local_name from .utils import get_local_name
from django.utils.html import format_html from django.utils.html import format_html

View File

@ -1,11 +1,10 @@
from time import sleep
from datetime import datetime from datetime import datetime
from django.db import transaction from django.db import transaction
from django_ledger.io import roles from django_ledger.io import roles
from django.core.mail import send_mail from django.core.mail import send_mail
from background_task import background from background_task import background
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from inventory.models import DealerSettings,CarMake,Dealer from inventory.models import DealerSettings,Dealer

View File

@ -5,7 +5,6 @@ from django.urls import reverse
from django.utils.formats import number_format from django.utils.formats import number_format
from django_ledger.io.io_core import get_localdate,validate_activity from django_ledger.io.io_core import get_localdate,validate_activity
from django.conf import settings from django.conf import settings
from django.utils.translation import get_language
register = template.Library() register = template.Library()

View File

@ -7,19 +7,16 @@
# """ # """
from calendar import month_abbr from calendar import month_abbr
from random import randint
from django import template from django import template
from django.db.models import Sum
from django.urls import reverse from django.urls import reverse
from django.utils.formats import number_format
from decimal import Decimal from decimal import Decimal
# from django_ledger import __version__ # from django_ledger import __version__
# from django_ledger.forms.app_filters import EntityFilterForm, ActivityFilterForm # from django_ledger.forms.app_filters import EntityFilterForm, ActivityFilterForm
# from django_ledger.forms.feedback import BugReportForm, RequestNewFeatureForm # from django_ledger.forms.feedback import BugReportForm, RequestNewFeatureForm
# from django_ledger.io import CREDIT, DEBIT, ROLES_ORDER_ALL # from django_ledger.io import CREDIT, DEBIT, ROLES_ORDER_ALL
from django_ledger.io.io_core import validate_activity, get_localdate from django_ledger.io.io_core import get_localdate
# from django_ledger.models import TransactionModel, BillModel, InvoiceModel, EntityUnitModel # from django_ledger.models import TransactionModel, BillModel, InvoiceModel, EntityUnitModel
# from django_ledger.settings import ( # from django_ledger.settings import (
# DJANGO_LEDGER_FINANCIAL_ANALYSIS, DJANGO_LEDGER_CURRENCY_SYMBOL, # DJANGO_LEDGER_FINANCIAL_ANALYSIS, DJANGO_LEDGER_CURRENCY_SYMBOL,

View File

@ -1,8 +1,6 @@
import json import json
from . import models as m from . import models as m
from datetime import datetime
from django.urls import reverse from django.urls import reverse
from django_ledger import models as lm
from django.test import Client, TestCase from django.test import Client, TestCase
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django_ledger.io.io_core import get_localdate from django_ledger.io.io_core import get_localdate

View File

@ -3,7 +3,6 @@ from django.urls import path
from django_tables2.export.export import TableExport from django_tables2.export.export import TableExport
from . import views from . import views
from allauth.account import views as allauth_views
urlpatterns = [ urlpatterns = [
@ -395,12 +394,12 @@ path(
# ), # ),
# Users URLs # Users URLs
path("user/create/", views.UserCreateView.as_view(), name="user_create"),
path("user/<int:pk>/update/", views.UserUpdateView.as_view(), name="user_update"),
path("user/<int:pk>/", views.UserDetailView.as_view(), name="user_detail"),
path("user/", views.UserListView.as_view(), name="user_list"), path("user/", views.UserListView.as_view(), name="user_list"),
path("user/<int:pk>/confirm/", views.UserDeleteview, name="user_delete"), path("user/create/", views.UserCreateView.as_view(), name="user_create"),
path("user/<int:pk>/groups/", views.UserGroupView, name="user_groups"), path("user/<slug:slug>/", views.UserDetailView.as_view(), name="user_detail"),
path("user/<slug:slug>/groups/", views.UserGroupView, name="user_groups"),
path("user/<slug:slug>/update/", views.UserUpdateView.as_view(), name="user_update"),
path("user/<slug:slug>/confirm/", views.UserDeleteview, name="user_delete"),
# Group URLs # Group URLs
path("group/create/", views.GroupCreateView.as_view(), name="group_create"), path("group/create/", views.GroupCreateView.as_view(), name="group_create"),
path("group/<int:pk>/update/", views.GroupUpdateView.as_view(), name="group_update"), path("group/<int:pk>/update/", views.GroupUpdateView.as_view(), name="group_update"),
@ -409,26 +408,26 @@ path(
path("group/<int:pk>/confirm/", views.GroupDeleteview, name="group_delete"), path("group/<int:pk>/confirm/", views.GroupDeleteview, name="group_delete"),
path("group/<int:pk>/permission/", views.GroupPermissionView, name="group_permission"), path("group/<int:pk>/permission/", views.GroupPermissionView, name="group_permission"),
# Organization URLs # Organization URLs
path(
"organizations/", views.OrganizationListView.as_view(), name="organization_list"
),
path(
"organizations/<int:pk>/",
views.OrganizationDetailView.as_view(),
name="organization_detail",
),
path( path(
"organizations/create/", "organizations/create/",
views.OrganizationCreateView.as_view(), views.OrganizationCreateView.as_view(),
name="organization_create", name="organization_create",
), ),
path( path(
"organizations/<int:pk>/update/", "organizations/", views.OrganizationListView.as_view(), name="organization_list"
),
path(
"organizations/<slug:slug>/",
views.OrganizationDetailView.as_view(),
name="organization_detail",
),
path(
"organizations/<slug:slug>/update/",
views.OrganizationUpdateView.as_view(), views.OrganizationUpdateView.as_view(),
name="organization_update", name="organization_update",
), ),
path( path(
"organizations/<int:pk>/delete/", "organizations/<slug:slug>/delete/",
views.OrganizationDeleteView, views.OrganizationDeleteView,
name="organization_delete", name="organization_delete",
), ),
@ -802,6 +801,11 @@ path(
path('entity/<slug:entity_slug>/data/pnl/', path('entity/<slug:entity_slug>/data/pnl/',
views.PnLAPIView.as_view(), views.PnLAPIView.as_view(),
name='entity-json-pnl'), name='entity-json-pnl'),
# Admin Management...
path('management/', views.management_view, name='management'),
path('management/user_management/', views.user_management, name='user_management'),
path('management/<str:content_type>/<slug:slug>/activate_account/', views.activate_account, name='activate_account'),
path('management/<str:content_type>/<slug:slug>/permenant_delete_account/', views.permenant_delete_account, name='permenant_delete_account'),
] ]

View File

@ -1,7 +1,6 @@
from decimal import Decimal from decimal import Decimal
from django.conf import settings from django.conf import settings
from inventory import models
from django_ledger.models.items import ItemModel from django_ledger.models.items import ItemModel
def calculate_vat(value): def calculate_vat(value):
"""Helper to calculate VAT dynamically for a given value.""" """Helper to calculate VAT dynamically for a given value."""

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,3 @@
import pymysql
from sqlalchemy import create_engine from sqlalchemy import create_engine
import pandas as pd import pandas as pd

View File

@ -1,6 +1,5 @@
from vininfo.utils import merge_wmi from vininfo.utils import merge_wmi
from vininfo.dicts import WMI
wmi_manufacturer_mapping = { wmi_manufacturer_mapping = {

View File

@ -1,10 +1,5 @@
import json
import requests
from django.urls import reverse
from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from inventory.models import PaymentHistory,Notification from inventory.models import Notification
from plans.models import Order, PlanPricing,AbstractOrder
def run(): def run():
user = User.objects.first() user = User.objects.first()

View File

@ -1,41 +1,13 @@
from django_ledger.forms.account import AccountModelUpdateForm, AccountModelCreateForm
import requests
import os
from dotenv import load_dotenv from dotenv import load_dotenv
from django.contrib.auth.models import Permission
from django.contrib.auth.models import Group
from django_ledger.models.invoice import InvoiceModel
from django_ledger.utils import accruable_net_summary
from decimal import Decimal
from django_ledger.models import ( from django_ledger.models import (
EstimateModel,
EntityModel, EntityModel,
ItemModel,
ItemTransactionModel,
AccountModel, AccountModel,
CustomerModel,
EntityManagementModel,
) )
# from rich import print # from rich import print
from datetime import date
from inventory.models import ( from inventory.models import (
Car,
Dealer,
VatRate,
Lead,
CarMake, CarMake,
CarModel,
Schedule,
CustomGroup,
) )
from inventory.utils import CarFinanceCalculator
from appointment.models import Appointment, AppointmentRequest, Service, StaffMember
from appointment.models import Appointment, AppointmentRequest, Service, StaffMember
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django_ledger.io.io_core import get_localdate
from datetime import datetime, timedelta
from django.utils import timezone
import hashlib
from django_ledger.io import roles from django_ledger.io import roles
User = get_user_model() User = get_user_model()

View File

@ -1,23 +1,8 @@
from django_ledger.forms.account import AccountModelUpdateForm,AccountModelCreateForm
import requests
import os
from dotenv import load_dotenv from dotenv import load_dotenv
from django.contrib.auth.models import Permission from django_ledger.models import EntityModel
from django.contrib.auth.models import Group
from django_ledger.models.invoice import InvoiceModel
from django_ledger.utils import accruable_net_summary
from decimal import Decimal
from django_ledger.models import EstimateModel,EntityModel,ItemModel,ItemTransactionModel,AccountModel,CustomerModel,EntityManagementModel
# from rich import print # from rich import print
from datetime import date from inventory.models import CarMake
from inventory.models import Car, Dealer, VatRate,Lead,CarMake,CarModel,Schedule,CustomGroup
from inventory.utils import CarFinanceCalculator
from appointment.models import Appointment,AppointmentRequest,Service,StaffMember
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django_ledger.io.io_core import get_localdate
from datetime import datetime, timedelta
from django.utils import timezone
import hashlib
from django_ledger.io import roles from django_ledger.io import roles
User = get_user_model() User = get_user_model()

View File

@ -1,24 +1,9 @@
from django_ledger.forms.account import AccountModelUpdateForm,AccountModelCreateForm
import requests
import os
from dotenv import load_dotenv from dotenv import load_dotenv
from django.contrib.auth.models import Permission
from django.contrib.auth.models import Group
from django_ledger.models.invoice import InvoiceModel from django_ledger.models.invoice import InvoiceModel
from django_ledger.utils import accruable_net_summary
from decimal import Decimal
from django_ledger.models import EstimateModel,EntityModel,ItemModel,ItemTransactionModel,AccountModel,CustomerModel,EntityManagementModel
from rich import print from rich import print
from datetime import date from inventory.models import Car
from inventory.models import Car, Dealer, VatRate,Lead,CarMake,CarModel,Schedule,CustomGroup
from inventory.utils import CarFinanceCalculator from inventory.utils import CarFinanceCalculator
from appointment.models import Appointment,AppointmentRequest,Service,StaffMember
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django_ledger.io.io_core import get_localdate
from datetime import datetime, timedelta
from django.utils import timezone
import hashlib
from django_ledger.io import roles
User = get_user_model() User = get_user_model()

View File

@ -0,0 +1,17 @@
{% extends 'base.html' %}
{% block content %}
<div class="d-flex justify-content-center align-items-center mt-10">
<div class="text-center">
<h1>Activate Account</h1>
<p>Are you sure you want to activate this account "{{ obj.email }}"?</p>
<form method="post">
{% csrf_token %}
<div class="d-flex justify-content-center">
<button class="btn btn-primary mx-2" type="submit">Activate</button>
<a class="btn btn-secondary mx-2" href="{% url 'user_management' %}">Cancel</a>
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,16 @@
{% extends "base.html" %}
{% block content %}
<h1><i class="fas fa-tools me-2"></i>Admin Management</h1>
<div class="row row-cols-1 row-cols-md-4 g-4 mt-10">
<div class="col">
<a href="{% url 'user_management' %}">
<div class="card h-100">
<div class="card-header text-center">
<h5 class="card-title">User Management</h5>
<span style="font-size: 2rem; font-weight: 500;" class="me-2"><i class="fas fa-user"></i></span>
</div>
</div>
</a>
</div>
</div>
{% endblock content %}

View File

@ -0,0 +1,18 @@
{% extends 'base.html' %}
{% block content %}
<div class="d-flex justify-content-center align-items-center mt-10">
<div class="text-center">
<h1 class="display-4">Delete Account</h1>
<p class="lead">Are you sure you want to delete this account "{{ obj.email }}"? This will delete all associated information for this user.</p>
<form method="post">
{% csrf_token %}
<div class="d-flex justify-content-center">
<button class="btn btn-danger mx-2" type="submit"><i class="fas fa-trash me-2"></i> Delete Permenantly</button>
<a class="btn btn-secondary mx-2" href="{% url 'user_management' %}"><i class="fas fa-ban me-2"></i>Cancel</a>
</div>
</form>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,243 @@
{% extends 'base.html' %}
{% load i18n static humanize %}
{% block title %}
{% trans 'User Management' %}
{% endblock title %}
{% block content %}
<section class="pt-5 pb-9">
<div class="row">
<h2 class="mb-4">{% trans 'User Management' %}</h2>
<div class="row g-3 justify-content-between mb-4">
<div class="col-12">
<h3 class="mb-3">{% trans 'Customers' %}</h3>
<div class="table-responsive scrollbar mx-n1 px-1">
<table class="table table-hover fs-9 mb-0">
<thead>
<tr>
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" style="width:20%;">{{ _('First Name') }}</th>
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" style="width:20%;">{{ _('Last Name') }}</th>
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" style="width:20%;">{{ _('Email') }}</th>
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" style="width:15%;">{{ _('Status') }}</th>
<th class="sort align-middle ps-4 pe-5 text-uppercase" scope="col" style="width:15%;">{{ _('Created date') }}</th>
<th class="sort text-end align-middle pe-0 ps-4" scope="col">{{ _('Actions') }}</th>
</tr>
</thead>
<tbody class="list" id="leal-tables-body">
{% for customer in customers %}
<tr>
<td class="ps-0">{{ customer.first_name }}</td>
<td class="ps-0">{{ customer.last_name }}</td>
<td class="ps-0">{{ customer.email }}</td>
<td class="ps-0">
{% if customer.active %}
<span class="fas fa-check-circle text-success"></span> {{ _('Active') }}
{% else %}
<span class="fas fa-times-circle text-danger"></span> {{ _('Inactive') }}
{% endif %}
</td>
<td class="ps-0">{{ customer.created|naturalday|capfirst }}</td>
<td class="align-middle white-space-nowrap text-end">
<div class="btn-reveal-trigger position-static">
<button
class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10"
type="button"
data-bs-toggle="dropdown"
data-boundary="window"
aria-haspopup="true"
aria-expanded="false"
data-bs-reference="parent">
<span class="fas fa-ellipsis-h fs-10"></span>
</button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a href="{% url 'activate_account' 'customer' customer.slug %}"><button class="dropdown-item">{% trans "Activate" %}</button></a>
<div class="dropdown-divider"></div>
<a href="{% url 'permenant_delete_account' 'customer' customer.slug %}"><button class="dropdown-item text-danger">{% trans "Permenantly Delete" %}</button></a>
</div>
</div>
</td>
</tr>
{% empty %}
<td colspan="6" class="text-center">{% trans 'No data available in table' %}</td>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<div class="row mt-5">
<div class="col-12">
<h3 class="mb-3">{% trans 'Organizations' %}</h3>
<div class="table-responsive scrollbar mx-n1 px-1">
<table class="table table-hover fs-9 mb-0">
<thead>
<tr>
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" style="width:20%;">{{ _('Name') }}</th>
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" style="width:20%;">{{ _('Arabic Name') }}</th>
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" style="width:20%;">{{ _('Email') }}</th>
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" style="width:15%;">{{ _('Status') }}</th>
<th class="sort align-middle ps-4 pe-5 text-uppercase" scope="col" style="width:15%;">{{ _('Create date') }}</th>
<th class="sort text-end align-middle pe-0 ps-4" scope="col">{{ _('Actions') }}</th>
</tr>
</thead>
<tbody class="list" id="leal-tables-body">
{% for organization in organizations %}
<tr>
<td class="ps-0">{{ organization.name }}</td>
<td class="ps-0">{{ organization.arabic_name }}</td>
<td class="ps-0">{{ organization.email }}</td>
<td class="ps-0">
{% if customer.active %}
<span class="fas fa-check-circle text-success"></span> {{ _('Active') }}
{% else %}
<span class="fas fa-times-circle text-danger"></span> {{ _('Inactive') }}
{% endif %}
</td>
<td class="ps-0">{{ organization.created|naturalday|capfirst }}</td>
<td class="align-middle white-space-nowrap text-end">
<div class="btn-reveal-trigger position-static">
<button
class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10"
type="button"
data-bs-toggle="dropdown"
data-boundary="window"
aria-haspopup="true"
aria-expanded="false"
data-bs-reference="parent">
<span class="fas fa-ellipsis-h fs-10"></span>
</button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a href="{% url 'activate_account' 'organization' organization.slug %}"><button class="dropdown-item">{% trans "Activate" %}</button></a>
<div class="dropdown-divider"></div>
<a href="{% url 'permenant_delete_account' 'organization' organization.slug %}"><button class="dropdown-item text-danger">{% trans "Permenantly Delete" %}</button></a>
</div>
</div>
</td>
</tr>
{% empty %}
<td colspan="6" class="text-center">{% trans 'No data available in table' %}</td>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<div class="row mt-5">
<div class="col-12">
<h3 class="mb-3">{% trans 'Vendors' %}</h3>
<div class="table-responsive scrollbar mx-n1 px-1">
<table class="table table-hover fs-9 mb-0">
<thead>
<tr>
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" style="width:20%;">{{ _('Name') }}</th>
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" style="width:20%;">{{ _('Arabic Name') }}</th>
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" style="width:20%;">{{ _('Email') }}</th>
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" style="width:15%;">{{ _('Status') }}</th>
<th class="sort align-middle ps-4 pe-5 text-uppercase" scope="col" style="width:15%;">{{ _('Create date') }}</th>
<th class="sort text-end align-middle pe-0 ps-4" scope="col">{{ _('Actions') }}</th>
</tr>
</thead>
<tbody class="list" id="leal-tables-body">
{% for vendor in vendors %}
<tr>
<td class="ps-0">{{ vendor.name }}</td>
<td class="ps-0">{{ vendor.arabic_name }}</td>
<td class="ps-0">{{ vendor.email }}</td>
<td class="ps-0">
{% if customer.active %}
<span class="fas fa-check-circle text-success"></span> {{ _('Active') }}
{% else %}
<span class="fas fa-times-circle text-danger"></span> {{ _('Inactive') }}
{% endif %}
</td>
<td class="ps-0">{{ vendor.created_at|naturalday|capfirst }}</td>
<td class="align-middle white-space-nowrap text-end">
<div class="btn-reveal-trigger position-static">
<button
class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10"
type="button"
data-bs-toggle="dropdown"
data-boundary="window"
aria-haspopup="true"
aria-expanded="false"
data-bs-reference="parent">
<span class="fas fa-ellipsis-h fs-10"></span>
</button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a href="{% url 'activate_account' 'vendor' vendor.slug %}"><button class="dropdown-item">{% trans "Activate" %}</button></a>
<div class="dropdown-divider"></div>
<a href="{% url 'permenant_delete_account' 'vendor' vendor.slug %}"><button class="dropdown-item text-danger">{% trans "Permenantly Delete" %}</button></a>
</div>
</div>
</td>
</tr>
{% empty %}
<td colspan="6" class="text-center">{% trans 'No data available in table' %}</td>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<div class="row mt-5">
<div class="col-12">
<h3 class="mb-3">{% trans 'Staff' %}</h3>
<div class="table-responsive scrollbar mx-n1 px-1">
<table class="table table-hover fs-9 mb-0">
<thead>
<tr>
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" style="width:20%;">{{ _('Name') }}</th>
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" style="width:20%;">{{ _('Arabic Name') }}</th>
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" style="width:20%;">{{ _('Email') }}</th>
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" style="width:15%;">{{ _('Status') }}</th>
<th class="sort align-middle ps-4 pe-5 text-uppercase" scope="col" style="width:15%;">{{ _('Create date') }}</th>
<th class="sort text-end align-middle pe-0 ps-4" scope="col">{{ _('Actions') }}</th>
</tr>
</thead>
<tbody class="list" id="leal-tables-body">
{% for obj in staff %}
<tr>
<td class="ps-0">{{ obj.name }}</td>
<td class="ps-0">{{ obj.arabic_name }}</td>
<td class="ps-0">{{ obj.email }}</td>
<td class="ps-0">
{% if obj.active %}
<span class="fas fa-check-circle text-success"></span> {{ _('Active') }}
{% else %}
<span class="fas fa-times-circle text-danger"></span> {{ _('Inactive') }}
{% endif %}
</td>
<td class="ps-0">{{ obj.created|naturalday|capfirst }}</td>
<td class="align-middle white-space-nowrap text-end">
<div class="btn-reveal-trigger position-static">
<button
class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10"
type="button"
data-bs-toggle="dropdown"
data-boundary="window"
aria-haspopup="true"
aria-expanded="false"
data-bs-reference="parent">
<span class="fas fa-ellipsis-h fs-10"></span>
</button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a href="{% url 'activate_account' 'staff' obj.slug %}"><button class="dropdown-item">{% trans "Activate" %}</button></a>
<div class="dropdown-divider"></div>
<a href="{% url 'permenant_delete_account' 'staff' obj.slug %}"><button class="dropdown-item text-danger">{% trans "Permenantly Delete" %}</button></a>
</div>
</div>
</td>
</tr>
{% empty %}
<td colspan="6" class="text-center">{% trans 'No data available in table' %}</td>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</section>
{% endblock %}

View File

@ -130,14 +130,16 @@
<h5 class="text-body-highlight mb-0 text-end">{{ _("Status")}} <h5 class="text-body-highlight mb-0 text-end">{{ _("Status")}}
{% if lead.status == "new" %} {% if lead.status == "new" %}
<span class="badge badge-phoenix badge-phoenix-primary"><span class="badge-label">{{_("New")}}</span><span class="fa fa-bell ms-1"></span></span> <span class="badge badge-phoenix badge-phoenix-primary"><span class="badge-label">{{_("New")}}</span><span class="fa fa-bell ms-1"></span></span>
{% elif lead.status == "pending" %} {% elif lead.status == "follow_up" %}
<span class="badge badge-phoenix badge-phoenix-warning"><span class="badge-label">{{_("Pending")}}</span><span class="fa fa-clock-o ms-1"></span></span> <span class="badge badge-phoenix badge-phoenix-warning"><span class="badge-label">{{_("Follow Up")}}</span><span class="fa fa-clock-o ms-1"></span></span>
{% elif lead.status == "in_progress" %} {% elif lead.status == "negotiation" %}
<span class="badge badge-phoenix badge-phoenix-info"><span class="badge-label">{{_("In Progress")}}</span><span class="fa fa-wrench ms-1"></span></span> <span class="badge badge-phoenix badge-phoenix-info"><span class="badge-label">{{_("Negotiation")}}</span><span class="fa fa-wrench ms-1"></span></span>
{% elif lead.status == "qualified" %} {% elif lead.status == "won" %}
<span class="badge badge-phoenix badge-phoenix-success"><span class="badge-label">{{_("Qualified")}}</span><span class="fa fa-check ms-1"></span></span> <span class="badge badge-phoenix badge-phoenix-success"><span class="badge-label">{{_("Won")}}</span><span class="fa fa-check ms-1"></span></span>
{% elif lead.status == "canceled" %} {% elif lead.status == "lost" %}
<span class="badge badge-phoenix badge-phoenix-danger"><span class="badge-label">{{_("Canceled")}}</span><span class="fa fa-times ms-1"></span></span> <span class="badge badge-phoenix badge-phoenix-danger"><span class="badge-label">{{_("Lost")}}</span><span class="fa fa-times ms-1"></span></span>
{% elif lead.status == "closed" %}
<span class="badge badge-phoenix badge-phoenix-danger"><span class="badge-label">{{_("Closed")}}</span><span class="fa fa-times ms-1"></span></span>
{% endif %} {% endif %}
</h5> </h5>
</div> </div>
@ -158,51 +160,51 @@
<div class="card-body"> <div class="card-body">
<div class="mb-3"> <div class="mb-3">
<div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-envelope-alt"> </span> <div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-envelope-alt"> </span>
<h5 class="text-body-highlight mb-0">{{ _("Email") }}</h5> <h5 class="text-body-highlight fw-bold mb-0">{{ _("Email") }}</h5>
</div> </div>
<a href="{{ lead.email}}">{{ lead.email }}</a> <span class="text-body-secondary">{{ lead.email }}</span>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-phone"> </span> <div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-phone"> </span>
<h5 class="text-body-highlight mb-0">{{ _("Phone") }}</h5> <h5 class="text-body-highlight fw-bold mb-0">{{ _("Phone") }}</h5>
</div> </div>
<a href="{{ lead.phone_number}}">{{ lead.phone_number}} </a> <span class="text-body-secondary">{{ lead.phone_number}} </span>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-dollar-alt"></span> <div class="d-flex align-items-center mb-1"><span class="currency">{{CURRENCY}}</span>&nbsp;
<h5 class="text-body-highlight mb-0">{{ _("Salary")}}</h5> <h5 class="text-body-highlight fw-bold mb-0">{{ _("Salary")}}</h5>
</div> </div>
<p class="mb-0 text-body-secondary">{{lead.salary}} </p> <p class="mb-0 text-body-secondary"><small><span class="currency">{{CURRENCY}}</span></small>&nbsp;{{lead.salary}} </p>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-clock"></span> <div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-clock"></span>
<h5 class="text-body-highlight mb-0">{{ _("Created")}}</h5> <h5 class="text-body-highlight fw-bold mb-0">{{ _("Created")}}</h5>
</div> </div>
<p class="mb-0 text-body-secondary">{{ lead.created|naturalday|capfirst }}</p> <span class="text-body-secondary">{{ lead.created|naturalday|capfirst }}</span>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-file-check-alt"></span> <div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-file-check-alt"></span>
<h5 class="text-body-highlight mb-0">{{ _("Lead Source")}}</h5> <h5 class="text-body-highlight fw-bold mb-0">{{ _("Lead Source")}}</h5>
</div> </div>
<p class="mb-0 text-body-secondary">{{ lead.source|upper }}</p> <span class="text-body-secondary">{{ lead.source|upper }}</span>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-file-check-alt"></span> <div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-file-check-alt"></span>
<h5 class="text-body-highlight mb-0">{{ _("Lead Channel")}}</h5> <h5 class="text-body-highlight fw-bold mb-0">{{ _("Lead Channel")}}</h5>
</div> </div>
<p class="mb-0 text-body-secondary">{{ lead.channel|upper }}</p> <span class="text-body-secondary">{{ lead.channel|upper }}</span>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-estate"></span> <div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-estate"></span>
<h5 class="mb-0">{{ _("Address") }}</h5> <h5 class="text-body-highlight fw-bold mb-0">{{ _("Address") }}</h5>
</div> </div>
<p class="mb-0 text-body-secondary">{{ lead.address}}</p> <span class="text-body-secondary">{{ lead.address}}</span>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-map"></span> <div class="d-flex align-items-center mb-1"><span class="me-2 uil uil-map"></span>
<h5 class="mb-0 text-body-highlight">{{ _("City") }}</h5> <h5 class="text-body-highlight fw-bold mb-0">{{ _("City") }}</h5>
</div> </div>
<p class="mb-0 text-body-secondary">{{ lead.city }}</p> <span class="text-body-secondary">{{ lead.city }}</span>
</div> </div>
</div> </div>
</div> </div>
@ -213,7 +215,7 @@
<div class="col-md-7 col-lg-7 col-xl-8"> <div class="col-md-7 col-lg-7 col-xl-8">
<div class="d-flex w-100 gap-5"> <div class="d-flex w-100 gap-5">
<div class="kanban-header bg-success w-50 text-white fw-bold"><i class="fa-solid fa-circle-check me-2"></i>{{lead.status|capfirst}} <br> &nbsp; <small>{% trans "Current Stage" %}</small></div> <div class="kanban-header bg-success w-50 text-white fw-bold"><i class="fa-solid fa-circle-check me-2"></i>{{lead.status|capfirst}} <br> &nbsp; <small>{% trans "Current Stage" %}</small></div>
<div class="kanban-header bg-secondary w-50 text-white fw-bold"><i class="fa-solid fa-circle-info me-2"></i>{{lead.next_action|capfirst}} <br> &nbsp; <small>{% trans "Next Action" %}</small></div> <div class="kanban-header bg-secondary w-50 text-white fw-bold"><i class="fa-solid fa-circle-info me-2"></i>{{lead.next_action|capfirst}} <br> &nbsp; <small>{% trans "Next Action" %} :</small>&nbsp; <small>{{lead.next_action_date|naturalday|capfirst}}</small></div>
</div> </div>
<ul class="nav main-tab nav-underline fs-9 deal-details scrollbar flex-nowrap w-100 pb-1 mb-6 justify-content-end mt-5" id="myTab" role="tablist" style="overflow-y: hidden;"> <ul class="nav main-tab nav-underline fs-9 deal-details scrollbar flex-nowrap w-100 pb-1 mb-6 justify-content-end mt-5" id="myTab" role="tablist" style="overflow-y: hidden;">
<li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link active" id="activity-tab" data-bs-toggle="tab" href="#tab-activity" role="tab" aria-controls="tab-activity" aria-selected="false" tabindex="-1"> <span class="fa-solid fa-chart-line me-2 tab-icon-color fs-8"></span>{{ _("Activity") }}</a></li> <li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link active" id="activity-tab" data-bs-toggle="tab" href="#tab-activity" role="tab" aria-controls="tab-activity" aria-selected="false" tabindex="-1"> <span class="fa-solid fa-chart-line me-2 tab-icon-color fs-8"></span>{{ _("Activity") }}</a></li>
@ -329,17 +331,17 @@
<td class="align-middle text-end white-space-nowrap pe-0 action py-2"> <td class="align-middle text-end white-space-nowrap pe-0 action py-2">
{% if note.created_by == request.user %} {% if note.created_by == request.user %}
<a id="updateBtn" <a id="updateBtn"
href="#" href="#"
onclick="updateNote(this)" onclick="updateNote(this)"
class="btn btn-sm btn-phoenix-primary me-2" class="btn btn-sm btn-phoenix-primary me-2"
data-pk="{{ note.pk }}" data-pk="{{ note.pk }}"
data-note="{{ note.note|escapejs }}" data-note="{{ note.note|escapejs }}"
data-url="{% url 'update_note' note.pk %}" data-url="{% url 'update_note' note.pk %}"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#noteModal" data-bs-target="#noteModal"
data-note-title="{{ _('Update') }}<i class='fas fa-pen-square text-primary ms-2'></i>"> data-note-title="{{ _('Update') }}<i class='fas fa-pen-square text-primary ms-2'></i>">
{{ _("Update") }} {{ _("Update") }}
</a> </a>
<button class="btn btn-phoenix-danger btn-sm delete-btn" <button class="btn btn-phoenix-danger btn-sm delete-btn"
data-url="{% url 'delete_note_to_lead' note.pk %}" data-url="{% url 'delete_note_to_lead' note.pk %}"
data-message="Are you sure you want to delete this note?" data-message="Are you sure you want to delete this note?"
@ -582,7 +584,6 @@
</div> </div>
<!-- note Modal --> <!-- note Modal -->
<div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" aria-hidden="true"> <div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" aria-hidden="true">
<div class="modal-dialog modal-md"> <div class="modal-dialog modal-md">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0"> <div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
@ -606,103 +607,120 @@
{% block customJS %} {% block customJS %}
<script> <script>
function updateNote(e) { function updateNote(e) {
let url = e.getAttribute('data-url') let url = e.getAttribute('data-url')
let note = e.getAttribute('data-note') let note = e.getAttribute('data-note')
document.querySelector('#id_note').value = note document.querySelector('#id_note').value = note
let form = document.querySelector('.add_note_form') let form = document.querySelector('.add_note_form')
form.action = url form.action = url
} }
function reset_form() { function reset_form() {
document.querySelector('#id_note').value = "" document.querySelector('#id_note').value = ""
let form = document.querySelector('.add_note_form') let form = document.querySelector('.add_note_form')
form.action = "{% url 'add_note' 'lead' lead.slug %}" form.action = "{% url 'add_note' 'lead' lead.slug %}"
} }
document.addEventListener("DOMContentLoaded", function () { let Toast = Swal.mixin({
let Toast = Swal.mixin({
toast: true,
position: "top-end",
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer;
}
});
// Display Django messages
{% if messages %}
{% for message in messages %}
Toast.fire({
icon: "{{ message.tags }}",
titleText: "{{ message|safe }}"
});
{% endfor %}
{% endif %}
function openActionModal(leadId, currentAction, nextAction, nextActionDate) {
const modal = new bootstrap.Modal(document.getElementById('actionTrackingModal'));
document.getElementById('leadId').value = leadId;
document.getElementById('currentAction').value = currentAction;
document.getElementById('nextAction').value = nextAction;
document.getElementById('nextActionDate').value = nextActionDate;
modal.show();
}
document.getElementById('actionTrackingForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
// Show loading indicator
Swal.fire({
toast: true, toast: true,
icon: 'info',
text: 'Please wait...',
allowOutsideClick: false,
position: "top-end", position: "top-end",
showConfirmButton: false, showConfirmButton: false,
timer: 2000, timer: 3000,
timerProgressBar: false, timerProgressBar: true,
didOpen: (toast) => { didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer; toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer; toast.onmouseleave = Swal.resumeTimer;
} }
}); });
fetch("{% url 'update_lead_actions' %}", { // Display Django messages
method: 'POST', {% if messages %}
body: formData, {% for message in messages %}
headers: { Toast.fire({
'X-CSRFToken': '{{ csrf_token }}' icon: "{{ message.tags }}",
} titleText: "{{ message|safe }}"
}) });
.then(response => response.json()) {% endfor %}
.then(data => { {% endif %}
Swal.close();
if (data.success) { function openActionModal(leadId, currentAction, nextAction, nextActionDate) {
const modal = new bootstrap.Modal(document.getElementById('actionTrackingModal'));
document.getElementById('leadId').value = leadId;
document.getElementById('currentAction').value = currentAction;
document.getElementById('nextAction').value = nextAction;
document.getElementById('nextActionDate').value = nextActionDate;
modal.show();
}
document.getElementById('actionTrackingForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
// Show loading indicator
Swal.fire({
toast: true,
icon: 'info',
text: 'Please wait...',
allowOutsideClick: false,
position: "top-end",
showConfirmButton: false,
timer: 2000,
timerProgressBar: false,
didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer;
}
});
fetch("{% url 'update_lead_actions' %}", {
method: 'POST',
body: formData,
headers: {
'X-CSRFToken': '{{ csrf_token }}'
}
})
.then(response => response.json())
.then(data => {
Swal.close();
if (data.success) {
// Success notification // Success notification
Swal.fire({ Swal.fire({
toast: true, toast: true,
icon: 'success', icon: 'success',
position: "top-end", position: "top-end",
text: data.message || 'Actions updated successfully', text: data.message || 'Actions updated successfully',
showConfirmButton: false, showConfirmButton: false,
timer: 2000, timer: 2000,
timerProgressBar: false, timerProgressBar: false,
didOpen: (toast) => { didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer; toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer; toast.onmouseleave = Swal.resumeTimer;
} }
}).then(() => { }).then(() => {
location.reload(); // Refresh after user clicks OK location.reload(); // Refresh after user clicks OK
}); });
} else { } else {
// Error notification // Error notification
Swal.fire({
toast: true,
icon: 'error',
position: "top-end",
text: data.message || 'Failed to update actions',
showConfirmButton: false,
timer: 2000,
timerProgressBar: false,
didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer;
}
});
}
})
.catch(error => {
Swal.close();
console.error('Error:', error);
Swal.fire({ Swal.fire({
toast: true, toast: true,
icon: 'error', icon: 'error',
position: "top-end", position: "top-end",
text: data.message || 'Failed to update actions', text: 'An unexpected error occurred',
showConfirmButton: false, showConfirmButton: false,
timer: 2000, timer: 2000,
timerProgressBar: false, timerProgressBar: false,
@ -711,34 +729,16 @@
toast.onmouseleave = Swal.resumeTimer; toast.onmouseleave = Swal.resumeTimer;
} }
}); });
}
})
.catch(error => {
Swal.close();
console.error('Error:', error);
Swal.fire({
toast: true,
icon: 'error',
position: "top-end",
text: 'An unexpected error occurred',
showConfirmButton: false,
timer: 2000,
timerProgressBar: false,
didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer;
}
}); });
}); });
});
// Helper function for notifications // Helper function for notifications
function notify(tag, msg) { function notify(tag, msg) {
Toast.fire({ Toast.fire({
icon: tag, icon: tag,
titleText: msg titleText: msg
}); });
} }
});
</script> </script>
{% endblock customJS %} {% endblock customJS %}

View File

@ -1,25 +1,25 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load i18n static crispy_forms_filters %} {% load i18n static crispy_forms_filters %}
{% block customcss %} {% block customcss %}
<style> <style>
.htmx-indicator{ .htmx-indicator{
opacity:0; opacity:0;
transition: opacity 500ms ease-in; transition: opacity 500ms ease-in;
} }
.htmx-request .htmx-indicator{ .htmx-request .htmx-indicator{
opacity:1; opacity:1;
} }
.htmx-request.htmx-indicator{ .htmx-request.htmx-indicator{
opacity:1; opacity:1;
} }
</style> </style>
{% endblock customcss %} {% endblock customcss %}
{% block content %} {% block content %}
<div class="container-fluid"> <div class="container-fluid">
<h1>{% if object %}{{ _("Update") }}{% else %}{{ _("Create") }}{% endif %}</h1> <h1>{% if object %}{{ _("Update") }}{% else %}{{ _("Create") }}{% endif %}</h1>
<div class="row mb-3"> <div class="row mb-3">
<div class="col-sm-6 col-md-8"> <div class="col-sm-6 col-md-8">
<form class="form" method="post"> <form class="form" method="post">
{% csrf_token %} {% csrf_token %}
@ -36,7 +36,7 @@
</div> </div>
</div> </div>
<script> <script>
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
// First, create the spinner div (or use the existing one) // First, create the spinner div (or use the existing one)
const spinner = document.createElement('div'); const spinner = document.createElement('div');

View File

@ -182,6 +182,7 @@
<td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="">{{ lead.email }}</a></td> <td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="">{{ lead.email }}</a></td>
<td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="tel:{{ lead.phone_number }}">{{ lead.phone_number }}</a></td> <td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="tel:{{ lead.phone_number }}">{{ lead.phone_number }}</a></td>
<td class="align-middle white-space-nowrap fw-semibold"> <td class="align-middle white-space-nowrap fw-semibold">
{% if request.user.staffmember.staff %}
<div class="accordion" id="accordionExample"> <div class="accordion" id="accordionExample">
<div class="accordion-item"> <div class="accordion-item">
<h2 class="accordion-header" id="headingTwo"> <h2 class="accordion-header" id="headingTwo">
@ -221,7 +222,8 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{% endif %}
</td> </td>
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.get_status|upper }}</td> <td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.get_status|upper }}</td>
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.staff|upper }}</td> <td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.staff|upper }}</td>

View File

@ -1,23 +1,23 @@
{% load i18n static humanize %} {% load i18n static humanize %}
{% load custom_filters %} {% load custom_filters %}
{% block customCSS %} {% block customCSS %}
<style> <style>
.bg-success-soft { .bg-success-soft {
background-color: rgba(25, 135, 84, 0.1) !important; background-color: rgba(25, 135, 84, 0.1) !important;
opacity: .8; opacity: .8;
} }
.bg-danger-soft { .bg-danger-soft {
background-color: rgba(220, 53, 69, 0.1) !important; background-color: rgba(220, 53, 69, 0.1) !important;
opacity: .8; opacity: .8;
} }
</style> </style>
{% endblock customCSS %} {% endblock customCSS %}
{% for opportunity in opportunities %} {% for opportunity in opportunities %}
<div class="col-12 col-md-6 col-lg-4 col-xl-3"> <div class="col-12 col-md-6 col-lg-4 col-xl-3">
<div class="card h-100 <div class="card h-100
{% if opportunity.get_stage_display == 'Closed Won' %}bg-success-soft {% if opportunity.get_stage_display == 'Closed Won' %}bg-success-soft
{% elif opportunity.get_stage_display == 'Closed Lost' %}bg-danger-soft{% endif %}"> {% elif opportunity.get_stage_display == 'Closed Lost' %}bg-danger-soft{% endif %}">
<div class="card-body"> <div class="card-body">
<h5 class="mb-4">Opportunity for {{ opportunity.customer.customer_name }}</h5> <h5 class="mb-4">Opportunity for {{ opportunity.customer.customer_name }}</h5>
@ -35,8 +35,8 @@
<span class="badge badge-phoenix fs-10 badge-phoenix-danger">{{ opportunity.get_stage_display }}</span> <span class="badge badge-phoenix fs-10 badge-phoenix-danger">{{ opportunity.get_stage_display }}</span>
{% endif %} {% endif %}
<span class="badge badge-phoenix fs-10 <span class="badge badge-phoenix fs-10
{% if opportunity.get_stage_display == 'Won' %}badge-phoenix-success {% if opportunity.get_stage_display == 'Won' %}badge-phoenix-success
{% elif opportunity.get_stage_display == 'Lost' %}badge-phoenix-danger{% endif %}"> {% elif opportunity.get_stage_display == 'Lost' %}badge-phoenix-danger{% endif %}">
{{ opportunity.get_status_display }} {{ opportunity.get_status_display }}
</span> </span>
</div> </div>
@ -61,7 +61,7 @@
</div> </div>
</td> </td>
<td class="text-end"> <td class="text-end">
<p class="fw-semibold fs-9 mb-0 text-body-emphasis"><span class="currency">{{ CURRENCY }}</span>{{ opportunity.expected_revenue }}</p> <p class="fw-semibold fs-9 mb-0 text-body-emphasis"><span class="currency">{{ CURRENCY }}</span>{{ opportunity.expected_revenue }}</p>
</td> </td>
</tr> </tr>

View File

@ -26,7 +26,7 @@
{% csrf_token %} {% csrf_token %}
{{ form|crispy }} {{ form|crispy }}
<div class="col-12"> <div class="col-12">
<button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i> <button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>
<!--<i class="bi bi-save"></i> --> <!--<i class="bi bi-save"></i> -->
{{ _("Save") }} {{ _("Save") }}
</button> </button>

View File

@ -6,6 +6,12 @@
</div> </div>
<div class="col-auto"> <div class="col-auto">
<div class="row g-2 g-sm-3"> <div class="row g-2 g-sm-3">
<div class="col-auto">
<a href="{% url 'order_list' %}" class="btn btn-phoenix-success"><span class="fas fa-list me-2"></span>{{ _("Orders") }}</a>
</div>
<div class="col-auto">
<a href="{% url 'billing_info' %}" class="btn btn-phoenix-info"><span class="fas fa-credit-card me-2"></span>{{ _("Billing Information") }}</a>
</div>
<div class="col-auto"> <div class="col-auto">
<a href="{% url 'account_change_password' %}" class="btn btn-phoenix-danger"><span class="fas fa-key me-2"></span>{{ _("Change Password") }}</a> <a href="{% url 'account_change_password' %}" class="btn btn-phoenix-danger"><span class="fas fa-key me-2"></span>{{ _("Change Password") }}</a>
</div> </div>
@ -108,7 +114,7 @@
<a href="{% url 'pricing_page' %}" class="btn btn-phoenix-secondary ms-2"><span class="fas fa-arrow-right me-2"></span>{{ _("Renew") }}</a> <a href="{% url 'pricing_page' %}" class="btn btn-phoenix-secondary ms-2"><span class="fas fa-arrow-right 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' %}" class="btn btn-phoenix-secondary ms-2"><span class="fas fa-arrow-right me-2"></span>{{ _("Upgrade") }}</a> <a href="{% url 'pricing_page' %}" class="btn btn-sm btn-phoenix-primary ms-2"><span class="fas fa-rocket me-2"></span>{{ _("Upgrade") }}</a>
{% endif %} {% endif %}
{% else %} {% else %}
<span class="text-body-tertiary fw-semibold">You have no active plan.</span> <a href="{% url 'pricing_page' %}" class="btn btn-phoenix-secondary ms-2"><span class="fas fa-arrow-right me-2"></span>{{ _("Subscribe") }}</a> <span class="text-body-tertiary fw-semibold">You have no active plan.</span> <a href="{% url 'pricing_page' %}" class="btn btn-phoenix-secondary ms-2"><span class="fas fa-arrow-right me-2"></span>{{ _("Subscribe") }}</a>

View File

@ -435,6 +435,11 @@
<a class="nav-link px-3 d-block" href="{% url 'dealer_settings' request.user.dealer.slug %}"> <span class="me-2 text-body align-bottom" data-feather="settings"></span>{{ _("Settings") }}</a> <a class="nav-link px-3 d-block" href="{% url 'dealer_settings' request.user.dealer.slug %}"> <span class="me-2 text-body align-bottom" data-feather="settings"></span>{{ _("Settings") }}</a>
{% endif %} {% endif %}
</li> </li>
<li class="nav-item">
{% if request.is_dealer %}
<a class="nav-link px-3 d-block" href="{% url 'management' %}"> <span class="me-2 text-body align-bottom" data-feather="shield"></span>{{ _("Admin Managemnet") }}</a>
{% endif %}
</li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link px-3 d-block" href=""> <span class="me-2 text-body align-bottom" data-feather="help-circle"></span>Help Center</a> <a class="nav-link px-3 d-block" href=""> <span class="me-2 text-body align-bottom" data-feather="help-circle"></span>Help Center</a>
</li> </li>

View File

@ -58,7 +58,7 @@
</div> </div>
</div> {% endcomment %} </div> {% endcomment %}
{% comment %} <div class="row justify-content-center g-1 mt-4"> {% comment %} <div class="row justify-content-center g-1 mt-4">
<div class="col-auto"> <div class="col-auto">
@ -73,7 +73,7 @@
<button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button> <button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a> <a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div> </div>
</form> </form>
</div> </div>

View File

@ -44,15 +44,15 @@
</div> {% endcomment %} </div> {% endcomment %}
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
<button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>
<!--<i class="bi bi-save"></i> -->
{{ _("Save") }}
</button>
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a> <button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>
<!--<i class="bi bi-save"></i> -->
{{ _("Save") }}
</button>
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div> </div>

View File

@ -106,7 +106,7 @@
<button type="submit" class="btn btn-sm btn-success me-1">{% trans "Save" %}</button> <button type="submit" class="btn btn-sm btn-success me-1">{% trans "Save" %}</button>
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger me-1">{% trans "Cancel" %}</a> <a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger me-1">{% trans "Cancel" %}</a>
</div> </div>
</main> </main>
</div> </div>
</div> </div>

View File

@ -20,7 +20,7 @@
<button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button> <button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a> <a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div> </div>
</form> </form>
</div> </div>
</div> </div>

View File

@ -23,7 +23,7 @@
<button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i> {{ _("Save") }}</button> <button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i> {{ _("Save") }}</button>
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a> <a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div> </div>
</form> </form>
</div> </div>
</div> </div>

View File

@ -4,39 +4,39 @@
{% block title %}{% trans "bank account" %}{% endblock title %} {% block title %}{% trans "bank account" %}{% endblock title %}
{% block content %} {% block content %}
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-8"> <div class="col-8">
<div class="card shadow rounded bg-body"> <div class="card shadow rounded bg-body">
<div class="card-header"> <div class="card-header">
<p class="mb-0"> <p class="mb-0">
{% if customer.created %} {% if customer.created %}
<!--<i class="bi bi-pencil-square"></i>--> <!--<i class="bi bi-pencil-square"></i>-->
{{ _("Edit Bank Account") }} {{ _("Edit Bank Account") }}
{% else %} {% else %}
<!--<i class="bi bi-person-plus"></i> --> <!--<i class="bi bi-person-plus"></i> -->
{{ _("Add Bank Account") }} {{ _("Add Bank Account") }}
{% endif %} {% endif %}
</p> </p>
</div>
<div class="card-body">
<form method="post" class="form" novalidate>
{% csrf_token %}
{{ form|crispy }}
{% for error in form.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
<div class="d-flex justify-content-start">
<button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>
<!--<i class="bi bi-save"></i> -->
{{ _("Save") }}
</button>
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div> </div>
</form> <div class="card-body">
<form method="post" class="form" novalidate>
{% csrf_token %}
{{ form|crispy }}
{% for error in form.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
<div class="d-flex justify-content-start">
<button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>
<!--<i class="bi bi-save"></i> -->
{{ _("Save") }}
</button>
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
</form>
</div>
</div>
</div> </div>
</div> </div>
</div>
</div> </div>
</div>
{% endblock %} {% endblock %}

View File

@ -43,14 +43,14 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -42,7 +42,7 @@
<button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button> <button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a> <a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div> </div>
</form> </form>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -26,7 +26,7 @@
<div class="text-danger">{{ error }}</div> <div class="text-danger">{{ error }}</div>
{% endfor %} {% endfor %}
<div class="d-flex justify-content-start"> <div class="d-flex justify-content-start">
<button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i> <button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>
<!--<i class="bi bi-save"></i> --> <!--<i class="bi bi-save"></i> -->
{{ _("Save") }} {{ _("Save") }}
@ -34,7 +34,7 @@
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a> <a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div> </div>
</form> </form>
</div> </div>
</div> </div>

View File

@ -17,11 +17,11 @@
<a href="{% url 'ledger_list' %}" class="btn btn-danger"><i class="fa-solid fa-ban"></i> {% trans "Cancel" %}</a> <a href="{% url 'ledger_list' %}" class="btn btn-danger"><i class="fa-solid fa-ban"></i> {% trans "Cancel" %}</a>
</div> {% endcomment %} </div> {% endcomment %}
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
<button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button> <button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a> <a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div> </div>
</form> </form>
</div> </div>

View File

@ -13,7 +13,7 @@
<div class="d-flex"> <div class="d-flex">
<a href="{% url 'organization_update' organization.pk %}" class="btn btn-sm btn-warning me-2">{% trans "Edit" %}</a> <a href="{% url 'organization_update' organization.pk %}" class="btn btn-sm btn-warning me-2">{% trans "Edit" %}</a>
<button class="btn btn-phoenix-danger btn-sm delete-btn" <button class="btn btn-phoenix-danger btn-sm delete-btn"
data-url="{% url 'organization_delete' organization.pk %}" data-url="{% url 'organization_delete' organization.slug %}"
data-message="Are you sure you want to delete this organization?" data-message="Are you sure you want to delete this organization?"
data-bs-toggle="modal" data-bs-target="#deleteModal"> data-bs-toggle="modal" data-bs-target="#deleteModal">
{% trans 'Delete' %}<i class="fas fa-trash ms-1"></i> {% trans 'Delete' %}<i class="fas fa-trash ms-1"></i>

View File

@ -93,7 +93,7 @@
{% trans 'Are you sure you want to delete this Organization?' %} {% trans 'Are you sure you want to delete this Organization?' %}
</p> </p>
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">{% trans 'No' %}</button> <button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">{% trans 'No' %}</button>
<a type="button" class="btn btn-danger btn-sm" href="{% url 'organization_delete' org.pk %}">{% trans 'Yes' %}</a> <a type="button" class="btn btn-danger btn-sm" href="{% url 'organization_delete' org.slug %}">{% trans 'Yes' %}</a>
</div> </div>
</div> </div>
</div> </div>
@ -102,7 +102,7 @@
<td class="name align-middle white-space-nowrap ps-0"> <td class="name align-middle white-space-nowrap ps-0">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<div> <div>
<a class="fs-8 fw-bold" href="{% url 'organization_detail' org.pk %}">{{ org.name }}</a> <a class="fs-8 fw-bold" href="{% url 'organization_detail' org.slug %}">{{ org.name }}</a>
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<p class="mb-0 text-body-highlight fw-semibold fs-9 me-2"></p><span class="badge badge-phoenix badge-phoenix-primary">{{ org.name }}</span> <p class="mb-0 text-body-highlight fw-semibold fs-9 me-2"></p><span class="badge badge-phoenix badge-phoenix-primary">{{ org.name }}</span>
</div> </div>
@ -121,7 +121,7 @@
<div class="btn-reveal-trigger position-static"> <div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button> <button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
<div class="dropdown-menu dropdown-menu-end py-2"> <div class="dropdown-menu dropdown-menu-end py-2">
<a href="{% url 'organization_update' org.pk %}" class="dropdown-item text-success-dark">{% trans 'Edit' %}</a> <a href="{% url 'organization_update' org.slug %}" class="dropdown-item text-success-dark">{% trans 'Edit' %}</a>
{% if perms.django_ledger.delete_customermodel %} {% if perms.django_ledger.delete_customermodel %}
<div class="dropdown-divider"></div><button class="dropdown-item text-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">{% trans 'Delete' %}</button> <div class="dropdown-divider"></div><button class="dropdown-item text-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">{% trans 'Delete' %}</button>
{% endif %} {% endif %}

View File

@ -22,7 +22,7 @@
<div class="container text-center" data-aos="fade-up"> <div class="container text-center" data-aos="fade-up">
<div class="py-5"> <div class="py-5">
<i class="bi bi-x-circle-fill text-danger" style="font-size: 5rem;"></i> <i class="bi bi-x-circle-fill text-danger" style="font-size: 5rem;"></i>
<h2 class="mt-4">{% trans "Payment Failed"%}</h2> <h2 class="mt-4">{% trans "Payment Failed"%}</h2>
{% if message %} {% if message %}
<p class="lead">{{message}}.</p> <p class="lead">{{message}}.</p>
{% else %} {% else %}

View File

@ -207,26 +207,26 @@
{% block customJS %} {% block customJS %}
<script> <script>
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
const form = document.getElementById('wizardForm'); const form = document.getElementById('wizardForm');
form.addEventListener('submit', function(e) { form.addEventListener('submit', function(e) {
e.preventDefault(); // Prevent default form submission e.preventDefault(); // Prevent default form submission
// Show loading alert // Show loading alert
Swal.fire({ Swal.fire({
title: 'Processing...', title: 'Processing...',
html: 'Please wait while we submit your form', html: 'Please wait while we submit your form',
allowOutsideClick: false, allowOutsideClick: false,
didOpen: () => { didOpen: () => {
Swal.showLoading(); Swal.showLoading();
} }
}); });
// Submit the form after a slight delay to ensure Swal is shown // Submit the form after a slight delay to ensure Swal is shown
setTimeout(() => { setTimeout(() => {
form.submit(); form.submit();
}, 100); }, 100);
}); });
const radios = document.querySelectorAll('.btn-check'); const radios = document.querySelectorAll('.btn-check');
radios.forEach(radio => { radios.forEach(radio => {

View File

@ -68,13 +68,13 @@
</div> {% endcomment %} </div> {% endcomment %}
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
<button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i> <button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>
<!--<i class="bi bi-save"></i> --> <!--<i class="bi bi-save"></i> -->
{{ _("Save") }} {{ _("Save") }}
</button> </button>
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a> <a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div> </div>

View File

@ -55,7 +55,7 @@
</td> </td>
<td class="align-middle product white-space-nowrap">{{ invoice.created }}</td> <td class="align-middle product white-space-nowrap">{{ invoice.created }}</td>
<td class="align-middle product white-space-nowrap"> <td class="align-middle product white-space-nowrap">
<a href="{% url 'invoice_detail' invoice.pk %}" <a href="{% url 'invoice_detail' invoice.pk %}"
class="btn btn-sm btn-phoenix-success"> class="btn btn-sm btn-phoenix-success">
<i class="fa-regular fa-eye me-1"></i> <i class="fa-regular fa-eye me-1"></i>
{% trans "View" %} {% trans "View" %}

View File

@ -27,7 +27,7 @@
</div> </div>
<h4 class="my-4">Groups</h4> <h4 class="my-4">Groups</h4>
<a class="btn btn-sm btn-primary mt-2 mb-4" href="{% url 'user_groups' user_.pk %}"><i class="fa-solid fa-users"></i> Manage Groups</a> <a class="btn btn-sm btn-primary mt-2 mb-4" href="{% url 'user_groups' user_.slug %}"><i class="fa-solid fa-users"></i> Manage Groups</a>
<table class="table table-hover table-responsive-sm fs-9 mb-0"> <table class="table table-hover table-responsive-sm fs-9 mb-0">
<thead> <thead>
<tr> <tr>
@ -48,13 +48,13 @@
</table> </table>
</div> </div>
<div class="card-footer d-flex "> <div class="card-footer d-flex ">
<a class="btn btn-sm btn-phoenix-primary me-1" href="{% url 'user_update' user_.id %}"> <a class="btn btn-sm btn-phoenix-primary me-1" href="{% url 'user_update' user_.slug %}">
{{ _("Edit") }} {{ _("Edit") }}
<i class="fa-solid fa-pen-to-square"></i> <i class="fa-solid fa-pen-to-square"></i>
</a> </a>
<button class="btn btn-phoenix-danger btn-sm delete-btn me-1" <button class="btn btn-phoenix-danger btn-sm delete-btn me-1"
data-url="{% url 'user_delete' user_.id %}" data-url="{% url 'user_delete' user_.slug %}"
data-message="{{ _("Are you sure you want to delete this user?")}}" data-message="{{ _("Are you sure you want to delete this user?")}}"
data-bs-toggle="modal" data-bs-target="#deleteModal"> data-bs-toggle="modal" data-bs-target="#deleteModal">
{{ _("Delete") }} {{ _("Delete") }}

View File

@ -2,10 +2,7 @@
{% load i18n %} {% load i18n %}
{% load crispy_forms_filters %} {% load crispy_forms_filters %}
{% block title %}{% trans "Group" %}{% endblock title %} {% block title %}{% trans "Group" %}{% endblock title %}
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="row"> <div class="row">
<div class="col-sm-9"> <div class="col-sm-9">
@ -16,7 +13,6 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-sm-9"> <div class="col-sm-9">
<form class="row g-3 mb-9" method="post" class="form" novalidate> <form class="row g-3 mb-9" method="post" class="form" novalidate>
{% csrf_token %} {% csrf_token %}
{{ redirect_field }} {{ redirect_field }}

View File

@ -11,8 +11,16 @@
<div class="col-auto"> <div class="col-auto">
<div class="d-md-flex justify-content-between"> <div class="d-md-flex justify-content-between">
<div> <div>
<a href="{% url 'user_create' %}" class="btn btn-sm btn-phoenix-primary"><i class="fa-solid fa-user-tie"></i> {% trans "Add New Staff" %}</a> {% if request.user.userplan %}
<a href="{% url 'group_list' %}" class="btn btn-sm btn-phoenix-success"><i class="fa-solid fa-user-group"></i> {% trans "Manage Groups & Permissions" %}</a> <a href="{% url 'user_create' %}" class="btn btn-sm btn-phoenix-primary"><i class="fa-solid fa-user-tie"></i> {% trans "Add New Staff" %}</a>
<a href="{% url 'group_list' %}" class="btn btn-sm btn-phoenix-success"><i class="fa-solid fa-user-group"></i> {% trans "Manage Groups & Permissions" %}</a>
{% else %}
<div class="alert alert-outline-info d-flex align-items-center" role="alert">
<i class="fa-solid fa-circle-info fs-6"></i>
<p class="mb-0 flex-1">{{ _("No Active Subscription,please activate your subscription.") }}<a href="{% url 'pricing_page' %}" class="ms-3 text-body-primary fs-9">Manage Subscription</a></p>
<button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endif %}
</div> </div>
</div> </div>
</div> </div>
@ -33,7 +41,7 @@
<tr> <tr>
<td class="align-middle white-space-nowrap ps-0"> <td class="align-middle white-space-nowrap ps-0">
<div> <div>
<a class="fs-8 fw-bold" href="{% url 'user_detail' user.pk%}">{{ user.arabic_name }}</a> <a class="fs-8 fw-bold" href="{% url 'user_detail' user.slug%}">{{ user.arabic_name }}</a>
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<p class="mb-0 text-body-highlight fw-semibold fs-9 me-2">{{ user.name }}</p> <p class="mb-0 text-body-highlight fw-semibold fs-9 me-2">{{ user.name }}</p>
</div> </div>
@ -47,7 +55,7 @@
<td class="align-middle white-space-nowrap"> <td class="align-middle white-space-nowrap">
<a class="btn btn-phoenix-success" <a class="btn btn-phoenix-success"
href="{% url 'user_detail' user.id %}"> href="{% url 'user_detail' user.slug %}">
<i class="fa-solid fa-eye"></i> <i class="fa-solid fa-eye"></i>
{% trans 'view'|capfirst %} {% trans 'view'|capfirst %}
</a> </a>

View File

@ -35,11 +35,11 @@
<div class="text-danger">{{ error }}</div> <div class="text-danger">{{ error }}</div>
{% endfor %} {% endfor %}
<div class="d-flex justify-content-start"> <div class="d-flex justify-content-start">
<button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i> <button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>
<!--<i class="bi bi-save"></i> --> <!--<i class="bi bi-save"></i> -->
{{ _("Save") }} {{ _("Save") }}
</button> </button>
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a> <a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div> </div>
</form> </form>

View File

@ -38,92 +38,92 @@
</div> </div>
</div> </div>
<div class="table-responsive scrollbar mx-n1 px-1"> <div class="table-responsive scrollbar mx-n1 px-1">
<table class="table table-hover fs-9 mb-0"> <table class="table table-hover fs-9 mb-0">
<thead> <thead>
<tr> <tr>
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" data-sort="name" style="width:25%;">{{ _("Name")|capfirst }}</th> <th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" data-sort="name" style="width:25%;">{{ _("Name")|capfirst }}</th>
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="email" style="width:15%;"> <th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="email" style="width:15%;">
<div class="d-inline-flex flex-center"> <div class="d-inline-flex flex-center">
<div class="d-flex align-items-center px-1 py-1 bg-success-subtle rounded me-2"><span class="text-success-dark" data-feather="mail"></span></div><span>{{ _("email")|capfirst }}</span> <div class="d-flex align-items-center px-1 py-1 bg-success-subtle rounded me-2"><span class="text-success-dark" data-feather="mail"></span></div><span>{{ _("email")|capfirst }}</span>
</div> </div>
</th> </th>
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="phone" style="width:15%; min-width: 180px;"> <th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="phone" style="width:15%; min-width: 180px;">
<div class="d-inline-flex flex-center"> <div class="d-inline-flex flex-center">
<div class="d-flex align-items-center px-1 py-1 bg-primary-subtle rounded me-2"><span class="text-primary-dark" data-feather="phone"></span></div><span>{{ _("Phone") }}</span> <div class="d-flex align-items-center px-1 py-1 bg-primary-subtle rounded me-2"><span class="text-primary-dark" data-feather="phone"></span></div><span>{{ _("Phone") }}</span>
</div> </div>
</th> </th>
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="contact" style="width:15%;"> <th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="contact" style="width:15%;">
<div class="d-inline-flex flex-center"> <div class="d-inline-flex flex-center">
<div class="d-flex align-items-center px-1 py-1 bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="user"></span></div><span>{{ _("Contact name")|capfirst }}</span> <div class="d-flex align-items-center px-1 py-1 bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="user"></span></div><span>{{ _("Contact name")|capfirst }}</span>
</div> </div>
</th> </th>
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="company" style="width:15%;"> <th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="company" style="width:15%;">
<div class="d-inline-flex flex-center"> <div class="d-inline-flex flex-center">
<div class="d-flex align-items-center px-1 py-1 bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div><span>{{ _("Address")|capfirst }}</span> <div class="d-flex align-items-center px-1 py-1 bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div><span>{{ _("Address")|capfirst }}</span>
</div> </div>
</th> </th>
<th class="sort align-middle ps-4 pe-5 text-uppercase" scope="col" data-sort="date" style="width:15%;"> <th class="sort align-middle ps-4 pe-5 text-uppercase" scope="col" data-sort="date" style="width:15%;">
{{ _("Create date") }}</th> {{ _("Create date") }}</th>
<th class="sort text-end align-middle pe-0 ps-4" scope="col"></th> <th class="sort text-end align-middle pe-0 ps-4" scope="col"></th>
</tr> </tr>
</thead> </thead>
<tbody class="list" id="leal-tables-body"> <tbody class="list" id="leal-tables-body">
{% for vendor in vendors %} {% for vendor in vendors %}
<tr class="hover-actions-trigger btn-reveal-trigger position-static"> <tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="name align-middle white-space-nowrap ps-0"> <td class="name align-middle white-space-nowrap ps-0">
<div class="d-flex align-items-center">
{% if vendor.logo %}
<div class="avatar avatar-xl me-3"><img class="rounded-circle" src="{{ vendor.logo.url }}" alt="" />
{% else %}
<div class="avatar avatar-xl me-3"><img class="rounded-circle" src="{% static 'images/icons/picture.svg' %}" alt="" />
{% endif %}
</div>
<div><a class="fs-8 fw-bold" href="{% url 'vendor_detail' vendor.slug %}">{{ vendor.arabic_name }}</a>
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
{% if vendor.logo %} <p class="mb-0 text-body-highlight fw-semibold fs-9 me-2">{{ vendor.name}}</p><!--<span class="badge badge-phoenix badge-phoenix-primary">{{ vendor.vendor_model.uuid }}</span>-->
<div class="avatar avatar-xl me-3"><img class="rounded-circle" src="{{ vendor.logo.url }}" alt="" />
{% else %}
<div class="avatar avatar-xl me-3"><img class="rounded-circle" src="{% static 'images/icons/picture.svg' %}" alt="" />
{% endif %}
</div>
<div><a class="fs-8 fw-bold" href="{% url 'vendor_detail' vendor.slug %}">{{ vendor.arabic_name }}</a>
<div class="d-flex align-items-center">
<p class="mb-0 text-body-highlight fw-semibold fs-9 me-2">{{ vendor.name}}</p><!--<span class="badge badge-phoenix badge-phoenix-primary">{{ vendor.vendor_model.uuid }}</span>-->
</div>
</div> </div>
</div> </div>
</td> </div>
<td class="email align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent"><a class="text-body-highlight" href="">{{ vendor.email }}</a></td> </td>
<td class="phone align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent"><a class="text-body-highlight" href="tel:{{ vendor.phone }}">{{ vendor.phone_number }}</a></td> <td class="email align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent"><a class="text-body-highlight" href="">{{ vendor.email }}</a></td>
<td class="contact align-middle white-space-nowrap ps-4 border-end border-translucent fw-semibold text-body-highlight">{{ vendor.contact_person }}</td> <td class="phone align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent"><a class="text-body-highlight" href="tel:{{ vendor.phone }}">{{ vendor.phone_number }}</a></td>
<td class="company align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 border-end border-translucent fw-semibold text-body-highlight"> <td class="contact align-middle white-space-nowrap ps-4 border-end border-translucent fw-semibold text-body-highlight">{{ vendor.contact_person }}</td>
{{ vendor.address }}</td> <td class="company align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 border-end border-translucent fw-semibold text-body-highlight">
<td class="date align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 text-body-tertiary">{{ vendor.created_at|date }}</td> {{ vendor.address }}</td>
<td class="align-middle white-space-nowrap text-end pe-0 ps-4"> <td class="date align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 text-body-tertiary">{{ vendor.created_at|date }}</td>
<div class="btn-reveal-trigger position-static"> <td class="align-middle white-space-nowrap text-end pe-0 ps-4">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button> <div class="btn-reveal-trigger position-static">
<div class="dropdown-menu dropdown-menu-end py-2"> <button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
<a href="{% url 'vendor_update' vendor.slug %}" class="dropdown-item text-success-dark"> <div class="dropdown-menu dropdown-menu-end py-2">
{% trans "Edit" %} <a href="{% url 'vendor_update' vendor.slug %}" class="dropdown-item text-success-dark">
</a> {% trans "Edit" %}
<div class="dropdown-divider"></div> </a>
<button class="delete-btn dropdown-item text-danger" <div class="dropdown-divider"></div>
data-url="{% url 'vendor_delete' vendor.slug %}" <button class="delete-btn dropdown-item text-danger"
data-message="{{ _("Are you sure you want to delete this vendor")}}?" data-url="{% url 'vendor_delete' vendor.slug %}"
data-bs-toggle="modal" data-bs-target="#deleteModal"> data-message="{{ _("Are you sure you want to delete this vendor")}}?"
{{ _("Delete") }} data-bs-toggle="modal" data-bs-target="#deleteModal">
</button> {{ _("Delete") }}
</div> </button>
</div> </div>
</td> </div>
</tr> </td>
{% endfor %} </tr>
</tbody> {% endfor %}
</tbody>
</table> </table>
</div> </div>
<div class="row align-items-center justify-content-end py-4 pe-0 fs-9"> <div class="row align-items-center justify-content-end py-4 pe-0 fs-9">
<!-- Optional: Pagination --> <!-- Optional: Pagination -->
{% if is_paginated %} {% if is_paginated %}
{% include 'partials/pagination.html' %} {% include 'partials/pagination.html' %}
{% endif %} {% endif %}
</div> </div>
</div> </div>
</section> </section>
{% include 'modal/delete_modal.html' %} {% include 'modal/delete_modal.html' %}
{% endblock %} {% endblock %}