This commit is contained in:
Marwan Alwali 2025-02-11 15:17:42 +03:00
parent c37f87299b
commit ec30867916
38 changed files with 1156 additions and 1036 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@ -1,3 +1,9 @@
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "car_inventory.settings")
django.setup()
from inventory.models import *
from rich import print
import random
@ -94,7 +100,7 @@ def run():
for vin in vin_list:
try:
for _ in range(15):
dealer = Dealer.objects.get(user__email="ismail.mosa.ibrahim@gmail.com")
dealer = Dealer.objects.get(user__email="marwan@tenhal.sa")
vin = f"{vin[:-4]}{random.randint(0, 9)}{random.randint(0, 9)}{random.randint(0, 9)}{random.randint(0, 9)}"
result = decodevin(vin)
make = CarMake.objects.get(name=result["maker"])
@ -126,3 +132,6 @@ def run():
print(make, model, serie, trim)
except Exception as e:
print(e)
if __name__ == "__main__":
run()

View File

@ -1,5 +1,7 @@
from appointment.models import Appointment, Service, StaffMember
from django.urls import reverse
from django_countries.widgets import CountrySelectWidget
from django_ledger.models import CustomerModel
from phonenumber_field.formfields import PhoneNumberField
from django.core.validators import MinLengthValidator
from django.core.validators import RegexValidator
@ -64,7 +66,7 @@ class StaffForm(forms.ModelForm):
email = forms.EmailField(
required=True,
label="Email",
widget=forms.EmailInput(attrs={"class": "form-control"}),
widget=forms.EmailInput(attrs={"class": "form-control form-control-sm"}),
)
class Meta:
@ -773,3 +775,5 @@ class EstimateModelCreateForm(EstimateModelCreateFormBase):
def get_customer_queryset(self):
return self.USER_MODEL.dealer.entity.get_customers()

View File

@ -0,0 +1,22 @@
# Generated by Django 5.1.5 on 2025-02-11 00:23
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0017_car_hash'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='customer',
name='user',
field=models.OneToOneField(default=4, on_delete=django.db.models.deletion.CASCADE, related_name='customer_profile', to=settings.AUTH_USER_MODEL),
preserve_default=False,
),
]

View File

@ -1007,6 +1007,7 @@ class Customer(models.Model):
dealer = models.ForeignKey(
Dealer, on_delete=models.CASCADE, related_name="customers"
)
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='customer_profile')
title = models.CharField(
choices=Title.choices, default=Title.NA, max_length=10, verbose_name=_("Title")
)

View File

@ -664,6 +664,23 @@ def create_customer(sender, instance, created, **kwargs):
print(f"Customer created: {name}")
@receiver(post_save, sender=models.Customer)
def create_customer_user(sender, instance, created, **kwargs):
if created:
user = User.objects.create(
username=instance.email,
email=instance.email,
password=None,
first_name=instance.first_name,
last_name=instance.last_name
)
user.is_active = True
user.is_staff = True
user.save()
instance.user = user
instance.save()
# Create Item
@receiver(post_save, sender=models.Car)
def create_item_model(sender, instance, created, **kwargs):

View File

@ -4,7 +4,7 @@ from num2words import num2words
register = template.Library()
@register.filter
def num_to_words(value, lang='en'):
def num_to_words(value, lang='ar'):
try:
return num2words(value, lang=lang)
except:

View File

@ -159,6 +159,7 @@ urlpatterns = [
views.mark_notification_as_read,
name="mark_notification_as_read",
),
path('crm/calender/', views.EmployeeCalendarView.as_view(), name='calendar_list'),
# Vendor URLs
path("vendors", views.VendorListView.as_view(), name="vendor_list"),
path("vendors/<uuid:pk>/", views.vendorDetailView, name="vendor_detail"),

View File

@ -112,6 +112,7 @@ from pyzbar.pyzbar import decode
from django.core.files.storage import default_storage
from plans.models import Plan,PlanPricing
from django_ledger.utils import accruable_net_summary
from appointment.views_admin import fetch_user_appointments
logger = logging.getLogger(__name__)
@ -2889,12 +2890,14 @@ class InvoicePreviewView(LoginRequiredMixin, DetailView):
template_name = "sales/invoices/invoice_preview.html"
def get_context_data(self, **kwargs):
dealer = get_user_type(self.request)
invoice = kwargs.get("object")
if invoice.get_itemtxs_data():
# data = get_financial_values(invoice)
calculator = CarFinanceCalculator(invoice)
finance_data = calculator.get_finance_data()
kwargs["data"] = finance_data
kwargs['dealer'] = dealer
# kwargs["vat_amount"] = data["vat_amount"]
# kwargs["total"] = data["grand_total"]
# kwargs["discount_amount"] = data["discount_amount"]
@ -4154,4 +4157,14 @@ class PnLAPIView(DjangoLedgerSecurityMixIn, EntityUnitMixIn, View):
}, status=401)
class EmployeeCalendarView(ListView):
template_name = 'crm/employee_calendar.html'
model = Appointment
context_object_name = 'appointments'
# def get_context_data(self):
# self.context['dealer'] = get_user_type(self.request)
# dealer =
# return Appointment.objects.all()

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -52,7 +52,7 @@ django-debug-toolbar==5.0.1
django-extensions==3.2.3
django-filter==24.3
django-formtools==2.5.1
django-ledger==0.7.3
django-ledger==0.7.4.1
django-money==3.5.3
django-next-url-mixin==0.4.0
django-nine==0.2.7
@ -85,7 +85,6 @@ filelock==3.17.0
fire==0.7.0
Flask==3.1.0
fonttools==4.55.7
fpdf==1.7.2
fpdf2==2.8.2
frozenlist==1.5.0
fsspec==2024.12.0

BIN
static/.DS_Store vendored

Binary file not shown.

View File

