Compare commits

...

6 Commits

55 changed files with 1909 additions and 1285 deletions

View File

@ -1,3 +1,4 @@
import logging
import uuid
from datetime import datetime
from django.conf import settings
@ -51,6 +52,10 @@ from imagekit.processors import ResizeToFill
# from simple_history.models import HistoricalRecords
from plans.models import Invoice
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
class Base(models.Model):
id = models.UUIDField(
unique=True,
@ -881,11 +886,11 @@ class Car(Base):
@property
def get_additional_services_vat(self):
vat = VatRate.objects.filter(dealer=self.dealer,is_active=True).first()
return sum([Decimal((x.price)*(vat.rate)) for x in self.additional_services.all()])
return sum([Decimal((x.price)*(vat.rate)) for x in self.additional_services.filter(taxable=True)])
def get_additional_services(self):
vat = VatRate.objects.filter(dealer=self.dealer,is_active=True).first()
return {"services": [[x,(x.price)*(vat.rate)] for x in self.additional_services.all()],
return {"services": [[x,((x.price)*(vat.rate) if x.taxable else 0)] for x in self.additional_services.all()],
"total_":self.get_additional_services_amount_,
"total":self.get_additional_services_amount,
"services_vat":self.get_additional_services_vat}
@ -3720,4 +3725,32 @@ class Ticket(models.Model):
return ", ".join(parts)
def __str__(self):
return f"#{self.id} - {self.subject} ({self.status})"
return f"#{self.id} - {self.subject} ({self.status})"
class CarImage(models.Model):
car = models.OneToOneField('Car', on_delete=models.CASCADE, related_name='generated_image')
image_hash = models.CharField(max_length=64, unique=True)
image = models.ImageField(upload_to='car_images/', null=True, blank=True)
is_generating = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
def generate_hash(self):
"""Simple hash generation"""
car = self.car
hash_string = f"{car.id_car_make.name if car.id_car_make else ''}-{car.id_car_model.name if car.id_car_model else ''}-{car.year}-{getattr(car, 'color', 'default')}"
return hashlib.sha256(hash_string.encode()).hexdigest()
def schedule_generation(self):
"""Schedule image generation"""
from django_q.tasks import async_task
from inventory.tasks import generate_car_image_task
self.is_generating = True
self.save()
async_task(
generate_car_image_task,
self.id,
task_name=f"generate_car_image_{self.car.vin}"
)

View File

@ -413,24 +413,26 @@ def create_item_model(sender, instance, created, **kwargs):
# quotation.save()
@receiver(post_save, sender=models.CarColors)
def update_car_when_color_changed(sender, instance, **kwargs):
"""
Signal receiver to handle updates to a car instance when its related
CarColors instance is modified. Triggered by the `post_save` signal
for the `CarColors` model. Ensures that the associated `Car` instance
is saved, propagating changes effectively.
# @receiver(post_save, sender=models.CarColors)
# def update_car_hash_when_color_changed(sender, instance, **kwargs):
# """
# Signal receiver to handle updates to a car instance when its related
# CarColors instance is modified. Triggered by the `post_save` signal
# for the `CarColors` model. Ensures that the associated `Car` instance
# is saved, propagating changes effectively.
:param sender: The model class (`CarColors`) that was saved.
:type sender: Type[models.CarColors]
:param instance: The specific instance of `CarColors` that was saved.
:type instance: models.CarColors
:param kwargs: Additional keyword arguments passed by the signal.
:type kwargs: dict
:return: None
"""
car = instance.car
car.save()
# :param sender: The model class (`CarColors`) that was saved.
# :type sender: Type[models.CarColors]
# :param instance: The specific instance of `CarColors` that was saved.
# :type instance: models.CarColors
# :param kwargs: Additional keyword arguments passed by the signal.
# :type kwargs: dict
# :return: None
# """
# car = instance.car
# car.hash = car.get_hash
# car.save()
@receiver(post_save, sender=models.Opportunity)
@ -1260,4 +1262,41 @@ def send_ticket_notification(sender, instance, created, **kwargs):
kwargs={"dealer_slug": instance.dealer.slug, "ticket_id": instance.pk},
),
),
)
)
@receiver(post_save, sender=models.CarColors)
def handle_car_image(sender, instance, created, **kwargs):
"""
Simple handler for car image generation
"""
try:
# Create or get car image record
car = instance.car
car_image, created = models.CarImage.objects.get_or_create(car=car, defaults={'image_hash': car.get_hash})
# Check for existing image with same hash
existing = models.CarImage.objects.filter(
image_hash=car_image.image_hash,
image__isnull=False
).exclude(car=car).first()
if existing:
# Copy existing image
car_image.image.save(
existing.image.name,
existing.image.file,
save=True
)
logger.info(f"Reused image for car {car.vin}")
else:
# Schedule async generation
async_task(
'inventory.tasks.generate_car_image_task',
car_image.id,
task_name=f"generate_car_image_{car.vin}"
)
logger.info(f"Scheduled image generation for car {car.vin}")
except Exception as e:
logger.error(f"Error handling car image for {car.vin}: {e}")

View File

@ -1,5 +1,8 @@
import base64
import logging
import requests
from PIL import Image
from io import BytesIO
from plans.models import Plan
from django.urls import reverse
from django.conf import settings
@ -18,7 +21,8 @@ from .utils import get_accounts_data,create_account
from django.template.loader import render_to_string
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import User, Group, Permission
from inventory.models import DealerSettings, Dealer,Schedule,Notification,CarReservation,CarStatusChoices
from inventory.models import DealerSettings, Dealer,Schedule,Notification,CarReservation,CarStatusChoices,CarImage
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
@ -928,4 +932,30 @@ def remove_reservation_by_id(reservation_id):
logger.error(f"Error removing reservation with ID {reservation_id}: {e}")
def test_task(**kwargs):
print("TASK : ",kwargs.get("dealer"))
print("TASK : ",kwargs.get("dealer"))
def generate_car_image_task(car_image_id):
"""
Simple async task to generate car image
"""
from inventory.utils import generate_car_image_simple
try:
car_image = CarImage.objects.get(id=car_image_id)
result = generate_car_image_simple(car_image)
return {
'success': result.get('success', False),
'car_image_id': car_image_id,
'error': result.get('error'),
'message': 'Image generated' if result.get('success') else 'Generation failed'
}
except CarImage.DoesNotExist:
error_msg = f"CarImage with id {car_image_id} not found"
logger.error(error_msg)
return {'success': False, 'error': error_msg}
except Exception as e:
error_msg = f"Unexpected error: {e}"
logger.error(error_msg)
return {'success': False, 'error': error_msg}

View File

@ -3,11 +3,15 @@ import secrets
import logging
import datetime
import requests
from PIL import Image
from io import BytesIO
from decimal import Decimal
from inventory import models
from django.urls import reverse
from django.conf import settings
from urllib.parse import urljoin
from django.utils import timezone
from django.db import transaction
from django_ledger.io import roles
from django.contrib import messages
from django.shortcuts import redirect
@ -20,16 +24,17 @@ from django_ledger.models import (
BillModel,
VendorModel,
)
from django.core.files.base import ContentFile
from django_ledger.models.items import ItemModel
from django.utils.translation import get_language
from django.core.exceptions import ObjectDoesNotExist
from django.utils.translation import gettext_lazy as _
from django_q.models import Schedule as DjangoQSchedule
from django.contrib.contenttypes.models import ContentType
from django_ledger.models.transactions import TransactionModel
from django_ledger.models.journal_entry import JournalEntryModel
from django.db import transaction
from django_q.models import Schedule as DjangoQSchedule
from django_ledger.io import roles
# from .tasks import generate_car_image_task
logger = logging.getLogger(__name__)
@ -1301,7 +1306,7 @@ def get_finance_data(estimate,dealer):
additional_services = car.get_additional_services()
discounted_price=(Decimal(car.marked_price) - discount)
vat_amount = discounted_price * vat.rate
total_services_vat=sum([ x[1] for x in additional_services.get("services")])
total_services_vat=sum([x[1] for x in additional_services.get("services")])
total_vat=vat_amount+total_services_vat
return {
"car": car,
@ -1311,7 +1316,7 @@ def get_finance_data(estimate,dealer):
"vat_rate": vat.rate,
"discount_amount": discount,
"additional_services": additional_services,
"final_price": discounted_price+ vat_amount,
"final_price": discounted_price + vat_amount,
"total_services_vat":total_services_vat,
"total_vat":total_vat,
"grand_total": discounted_price + total_vat + additional_services.get("total")
@ -1649,7 +1654,7 @@ def _post_sale_and_cogs(invoice, dealer):
)
TransactionModel.objects.create(
journal_entry=je_sale,
account=vat_acc,
amount=car.get_additional_services_vat,
tx_type='credit',
@ -2348,4 +2353,274 @@ def create_account(entity, coa, account_data):
account.save()
logger.info(f"Created default account: {account}")
except Exception as e:
logger.error(f"Error creating default account: {account_data['code']}, {e}")
logger.error(f"Error creating default account: {account_data['code']}, {e}")
def get_or_generate_car_image(car):
"""
Utility function to get or generate car image asynchronously
"""
try:
car_image, created = models.CarImage.objects.get_or_create(car=car)
if created:
car_image.image_hash = car.get_hash
car_image.save()
if car_image.image:
return car_image.image.url
# Check for existing image with same hash
existing = models.CarImage.objects.filter(
image_hash=car_image.image_hash,
image__isnull=False
).exclude(car=car).first()
if existing:
car_image.image.save(
existing.image.name,
existing.image.file,
save=True
)
return car_image.image.url
# If no image exists and not already generating, schedule generation
if not car_image.is_generating:
car_image.schedule_image_generation()
return None # Return None while image is being generated
except Exception as e:
logger.error(f"Error getting/generating car image: {e}")
return None
def force_regenerate_car_image(car):
"""
Force regeneration of car image (useful for admin actions)
"""
try:
car_image, created = models.CarImage.objects.get_or_create(car=car)
car_image.image_hash = car.get_hash
car_image.image.delete(save=False) # Remove old image
car_image.is_generating = False
car_image.generation_attempts = 0
car_image.last_generation_error = None
car_image.save()
car_image.schedule_image_generation()
return True
except Exception as e:
logger.error(f"Error forcing image regeneration: {e}")
return False
class CarImageAPIClient:
"""Simple client to handle authenticated requests to the car image API"""
BASE_URL = "http://10.10.1.111:8888"
USERNAME = "faheed"
PASSWORD = "Tenhal@123"
def __init__(self):
self.session = None
self.csrf_token = None
def login(self):
"""Login to the API and maintain session"""
try:
# Start fresh session
self.session = requests.Session()
# Step 1: Get CSRF token
response = self.session.get(f"{self.BASE_URL}/login")
response.raise_for_status()
# Get CSRF token from cookies
self.csrf_token = self.session.cookies.get('csrftoken')
if not self.csrf_token:
raise Exception("CSRF token not found in cookies")
# Step 2: Login
login_data = {
"username": self.USERNAME,
"password": self.PASSWORD,
"csrfmiddlewaretoken": self.csrf_token
}
login_response = self.session.post(
f"{self.BASE_URL}/login",
data=login_data
)
if login_response.status_code != 200:
raise Exception(f"Login failed with status {login_response.status_code}")
logger.info("Successfully logged in to car image API")
return True
except Exception as e:
logger.error(f"Login failed: {e}")
self.session = None
self.csrf_token = None
return False
def generate_image(self, payload):
"""Generate car image using authenticated session"""
if not self.session or not self.csrf_token:
if not self.login():
raise Exception("Cannot generate image: Login failed")
try:
headers = {
'X-CSRFToken': self.csrf_token,
'Referer': self.BASE_URL,
}
print(payload)
generate_data = {
"year": payload['year'],
"make": payload['make'],
"model": payload['model'],
"exterior_color": payload['color'],
"angle": "3/4 rear",
"reference_image": ""
}
response = self.session.post(
f"{self.BASE_URL}/generate",
json=generate_data,
headers=headers,
timeout=160
)
response.raise_for_status()
# Parse response
result = response.json()
image_url = result.get('url')
if not image_url:
raise Exception("No image URL in response")
# Download the actual image
image_response = self.session.get(
f"{self.BASE_URL}{image_url}",
timeout=160
)
image_response.raise_for_status()
return image_response.content, None
except requests.RequestException as e:
error_msg = f"API request failed: {e}"
logger.error(error_msg)
return None, error_msg
except Exception as e:
error_msg = f"Unexpected error: {e}"
logger.error(error_msg)
return None, error_msg
# Global client instance
api_client = CarImageAPIClient()
def resize_image(image_data, max_size=(800, 600)):
"""
Resize image to make it smaller while maintaining aspect ratio
Returns resized image data in the same format
"""
try:
img = Image.open(BytesIO(image_data))
original_format = img.format
original_mode = img.mode
# Calculate new size maintaining aspect ratio
img.thumbnail(max_size, Image.Resampling.LANCZOS)
# Save back to bytes in original format
output_buffer = BytesIO()
if original_format and original_format.upper() in ['JPEG', 'JPG']:
img.save(output_buffer, format='JPEG', quality=95, optimize=True)
elif original_format and original_format.upper() == 'PNG':
# Preserve transparency for PNG
if original_mode == 'RGBA':
img.save(output_buffer, format='PNG', optimize=True)
else:
img.save(output_buffer, format='PNG', optimize=True)
else:
# Default to JPEG for other formats
if img.mode in ('RGBA', 'LA', 'P'):
# Convert to RGB if image has transparency
background = Image.new('RGB', img.size, (255, 255, 255))
if img.mode == 'RGBA':
background.paste(img, mask=img.split()[3])
else:
background.paste(img, (0, 0))
img = background
img.save(output_buffer, format='JPEG', quality=95, optimize=True)
resized_data = output_buffer.getvalue()
logger.info(f"Resized image from {len(image_data)} to {len(resized_data)} bytes")
return resized_data, None
except Exception as e:
error_msg = f"Image resizing failed: {e}"
logger.error(error_msg)
return None, error_msg
def generate_car_image_simple(car_image):
"""
Simple function to generate car image with authentication and resizing
"""
car = car_image.car
# Prepare payload
payload = {
'make': car.id_car_make.name if car.id_car_make else '',
'model': car.id_car_model.name if car.id_car_model else '',
'year': car.year,
'color': car.colors.exterior.name
}
logger.info(f"Generating image for car {car.vin}")
# Generate image using API client
image_data, error = api_client.generate_image(payload)
if error:
return {'success': False, 'error': error}
if not image_data:
return {'success': False, 'error': 'No image data received'}
try:
# Resize the image to make it smaller
resized_data, resize_error = resize_image(image_data, max_size=(800, 600))
if resize_error:
# If resizing fails, use original image but log warning
logger.warning(f"Resizing failed, using original image: {resize_error}")
resized_data = image_data
# Determine file extension based on content
try:
img = Image.open(BytesIO(resized_data))
file_extension = img.format.lower() if img.format else 'jpg'
except:
file_extension = 'jpg'
# Save the resized image
car_image.image.save(
f"{car_image.image_hash}.{file_extension}",
ContentFile(resized_data),
save=False
)
logger.info(f"Successfully generated and resized image for car {car.vin}")
return {'success': True}
except Exception as e:
error_msg = f"Image processing failed: {e}"
logger.error(error_msg)
return {'success': False, 'error': error_msg}

View File

@ -4979,6 +4979,7 @@ def create_estimate(request, dealer_slug, slug=None):
.annotate(hash_count=Count("hash"))
.distinct()
)
context = {
"form": form,
"items": [
@ -6328,6 +6329,7 @@ def lead_create(request, dealer_slug):
qs = form.fields["id_car_make"].queryset.filter(
is_sa_import=True, pk__in=dealer_make_list
)
# print(qs)
form.fields["staff"].queryset = (
form.fields["staff"]
.queryset.select_related("user")
@ -6346,10 +6348,12 @@ def lead_create(request, dealer_slug):
form.fields["staff"].queryset = models.Staff.objects.filter(
dealer=dealer, pk=request.staff.pk
)
qs = qs.order_by("name")
form.fields["id_car_make"].queryset = qs
form.fields["id_car_make"].choices = [
(obj.id_car_make, obj.get_local_name()) for obj in qs
]
]
if first_make := qs.first():
form.fields["id_car_model"].queryset = first_make.carmodel_set.all()
@ -8435,7 +8439,7 @@ class FiscalYearIncomeStatementViewBase(
"""
template_name = "ledger/reports/income_statement.html"
permission_required = ["inventory.view_carfinance"]
permission_required = ["django_ledger.view_ledgermodel"]
def get_login_url(self):
return reverse("account_login")
@ -8574,7 +8578,7 @@ class FiscalYearCashFlowStatementViewBase(
"""
template_name = "ledger/reports/cash_flow_statement.html"
permission_required = ["inventory.view_carfinance"]
permission_required = ["django_ledger.view_ledgermodel"]
def get_login_url(self):
return reverse("account_login")
@ -8763,7 +8767,7 @@ class FiscalYearEntityModelDashboardView(
:type permission_required: list
"""
permission_required = ["inventory.view_carfinance"]
permission_required = ["django_ledger.view_ledgermodel"]
def get_login_url(self):
return reverse("account_login")
@ -11433,6 +11437,10 @@ def create_ticket(request,dealer_slug):
def ticket_list(request,dealer_slug):
dealer= get_object_or_404(models.Dealer, slug=dealer_slug)
tickets = models.Ticket.objects.filter(dealer=dealer).order_by('-created_at')
query=request.GET.get('q')
if query:
tickets=tickets.filter(Q(id__icontains=query)| Q(subject__icontains=query))
return render(request, 'support/ticket_list.html', {'tickets': tickets})
@login_required

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 MiB

View File

@ -3,52 +3,45 @@
{% load i18n static %}
{% load allauth account %}
{% block title %}
{% trans 'User Settings' %}
{% trans 'Dealer Settings' %}
{% endblock %}
{% block content %}
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
Dealer Settings
<span class="fas fa-solid fa-gear ms-2 text-primary"></span>
</h3>
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5">
<div class="col-md-6">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% trans "Dealer Settings" %}
<i class="fas fa-solid fa-gear ms-2"></i>
</h3>
</div>
<div class="card-body bg-light-subtle ">
<form action="" method="post">
{% csrf_token %}
<div class="col-12">
<div class=" mb-4">
<div class="row gx-3 mb-4 gy-6 gy-sm-3">
<div class="col-12">
<h4 class="mb-4">{% trans 'Default Invoice Accounts' %}</h4>
<div class="form-icon-container mb-3">{{ form.invoice_cash_account|as_crispy_field }}</div>
<div class="form-icon-container mb-3">{{ form.invoice_prepaid_account|as_crispy_field }}</div>
<div class="form-icon-container mb-3">{{ form.invoice_unearned_account|as_crispy_field }}</div>
</div>
</div>
<div class="row gx-3 mb-4 gy-6 gy-sm-3">
<div class="col-12">
<h4 class="mb-4">{% trans 'Default Bill Accounts' %}</h4>
<div class="form-icon-container mb-3">{{ form.bill_cash_account|as_crispy_field }}</div>
<div class="form-icon-container mb-3">{{ form.bill_prepaid_account|as_crispy_field }}</div>
<div class="form-icon-container mb-3">{{ form.bill_unearned_account|as_crispy_field }}</div>
</div>
</div>
<div class="text-center mb-6">
<div>
<button type="submit" class="btn btn-phoenix-primary"><i class="fa-solid fa-pen-to-square me-1"></i>{% trans 'Update' %}</button>
</div>
</div>
</div>
</div>
</form>
<div class="card-body p-4 p-md-5">
<form action="" method="post" class="needs-validation" novalidate>
{% csrf_token %}
<div class="row g-1">
<div class="col-12">
<h4 class="mb-4 text-center">{% trans 'Default Invoice Accounts' %}</h4>
{{ form.invoice_cash_account|as_crispy_field }}
{{ form.invoice_prepaid_account|as_crispy_field }}
{{ form.invoice_unearned_account|as_crispy_field }}
</div>
<div class="col-12 mt-4">
<h4 class="mb-4 text-center">{% trans 'Default Bill Accounts' %}</h4>
{{ form.bill_cash_account|as_crispy_field }}
{{ form.bill_prepaid_account|as_crispy_field }}
{{ form.bill_unearned_account|as_crispy_field }}
</div>
</div>
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-phoenix-primary btn-lg" type="submit">
<i class="fa-solid fa-pen-to-square me-1"></i>
{% trans 'Update' %}
</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
</main>
{% endblock %}

View File

@ -8,50 +8,46 @@
{% endblock title %}
{% block content %}
<!---->
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{% trans 'Create Bill' %}<span class="fas fa-money-bills ms-2 text-primary"></span>
</h3>
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5 ">
<div class="col-md-6">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% trans 'Create Bill' %}
<i class="fas fa-money-bills ms-2"></i>
</h3>
</div>
<div class="card-body bg-light-subtle">
<form action="{{ form_action_url }}" method="post" id="djl-bill-model-create-form-id">
<div class="card-body">
{% csrf_token %}
{% if po_model %}
<div class="text-center mb-4">
<h3 class="h5">{% trans 'Bill for' %} {{ po_model.po_number }}</h3>
<p class="text-muted mb-3">{% trans 'Bill for' %} {{ po_model.po_title }}</p>
<div class="d-flex flex-column gap-2">
{% for itemtxs in po_itemtxs_qs %}
<span class="badge bg-secondary">{{ itemtxs }}</span>
{% endfor %}
</div>
<div class="card-body p-4 p-md-5">
<form action="{{ form_action_url }}" method="post" id="djl-bill-model-create-form-id" class="needs-validation" novalidate>
{% csrf_token %}
{% if po_model %}
<div class="text-center mb-4">
<h3 class="h5">{% trans 'Bill for' %} {{ po_model.po_number }}</h3>
<p class="text-muted mb-3">{% trans 'Bill for' %} {{ po_model.po_title }}</p>
<div class="d-flex flex-column gap-2">
{% for itemtxs in po_itemtxs_qs %}
<span class="badge bg-secondary">{{ itemtxs }}</span>
{% endfor %}
</div>
{% endif %}
<div class="mb-4">
{{ form|crispy }}
</div>
<hr class="my-2">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-primary md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'bill_list' request.dealer.slug%}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
{% endif %}
<div class="mb-4">
{{ form|crispy }}
</div>
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{{ _("Save") }}
</button>
<a href="{% url 'bill_list' request.dealer.slug%}" class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
<!---->
{% endblock %}
</main>
{% endblock %}

View File

@ -1,54 +1,59 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% load i18n static %}
{% load django_ledger %}
{% load widget_tweaks %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-12 text-center mb-4">
<h1 class="display-4">{% trans 'Create Chart of Accounts' %}</h1>
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5">
<div class="col-12 col-sm-10 col-md-8 col-lg-6 col-xl-5">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% trans 'Create Chart of Accounts' %}
<i class="fa-solid fa-chart-pie ms-2"></i>
</h3>
</div>
<div class="col-lg-6 col-md-8">
<div class="card shadow-sm">
<div class="card-body p-4">
<form method="post" id="{{ form.get_form_id }}">
{% csrf_token %}
{# Bootstrap form rendering #}
<div class="mb-3">
{{ form.name.label_tag }}
{{ form.name|add_class:"form-control" }}
{% if form.name.help_text %}
<small class="form-text text-muted">{{ form.name.help_text }}</small>
{% endif %}
{% for error in form.name.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
</div>
<div class="mb-3">
{{ form.description.label_tag }}
{{ form.description|add_class:"form-control" }}
{% if form.description.help_text %}
<small class="form-text text-muted">{{ form.description.help_text }}</small>
{% endif %}
{% for error in form.description.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
</div>
<div class="d-flex justify-content-center gap-2 mt-4">
<button type="submit" class="btn btn-phoenix-primary">Submit</button>
<a href="{% url 'coa-list' request.dealer.slug request.entity.slug %}" class="btn btn-phoenix-secondary">
{% trans 'Back' %}
</a>
</div>
</form>
<div class="card-body p-4 p-md-5">
<form method="post" id="{{ form.get_form_id }}" class="needs-validation" novalidate>
{% csrf_token %}
{# Bootstrap form rendering #}
<div class="mb-3">
{{ form.name.label_tag }}
{{ form.name|add_class:"form-control" }}
{% if form.name.help_text %}
<small class="form-text text-muted">{{ form.name.help_text }}</small>
{% endif %}
{% for error in form.name.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
</div>
</div>
<div class="mb-3">
{{ form.description.label_tag }}
{{ form.description|add_class:"form-control" }}
{% if form.description.help_text %}
<small class="form-text text-muted">{{ form.description.help_text }}</small>
{% endif %}
{% for error in form.description.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
</div>
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button type="submit" class="btn btn-phoenix-primary btn-lg me-md-2">
<i class="fa-solid fa-plus me-1"></i>
{% trans 'Create' %}
</button>
<a href="{% url 'coa-list' request.dealer.slug request.entity.slug %}"
class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans 'Cancel' %}
</a>
</div>
</form>
</div>
</div>
</div>
</main>
{% endblock %}

View File

@ -1,5 +1,6 @@
{% extends 'base.html' %}
{% load i18n static crispy_forms_filters %}
{% block title %}
{% if object %}
{% trans 'Update Lead' %}
@ -7,6 +8,7 @@
{% trans 'Add New Lead' %}
{% endif %}
{% endblock %}
{% block customcss %}
<style>
.htmx-indicator{
@ -28,51 +30,41 @@
}
</style>
{% endblock customcss %}
{% block content %}
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{% if object %}
{{ _("Update Lead") }}
{% else %}
{{ _("Create New Lead") }}
{% endif %}
<li class="fas fa-bullhorn text-primary ms-2"></li>
</h3>
</div>
<div class="card-body bg-light-subtle">
<form class="form" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<hr class="my-2">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{{ _("Save") }}
</button>
<a href="{% url 'lead_list' request.dealer.slug %}" class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
<main class="d-flex align-items-center justify-content-center min-vh-100 py-5">
<div class="col-md-8">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% if object %}
{% trans "Update Lead" %}
<i class="fa-solid fa-edit ms-2"></i>
{% else %}
{% trans "Create New Lead" %}
<i class="fa-solid fa-bullhorn ms-2"></i>
{% endif %}
</h3>
</div>
<div class="card-body p-4 p-md-5">
<form class="form" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{% trans "Save" %}
</button>
<a href="{% url 'lead_list' request.dealer.slug %}" class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const spinner = document.createElement('div');
spinner.id = 'spinner';
spinner.className = 'htmx-indicator spinner-border text-primary inline-spinner';
spinner.innerHTML = '<span class="visually-hidden">Loading...</span>';
const targetFieldDiv = document.getElementById('div_id_id_car_model');
if (targetFieldDiv) {
targetFieldDiv.parentNode.insertBefore(spinner, targetFieldDiv.nextSibling);
}
});
</script>
{% endblock %}
</main>
{% endblock %}

View File

@ -1,42 +1,60 @@
{% extends "base.html" %}
{% load i18n static %}
{% load crispy_forms_filters %}
{% block title %}
{# Check if an 'object' exists in the context #}
{% if object %}
{% trans 'Update Customer' %}
{% else %}
{% trans 'Add New Customer' %}
{% endif %}
{% endblock %}
{% block content %}
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-o rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{% if customer.created %}
{{ _("Edit Customer") }}
{% else %}
{{ _("Add Customer") }}
{% endif %}
<i class="fa-solid fa-user ms-2 text-primary"></i>
</h3>
</div>
<div class="card-body bg-light-subtle">
<form method="post"
class="form row g-3 needs-validation"
enctype="multipart/form-data"
novalidate>
{% csrf_token %}
{{ form|crispy }}
<hr class="my-2">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'customer_list' request.dealer.slug %}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
<main class="d-flex align-items-center justify-content-center min-vh-100 py-5 ">
<div class="col-md-8">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% if object %}
{% trans "Update Customer" %}
<i class="fa-solid fa-user-edit ms-2"></i>
{% else %}
{% trans "Add New Customer" %}
<i class="fa-solid fa-user-plus ms-2"></i>
{% endif %}
</h3>
</div>
<div class="card-body p-4 p-md-5">
<form method="post" class="form" enctype="multipart/form-data" novalidate>
{% csrf_token %}
{{ form|crispy }}
{% if form.errors %}
<div class="alert alert-danger mt-4" role="alert">
<h4 class="alert-heading small">{% trans "Please correct the following errors:" %}</h4>
<ul class="mb-0">
{% for field, errors in form.errors.items %}
<li><strong>{{ field|capfirst }}:</strong> {% for error in errors %}{{ error }}{% endfor %}</li>
{% endfor %}
</ul>
</div>
</form>
</div>
{% endif %}
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center">
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{% trans "Save" %}
</button>
<a href="{% url 'customer_list' request.dealer.slug %}" class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
{% endblock %}
</div>
</main>
{% endblock %}

View File

@ -5,32 +5,34 @@
{{ _("Update Dealer Information") }}
{% endblock title %}
{% block content %}
<!---->
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{{ _("Update Dealer Information") }}<span class="fas fa-car ms-2 text-primary"></span>
</h3>
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5">
<div class="col-md-8">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{{ _("Update Dealer Information") }}
<i class="fas fa-car ms-2"></i>
</h3>
</div>
<div class="card-body bg-light-subtle">
<div class="card-body p-4 p-md-5">
<form hx-boost="false" method="post" enctype="multipart/form-data" class="needs-validation" novalidate>
{% csrf_token %}
{{ form|crispy }}
<hr class="my-2">
{% csrf_token %}
{{ form|crispy }}
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-primary md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'dealer_detail' request.dealer.slug %}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{{ _("Save") }}
</button>
<a href="{% url 'dealer_detail' request.dealer.slug %}"
class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
<!---->
{% endblock %}
</main>
{% endblock %}

View File

@ -2,7 +2,7 @@
{% load i18n %}
{% load crispy_forms_filters %}
{% block title %}
{# Check if an 'object' exists in the context #}
{# Check if an 'object' exists in the context #}
{% if object %}
{% trans 'Update Group' %}
{% else %}
@ -10,41 +10,49 @@
{% endif %}
{% endblock %}
{% block content %}
<!---->
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{% if staff.created %}
{{ _("Edit Group") }}
{% else %}
{{ _("Create Group") }}
{% endif %}
<i class="fa-solid fa-user-group text-primary ms-2"></i>
</h3>
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5">
<div class="col-12 col-sm-10 col-md-8 col-lg-6 col-xl-5">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% if object %}
{% trans "Update Group" %}
<i class="fa-solid fa-user-group ms-2"></i>
{% else %}
{% trans "Create Group" %}
<i class="fa-solid fa-user-plus ms-2"></i>
{% endif %}
</h3>
</div>
<div class="card-body bg-light-subtle">
<form class="row g-3 " method="post" class="form" novalidate>
<div class="card-body p-4 p-md-5">
<form method="post" class="needs-validation" novalidate>
{% csrf_token %}
{{ redirect_field }}
{{ form|crispy }}
{% for error in form.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
<hr class="my-2">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-primary md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'group_list' request.dealer.slug %}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
{% if form.errors %}
<div class="alert alert-danger mt-4" role="alert">
<h4 class="alert-heading small">{% trans "Please correct the following errors:" %}</h4>
<ul class="mb-0">
{% for field, errors in form.errors.items %}
<li><strong>{{ field|capfirst }}:</strong> {% for error in errors %}{{ error }}{% endfor %}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center">
<button class="btn btn-phoenix-primary btn-lg md-me-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>{% trans "Save" %}
</button>
<a href="{% url 'group_list' request.dealer.slug %}" class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
<!---->
{% endblock %}
</main>
{% endblock %}

View File

@ -6,62 +6,70 @@
{% trans "Groups" %}
{% endblock title %}
{% block content %}
{% if groups or request.GET.q%}
<section class="">
<div class="row mt-4">
<div class="col-auto">
<div class="d-md-flex justify-content-between">
<div>
<main class="py-5">
<div class="container">
{% if groups or request.GET.q %}
<div class="card border-0 rounded-4 animate__animated animate__fadeInUp">
<div class="card-header border-bottom d-flex flex-column flex-md-row justify-content-between align-items-md-center p-4">
<h5 class="card-title mb-2 mb-md-0 me-md-4 fw-bold"> <i class="fa-solid fa-user-group fs-3 me-1 text-primary "></i>{% trans "Groups" %}</h5>
<div class="d-flex gap-2">
<a href="{% url 'group_create' request.dealer.slug %}"
class="btn btn-sm btn-phoenix-primary me-5"><span class="fas fa-plus me-2"></span>{% trans "Add Group" %}</a>
class="btn btn-phoenix-primary">
<i class="fa-solid fa-user-group fs-9 me-1"></i>
<span class="fas fa-plus me-2"></span>{% trans "Add Group" %}
</a>
<a href="{% url 'user_list' request.dealer.slug %}"
class="btn btn-sm btn-phoenix-secondary"><span class="fas fas fa-arrow-left me-2"></span>{% trans "Back to Staffs" %}</a>
class="btn btn-phoenix-secondary">
<span class="fas fas fa-arrow-left me-2"></span>{% trans "Back to Staffs" %}
</a>
</div>
</div>
</div>
<div class="table-responsive scrollbar mx-n1 px-1 mt-3">
<table class="table align-items-center table-flush table-hover">
<thead>
<tr class="bg-body-highlight">
<th>{% trans 'name'|capfirst %}</th>
<th>{% trans 'total Users'|capfirst %}</th>
<th>{% trans 'total permission'|capfirst %}</th>
<th>{% trans 'actions'|capfirst %}</th>
</tr>
</thead>
<tbody>
{% for group in groups %}
<tr>
<td class="align-middle white-space-nowrap ps-1">{{ group.name }}</td>
<td class="align-middle white-space-nowrap">
<i class="fa-solid fa-users me-1"></i> {{ group.users.count }}
</td>
<td class="align-middle white-space-nowrap">
<i class="fa-solid fa-unlock me-1"></i> {{ group.permissions.count }}
</td>
<td class="align-middle white-space-nowrap">
<a class="btn btn-phoenix-success"
href="{% url 'group_detail' request.dealer.slug group.id %}">
<i class="fa-solid fa-eye"></i>
{% trans 'view'|capfirst %}
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% if page_obj.paginator.num_pages > 1 %}
<div class="d-flex justify-content-end mt-3">
<div class="d-flex">{% include 'partials/pagination.html' %}</div>
<div class="card-body p-0">
<div class="table-responsive scrollbar mx-n1 px-1 mt-3">
<table class="table align-items-center table-hover mb-0">
<thead>
<tr class="bg-light">
<th scope="col" class="text-secondary text-uppercase fw-bold ps-4">{% trans 'name'|capfirst %}</th>
<th scope="col" class="text-secondary text-uppercase fw-bold">{% trans 'total Users'|capfirst %}</th>
<th scope="col" class="text-secondary text-uppercase fw-bold">{% trans 'total permission'|capfirst %}</th>
<th scope="col" class="text-secondary text-uppercase fw-bold text-end pe-4">{% trans 'actions'|capfirst %}</th>
</tr>
</thead>
<tbody>
{% for group in groups %}
<tr>
<td class="align-middle white-space-nowrap ps-4">{{ group.name }}</td>
<td class="align-middle white-space-nowrap">
<i class="fa-solid fa-users me-1"></i> {{ group.users.count }}
</td>
<td class="align-middle white-space-nowrap">
<i class="fa-solid fa-unlock me-1"></i> {{ group.permissions.count }}
</td>
<td class="align-middle white-space-nowrap text-end pe-4">
<a class="btn btn-phoenix-secondary btn-sm"
href="{% url 'group_detail' request.dealer.slug group.id %}">
<i class="fa-solid fa-eye me-1"></i>
{% trans 'view'|capfirst %}
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
</div>
</section>
{% else %}
{% url "group_create" request.dealer.slug as create_group_url %}
{% include "empty-illustration-page.html" with value="group" url=create_group_url %}
{% endif %}
{% endblock %}
{% if page_obj.paginator.num_pages > 1 %}
<div class="card-footer bg-light border-top">
<div class="d-flex justify-content-end">
{% include 'partials/pagination.html' %}
</div>
</div>
{% endif %}
</div>
{% else %}
{% url "group_create" request.dealer.slug as create_group_url %}
{% include "empty-illustration-page.html" with value="group" url=create_group_url %}
{% endif %}
</div>
</main>
{% endblock %}

View File

@ -3,10 +3,10 @@
<nav class="navbar navbar-vertical navbar-expand-lg ">
<div class="collapse navbar-collapse" id="navbarVerticalCollapse">
<div class="navbar-vertical-content d-flex flex-column">
<ul class="navbar-nav flex-column" id="navbarVerticalNav" hx-boost="true" hx-target="#main_content" hx-select="#main_content" hx-swap="outerHTML" hx-select-oob="#toast-container" hx-indicator="#spinner">
<ul class="navbar-nav flex-column" id="navbarVerticalNav" hx-boost="false" hx-target="#main_content" hx-select="#main_content" hx-swap="outerHTML" hx-select-oob="#toast-container" hx-indicator="#spinner">
<li class="nav-item">
<p class="navbar-vertical-label text-primary fs-8 text-truncate">{{request.dealer|default:"Apps"}}</p>
<hr class="navbar-vertical-line">
{% comment %} <p class="navbar-vertical-label text-primary fs-8 text-truncate">{{request.dealer|default:"Apps"}}</p>
<hr class="navbar-vertical-line"> {% endcomment %}
{% if perms.inventory.can_view_inventory %}
<div class="nav-item-wrapper">
<a id="inventory-nav" class="nav-link dropdown-indicator label-1 inventory-nav" href="#nv-inventory" role="button" data-bs-toggle="collapse" aria-expanded="false" aria-controls="nv-inventory">
@ -26,7 +26,7 @@
</div>
</a>
</li>
{% endif %}
{% if perms.inventory.view_car%}
@ -386,7 +386,7 @@
</a>
</li>
<li class="nav-item">
<li class="nav-item mb-4">
<a class="nav-link" href="#">
<div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-robot"></span></span>
@ -394,9 +394,22 @@
</div>
</a>
</li>
<li class="nav-item ">
<a class="nav-link" href="#">
<div class="d-flex align-items-center">
{% if user.is_authenticated %}
<span class="nav-link-icon"><span class="fa-solid fa-car"></span></span>
<span class="nav-link-text">{{ request.dealer.user.username }}</span>
{% endif %}
</div>
</a>
</li>
</ul>
</div>
{% endif %}
</div>
@ -433,15 +446,15 @@
</a>
</div>
{% if request.user.is_authenticated%}
<div class="navbar-logo">
<div class="d-flex align-items-center">
{% with name_to_display=request.user.first_name|default:request.dealer.name %}
<h6 class="text-info ms-2 d-none d-sm-block fs-7"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
<h6 class="text-gray-600 ms-2 d-none d-sm-block fs-8"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="{% trans 'Logged in as ' %}{{request.user.username }}">
{% trans 'Hello, ' %}{{ name_to_display }}
{% trans 'Hello, ' %}{{ name_to_display }}
</h6>
{% endwith %}
</div>
@ -518,11 +531,12 @@
<li class="nav-item">
<a class="nav-link px-3 d-block" href="{% url 'user_list' request.dealer.slug %}"><span class="me-2 text-body align-bottom" data-feather="users"></span>{{ _("Staff & Groups") }}</a>
</li>
<li class="nav-item">
{% comment %} <li class="nav-item">
<a class="nav-link px-3 d-block" href="{% url 'dealer_activity' request.dealer.slug %}"> <span class="me-2 text-body align-bottom" data-feather="lock"></span>{{ _("Activities") }}</a>
</li>
</li> {% endcomment %}
{% endif %}
<li class="nav-item">
{% if request.is_dealer %}
<a class="nav-link px-3 d-block" href="{% url 'dealer_settings' request.dealer.slug %}"> <span class="me-2 text-body align-bottom" data-feather="settings"></span>{{ _("Settings") }}</a>
{% endif %}

View File

@ -1,16 +1,41 @@
<!-- templates/cars/car_confirm_delete.html -->
{% extends 'base.html' %}
{% load i18n %}
{% block title %}Delete Car{% endblock %}
{% block content %}
<div class="mt-4 ms-4">
<h1>Delete Car</h1>
<p class="text-danger">Are you sure you want to delete the car "{{ car }}"?</p>
<form method="post">
{% csrf_token %}
<button type="submit" class="btn btn-phoenix-danger">Confirm Delete</button>
<a href="{% url 'car_list' request.dealer.slug %}"
class="btn btn-phoenix-secondary">{% trans 'Cancel' %}</a>
</form>
<main class="d-flex align-items-center justify-content-center min-vh-50 py-5">
<div class="col-md-6 ">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-body p-4 p-md-5 text-center bg-gradient">
<div class="mb-4">
<i class="fa-solid fa-triangle-exclamation text-danger" style="font-size: 2rem;"></i>
</div>
<h1 class="card-title fw-bold mb-3 fs-4">{% trans 'Confirm Deletion' %}</h1>
<p class="fs-7 mb-4">
{% trans "Are you absolutely sure you want to delete the car" %}
</p>
<p class="fs-6 mb-4">
"<strong class="">{{ car }}</strong>"?
</p>
<p class="fs-7 mb-4">
{% trans "This action is permanent and cannot be undone." %}
</p>
<form method="post" class="d-grid gap-3 d-sm-flex justify-content-sm-center">
{% csrf_token %}
<button type="submit" class="btn btn-phoenix-danger btn-lg px-5">
<i class="fa-solid fa-trash-can me-2"></i>{% trans 'Confirm Delete' %}
</button>
<a href="{% url 'car_list' request.dealer.slug %}" class="btn btn-phoenix-secondary btn-lg px-5">
<i class="fa-solid fa-ban me-2"></i>{% trans 'Cancel' %}
</a>
</form>
</div>
</div>
</div>
{% endblock %}
</main>
{% endblock %}

View File

@ -76,13 +76,279 @@
{% if perms.inventory.view_car %}
<div class="row-fluid {% if car.status == 'sold' %}disabled{% endif %}">
<div class="row g-3 justify-content-between">
<div class="col-lg-12 col-xl-6">
<div class="avatar avatar-5xl mb-3">
<img class="rounded h-100 w-100"
src="{% static 'images/cars/' %}{{ car.vin }}.png"
alt="{{ car.vin }}" />
</div>
<div class="card mb-3 rounded shadow d-flex align-content-center
<div class="col-md-6">
<div class="row mb-2">
<div class="col-md-4">
<div class="avatar avatar-6xl mb-3">
<img class="rounded"
src="{% static 'images/car_images/' %}{{ car.get_hash }}.png"
alt="{{ car.vin }}" />
</div>
</div>
<div class="col-md-8">
<div class="card rounded shadow d-flex align-content-center
{% if car.get_transfer %}transfer{% endif %}">
<p class="card-header rounded-top fw-bold">{% trans 'Financial Details' %}</p>
<div class="card-body">
<div class="table-responsive scrollbar mb-3">
<table class="table table-sm fs-9 mb-0 overflow-hidden">
{% if car.marked_price %}
<tr>
<th>{% trans "Cost Price"|capfirst %}</th>
<td>{{ car.cost_price|floatformat:2 }}</td>
</tr>
<tr>
<th>{% trans "Marked Price"|capfirst %}</th>
<td>{{ car.marked_price|floatformat:2 }}</td>
</tr>
{% comment %} <tr>
<th>{% trans "Selling Price"|capfirst %}</th>
<td>{{ car.finances.selling_price|floatformat:2 }}</td>
</tr>
<tr>
<th>{% trans "Discount Amount"|capfirst %}</th>
<td>{{ car.finances.discount_amount|floatformat:2 }}</td>
</tr>
<tr>
<th>{% trans "Additional Fee"|capfirst %}</th>
<td></td>
</tr>
{% if car.finances.additional_services.first.pk %}
{% for service in car.finances.additional_services.all %}
<tr>
<td>{{ service.name }}</td>
<td>{{ service.price_|floatformat:2 }}</td>
</tr>
{% endfor %}
{% endif %}
<tr>
<th>{% trans "VAT Amount"|capfirst %}</th>
<td>{{ car.finances.vat_amount|floatformat:2 }}</td>
</tr>
<tr>
<th>{% trans "Total"|capfirst %}</th>
<td>{{ car.finances.total_vat|floatformat:2 }}</td>
</tr> {% endcomment %}
<tr>
<td colspan="2">
{% if not car.get_transfer %}
<a href="{% url 'car_finance_update' request.dealer.slug car.slug %}"
class="btn btn-phoenix-warning btn-sm mb-3">{% trans "Edit" %}</a>
{% else %}
<span class="badge bg-danger">{% trans "Cannot Edit, Car in Transfer." %}</span>
{% endif %}
</td>
</tr>
{% else %}
<p>{% trans "No finance details available." %}</p>
<a href="{% url 'car_finance_update' request.dealer.slug car.slug %}"
class="btn btn-phoenix-success btn-sm mb-3">{% trans "Add" %}</a>
{% endif %}
</table>
</div>
</div>
</div>
</div>
</div>
{% if perms.inventory.view_carcolors %}
<div class="card rounded shadow d-flex align-content-center mt-3
{% if car.get_transfer %}transfer{% endif %}">
<p class="card-header rounded-top fw-bold">{% trans 'Colors Details' %}</p>
<div class="card-body">
<div class="table-responsive scrollbar mb-3">
<table class="table table-sm fs-9 mb-0 overflow-hidden">
<!--test-->
{% if car.colors %}
<tr>
<th>{% trans 'Exterior' %}</th>
<td>
<span>{{ car.colors.exterior.get_local_name }}</span>
</td>
<td class="align-middle">
<div class="text-end color-div"
style="background-color: rgb({{ car.colors.exterior.rgb }})">
</div>
</td>
</tr>
<tr>
<th>{% trans 'Interior' %}</th>
<td>
<span>{{ car.colors.interior.get_local_name }}</span>
</td>
<td class="align-middle">
<div class="text-end color-div"
style="background-color: rgb({{ car.colors.interior.rgb }})">
</div>
</td>
</tr>
{% if perms.inventory.change_carcolors %}
<tr>
<td colspan="2">
{% if not car.get_transfer %}
<a href="{% url 'car_colors_update' request.dealer.slug car.slug %}"
class="btn btn-phoenix-warning btn-sm mb-3">{% trans "Edit" %}</a>
{% else %}
<span class="badge bg-danger">{% trans "Cannot Edit, Car in Transfer." %}</span>
{% endif %}
</td>
</tr>
{% endif %}
{% else %}
<tr>
<td colspan="2">
<p>{% trans "No color details available." %}</p>
{% if perms.inventory.add_carcolors %}
<a class="btn btn-phoenix-success btn-sm mb-3"
href="{% url 'add_color' request.dealer.slug car.slug %}">{{ _("Add Color") }}</a>
{% endif %}
</td>
</tr>
{% endif %}
<!--test-->
</table>
</div>
</div>
</div>
{% endif %}
{% if car.status != 'transfer' %}
{% if perms.inventory.view_carreservation %}
<div class="card rounded shadow d-flex align-content-center mt-3 h-full w-100">
<p class="card-header rounded-top fw-bold">{% trans 'Reservations Details' %}</p>
<div class="card-body">
<div class="table-responsive scrollbar mb-3">
<table class="table table-sm fs-9 mb-0 overflow-hidden">
{% if car.is_reserved %}
<thead>
<tr>
<th>{% trans "Reserved By" %}</th>
<th>{% trans "Expires At" %}</th>
<th>{% trans 'Actions' %}</th>
</tr>
</thead>
<tbody>
{% for reservation in car.reservations.all %}
<tr>
<td>{{ reservation.reserved_by.dealer }}</td>
<td>{{ reservation.reserved_until }}</td>
{% if perms.inventory.change_carreservation %}
<td>
{% if reservation.is_active %}
<form method="post"
action="{% url 'reservations' request.dealer.slug reservation.id %}">
{% csrf_token %}
<div class="btn-group">
<button type="submit"
name="action"
value="renew"
class="btn btn-sm btn-phoenix-success px-3 py-1">
{% trans "Renew" %}
</button>
<button type="submit"
name="action"
value="cancel"
class="btn btn-sm btn-phoenix-secondary px-3 py-1">
{% trans "Cancel" %}
</button>
</div>
</form>
{% else %}
<span class="badge badge-phoenix badge-phoenix-danger fs-10">{% trans "Expired" %}</span>
{% endif %}
</td>
{% endif %}
</tr>
{% endfor %}
{% else %}
{% if perms.inventory.add_carreservation %}
<tr>
<td>
<button type="button"
class="btn btn-sm btn-phoenix-success"
data-bs-toggle="modal"
data-bs-target="#reserveModal">
{% trans 'Reserve' %}
</button>
</td>
</tr>
{% endif %}
</tbody>
{% endif %}
</table>
</div>
</div>
</div>
{% endif %}
{% endif %}
<!-- Transfer Table -->
{% if car.status == 'transfer' and car.get_transfer %}
<div class="card rounded shadow d-flex align-content-center mt-3">
<p class="card-header rounded-top fw-bold">{% trans 'Transfer Details' %}</p>
<div class="card-body">
<div class="table-responsive scrollbar mb-3">
<table class="table table-sm fs-9 mb-0 overflow-hidden">
<thead>
<tr>
<th>{% trans "Action" %}</th>
<th>{% trans "Status" %}</th>
<th>{% trans "From Showroom" %}</th>
<th>{% trans "To Showroom" %}</th>
<th>{% trans 'Date' %}</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span class="badge badge-phoenix badge-phoenix-info">{% trans "Transfer" %}</span>
</td>
<td>
{% if car.get_transfer.status == "draft" %}
<span class="badge badge-phoenix badge-phoenix-warning">{% trans "waiting for approval" %}</span>
{% elif car.get_transfer.status == "approved" %}
<span class="badge badge-phoenix badge-phoenix-info">{% trans "waiting for dealer acceptance" %}</span>
{% endif %}
</td>
<td>{{ car.get_transfer.from_dealer|title }}</td>
<td>{{ car.get_transfer.to_dealer|title }}</td>
<td>{{ car.get_transfer.transfer_date|date:"Y-m-d" }}</td>
<td>
{% if car.get_transfer.status == "draft" %}
<a class="btn btn-sm btn-phoenix-success"
href="{% url 'transfer_detail' car.get_transfer.pk %}">{% trans "Approve" %}</a>
{% endif %}
</td>
<td>
<a class="btn btn-sm btn-phoenix-success"
href="{% url 'transfer_detail' car.get_transfer.pk %}?action=cancel">{% trans "Cancel" %}</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
{% endif %}
</div>
<div class="col-md-6">
<div class="card mb-3 rounded shadow d-flex align-content-center
{% if car.get_transfer %}disabled{% endif %}">
<p class="card-header rounded-top fw-bold">{% trans 'Car Details' %}</p>
<div class="card-body">
@ -234,7 +500,7 @@
{% if not car.get_transfer %}
{% if perms.inventory.change_car %}
<a href="{% url 'car_update' request.dealer.slug car.slug %}"
class="btn btn-phoenix-primary btn-sm mt-1">{% trans "Edit" %}
class="btn btn-phoenix-primary btn-sm mt-1 me-3 mb-3">{% trans "Edit" %}
<span class="fas fa-solid fa-pencil ms-1"></span>
</a>
<a href="{% url 'transfer' car.slug %}"
@ -249,257 +515,10 @@
</div>
</div>
</div>
<div class="col-lg-6 col-xl-6">
{% if perms.inventory.view_carfinance %}
<div class="card rounded shadow d-flex align-content-center
{% if car.get_transfer %}transfer{% endif %}">
<p class="card-header rounded-top fw-bold">{% trans 'Financial Details' %}</p>
<div class="card-body">
<div class="table-responsive scrollbar mb-3">
<table class="table table-sm fs-9 mb-0 overflow-hidden">
{% if car.marked_price %}
<tr>
{% if perms.inventory.view_carfinance %}
<th>{% trans "Cost Price"|capfirst %}</th>
<td>{{ car.cost_price|floatformat:2 }}</td>
{% endif %}
</tr>
<tr>
<th>{% trans "Marked Price"|capfirst %}</th>
<td>{{ car.marked_price|floatformat:2 }}</td>
</tr>
{% comment %} <tr>
<th>{% trans "Selling Price"|capfirst %}</th>
<td>{{ car.finances.selling_price|floatformat:2 }}</td>
</tr>
<tr>
<th>{% trans "Discount Amount"|capfirst %}</th>
<td>{{ car.finances.discount_amount|floatformat:2 }}</td>
</tr>
<tr>
<th>{% trans "Additional Fee"|capfirst %}</th>
<td></td>
</tr>
{% if car.finances.additional_services.first.pk %}
{% for service in car.finances.additional_services.all %}
<tr>
<td>{{ service.name }}</td>
<td>{{ service.price_|floatformat:2 }}</td>
</tr>
{% endfor %}
{% endif %}
<tr>
<th>{% trans "VAT Amount"|capfirst %}</th>
<td>{{ car.finances.vat_amount|floatformat:2 }}</td>
</tr>
<tr>
<th>{% trans "Total"|capfirst %}</th>
<td>{{ car.finances.total_vat|floatformat:2 }}</td>
</tr> {% endcomment %}
{% if perms.inventory.change_carfinance %}
<tr>
<td colspan="2">
{% if not car.get_transfer %}
<a href="{% url 'car_finance_update' request.dealer.slug car.slug %}"
class="btn btn-phoenix-warning btn-sm mb-3">{% trans "Edit" %}</a>
{% else %}
<span class="badge bg-danger">{% trans "Cannot Edit, Car in Transfer." %}</span>
{% endif %}
</td>
</tr>
{% endif %}
{% else %}
<p>{% trans "No finance details available." %}</p>
{% if perms.inventory.add_carfinance %}
<a href="{% url 'car_finance_update' request.dealer.slug car.slug %}"
class="btn btn-phoenix-success btn-sm mb-3">{% trans "Add" %}</a>
{% endif %}
{% endif %}
</table>
</div>
</div>
</div>
{% endif %}
{% if perms.inventory.view_carcolors %}
<div class="card rounded shadow d-flex align-content-center mt-3
{% if car.get_transfer %}transfer{% endif %}">
<p class="card-header rounded-top fw-bold">{% trans 'Colors Details' %}</p>
<div class="card-body">
<div class="table-responsive scrollbar mb-3">
<table class="table table-sm fs-9 mb-0 overflow-hidden">
<!--test-->
{% if car.colors %}
<tr>
<th>{% trans 'Exterior' %}</th>
<td>
<span>{{ car.colors.exterior.get_local_name }}</span>
</td>
<td class="align-middle">
<div class="text-end color-div"
style="background-color: rgb({{ car.colors.exterior.rgb }})">
</div>
</td>
</tr>
<tr>
<th>{% trans 'Interior' %}</th>
<td>
<span>{{ car.colors.interior.get_local_name }}</span>
</td>
<td class="align-middle">
<div class="text-end color-div"
style="background-color: rgb({{ car.colors.interior.rgb }})">
</div>
</td>
</tr>
{% if perms.inventory.change_carcolors %}
<tr>
<td colspan="2">
{% if not car.get_transfer %}
<a href="{% url 'car_colors_update' request.dealer.slug car.slug %}"
class="btn btn-phoenix-warning btn-sm mb-3">{% trans "Edit" %}</a>
{% else %}
<span class="badge bg-danger">{% trans "Cannot Edit, Car in Transfer." %}</span>
{% endif %}
</td>
</tr>
{% endif %}
{% else %}
<tr>
<td colspan="2">
<p>{% trans "No color details available." %}</p>
{% if perms.inventory.add_carcolors %}
<a class="btn btn-phoenix-success btn-sm mb-3"
href="{% url 'add_color' request.dealer.slug car.slug %}">{{ _("Add Color") }}</a>
{% endif %}
</td>
</tr>
{% endif %}
<!--test-->
</table>
</div>
</div>
</div>
{% endif %}
{% if car.status != 'transfer' %}
{% if perms.inventory.view_carreservation %}
<div class="card rounded shadow d-flex align-content-center mt-3">
<p class="card-header rounded-top fw-bold">{% trans 'Reservations Details' %}</p>
<div class="card-body">
<div class="table-responsive scrollbar mb-3">
<table class="table table-sm fs-9 mb-0 overflow-hidden">
{% if car.is_reserved %}
<thead>
<tr>
<th>{% trans "Reserved By" %}</th>
<th>{% trans "Expires At" %}</th>
<th>{% trans 'Actions' %}</th>
</tr>
</thead>
<tbody>
{% for reservation in car.reservations.all %}
<tr>
<td>{{ reservation.reserved_by.dealer }}</td>
<td>{{ reservation.reserved_until }}</td>
{% if perms.inventory.change_carreservation %}
<td>
{% if reservation.is_active %}
<form method="post"
action="{% url 'reservations' request.dealer.slug reservation.id %}">
{% csrf_token %}
<div class="btn-group">
<button type="submit"
name="action"
value="renew"
class="btn btn-sm btn-phoenix-success px-3 py-1">
{% trans "Renew" %}
</button>
<button type="submit"
name="action"
value="cancel"
class="btn btn-sm btn-phoenix-secondary px-3 py-1">
{% trans "Cancel" %}
</button>
</div>
</form>
{% else %}
<span class="badge badge-phoenix badge-phoenix-danger fs-10">{% trans "Expired" %}</span>
{% endif %}
</td>
{% endif %}
</tr>
{% endfor %}
{% else %}
{% if perms.inventory.add_carreservation %}
<tr>
<td>
<button type="button"
class="btn btn-sm btn-phoenix-success"
data-bs-toggle="modal"
data-bs-target="#reserveModal">
{% trans 'Reserve' %}
</button>
</td>
</tr>
{% endif %}
</tbody>
{% endif %}
</table>
</div>
</div>
</div>
{% endif %}
{% endif %}
<!-- Transfer Table -->
{% if car.status == 'transfer' and car.get_transfer %}
<div class="card rounded shadow d-flex align-content-center mt-3">
<p class="card-header rounded-top fw-bold">{% trans 'Transfer Details' %}</p>
<div class="card-body">
<div class="table-responsive scrollbar mb-3">
<table class="table table-sm fs-9 mb-0 overflow-hidden">
<thead>
<tr>
<th>{% trans "Action" %}</th>
<th>{% trans "Status" %}</th>
<th>{% trans "From Showroom" %}</th>
<th>{% trans "To Showroom" %}</th>
<th>{% trans 'Date' %}</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span class="badge badge-phoenix badge-phoenix-info">Transfer</span>
</td>
<td>
{% if car.get_transfer.status == "draft" %}
<span class="badge badge-phoenix badge-phoenix-warning">waiting for approval</span>
{% elif car.get_transfer.status == "approved" %}
<span class="badge badge-phoenix badge-phoenix-info">waiting for dealer acceptance</span>
{% endif %}
</td>
<td>{{ car.get_transfer.from_dealer|title }}</td>
<td>{{ car.get_transfer.to_dealer|title }}</td>
<td>{{ car.get_transfer.transfer_date|date:"Y-m-d" }}</td>
<td>
{% if car.get_transfer.status == "draft" %}
<a class="btn btn-sm btn-phoenix-success"
href="{% url 'transfer_detail' car.get_transfer.pk %}">Approve</a>
{% endif %}
</td>
<td>
<a class="btn btn-sm btn-phoenix-success"
href="{% url 'transfer_detail' car.get_transfer.pk %}?action=cancel">Cancel</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
{% endif %}
</div>
</div>
{% if car.status == 'sold' %}
<img class="car_status"
src="{% static 'images/sold.png' %}"
@ -508,6 +527,7 @@
alt="">
{% endif %}
</div>
<!-- Custom Card Modal -->
<div class="modal fade"
id="customCardModal"

View File

@ -6,34 +6,34 @@
{% trans 'Edit Car' %}
{% endblock %}
{% block content %}
<!---->
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{% trans 'Edit Car' %}
<span class="fas fa-solid fa-car text-primary ms-2"></span>
</h3>
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5">
<div class="col-12 col-sm-10 col-md-8 col-lg-6 col-xl-5">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% trans 'Edit Car' %}
<i class="fas fa-solid fa-car ms-2"></i>
</h3>
</div>
<div class="card-body bg-light-subtle">
<form method="post" class="needs-validation" novalidate>
{% csrf_token %} {{ form|crispy }}
<!-- Save and Back Buttons -->
<hr class="my-2">
<div class="card-body p-4 p-md-5">
<form method="post" class="needs-validation" novalidate>
{% csrf_token %}
{{ form|crispy }}
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-success md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'car_detail' request.dealer.slug car.slug %}" class="btn btn-lg btn-phoenix-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{{ _("Save") }}
</button>
<a href="{% url 'car_detail' request.dealer.slug car.slug %}"
class="btn btn-phoenix-danger btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
<!---->
{% endblock %}
</main>
{% endblock %}

View File

@ -1,50 +1,54 @@
{% extends 'base.html' %}
{% load crispy_forms_filters %}
{% extends "base.html" %}
{% load i18n %}
{% load crispy_forms_filters %}
{% load custom_filters %}
{% block title %}
{% trans "Car Finance Details" %}
{% endblock %}
{% block content %}
<!---->
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{% trans "Finance Details for" %}<span class="fas fa-solid fa-car text-primary ms-2"></span>&nbsp;{{ car.id_car_make.get_local_name }} - {{ car.id_car_model.get_local_name }}
</h3>
{% if form.errors %}
<div class="alert alert-danger">
<ul>
{% for field in form %}
{% for error in field.errors %}<li>{{ field.label }}: {{ error }}</li>{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}<li>{{ error }}</li>{% endfor %}
</ul>
</div>
{% endif %}
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5">
<div class="col-md-8">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% trans "Finance Details for" %}
<span class="text-gray-300">{{car.id_car_make.name}}&nbsp;{{car.id_car_model.name}}&nbsp;{{car.id_car_serie.serie}}&nbsp;{{car.year}}</span>
<i class="fas fa-solid fa-car ms-2"></i>
</h3>
<p class="text-center mt-1">VIN:&nbsp;&nbsp;{{car.vin}}</p>
</div>
<div class="card-body bg-light-subtle">
<div class="card-body p-4 p-md-5">
{% if form.errors %}
<div class="alert alert-danger mt-4" role="alert">
<h4 class="alert-heading small">{% trans "Please correct the following errors:" %}</h4>
<ul class="mb-0">
{% for field, errors in form.errors.items %}
<li><strong>{{ field|capfirst }}:</strong> {% for error in errors %}{{ error }}{% endfor %}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<form method="post" class="needs-validation" novalidate>
<div class="row g-1">
<div class="col-lg-4 col-xl-12">
{% csrf_token %}
{{ form|crispy }}
</div>
</div>
<hr class="my-2">
<div class="row g-1">
<div class="col-lg-4 col-xl-12">
{% csrf_token %}
{{ form|crispy }}
</div>
</div>
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-primary md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'car_detail' request.dealer.slug car.slug %}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{{ _("Save") }}
</button>
<a href="{% url 'car_detail' request.dealer.slug car.slug %}" class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
<!---->
<!-- JavaScript Section -->
{% endblock %}
</main>
{% endblock %}

View File

@ -70,7 +70,7 @@
<div class="card-body bg-primary-subtle">
<label class="label" for="vin">{% trans 'VIN'|capfirst %}:</label>
<div class="input-group">
<input id="vin"
<input id="vin"
name="vin"
type="text"
class="form-control form-control-sm"
@ -180,7 +180,7 @@
</div>
</div>
<!-- Stock Type Card -->
<div class="col-lg-4 col-xl-3">
<div class="col-lg-4 col-xl-3">
<div class="card h-100">
<div class="card-body bg-info-subtle">
<label class="label" for="stock_type">{% trans 'Stock Type'|capfirst %}:</label>

View File

@ -24,7 +24,6 @@
</style>
{% endblock customCSS %}
{% block content %}
{% if cars or request.GET.q%}
<div class="container-fluid" id="projectSummary">
<div class="row g-3 justify-content-between align-items-end mb-4">
@ -189,17 +188,17 @@
hx-on::before-request="on_before_request()"
hx-on::after-request="on_after_request()"></div>
<div class="w-100 list table-responsive">
{% for car in cars %}
<div class="card border mb-3 py-0 px-0" id="project-list-table-body">
<div class="card-body">
<div class="row align-items-center">
<!-- Vehicle Image/Icon -->
<div class="col-auto">
<div class="avatar avatar-3xl">
<img class="rounded-soft shadow shadow-lg"
src="{% static 'images/cars/' %}{{ car.vin }}.png"
src="{% static 'images/car_images/' %}{{ car.get_hash }}.png"
alt="{{ car.vin }}" />
</div>
</div>
@ -269,11 +268,11 @@
<div class="dropdown-menu dropdown-menu-end py-2">
<a class="dropdown-item"
href="{% url 'car_detail' request.dealer.slug car.slug %}"> <span class="fas fa-eye me-2"></span>{{ _("View") }} </a>
{% if perms.inventory.change_car %}
{% if perms.inventory.change_car and not car.status == 'sold' %}
<a class="dropdown-item"
href="{% url 'car_update' request.dealer.slug car.slug %}"> <span class="fas fa-edit me-2"></span>{{ _("Edit") }} </a>
{% endif %}
{% if perms.inventory.delete_car %}
{% if perms.inventory.delete_car and not car.status == 'sold' %}
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger"
href="{% url 'car_delete' request.dealer.slug car.slug %}"> <span class="fas fa-trash me-2"></span>{{ _("Remove") }} </a>
@ -311,5 +310,4 @@
{% endblock %}

View File

@ -6,31 +6,35 @@
{{ _("Add New Expense") }}
{% endblock title %}
{% block content %}
<!---->
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{{ _("Add Expense") }}
<span class="fas fa-money-bill-wave ms-2 text-primary"></span>
</h3>
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5">
<div class="col-md-6">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{{ _("Add Expense") }}
<i class="fas fa-money-bill-wave ms-2"></i>
</h3>
</div>
<div class="card-body bg-light-subtle">
<form method="post" action="">
{% csrf_token %}
{{ form|crispy }}
<div class="card-body p-4 p-md-5">
<form method="post" action="" class="needs-validation" novalidate>
{% csrf_token %}
{{ form|crispy }}
<hr class="my-2">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-primary md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'item_expense_list' request.dealer.slug %}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{{ _("Save") }}
</button>
<a href="{% url 'item_expense_list' request.dealer.slug %}"
class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
<!---->
{% endblock content %}
</main>
{% endblock content %}

View File

@ -6,48 +6,34 @@
{{ _("Update Expense") }}
{% endblock title %}
{% block content %}
{% comment %} <div class="row">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ _("Update Expense") }}</div>
<div class="card-body">
<form method="post" action="">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-phoenix-primary">{% trans 'Save' %}</button>
</form>
</div>
</div>
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5">
<div class="col-md-6">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{{ _("Update Expense") }}
<i class="fas fa-money-bill-wave ms-2"></i>
</h3>
</div>
</div>
</div> {% endcomment %}
<!---->
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{{ _("Update Expense") }}
<span class="fas fa-money-bill-wave ms-2 text-primary"></span>
</h3>
</div>
<div class="card-body bg-light-subtle">
<form method="post" action="">
{% csrf_token %}
{{ form|crispy }}
<hr class="my-2">
<div class="card-body p-4 p-md-5">
<form method="post" action="" class="needs-validation" novalidate>
{% csrf_token %}
{{ form|crispy }}
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-success md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'item_expense_list' request.dealer.slug %}" class="btn btn-lg btn-phoenix-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{{ _("Save") }}
</button>
<a href="{% url 'item_expense_list' request.dealer.slug %}"
class="btn btn-phoenix-danger btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
<!---->
{% endblock content %}
</main>
{% endblock content %}

View File

@ -3,7 +3,7 @@
{% load static %}
{% load i18n %}
{% block title %}
{# Check if an 'object' exists in the context #}
{# Check if an 'object' exists in the context #}
{% if object %}
{% trans 'Update Service' %}
{% else %}
@ -11,39 +11,50 @@
{% endif %}
{% endblock %}
{% block content %}
<!---->
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{% if service.pk %}
{{ _("Update Service") }}
{% else %}
{{ _("Add Service") }}
{% endif %}
<span class="fas fa-tools ms-2 text-primary"></span>
</h3>
<main class="d-flex align-items-center justify-content-center min-vh-100 py-5">
<div class="col-12 col-sm-10 col-md-8 col-lg-6 col-xl-5">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% if object %}
{% trans "Update Service" %}
<i class="fas fa-tools ms-2"></i>
{% else %}
{% trans "Add New Service" %}
<i class="fas fa-tools ms-2"></i>
{% endif %}
</h3>
</div>
<div class="card-body bg-light-subtle">
<div class="card-body p-4 p-md-5">
<form method="post" action="" class="needs-validation" novalidate>
{% csrf_token %}
{{ form|crispy }}
{% if form.errors %}
<div class="alert alert-danger mt-4" role="alert">
<h4 class="alert-heading small">{% trans "Please correct the following errors:" %}</h4>
<ul class="mb-0">
{% for field, errors in form.errors.items %}
<li><strong>{{ field|capfirst }}:</strong> {% for error in errors %}{{ error }}{% endfor %}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<form method="post" action="">
{% csrf_token %}
{{ form|crispy }}
<hr class="my-2">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-primary md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'item_service_list' request.dealer.slug%}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{{ _("Save") }}
</button>
<a href="{% url 'item_service_list' request.dealer.slug %}" class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
<!---->
{% endblock content %}
</main>
{% endblock content %}

View File

@ -2,7 +2,7 @@
{% load i18n %}
{% load crispy_forms_filters %}
{% block title %}
{# Check if an 'object' exists in the context #}
{# Check if an 'object' exists in the context #}
{% if object %}
{% trans 'Update Bank Account' %}
{% else %}
@ -10,41 +10,50 @@
{% endif %}
{% endblock %}
{% block content %}
<!---->
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{% if customer.created %}
{{ _("Edit Bank Account") }}
{% else %}
{{ _("Add Bank Account") }}
{% endif %}
<span class="fas fa-bank ms-2 text-primary"></span>
</h3>
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5 ">
<div class="col-md-8">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% if object %}
{% trans "Update Bank Account" %}
<i class="fa-solid fa-bank ms-2"></i>
{% else %}
{% trans "Add New Bank Account" %}
<i class="fa-solid fa-bank ms-2"></i>
{% endif %}
</h3>
</div>
<div class="card-body bg-light-subtle">
<form method="post" class="form" novalidate>
{% csrf_token %}
{{ form|crispy }}
{% for error in form.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
<hr class="my-2">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-primary md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'bank_account_list' request.dealer.slug%}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
</form>
<div class="card-body p-4 p-md-5">
<form method="post" class="needs-validation" novalidate>
{% csrf_token %}
{{ form|crispy }}
{% if form.errors %}
<div class="alert alert-danger mt-4" role="alert">
<h4 class="alert-heading small">{% trans "Please correct the following errors:" %}</h4>
<ul class="mb-0">
{% for field, errors in form.errors.items %}
<li><strong>{{ field|capfirst }}:</strong> {% for error in errors %}{{ error }}{% endfor %}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center">
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{% trans "Save" %}
</button>
<a href="{% url 'bank_account_list' request.dealer.slug %}" class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
<!---->
{% endblock %}
</main>
{% endblock %}

View File

@ -34,9 +34,27 @@
<td class="align-middle product white-space-nowrap">{{ bank.account_type|capfirst }}</td>
<td class="align-middle product white-space-nowrap">
{% if perms.django_ledger.change_bankaccountmodel %}
<a href="{% url 'bank_account_update' request.dealer.slug bank.pk %}"
class="btn btn-sm btn-phoenix-success">{% trans "Update" %}</a>
{% endif %}
<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 class="dropdown-item" href="{% url 'bank_account_update' request.dealer.slug bank.pk %}" >
<i class="fa fa-edit me-2"></i>{% trans "Update" %}
</a>
<a class="text-danger dropdown-item" href="#" >
<i class="fa fa-trash me-2"></i>{% trans "Delete" %}
</a>
</div>
{% endif %}
</td>
</tr>
{% empty %}

View File

@ -5,42 +5,36 @@
{{ _("Create Journal Entry") }}
{% endblock title %}
{% block content %}
{% comment %} <div class="row mt-4">
<h3 class="text-center">{% trans "Create Journal Entry" %}</h3>
<form id="mainForm" method="post" class="needs-validation">
{% csrf_token %}
<div class="row g-3">
{{ form|crispy }}
<main class="d-flex align-items-center justify-content-center min-vh-100 py-5">
<div class="col-12 col-sm-10 col-md-8 col-lg-6 col-xl-5">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% trans "Create Journal Entry" %}
<i class="fas fa-book-open ms-2"></i>
</h3>
</div>
<div class="mt-5 text-center">
<button type="submit" class="btn btn-phoenix-success me-2"><i class="fa-solid fa-floppy-disk me-1"></i>{% trans "Save" %}</button>
<a href="{% url 'journalentry_list' request.dealer.slug ledger.pk %}" class="btn btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i> {% trans "Cancel" %}</a>
</div>
</form>
</div> {% endcomment %}
<!---->
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center text-white">{% trans "Create Journal Entry" %}</h3>
</div>
<div class="card-body bg-light-subtle">
<form id="mainForm" method="post" class="needs-validation">
{% csrf_token %}
<div class="row g-3">{{ form|crispy }}</div>
<hr class="my-2">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-success md-me-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}
</button>
<a href="{% url 'journalentry_list' request.dealer.slug ledger.pk %}"
class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i> {% trans "Cancel" %}</a>
</div>
</form>
</div>
<div class="card-body p-4 p-md-5">
<form id="mainForm" method="post" class="needs-validation" novalidate>
{% csrf_token %}
<div class="row g-3">
{{ form|crispy }}
</div>
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{{ _("Save") }}
</button>
<a href="{% url 'journalentry_list' request.dealer.slug ledger.pk %}"
class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
<!---->
{% endblock content %}
</main>
{% endblock content %}

View File

@ -5,38 +5,36 @@
{{ _("Create Ledger") }}
{% endblock title %}
{% block content %}
<!---->
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{% trans "Create Ledger" %}
<span class="fas fa-book-open ms-2 text-primary"></span>
</h3>
<main class="d-flex align-items-center justify-content-center min-vh-100 py-5 ">
<div class="col-12 col-sm-10 col-md-8 col-lg-6 col-xl-5">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% trans "Create Ledger" %}
<i class="fas fa-book-open ms-2"></i>
</h3>
</div>
<div class="card-body bg-light-subtle">
<form id="mainForm" method="post" class="needs-validation">
<div class="card-body p-4 p-md-5">
<form id="mainForm" method="post" class="needs-validation" novalidate>
{% csrf_token %}
<div class="row g-3">
{{ form|crispy }}
</div>
<hr class="my-2">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-primary md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'ledger_list' request.dealer.slug request.entity.slug %}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
<div class="row g-3">
{{ form|crispy }}
</div>
</form>
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{{ _("Save") }}
</button>
<a href="{% url 'ledger_list' request.dealer.slug request.entity.slug %}" class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
<!---->
{% endblock content %}
</main>
{% endblock content %}

View File

@ -4,37 +4,69 @@
{% trans "Organization Details" %}
{% endblock title %}
{% block content %}
<div class="row my-4">
<h2 class="mb-2">{{ organization.get_local_name }}</h2>
<ul class="list-group mb-4">
<li class="list-group-item">
<strong>{% trans "CRN" %}:</strong> {{ organization.crn }}
</li>
<li class="list-group-item">
<strong>{% trans "VRN" %}:</strong> {{ organization.vrn }}
</li>
<li class="list-group-item">
<strong>{% trans "Phone" %}:</strong> {{ organization.phone_number }}
</li>
<li class="list-group-item">
<strong>{% trans "Address" %}:</strong> {{ organization.address }}
</li>
</ul>
<div class="d-flex">
{% if perms.inventory.change_organization %}
<a href="{% url 'organization_update' request.dealer.slug organization.slug %}"
class="btn btn-sm btn-phoenix-primary me-2"><span class="fas fa-edit me-1"></span>{% trans "Edit" %}</a>
{% endif %}
{% if perms.inventory.delete_organization %}
<button class="btn btn-phoenix-danger btn-sm delete-btn"
data-url="{% url 'organization_delete' request.dealer.slug organization.slug %}"
data-message="Are you sure you want to delete this organization?"
data-bs-toggle="modal"
data-bs-target="#deleteModal">
<i class="fas fa-trash me-1"></i> {% trans 'Delete' %}
</button>
{% endif %}
<main class="py-5 min-vh-80 d-flex justify-content-center align-items-center">
<div class="container py-4">
<div class="row justify-content-center">
<div class="col-12 col-lg-8 col-xl-6">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h2 class="card-title mb-0 fs-3 fw-bold text-center">
<i class="fas fa-building me-2"></i>
{{ organization.get_local_name }}
</h2>
</div>
<div class="card-body p-4 p-md-5">
<ul class="list-group list-group-flush rounded-3 border">
<li class="list-group-item d-flex justify-content-between align-items-center p-3">
<div class=" fw-semibold">
<i class="fas fa-id-card-alt me-2 text-primary"></i>
{% trans "CRN" %}:
</div>
<span class="">{{ organization.crn }}</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center p-3">
<div class=" fw-semibold">
<i class="fas fa-receipt me-2 text-primary"></i>
{% trans "VRN" %}:
</div>
<span class="">{{ organization.vrn }}</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center p-3">
<div class="fw-semibold">
<i class="fas fa-phone-alt me-2 text-primary"></i>
{% trans "Phone" %}:
</div>
<span class="">{{ organization.phone_number }}</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center p-3">
<div class="fw-semibold">
<i class="fas fa-map-marker-alt me-2 text-primary"></i>
{% trans "Address" %}:
</div>
<span class=" text-end ms-3">{{ organization.address }}</span>
</li>
</ul>
<div class="d-grid gap-2 d-sm-flex justify-content-sm-center mt-4 pt-2">
{% if perms.inventory.change_organization %}
<a href="{% url 'organization_update' request.dealer.slug organization.slug %}"
class="btn btn-phoenix-primary btn-lg flex-grow-1"><i class="fas fa-edit me-2"></i>{% trans "Edit Details" %}</a>
{% endif %}
{% if perms.inventory.delete_organization %}
<button class="btn btn-phoenix-danger btn-lg delete-btn flex-grow-1"
data-url="{% url 'organization_delete' request.dealer.slug organization.slug %}"
data-message="Are you sure you want to delete this organization?"
data-bs-toggle="modal"
data-bs-target="#deleteModal">
<i class="fas fa-trash me-2"></i>{% trans 'Delete' %}
</button>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
{% include 'modal/delete_modal.html' %}
{% endblock %}
</main>
{% include 'modal/delete_modal.html' %}
{% endblock %}

View File

@ -1,44 +1,61 @@
{% extends 'base.html' %}
{% extends "base.html" %}
{% load i18n %}
{% load crispy_forms_filters %}
{% block title %}
{# Check if an 'object' exists in the context #}
{% if object %}
{% trans 'Update Organization' %}
{% else %}
{% trans 'Add New Organization' %}
{% endif %}
{% endblock %}
{% block content %}
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{% if object %}
{% trans 'Update Organization'%}
{% else %}
{% trans 'Add New Organization'%}
{% endif %}
<span class=" fas fa-solid fa-city ms-2 text-primary"></span>
</h3>
<main class="d-flex align-items-center justify-content-center min-vh-100 py-5">
<div class="col-md-8">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% if object %}
{% trans 'Update Organization' %}
<i class="fa-solid fa-edit ms-2"></i>
{% else %}
{% trans 'Add New Organization' %}
<i class="fa-solid fa-building ms-2"></i>
{% endif %}
</h3>
</div>
<div class="card-body bg-light-subtle">
<form class="form" method="post" enctype="multipart/form-data">
<div class="card-body p-4 p-md-5">
<form class="form" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ redirect_field }}
{{ form|crispy }}
<hr class="my-2">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-primary md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'organization_list' request.dealer.slug %}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
{% if form.errors %}
<div class="alert alert-danger mt-4" role="alert">
<h4 class="alert-heading small">{% trans "Please correct the following errors:" %}</h4>
<ul class="mb-0">
{% for field, errors in form.errors.items %}
<li><strong>{{ field|capfirst }}:</strong> {% for error in errors %}{{ error }}{% endfor %}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center">
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{% trans "Save" %}
</button>
<a href="{% url 'organization_list' request.dealer.slug %}" class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
</main>
{% endblock %}

View File

@ -1,60 +1,39 @@
{% extends 'base.html' %}
{% load i18n crispy_forms_filters %}
{% block title %}
{% trans 'Billing Information' %}{% endblock %}
{% block content %}
{% comment %} <div class="row mb-3">
<div class="col-sm-6">
<form action="{% url 'billing_info' %}{% if request.GET.next %}?next={{ request.GET.next }}{% endif %}" method="post" class="form">
<h3>{% trans "Provide billing data"|upper %}</h3>
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-sm btn-phoenix-success me-2">
<i class="fa fa-save me-1"></i>{{ _("Save") }}
</button>
{% if object %}
<a class="btn btn-sm btn-phoenix-danger " href="{% url 'billing_info_delete' %}"><i class="fa-solid fa-trash me-1"></i> {{ _("Delete") }}</a>
{% endif %}
</form>
</div>
</div> {% endcomment %}
<!---->
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{% trans "Provide billing data"|upper %}<span class="fas fa-file-invoice-dollar ms-2 text-primary"></span>
</h3>
{% trans 'Billing Information' %}
{% endblock %}
{% block content %}
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5">
<div class="col-md-8">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% trans "Provide billing data"|upper %}
<i class="fas fa-file-invoice-dollar ms-2"></i>
</h3>
</div>
<div class="card-body bg-light-subtle">
<form action="{% url 'billing_info' %}{% if request.GET.next %}?next={{ request.GET.next }}{% endif %}" method="post" class="form">
{% csrf_token %}
{{ form|crispy }}
<hr class="my-2">
<div class="card-body p-4 p-md-5">
<form action="{% url 'billing_info' %}{% if request.GET.next %}?next={{ request.GET.next }}{% endif %}"
method="post" class="needs-validation" novalidate>
{% csrf_token %}
{{ form|crispy }}
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-primary md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
{% if object %}
<a class="btn btn-lg btn-phoenix-danger" href="{% url 'billing_info_delete' %}"><i class="fa-solid fa-trash me-1"></i> {{ _("Delete") }}</a>
{% endif %}
</div>
</form>
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{{ _("Save") }}
</button>
{% if object %}
<a class="btn btn-phoenix-danger btn-lg" href="{% url 'billing_info_delete' %}">
<i class="fa-solid fa-trash me-1"></i>
{{ _("Delete") }}
</a>
{% endif %}
</div>
</form>
</div>
</div>
<!---->
{% endblock %}
</div>
</main>
{% endblock %}

View File

@ -280,7 +280,7 @@
<tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="7">{% trans "Vat" %} ({{ data.vat_rate }})</td>
<td class="align-middle text-start fw-semibold">
<span id="">+ {{ data.vat_amount }}<span class="icon-saudi_riyal"></span></span>
<span id="">+ {{ data.vat_amount|floatformat:2 }}<span class="icon-saudi_riyal"></span></span>
</td>
</tr>
<tr class="bg-body-secondary total-sum">

View File

@ -121,7 +121,7 @@
width: 0;
}
</style>
<div class="row justify-content-center mt-5 mb-3">
<div class="row d-flex justify-content-center align-items-center mt-5 mb-3 ms-6 ps-3" >
<div class="row">
<div class="col">
{% if not items %}
@ -137,19 +137,19 @@
{% endif %}
</div>
<div>
<div class="col-lg-12 col-md-10 needs-validation {% if not items or not customer_count %}d-none{% endif %}">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<div class="col-md-10 ms-4 needs-validation {% if not items or not customer_count %}d-none{% endif %}">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 text-center">
{% trans "Create Quotation" %}<i class="fa-regular fa-file-lines text-primary ms-2"></i>
{% trans "Create Quotation" %}<i class="fa-regular fa-file-lines ms-2"></i>
</h3>
</div>
<div class="card-body bg-light-subtle">
<div class="card-body p-4 p-md-5">
<form id="mainForm" method="post" class="needs-validation {% if not items and not customer_count %}d-none{% endif %}">
{% csrf_token %}
<div class="row g-3 col-12">
<div class="row g-3">
{{ form|crispy }}
<div class="custom-select">
<!-- Hidden native select for form submission -->

View File

@ -6,20 +6,33 @@
{{ _("Sale Order") }}
{% endblock title %}
{% block content %}
<div class="row">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ _("Sale Order") }}</div>
<div class="card-body">
<form method="post" action="{% url 'create_sale_order' request.dealer.slug estimate.pk %}">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-phoenix-primary">{% trans 'Save' %}</button>
</form>
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5">
<div class="col-12 col-sm-10 col-md-8 col-lg-6 col-xl-5">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{{ _("Create Sale Order") }}
<i class="fas fa-file-invoice-dollar ms-2"></i>
</h3>
</div>
<div class="card-body p-4 p-md-5">
<form method="post" action="{% url 'create_sale_order' request.dealer.slug estimate.pk %}" class="needs-validation" novalidate>
{% csrf_token %}
{{ form|crispy }}
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{% trans 'Save' %}
</button>
<a href="{% url 'home' request.dealer.slug %}" class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</div>
</form>
</div>
</div>
</div>
</main>
{% endblock content %}

View File

@ -6,30 +6,34 @@
{{ _("Invoice") }}
{% endblock title %}
{% block content %}
<div class="row paid justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{{ _("Add Invoice") }}<i class="fa-solid fa-receipt ms-2 text-primary"></i>
</h3>
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5">
<div class="col-12 col-sm-10 col-md-8 col-lg-6 col-xl-5">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{{ _("Add Invoice") }}
<i class="fa-solid fa-receipt ms-2"></i>
</h3>
</div>
<div class="card-body bg-light-subtle">
<form method="post" action="">
{% csrf_token %}
{{ form|crispy }}
<hr class="my-2">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-success md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'invoice_list' request.dealer.slug %}" class="btn btn-lg btn-phoenix-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
</form>
</div>
<div class="card-body p-4 p-md-5">
<form method="post" action="" class="needs-validation" novalidate>
{% csrf_token %}
{{ form|crispy }}
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{{ _("Save") }}
</button>
<a href="{% url 'invoice_list' request.dealer.slug %}"
class="btn btn-phoenix-danger btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
<!---->
{% endblock content %}
</main>
{% endblock content %}

View File

@ -4,18 +4,33 @@
{% load i18n %}
{% block content %}
<div class="card">
<div class="card-header bg-primary text-white">
<h2 class="h4 mb-0">Create Support Ticket</h2>
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5">
<div class="col-12 col-sm-10 col-md-8 col-lg-6 col-xl-5">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% trans "Create Support Ticket" %}
<i class="fa-solid fa-headset ms-2"></i>
</h3>
</div>
<div class="card-body p-4 p-md-5">
<form method="post" class="needs-validation" novalidate>
{% csrf_token %}
{{ form|crispy }}
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button type="submit" class="btn btn-phoenix-primary btn-lg me-md-2">
<i class="fa-solid fa-paper-plane me-1"></i>
{% trans "Submit Ticket" %}
</button>
<a href="{% url 'ticket_list' request.dealer.slug %}" class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
<div class="card-body">
<form method="post">
{% csrf_token %}
{{form|crispy}}
<button type="submit" class="btn btn-primary">Submit Ticket</button>
<a href="{% url 'ticket_list' request.dealer.slug %}" class="btn btn-secondary">Cancel</a>
</form>
</div>
</div>
{% endblock %}
</main>
{% endblock %}

View File

@ -2,59 +2,76 @@
{% load static %}
{% load crispy_forms_tags %}
{% load i18n %}
{% block title %}
{% trans 'Ticket' %} #{{ ticket.id }}
{% endblock title %}
{% block content %}
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h2 class="h4 mb-0">Ticket #{{ ticket.id }}: {{ ticket.subject }}</h2>
<div>
<a href="{% url 'ticket_list' request.dealer.slug %}" class="btn btn-sm btn-outline-secondary">
Back to List
</a>
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5 ">
<div class="col-12 col-sm-10 col-md-8 col-lg-6 col-xl-5">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% trans 'Ticket' %} #{{ ticket.id }}
<i class="fas fa-headset ms-2"></i>
</h3>
</div>
<div class="card-body p-4 p-md-5">
<div class="row g-3">
<div class="col-12 text-center mb-3">
<h4 class="h5 fw-bold">{{ ticket.subject }}</h4>
</div>
<div class="col-sm-6">
<strong>{% trans 'Status:' %}</strong>
<span class="badge
{% if ticket.status == 'open' %}bg-primary
{% elif ticket.status == 'in_progress' %}bg-info
{% elif ticket.status == 'resolved' %}bg-success
{% else %}bg-secondary{% endif %}">
{{ ticket.get_status_display }}
</span>
</div>
<div class="col-sm-6 text-sm-end">
<strong>{% trans 'Priority:' %}</strong>
<span class="badge
{% if ticket.priority == 'low' %}bg-success
{% elif ticket.priority == 'medium' %}bg-warning
{% elif ticket.priority == 'high' %}bg-danger
{% else %}bg-dark{% endif %}">
{{ ticket.get_priority_display }}
</span>
</div>
<div class="col-sm-6">
<strong>{% trans 'Created:' %}</strong>
<br class="d-sm-none">{{ ticket.created_at|date:"M d, Y" }}
</div>
<div class="col-sm-6 text-sm-end">
<strong>{% trans 'Last Updated:' %}</strong>
<br class="d-sm-none">{{ ticket.updated_at|date:"M d, Y" }}
</div>
</div>
<hr class="my-4">
<div class="mb-4">
<h5 class="fw-bold mb-2">{% trans 'Description' %}</h5>
<div class="p-3 bg-light rounded-3">
{{ ticket.description|linebreaks }}
</div>
</div>
{% if ticket.resolution_notes %}
<div class="mb-4">
<h5 class="fw-bold mb-2">{% trans 'Resolution Notes' %}</h5>
<div class="p-3 bg-light rounded-3">
{{ ticket.resolution_notes|linebreaks }}
</div>
</div>
{% endif %}
<div class="d-grid mt-4">
<a href="{% url 'ticket_list' request.dealer.slug %}" class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-arrow-left me-1"></i>
{% trans 'Back to Tickets' %}
</a>
</div>
</div>
</div>
</div>
<div class="card-body">
<div class="row mb-4">
<div class="col-md-6">
<p><strong>Status:</strong>
<span class="badge
{% if ticket.status == 'open' %}bg-primary
{% elif ticket.status == 'in_progress' %}bg-info
{% elif ticket.status == 'resolved' %}bg-success
{% else %}bg-secondary{% endif %}">
{{ ticket.get_status_display }}
</span>
</p>
<p><strong>Priority:</strong>
<span class="badge
{% if ticket.priority == 'low' %}bg-success
{% elif ticket.priority == 'medium' %}bg-warning
{% elif ticket.priority == 'high' %}bg-danger
{% else %}bg-dark{% endif %}">
{{ ticket.get_priority_display }}
</span>
</p>
</div>
<div class="col-md-6">
<p><strong>Created:</strong> {{ ticket.created_at|date:"M d, Y H:i" }}</p>
<p><strong>Last Updated:</strong> {{ ticket.updated_at|date:"M d, Y H:i" }}</p>
</div>
</div>
<div class="mb-4">
<h3 class="h5">Description</h3>
<div class="p-3 rounded">
{{ ticket.description|linebreaks }}
</div>
</div>
<div class="mb-4">
<h3 class="h5">Resolution Notes</h3>
<div class="p-3 rounded">
{{ ticket.resolution_notes|linebreaks }}
</div>
</div>
<!-- You can add comments/replies section here later -->
</div>
</div>
</main>
{% endblock %}

View File

@ -1,80 +1,116 @@
{% extends "base.html" %}
{% load static %}
{% load i18n %}
{% block title %}
{% trans "My Tickets" %}
{% endblock title %}
{% block content %}
<div class="card">
<div class="card-body">
<h5 class="card-title">Need help?</h5>
<p class="card-text">Raise a ticket and we will get back to you as soon as possible.</p>
<a href="{% url 'create_ticket' request.dealer.slug %}" class="btn btn-phoenix-primary">Raise a Ticket</a>
<main class="py-5">
<div class="container">
<div class="row justify-content-center mb-5">
<div class="col-lg-8">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInDown">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4 text-center">
<i class="fa-solid fa-headset fa-2x mb-2"></i>
<h2 class="card-title fw-bold mb-0">
{% trans "Need Help?" %}
</h2>
</div>
<div class="card-body p-4 p-md-5 text-center bg-white">
<p class="card-text text-muted mb-4">
{% blocktrans %}
Our support team is ready to assist you. Raise a new ticket below, and we'll get back to you as soon as possible.
{% endblocktrans %}
</p>
<a href="{% url 'create_ticket' request.dealer.slug %}" class="btn btn-phoenix-primary btn-lg shadow-sm">
<i class="fa-solid fa-plus me-1"></i>
{% trans "Raise a New Ticket" %}
</a>
</div>
</div>
</div>
</div>
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
{% endif %}
<div class="card">
<div class="card-body">
<h5 class="card-title">Tickets</h5>
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead class="">
<tr>
<th>ID</th>
<th>Subject</th>
<th>Status</th>
<th>Priority</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for ticket in tickets %}
<tr>
<td>#{{ ticket.id }}</td>
<td>{{ ticket.subject }}</td>
<td>
<span class="badge
{% if ticket.status == 'open' %}bg-primary
{% elif ticket.status == 'in_progress' %}bg-info
{% elif ticket.status == 'resolved' %}bg-success
{% else %}bg-secondary{% endif %}">
{{ ticket.get_status_display }}
</span>
</td>
<td>
<span class="badge
{% if ticket.priority == 'low' %}bg-success
{% elif ticket.priority == 'medium' %}bg-warning
{% elif ticket.priority == 'high' %}bg-danger
{% else %}bg-dark{% endif %}">
{{ ticket.get_priority_display }}
</span>
</td>
<td>{{ ticket.created_at|date:"M d, Y H:i" }}</td>
<td>
<a href="{% url 'ticket_detail' request.dealer.slug ticket.id %}" class="btn btn-sm btn-outline-primary">
View
</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center">No tickets found.</td>
</tr>
{% if messages %}
<div class="alert-container mb-4">
{% for message in messages %}
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endif %}
<div class="card shadow-lg border-0 rounded-4 animate__animated animate__fadeInUp">
<div class="card-header border-bottom d-flex flex-column flex-md-row justify-content-between align-items-md-center p-4">
<h5 class="card-title mb-2 mb-md-0 me-md-4 fw-bold">{% trans "My Tickets" %}</h5>
<div class="input-group w-100 w-md-50">
{% include 'partials/search_box.html' %}
</div>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-striped table-hover mb-0">
<thead class="bg-light">
<tr>
<th scope="col" class="text-secondary text-uppercase fw-bold ps-4">ID</th>
<th scope="col" class="text-secondary text-uppercase fw-bold">Subject</th>
<th scope="col" class="text-secondary text-uppercase fw-bold">Status</th>
<th scope="col" class="text-secondary text-uppercase fw-bold">Priority</th>
<th scope="col" class="text-secondary text-uppercase fw-bold">Created</th>
<th scope="col" class="text-secondary text-uppercase fw-bold text-end pe-4">Actions</th>
</tr>
</thead>
<tbody>
{% for ticket in tickets %}
<tr>
<td class="text-muted ps-4">#{{ ticket.id }}</td>
<td>{{ ticket.subject }}</td>
<td>
<span class="badge
{% if ticket.status == 'open' %}bg-primary
{% elif ticket.status == 'in_progress' %}bg-info
{% elif ticket.status == 'resolved' %}bg-success
{% else %}bg-secondary{% endif %}">
{{ ticket.get_status_display }}
</span>
</td>
<td>
<span class="badge
{% if ticket.priority == 'low' %}bg-success
{% elif ticket.priority == 'medium' %}bg-warning
{% elif ticket.priority == 'high' %}bg-danger
{% else %}bg-dark{% endif %}">
{{ ticket.get_priority_display }}
</span>
</td>
<td>
<span class="d-block">{{ ticket.created_at|date:"M d, Y" }}</span>
<span class="text-muted small d-block">{{ ticket.created_at|time:"H:i" }}</span>
</td>
<td class="text-end pe-4">
<a href="{% url 'ticket_detail' request.dealer.slug ticket.id %}" class="btn btn-phoenix-primary btn-sm">
<i class="fa-solid fa-eye me-1"></i>
{% trans "View" %}
</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center text-muted py-5">
<i class="fas fa-ticket-alt fs-2 mb-3"></i>
<p class="mb-0">{% trans "No tickets found." %}</p>
<p class="text-muted small">{% trans "All your past and present tickets will appear here." %}</p>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</main>
{% endblock %}

View File

@ -1,8 +1,6 @@
{% extends "base.html" %}
{% load i18n %}
{% load crispy_forms_filters %}
{% load i18n crispy_forms_filters %}
{% block title %}
{# Check if an 'object' exists in the context #}
{% if object %}
{% trans 'Update Staff' %}
{% else %}
@ -10,49 +8,51 @@
{% endif %}
{% endblock %}
{% block content %}
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{% if staff.created %}
{{ _("Edit Staff") }}
{% else %}
{{ _("Add Staff") }}
{% endif %}
<i class="fa-solid fa-user-tie text-primary ms-2"></i>
</h3>
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5">
<div class="col-md-8">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% if object %}
{% trans "Update Staff" %}
<i class="fa-solid fa-user-tie ms-2"></i>
{% else %}
{% trans "Add New Staff" %}
<i class="fa-solid fa-user-tie ms-2"></i>
{% endif %}
</h3>
</div>
<div class="card-body bg-light-subtle">
<form class="row g-3 mb-3" method="post" class="form" novalidate>
{% csrf_token %}
{{ redirect_field }}
{{ form.first_name|as_crispy_field }}
{{ form.last_name|as_crispy_field }}
{{ form.arabic_name|as_crispy_field }}
{{ form.email|as_crispy_field }}
{{ form.phone_number|as_crispy_field }}
{{ form.address|as_crispy_field }}
{{ form.logo|as_crispy_field }}
{{ form.group|as_crispy_field }}
{% for error in form.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
<hr class="my-2">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-primary md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'user_list' request.dealer.slug %}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
</form>
<div class="card-body p-4 p-md-5">
<form class="needs-validation" method="post" novalidate>
{% csrf_token %}
{{ redirect_field }}
{{ form|crispy }}
{% if form.errors %}
<div class="alert alert-danger mt-4" role="alert">
<h4 class="alert-heading small">{% trans "Please correct the following errors:" %}</h4>
<ul class="mb-0">
{% for field, errors in form.errors.items %}
<li><strong>{{ field|capfirst }}:</strong> {% for error in errors %}{{ error }}{% endfor %}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{{ _("Save") }}
</button>
<a href="{% url 'user_list' request.dealer.slug %}" class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
</main>
{% endblock %}

View File

@ -5,37 +5,46 @@
{% trans "Group" %}
{% endblock title %}
{% block content %}
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-5 text-center">
{{ _("Manage Groups") }}<i class="fa-solid fa-users ms-2 text-primary"></i>
</h3>
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5 ">
<div class="col-12 col-sm-10 col-md-8 col-lg-6 col-xl-5">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{{ _("Manage Groups") }}
<i class="fa-solid fa-users ms-2"></i>
</h3>
</div>
<div class="card-body bg-light-subtle">
<form class="row g-3 mb-3" method="post" class="form" enctype="multipart/form-data" novalidate >
{% csrf_token %}
{{ redirect_field }}
{{ form|crispy }}
{% for error in form.errors %}<div class="text-danger">{{ error }}</div>{% endfor %}
<hr class="my-2">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-primary md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'user_detail' request.dealer.slug staff.slug %}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
</form>
<div class="card-body p-4 p-md-5">
<form class="needs-validation" method="post" enctype="multipart/form-data" novalidate>
{% csrf_token %}
{{ redirect_field }}
{{ form|crispy }}
{% if form.errors %}
<div class="alert alert-danger mt-4" role="alert">
<h4 class="alert-heading small">{% trans "Please correct the following errors:" %}</h4>
<ul class="mb-0">
{% for field, errors in form.errors.items %}
<li><strong>{{ field|capfirst }}:</strong> {% for error in errors %}{{ error }}{% endfor %}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{{ _("Save") }}
</button>
<a href="{% url 'user_detail' request.dealer.slug staff.slug %}" class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
</main>
{% endblock %}

View File

@ -1,18 +1,20 @@
{% extends 'base.html' %}
{% load i18n %}
{% block content %}
<main class="d-flex align-items-center justify-content-center min-vh-100 py-5">
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5">
<div class="col-12 col-sm-10 col-md-8 col-lg-6 col-xl-5">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp" style="background-color: #f8f9fa;">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h1 class="h3 fw-bold mb-0 text-center">
<i class="fas fa-lock me-2"></i> {% trans "Set New Password" %}
</h1>
</div>
<div class="card-body p-4 p-md-5">
<div class="text-center mb-4">
<h1 class="h3 fw-bold text-dark mb-2">{% trans "Set New Password" %}</h1>
<p class="text-muted">{% trans "Enter your new password below." %}</p>
<p class="mb-0 fs-5">{% trans "Enter your new password below." %}</p>
</div>
<form method="post" class="needs-validation" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-floating mb-3">
{{ field.errors }}
@ -20,17 +22,16 @@
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
</div>
{% endfor %}
<div class="d-grid mt-4">
<button type="submit" class="btn btn-primary btn-lg rounded-pill fw-bold">
<button type="submit" class="btn btn-phoenix-primary btn-lg rounded-pill fw-bold">
{% trans "Change Password" %}
</button>
</div>
</form>
</div>
<div class="card-footer bg-light border-0 py-3 text-center">
<div class="card-footer bg-gray-300 border-0 py-3 text-center">
<small class="text-muted">
{% trans "Remember to choose a strong password." %}
<i class="fas fa-info-circle me-1"></i> {% trans "Remember to choose a strong password." %}
</small>
</div>
</div>

View File

@ -2,7 +2,6 @@
{% load i18n %}
{% load crispy_forms_filters %}
{% block title %}
{# Check if an 'object' exists in the context #}
{% if object %}
{% trans 'Update Vendor' %}
{% else %}
@ -10,37 +9,51 @@
{% endif %}
{% endblock %}
{% block content %}
<div class="row justify-content-center mt-5 mb-3">
<div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{% if vendor.created %}
{{ _("Edit Vendor") }}
{% else %}
{{ _("Add Vendor") }}
{% endif %}
<span class="fas fa-cube ms-2 text-primary"></span>
</h3>
<main class="d-flex align-items-center justify-content-center min-vh-80 py-5 ">
<div class="col-md-8 ">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center">
{% if object %}
{% trans "Update Vendor" %}
<i class="fas fa-cube ms-2"></i>
{% else %}
{% trans "Add New Vendor" %}
<i class="fas fa-cube ms-2"></i>
{% endif %}
</h3>
</div>
<div class="card-body bg-light-subtle">
<form class="row g-3 mb-3" method="post" class="form" enctype="multipart/form-data" novalidate >
{% csrf_token %}
{{ redirect_field }}
{{ form|crispy }}
{% for error in form.errors %}<div class="text-danger">{{ error }}</div>{% endfor %}
<hr class="my-2">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-primary md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'vendor_list' request.dealer.slug%}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
</form>
<div class="card-body p-4 p-md-5">
<form class="needs-validation" method="post" enctype="multipart/form-data" novalidate>
{% csrf_token %}
{{ redirect_field }}
{{ form|crispy }}
{% if form.errors %}
<div class="alert alert-danger mt-4" role="alert">
<h4 class="alert-heading small">{% trans "Please correct the following errors:" %}</h4>
<ul class="mb-0">
{% for field, errors in form.errors.items %}
<li><strong>{{ field|capfirst }}:</strong> {% for error in errors %}{{ error }}{% endfor %}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<hr class="my-4">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-phoenix-primary btn-lg me-md-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>
{{ _("Save") }}
</button>
<a href="{% url 'vendor_list' request.dealer.slug %}" class="btn btn-phoenix-secondary btn-lg">
<i class="fa-solid fa-ban me-1"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
</div>
<!---->
{% endblock %}
</main>
{% endblock %}