@ -0,0 +1,43 @@
body {
font-family: 'Roboto', sans-serif;
background-color: #f8f9fa;
margin: 0;
padding: 0;
}
.pdf-container {
width: 210mm;
min-height: 297mm;
padding: 20mm;
margin: auto;
background: white;
border-radius: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
justify-content: space-between;
}
.pdf-header {
text-align: center;
border-bottom: 2px solid #dee2e6;
padding-bottom: 10px;
margin-bottom: 20px;
font-size: 18px;
font-weight: bold;
}
.pdf-content {
flex: 1;
padding: 10px 0;
}
.pdf-footer {
text-align: center;
margin-top: auto;
padding: 10px;
background: #f8f9fa;
font-size: 12px;
color: #666;
border-top: 1px solid #ddd;
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -217,7 +217,7 @@ function displayEventList(events, date) {
eventListHtml += `<div class="djangoAppt_no-events">` + noEventTxt + `</div>`;
}
eventListHtml += `<button class="btn btn-primary djangoAppt_btn-new-event" onclick="createNewAppointment('${date_obj}')">` + newEventTxt + `</button></div>`;
eventListHtml += `<button class="btn btn-sm btn-primary" onclick="createNewAppointment('${date_obj}')">` + newEventTxt + `</button></div>`;
const eventListContainer = document.getElementById('event-list-container');
eventListContainer.innerHTML = eventListHtml;
@ -580,10 +580,12 @@ async function showCreateAppointmentModal(defaultStartTime, formattedDate) {
if (isUserSuperUser) {
staffDropdown = await populateStaffMembers(null, false);
staffDropdown.id = "staffSelect";
staffDropdown.classList.add('form-select')
staffDropdown.disabled = false; // Enable dropdown
attachEventListenersToDropdown(); // Attach event listener
}
servicesDropdown.id = "serviceSelect";
servicesDropdown.classList.add('form-select')
servicesDropdown.disabled = false; // Enable dropdown
document.getElementById('eventModalBody').innerHTML = prepareCreateAppointmentModalContent(servicesDropdown, staffDropdown, defaultStartTime, formattedDate);
@ -635,6 +637,8 @@ async function getAppointmentData(eventId, isCreatingMode, defaultStartTime) {
async function getServiceDropdown(serviceId, isEditMode) {
const servicesDropdown = await populateServices(serviceId, !isEditMode);
servicesDropdown.id = "serviceSelect";
servicesDropdown.classList.add('form-select');
servicesDropdown.classList.add('form-select-sm');
servicesDropdown.disabled = !isEditMode;
return servicesDropdown;
}
@ -643,6 +647,8 @@ async function getServiceDropdown(serviceId, isEditMode) {
async function getStaffDropdown(staffId, isEditMode) {
const staffDropdown = await populateStaffMembers(staffId, !isEditMode);
staffDropdown.id = "staffSelect";
staffDropdown.classList.add('form-select');
staffDropdown.classList.add('form-select-sm');
staffDropdown.disabled = !isEditMode;
return staffDropdown;
}

View File

@ -15,7 +15,7 @@ const calendar = new FullCalendar.Calendar(calendarEl, {
left: 'title',
right: 'prev,today,next',
},
height: '400px',
themeSystem: 'bootstrap',
nowIndicator: true,
bootstrapFontAwesome: {

3
static/js/html2pdf.bundle.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -221,3 +221,4 @@ const getDataTableInit = () => {
}
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,97 +1,98 @@
{% extends BASE_TEMPLATE %}
{% load i18n %}
{% load static %}
{% block customCSS %}
<link rel="stylesheet" type="text/css" href="{% static 'css/app_admin/display_appointment.css' %}"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA=="
crossorigin="anonymous" referrerpolicy="no-referrer"/>
{% endblock %}
{% block title %}
{{ page_title }}
{% endblock %}
{% block description %}
{{ page_description }}
{% endblock %}
{% block body %}
<section class="content content-wrapper">
<div class="appointment-display-content">
<div class="app-content">
<div class="appointment-card">
<h2>{{ page_title }}</h2>
<div class="appointment-details">
<div class="appointment-detail hover-element">
<i class="fas fa-calendar-alt"></i>
<strong>{% trans 'Date' %}:</strong> {{ appointment.get_date }}
</div>
<div class="appointment-detail hover-element">
<i class="fas fa-clock"></i>
<strong>{% trans 'Start time' %}:</strong> {{ appointment.get_start_time|time:"g:i A" }}
</div>
<div class="appointment-detail hover-element">
<i class="fas fa-clock"></i>
<strong>{% trans 'End time' %}:</strong> {{ appointment.get_end_time|time:"g:i A" }}
</div>
<div class="appointment-detail hover-element">
<i class="fas fa-hands-helping"></i>
<strong>{% trans 'Service' %}:</strong> {{ appointment.get_service_name }}
</div>
<div class="appointment-detail hover-element">
<i class="fas fa-user"></i>
<strong>{% trans 'Client' %}:</strong> {{ appointment.get_client_name }}
</div>
<div class="appointment-detail hover-element">
<i class="fas fa-envelope"></i>
<strong>{% trans 'Email' %}:</strong> {{ appointment.client.email }}
</div>
<div class="appointment-detail hover-element">
<i class="fas fa-phone"></i>
<strong>{% trans 'Phone' %}:</strong> {{ appointment.phone }}
</div>
<div class="appointment-detail hover-element">
<i class="fas fa-comment"></i>
<strong>{% trans 'Wants reminder' %}:</strong> {{ appointment.want_reminder }}
</div>
<div class="appointment-detail hover-element">
<i class="fas fa-map-marker-alt"></i>
<strong>{% trans 'Client address' %}:</strong> {{ appointment.address }}
</div>
<div class="appointment-detail hover-element">
<i class="fas fa-info-circle"></i>
<strong>{% trans 'Additional Information' %}:</strong> {{ appointment.additional_info }}
</div>
<div class="appointment-detail {% if appointment.is_paid %} is-paid-true {% else %} is-paid-false {% endif %}">
<i class="fas fa-money-bill-wave"></i>
<strong>{% trans 'Is paid' %}:</strong> {{ appointment.is_paid_text }}
</div>
<div class="appointment-detail hover-element">
<i class="fas fa-dollar-sign"></i>
<strong>{% trans 'Service price' %}:</strong> {{ appointment.get_appointment_amount_to_pay_text }}
</div>
{% block title %}{{ page_title }}{% endblock %}
{% block description %}{{ page_description }}{% endblock %}
{% block content %}
<div class="container py-5">
<div class="card bg-body">
<div class="card-header ">
<h4 class="mb-0">{{ page_title }}</h4>
</div>
<div class="card-body">
<div class="row g-3">
<div class="col-md-6">
<div class="d-flex align-items-center">
<i class="fas fa-calendar-alt me-2 text-primary"></i>
<strong class="me-2">{% trans 'Date' %}:</strong> {{ appointment.get_date }}
</div>
</div>
<div class="messages" style="margin: 20px 0">
{% if messages %}
{% for message in messages %}
<div class="alert alert-dismissible {% if message.tags %}alert-{% if message.level == DEFAULT_MESSAGE_LEVELS.ERROR %}danger{% else %}{{ message.tags }}{% endif %}{% endif %}"
role="alert">{{ message }}</div>
{% endfor %}
{% endif %}
<div class="col-md-6">
<div class="d-flex align-items-center">
<i class="fas fa-clock me-2 text-primary"></i>
<strong class="me-2">{% trans 'Start time' %}:</strong> {{ appointment.get_start_time|time:"g:i A" }}
</div>
</div>
<div class="col-md-6">
<div class="d-flex align-items-center">
<i class="fas fa-clock me-2 text-primary"></i>
<strong class="me-2">{% trans 'End time' %}:</strong> {{ appointment.get_end_time|time:"g:i A" }}
</div>
</div>
<div class="col-md-6">
<div class="d-flex align-items-center">
<i class="fas fa-hands-helping me-2 text-primary"></i>
<strong class="me-2">{% trans 'Service' %}:</strong> {{ appointment.get_service_name }}
</div>
</div>
<div class="col-md-6">
<div class="d-flex align-items-center">
<i class="fas fa-user me-2 text-primary"></i>
<strong class="me-2">{% trans 'Client' %}:</strong> {{ appointment.get_client_name }}
</div>
</div>
<div class="col-md-6">
<div class="d-flex align-items-center">
<i class="fas fa-envelope me-2 text-primary"></i>
<strong class="me-2">{% trans 'Email' %}:</strong> {{ appointment.client.email }}
</div>
</div>
<div class="col-md-6">
<div class="d-flex align-items-center">
<i class="fas fa-phone me-2 text-primary"></i>
<strong class="me-2">{% trans 'Phone' %}:</strong> {{ appointment.phone }}
</div>
</div>
<div class="col-md-6">
<div class="d-flex align-items-center">
<i class="fas fa-comment me-2 text-primary"></i>
<strong class="me-2">{% trans 'Wants reminder' %}:</strong> {{ appointment.want_reminder }}
</div>
</div>
<div class="col-md-6">
<div class="d-flex align-items-center">
<i class="fas fa-map-marker-alt me-2 text-primary"></i>
<strong class="me-2">{% trans 'Client address' %}:</strong> {{ appointment.address }}
</div>
</div>
<div class="col-md-6">
<div class="d-flex align-items-center">
<i class="fas fa-info-circle me-2 text-primary"></i>
<strong class="me-2">{% trans 'Additional Information' %}:</strong> {{ appointment.additional_info }}
</div>
</div>
<div class="col-md-6">
<div class="d-flex align-items-center">
<i class="fas fa-money-bill-wave me-2 text-primary"></i>
<strong class="me-2">{% trans 'Is paid' %}:</strong> {{ appointment.is_paid_text }}
</div>
</div>
<div class="col-md-6">
<div class="d-flex align-items-center">
<i class="fas fa-dollar-sign me-2 text-primary"></i>
<strong class="me-2">{% trans 'Service price' %}:</strong> {{ appointment.get_appointment_amount_to_pay_text }}
</div>
</div>
</div>
</div>
</section>
</div>
</div>
{% endblock %}
{% block customJS %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.js"
integrity="sha512-3CuraBvy05nIgcoXjVN33mACRyI89ydVHg7y/HMN9wcTVbHeur0SeBzweSd/rxySapO7Tmfu68+JlKkLTnDFNg=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"
integrity="sha512-t/mY3un180WRfsSkWy4Yi0tAxEDGcY2rAEx873hb5BrkvLA0QLk54+SjfYgFBBoCdJDV1H86M8uyZdJhAOHeyA=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/6.1.10/index.global.min.js"
integrity="sha512-JCQkxdym6GmQ+AFVioDUq8dWaWN6tbKRhRyHvYZPupQ6DxpXzkW106FXS1ORgo/m3gxtt5lHRMqSdm2OfPajtg=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
{% block extra_js %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/6.1.10/index.global.min.js" crossorigin="anonymous"></script>
{% endblock %}

View File

@ -35,9 +35,9 @@
</div>
</section>
<div id="customContextMenu" style="display: none; position: absolute; z-index: 1000;">
<ul>
<li id="newAppointmentOption"><a href="#">{{ _("New Appointment")}}</a></li>
</ul>
<a id="newAppointmentOption" class="btn btn-sm btn-phoenix-success rounded-pill me-1 mb-1" href="#">{{ _("New Appointment")}}</a>
</div>
{% include 'modal/confirm_modal.html' %}
@ -103,7 +103,7 @@
if (isUserSuperUser) {
superuserInputField = `
<div class="flex-container-appt">
<label>{% trans 'Staff Member' %}:</label>
<label class="form-label">{% trans 'Staff Member' %}:</label>
${staffDropdown.outerHTML}
</div>
`;
@ -112,27 +112,27 @@
return `
${superuserInputField}
<div class="flex-container-appt">
<label>{% trans 'Service Name' %}:</label>
<label class="form-label">{% trans 'Service Name' %}:</label>
${servicesDropdown.outerHTML}
</div>
<label for="clientName">{% trans 'Client Name' %}:</label>
<input type="text" name="clientName" value="${appointment.client_name || ''}" ${disabledAttribute} id="clientName" placeholder="John Doe">
<label for="clientEmail">{% trans 'Client Email' %}:</label>
<input type="email" name="clientEmail" value="${appointment.client_email || ''}" ${disabledAttribute} id="clientEmail" placeholder="john.doe@example.com">
<label class="form-label" for="clientName">{% trans 'Client Name' %}:</label>
<input type="text" name="clientName" class="form-control form-control-sm" value="${appointment.client_name || ''}" ${disabledAttribute} id="clientName" placeholder="">
<label class="form-label" for="clientEmail">{% trans 'Client Email' %}:</label>
<input type="email" name="clientEmail" class="form-control form-control-sm" value="${appointment.client_email || ''}" ${disabledAttribute} id="clientEmail" placeholder="">
<span id="emailError" style="display:none;"></span>
<label for="clientPhone">{% trans 'Phone Number' %}:</label>
<input type="tel" name="clientPhone" value="${appointment.client_phone || ''}" ${disabledAttribute} id="clientPhone" placeholder="+12392350799">
<label for="clientAddress">{% trans 'Client address' %}:</label>
<input type="text" name="clientAddress" value="${appointment.client_address || ''}" ${disabledAttribute} id="clientAddress" placeholder="Naples, Florida">
<label class="form-label" for="clientPhone">{% trans 'Phone Number' %}:</label>
<input type="tel" name="clientPhone" class="form-control form-control-sm" value="${appointment.client_phone || ''}" ${disabledAttribute} id="clientPhone" placeholder="+9665********">
<label class="form-label" for="clientAddress">{% trans 'Client address' %}:</label>
<input type="text" name="clientAddress" class="form-control form-control-sm" value="${appointment.client_address || ''}" ${disabledAttribute} id="clientAddress" placeholder="">
<div class="flex-container-appt">
<label for="want_reminder">{% trans 'Wants reminder' %}:</label>
<input type="checkbox" name="want_reminder" id="want_reminder" value="true" ${appointment.want_reminder ? 'checked' : ''} ${disabledAttribute}>
<label class="form-check-label" for="want_reminder">{% trans 'Wants reminder' %}:</label>
<input class="form-check-input" type="checkbox" name="want_reminder" id="want_reminder" value="true" ${appointment.want_reminder ? 'checked' : ''} ${disabledAttribute}>
</div>
<label for="additional_info">{% trans 'Additional Information' %}:</label>
<input type="text" name="additional_info" value="${appointment.additional_info || ''}" ${disabledAttribute} placeholder="{% trans 'Client wants this and that' %}" id="additional_info">
<label class="form-label" for="additional_info">{% trans 'Additional Information' %}:</label>
<input class="form-control form-control-sm" type="text" name="additional_info" value="${appointment.additional_info || ''}" ${disabledAttribute} placeholder="{% trans 'Client wants this and that' %}" id="additional_info">
<div class="flex-container-appt">
<label for="startTime">{% trans 'Start time' %}:</label>
<input type="time" name="startTime" value="${startTimeValue}" ${disabledAttribute}>
<label class="form-label" for="startTime">{% trans 'Start time' %}:</label>
<input class="form-control form-control-sm" type="time" name="startTime" value="${startTimeValue}" ${disabledAttribute}>
</div>
`;
}
@ -143,8 +143,8 @@
return `
${commonInputs}
<div class="flex-container-appt">
<label for="endTime">{% trans 'End time' %}:</label>
<input type="time" name="endTime" value="${moment(appointment.end_time).format('HH:mm:ss')}" ${!isEditMode ? 'disabled' : ''}>
<label class="form-label" for="endTime">{% trans 'End time' %}:</label>
<input class="form-control form-control-sm" type="time" name="endTime" value="${moment(appointment.end_time).format('HH:mm:ss')}" ${!isEditMode ? 'disabled' : ''}>
</div>
`;
}
@ -156,7 +156,7 @@
return `
${commonInputs}
<label for="date" style="display: none"></label>
<input type="hidden" name="date" value="${formattedDate}">
<input type="hidden" name="date" value="${formattedDate}" class="datepicker">
`;
}
</script>

View File

@ -34,7 +34,7 @@
<!-- Appointment Information Section -->
<div class="row mt-4">
<div class="col-6">
<h3>{% trans 'Appointment Information' %}</h3>
<h3>{% trans 'Appointments Information' %}</h3>
<small>
{{ service_msg }}
</small>

View File

@ -0,0 +1,22 @@
<!-- crm/employee_calendar.html -->
<h1>Upcoming Test Drives</h1>
<table>
<thead>
<tr>
<th>Customer</th>
<th>Vehicle</th>
<th>Date/Time</th>
<th>Staff</th>
</tr>
</thead>
<tbody>
{% for appointment in appointments %}
<tr>
<td>{{ appointment.client.name }}</td>
<td>{{ appointment.service.name }}</td>
<td>{{ appointment.start_time|date:"M j, Y H:i" }}</td>
<td>{{ appointment.staff.user.get_full_name }}</td>
</tr>
{% endfor %}
</tbody>
</table>

View File

@ -199,24 +199,7 @@
</thead>
<tbody class="list" id="lead-details-table-body">
{% for note in notes %}
<div class="modal fade" id="deleteModal" data-bs-keyboard="false" tabindex="-1" aria-labelledby="deleteModalModal" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
<h4 class="mb-0 me-2 text-danger">{{ _("Delete")}}<i class="fas fa-exclamation-circle text-danger ms-2"></i></h4>
<button class="btn p-0 text-body-quaternary fs-6" data-bs-dismiss="modal" aria-label="Close"><span class="fas fa-times"></span></button>
</div>
<div class="modal-body p-4">
<p>{{ _("Are you sure you want to delete this note?") }}</p>
</div>
<div class="modal-footer flex justify-content-center border-top-0">
<a class="btn btn-sm btn-danger w-100" href="{% url 'delete_note' note.pk %}">
{{ _("Delete") }}
</a>
</div>
</div>
</div>
</div>
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="align-middle text-start fw-bold text-body-tertiary ps-1">{{note.note}}</td>
{% if note.created_by.staff %}
@ -230,9 +213,13 @@
<a id="updateBtn" href="#" class="btn btn-sm btn-phoenix-primary me-2" data-url="{% url 'update_note' note.pk %}" data-bs-toggle="modal" data-bs-target="#noteModal" data-note-title="{{ _("Update") }}<i class='fas fa-pen-square text-primary ms-2'></i>">
<i class="fas fa-pen"></i>
</a>
<button class="btn btn-sm btn-phoenix-danger text-danger" type="button" data-bs-toggle="modal" data-bs-target="#deleteModal">
<i class="fa fa-trash"></i>
</button>
<button class="btn btn-phoenix-danger btn-sm delete-btn"
data-url="{% url 'delete_note' note.pk %}"
data-message="Are you sure you want to delete this note?"
data-bs-toggle="modal" data-bs-target="#deleteModal">
<i class="fas fa-trash"></i>
</button>
{% endif %}
</td>
</tr>
@ -587,6 +574,7 @@
</div>
</div>
</div>
{% include 'modal/delete_modal.html' %}
<!-- add update Modal -->
<div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
@ -622,7 +610,7 @@ document.addEventListener("DOMContentLoaded", function () {
modalTitle.innerHTML = title;
})
.catch((error) => {
modalBody.innerHTML = '<p class="text-danger">Error loading form. Please try again later.</p>';
modalBody.innerHTML = '<p class="text-danger">{% trans 'Error loading form. Please try again later' %}.</p>';
console.error("Error loading form:", error);
});
});

View File

@ -9,7 +9,7 @@
<div class="col-auto">
<div class="d-md-flex justify-content-between">
<div>
<a href="{% url 'lead_create' %}" class="btn btn-phoenix-primary"><span class="fas fa-plus me-2"></span>{{ _("Add Lead") }}</a>
<a href="{% url 'lead_create' %}" class="btn btn-sm btn-phoenix-primary"><span class="fas fa-plus me-2"></span>{{ _("Add Lead") }}</a>
</div>
</div>
</div>
@ -91,24 +91,19 @@
<div class="modal fade" id="deleteModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deleteModalLabel">
{% trans "Delete Lead" %}
<span data-feather="alert-circle"></span>
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
<h4 class="mb-0 me-2 text-danger">{{ _("Delete")}}<i class="fas fa-exclamation-circle text-danger ms-2"></i></h4>
<button class="btn p-0 text-body-quaternary fs-6" data-bs-dismiss="modal" aria-label="Close"><span class="fas fa-times"></span></button>
</div>
<div class="modal-body p-4">
<p>{% trans "Are you sure you want to delete this lead?" %}</p>
</div>
<div class="modal-body text-center">
<p class="mb-0 text-danger fw-bold">
{% trans "Are you sure you want to delete this lead?" %}
</p>
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">
{% trans "No" %}
</button>
<a type="button" class="btn btn-danger btn-sm" href="{% url 'lead_delete' lead.pk %}">
<div class="modal-footer flex justify-content-center border-top-0">
<a type="button" class="btn btn-sm btn-danger w-100" href="{% url 'lead_delete' lead.pk %}">
{% trans "Yes" %}
</a>
</div>
</div>
</div>
</div>

View File

@ -69,37 +69,7 @@
{% for customer in customers %}
<!-- Delete Modal -->
<div class="modal fade" id="deleteModal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="deleteModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deleteModalLabel">
{% trans "Delete Customer" %}
<span data-feather="alert-circle"></span>
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-center">
<p class="mb-0 text-danger fw-bold">
{% trans "Are you sure you want to delete this customer?" %}
</p>
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">
{% trans "No" %}
</button>
{% comment %} <a type="button" class="btn btn-danger btn-sm" href="{% url 'customer_delete' customer.id %}">
{% trans "Yes" %}
</a> {% endcomment %}
</div>
</div>
</div>
</div>
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td>
@ -119,13 +89,15 @@
{{ customer.address_1 }}</td>
<td class="date align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 text-body-tertiary">{{ customer.created|date }}</td>
<td class="align-middle white-space-nowrap text-end pe-0 ps-4">
<div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a href="{% url 'customer_update' customer.pk %}" class="dropdown-item text-success-dark">{% trans "Edit" %}</a>
<div class="dropdown-divider"></div><button class="dropdown-item text-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">{% trans "Delete" %}</button>
</div>
</div>
<a href="#" class="btn btn-sm btn-phoenix-primary me-2" data-url="{% url 'customer_update' customer.pk %}">
<i class="fas fa-pen"></i>
</a>
<button class="btn btn-phoenix-danger btn-sm delete-btn"
data-url="{% url 'customer_delete' customer.pk %}"
data-message="Are you sure you want to delete this customer?"
data-bs-toggle="modal" data-bs-target="#deleteModal">
<i class="fas fa-trash"></i>
</button>
</td>
</tr>
{% endfor %}
@ -134,12 +106,13 @@
</table>
</div>
<div class="row align-items-center justify-content-end py-4 pe-0 fs-9">
<!-- Optional: Pagination -->
{% if is_paginated %}
{% include 'partials/pagination.html' %}
{% endif %}
</div>
</div>
{% include 'modal/delete_modal.html' %}
{% endblock %}

View File

@ -413,7 +413,11 @@
<span class="fa fa-user text-body-tertiary" style="width: 32px;"></span>
{% endif %}
</div>
{% if user.dealer %}
<h6 class="mt-2 text-body-emphasis">{{ user.dealer.get_local_name }}</h6>
{% else %}
<h6 class="mt-2 text-body-emphasis">{{ user.staff.get_local_name }}</h6>
{% endif %}
</div>
</div>
<div class="overflow-auto scrollbar" style="height: 10rem;">

View File

@ -0,0 +1,48 @@
{% load i18n %}
<div class="modal fade" id="deleteModal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="deleteModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
<h4 class="mb-0 me-2 text-danger">
{{ _("Delete") }}
<i class="fas fa-exclamation-circle text-danger ms-2"></i>
</h4>
<button class="btn p-0 text-body-quaternary fs-6" data-bs-dismiss="modal" aria-label="Close">
<span class="fas fa-times"></span>
</button>
</div>
<div class="modal-body p-4">
<p id="deleteModalText">
</p>
</div>
<div class="modal-footer flex justify-content-center border-top-0">
<a id="deleteModalConfirm" type="button" class="btn btn-sm btn-danger w-100" href="">
{{ _("Delete") }}
</a>
</div>
</div>
</div>
</div>
<script>
document.addEventListener("DOMContentLoaded", function () {
const deleteModal = document.getElementById("deleteModal");
const confirmDeleteBtn = document.getElementById("deleteModalConfirm");
const deleteModalMessage = document.getElementById("deleteModalText");
document.querySelectorAll(".delete-btn").forEach(button => {
button.addEventListener("click", function () {
let deleteUrl = this.getAttribute("data-url");
let deleteMessage = this.getAttribute("data-message");
confirmDeleteBtn.setAttribute("href", deleteUrl);
deleteModalMessage.innerHTML = deleteMessage;
});
});
});
</script>

View File

@ -4,33 +4,35 @@
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="eventModalLabel">{% trans 'Event Details' %}</h5>
<button type="button" class="btn-close" data-dismiss="modal" aria-label="Close"
onclick="closeModal()"></button>
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
<h4 class="modal-title" id="eventModalLabel">{% trans 'Appointment Details' %}</h4>
<button class="btn p-0 text-body-quaternary fs-6" data-bs-dismiss="modal" aria-label="Close" onclick="closeModal()">
<span class="fas fa-times"></span>
</button>
</div>
<div class="modal-body" id="eventModalBody">
<!-- Event details will be populated here -->
</div>
<div class="modal-footer">
<button type="button" class="btn btn-phoenix-success" id="eventGoBtn"
<div class="btn-group btn-group-sm mt-2 gap-1" role="group">
<button type="button" class="btn btn-sm btn-phoenix-success" id="eventGoBtn"
onclick="goToEvent()">{% trans 'Go' %}</button>
<button type="button" class="btn btn-phoenix-secondary" data-dismiss="modal"
<button type="button" class="btn btn-sm btn-phoenix-secondary" data-dismiss="modal"
onclick="closeModal()">{% trans 'Close' %}
</button>
<button type="button" class="btn btn-phoenix-secondary" id="eventCancelBtn" style="display: none;"
<button type="button" class="btn btn-sm btn-phoenix-secondary" id="eventCancelBtn" style="display: none;"
onclick="cancelEdit()">{% trans 'Cancel' %}
</button>
<button type="button" class="btn btn-phoenix-primary" id="eventEditBtn"
<button type="button" class="btn btn-sm btn-phoenix-primary" id="eventEditBtn"
onclick="toggleEditMode()">{% trans 'Edit' %}</button>
<button type="button" class="btn btn-primary" id="eventSubmitBtn" style="display: none;"
<button type="button" class="btn btn-sm btn-primary" id="eventSubmitBtn" style="display: none;"
onclick="submitChanges()">{% trans 'Submit' %}
</button>
<button type="button" class="btn btn-phoenix-danger" id="eventDeleteBtn"
onclick="deleteAppointment()" style="display: none;">
{% trans 'Delete' %}
</button>
</div>
</div>
</div>

View File

@ -229,7 +229,7 @@
<td class="align-middle">{{item.model}}</td>
<td class="align-middle">{{item.year}}</td>
<td class="align-middle">{{item.vin}}</td>
<td class="align-middle">{{item.quantity}}</td>
<td class="align-middle">{{item.quantity|floatformat:-1}}</td>
<td class="align-middle ps-5">{{item.total}}</td>
<td class="align-middle text-body-tertiary fw-semibold">{{item.total}}</td>
</tr>

View File

@ -1,280 +1,193 @@
{% load i18n static custom_filters%}
{% load i18n static custom_filters num2words_tags%}
<!DOCTYPE html>
<html lang="en">
<html lang="ar">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>invoice</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<title>Invoice</title>
<!-- CSS -->
<link href="{% static 'css/theme.min.css' %}" type="text/css" rel="stylesheet" id="style-default">
<link href="{% static 'css/user.min.css' %}" type="text/css" rel="stylesheet" id="user-style-default">
<!-- Google Fonts - Roboto -->
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
<!-- Custom CSS -->
<style>
body {
background-color: #f8f9fa;
font-family: 'Roboto', sans-serif;
margin: 0; /* Reset body margin */
padding: 0; /* Reset body padding */
margin: 0;
padding: 0;
background-color: #f8f9fa;
}
.invoice-row {
background: #fff;
border-radius: 12px;
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1);
padding: 3rem;
margin: 3rem auto;
max-width: 1000px;
.invoice-container {
width: 210mm;
min-height: 297mm;
padding: 10mm;
margin: auto;
background: white;
border-radius: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
}
.invoice-header {
border-bottom: 2px solid #dee2e6;
padding-bottom: 1.5rem;
margin-bottom: 2.5rem;
text-align: center;
border-bottom: 2px solid #dee2e6;
padding-bottom: 10px;
margin-bottom: 20px;
}
.invoice-header h1 {
font-size: 2.5rem;
font-weight: 700;
color: #333;
margin-bottom: 0.5rem;
.qr-code {
text-align: center;
margin-top: 10px;
}
.invoice-header p {
font-size: 1.1rem;
color: #666;
font-weight: 400;
.qr-code img {
width: 3cm;
height: 3cm;
}
.invoice-details {
margin-bottom: 2.5rem;
}
.invoice-details-en {
text-align: left;
}
.invoice-details-ar {
text-align: right;
}
.invoice-details p {
margin: 0.75rem 0;
color: #555;
font-size: 1rem;
font-weight: 400;
}
.invoice-table {
margin-bottom: 2.5rem;
.invoice-details, .invoice-table {
font-size: 12px;
}
.invoice-table th {
background-color: #f8f9fa;
font-weight: 500;
color: #333;
}
.invoice-table td {
color: #555;
font-weight: 400;
}
.additional-charges {
margin-top: 2rem;
margin-bottom: 1.5rem;
}
.additional-charges p {
margin: 0.5rem 0;
color: #555;
font-size: 1rem;
font-weight: 400;
font-weight: 600;
}
.invoice-total {
text-align: right;
font-size: 1.5rem;
font-weight: 500;
color: #333;
margin-top: 1rem;
font-size: 14px;
font-weight: 600;
margin-top: 10px;
}
.footer-note {
text-align: center;
color: #777;
margin-top: 3rem;
font-size: 1rem;
font-weight: 400;
}
.logo {
max-width: 150px;
margin-bottom: 1.5rem;
}
.highlight {
color: #007bff;
font-weight: 500;
}
.btn-primary {
background-color: #007bff;
border-color: #007bff;
font-weight: 500;
padding: 0.75rem 1.5rem;
font-size: 1rem;
}
.btn-primary:hover {
background-color: #0056b3;
border-color: #0056b3;
}
.button-row {
text-align: right;
margin-top: 2rem;
margin-right:10rem;
}
position: absolute;
bottom: 35mm;
font-size: 10px;
margin-top: auto;
margin-right: auto;
width: 28%;
}
</style>
</head>
<body>
<div class="button-row">
<button id="download-pdf" class="btn btn-primary">Download Invoice</button>
</div>
<div class="invoice-row" id="invoice-content">
<!-- Header -->
<div class="invoice-container" id="invoice-content">
<div class="invoice-header">
<h3 style="margin-top: 10px;">Invoice / فاتورة</h3>
<p></p>
<h5>Tax Invoice / فاتورة ضريبية</h5>
</div>
<!-- Details -->
<div class="details-row">
<div class="col-12">
<table class="table table-responsive">
<tr>
<td class="col-3 text-start p-2">
<strong>Invoice Number</strong>
</td>
<td class="col-6 text-center p-2">
<span class="highlight">{{invoice.invoice_number}}</span>
</td>
<td class="col-3 text-end p-2">
<strong>رقم الفاتورة</strong>
</td>
</tr>
<tr>
<td class="col-3 text-start p-2">
<strong>Date</strong>
</td>
<td class="col-6 text-center p-2">
<span class="highlight">{{invoice.date_in_review}}</span>
</td>
<td class="col-3 text-end p-2">
<strong>التاريخ</strong>
</td>
</tr>
<tr>
<td class="col-3 text-start p-2">
<strong>Customer</strong>
</td>
<td class="col-6 text-center p-2">
<span class="highlight">{{invoice.customer.customer_name}}</span>
</td>
<td class="col-3 text-end p-2">
<strong>العميل</strong>
</td>
</tr>
<tr>
<td class="col-3 text-start p-2">
<strong>Email</strong>
</td>
<td class="col-6 text-center p-2">
<span class="highlight">{{invoice.customer.email}}</span>
</td>
<td class="col-3 text-end p-2">
<strong>البريد الالكتروني</strong>
</td>
</tr>
<tr>
<td class="col-3 text-start p-2">
<strong>Terms</strong>
</td>
<td class="col-6 text-center p-2">
<span class="highlight">{{invoice.get_terms_display}}</span>
</td>
<td class="col-3 text-end p-2">
<strong>طريقة الدفع</strong>
</td>
</tr>
<div class="qr-code">
<img src="{% static 'qr_code/Marwan_qr.png' %}" alt="QR Code">
</div>
<div class="invoice-details">
<table class="table table-sm table-responsive ">
<tr><td></td><td class="text-end"></td><td class="text-end"><img class="rounded-soft" src="{{ dealer.logo.url }}" alt="" style="height: 2cm; width: 2cm; border-radius: 0.3333333333rem;"/></td></tr>
<tr><td><strong>{{ dealer.name }}</strong></td><td></td><td class="text-end"><strong>{{ dealer.arabic_name }}</strong></td></tr>
<tr><td><strong>Address</strong></td><td>{{ dealer.address }}</td><td class="text-end"><strong>العنوان</strong></td></tr>
<tr><td><strong>Phone</strong></td><td>{{ dealer.phone_number }}</td><td class="text-end"><strong>جوال</strong></td></tr>
<tr><td><strong>VAT Number</strong></td><td>{{ dealer.vrn }}</td><td class="text-end"><strong>الرقم الضريبي</strong></td></tr>
</table>
</div>
<div class="invoice-details">
<table class="table table-sm table-bordered">
<tr><td class="ps-1"><strong>Invoice Number</strong></td><td class="text-center">{{ invoice.invoice_number }}</td><td class="text-end p-1"><strong>رقم الفاتورة</strong></td></tr>
<tr><td class="ps-1"><strong>Date</strong></td><td class="text-center">{{ invoice.date_in_review }}</td><td class="text-end p-1"><strong>التاريخ</strong></td></tr>
<tr><td class="ps-1"><strong>Customer</strong></td><td class="text-center">{{ invoice.customer.customer_name }}</td><td class="text-end p-1"><strong>العميل</strong></td></tr>
<tr><td class="ps-1"><strong>VAT Number</strong></td><td class="text-center"></td><td class="text-end p-1"><strong>الرقم الضريبي</strong></td></tr>
<tr><td class="ps-1"><strong>Email</strong></td><td class="text-center">{{ invoice.customer.email }}</td><td class="text-end p-1"><strong>البريد الالكتروني</strong></td></tr>
<tr><td class="ps-1"><strong>Terms</strong></td><td class="text-center">{{ invoice.get_terms_display }}</td><td class="text-end p-1"><strong>طريقة الدفع</strong></td></tr>
</table>
</div>
</div>
<!-- Items Table -->
<div class="invoice-table mt-3">
<table class="table table-bordered">
<div class="invoice-table">
<table class="table table-sm table-bordered">
<thead>
<tr>
<th><small class="fs-10">Make</small><br><small class="fs-10">الصنف</small></th>
<th><small class="fs-10">Model</small><br><small class="fs-10">الموديل</small></th>
<th><small class="fs-10">Year</small><br><small class="fs-10">السنة</small></th>
<th><small class="fs-10">VIN</small><br><small class="fs-10">رقم الهيكل</small></th>
<th><small class="fs-10">Quantity</small><br><small class="fs-10">العدد</small></th>
<th><small class="fs-10">Unit Price</small><br><small class="fs-10">سعر الوحدة</small></th>
<th><small class="fs-10">Total</small><br><small class="fs-10">الإجمالي</small></th>
</tr>
<th class="text-wrap text-center">Make / الصانع</th>
<th class="text-wrap text-center">Model / الموديل</th>
<th class="text-wrap text-center">Year / السنة</th>
<th class="text-wrap text-center">VIN / الهيكل</th>
<th class="text-wrap text-center">Quantity / الكمية</th>
<th class="text-wrap text-center">Unit Price / سعر الوحدة</th>
<th class="text-wrap text-center">VAT / الضريبة</th>
<th class="text-wrap text-center">Total / الإجمالي</th></tr>
</thead>
<tbody>
{% for item in data.cars %}
<tr>
<td class="">{{item.make}}</td>
<td class="">{{item.model}}</td>
<td class="">{{item.year}}</td>
<td class="">{{item.vin}}</td>
<td class="align-middle">{{item.quantity}}</td>
<td class="align-middle ps-5">{{item.selling_price}}</td>
<td class="align-middle text-body-tertiary fw-semibold">{{item.total}}</td>
<td class="ps-1">{{ item.make }}</td>
<td class="ps-1">{{ item.model }}</td>
<td class="text-center">{{ item.year }}</td>
<td class="ps-1">{{ item.vin }}</td>
<td class="text-center">{{ item.quantity|floatformat:-1 }}</td>
<td class="text-center">{{ item.selling_price }}</td>
<td class="text-center">{{ item.vat_amount }}</td>
<td class="text-center">{{ item.total }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="invoice-note">Additional Services \ الخدمات الإضافية</div>
<div class="invoice-table">
<table class="table table-sm table-bordered">
<thead>
<tr>
<th class="text-wrap text-center">Type / النوع</th>
<th class="text-wrap text-center">Quantity / الكمية</th>
<th class="text-wrap text-center">Unit Price / سعر الوحدة</th>
<th class="text-wrap text-center">VAT / الضريبة</th>
<th class="text-wrap text-center">Total / الإجمالي</th></tr>
</thead>
<tbody>
{% for item in data.cars %}
<tr>
<td class="ps-1">{{ item }}</td>
<td class="text-center">{{ item.quantity|floatformat:-1 }}</td>
<td class="text-center">{{ item.selling_price }}</td>
<td class="text-center">{{ item.vat_amount }}</td>
<td class="text-center">{{ item.total }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="d-flex justify-content-end">
<div class="table-responsive">
<table class="table table-sm table-responsive ">
<tr>
<td class="text-start ps-1"><strong class="fs-9">VAT</strong></td>
<td class="text-center"><span class="fs-9">{{ data.total_vat_amount }} {{ CURRENCY }}</span></td>
<td class="text-end"><strong class="fs-9">ضريبة القيمة المضافة</strong></td>
</tr>
<tr>
<td class="text-start ps-1"><strong class="fs-9">Total</strong></td>
<td class="text-center"><span class="fs-9">{{ data.grand_total }} {{ CURRENCY }}</span></td>
<td class="text-end"><strong class="fs-9">الإجمالي</strong></td>
</tr>
<tr>
<!-- Additional Charges (VAT and Services) -->
<div class="additional-charges">
<td class="text-end" colspan="3"><span class="fs-9 fw-bold">كتابةً: </span><span class="fs-9">{{ data.grand_total|num_to_words }} {{ CURRENCY }}</span></td>
<p><strong>VAT/ضريبة القيمة المضافة ({{vat}}%):</strong> <span class="highlight">{{data.vat|percentage}}&nbsp;{{ _("SAR") }}</span></p>
<p><strong>Additional Services/ الخدمات الإضافية</strong>
<br>
{% for service in data.additional_services %}
<span class="highlight">{{service.name}} - {{service.price}}&nbsp;{{ _("SAR") }}</span><br>
{% endfor %}
</p>
</tr>
</table>
</div>
</div>
<!-- Total -->
<div class="invoice-total">
<p><strong>Total/الإجمالي</strong> <span class="highlight">{{data.grand_total}}&nbsp;{{ _("SAR") }}</span></p>
<div class="footer-note d-flex justify-content-between align-items-end">
<div class="logo-img text-center">
<img src="{% static 'images/logos/logo-d-pdf.png' %}" style="width: 10mm; height: 10mm;"/>
<p class="fs-11 fw-bold">Haikal | هيكل</p>
</div>
<p class="fs-11">Powered by <a class="text-decoration-none" href="https://tenhal.sa" style="color: #112e40;">TENHAL | تنحل</a></p>
</div>
<!-- Footer Note -->
<div class="footer-note">
<p><small class="text-end">تواصل معنا <a href="mailto:haikal@tenhal.sa">haikal@tenhal.sa</a>.</small>
<small class="text-start">Contact US <a href="mailto:haikal@tenhal.sa">haikal@tenhal.sa</a>.</small></p>
<p>Made by TENHAL.SA</p>
</div>
<!-- Button row -->
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
<script src="{% static 'vendors/bootstrap/bootstrap.min.js' %}"></script>
<script src="{% static 'js/html2pdf.bundle.min.js' %}"></script>
<script>
document.getElementById('download-pdf').addEventListener('click', function () {
const element = document.getElementById('invoice-content');
const options = {
html2pdf().from(document.getElementById('invoice-content')).set({
margin: 0,
filename: '{{invoice.invoice_number}}.pdf',
filename: "{{ invoice.invoice_number_invoice.customer.name_invoice.date_in_review }}.pdf",
image: { type: 'jpeg', quality: 0.98 },
html2canvas: {
scale: 2,
scrollX: 0,
scrollY: 0,
useCORS: true,
},
html2canvas: { scale: 2 },
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }
};
html2pdf().from(element).set(options).save();
}).save();
});
</script>
</body>
</html>
</html>