Compare commits
7 Commits
2a8e2bd276
...
f10b9311bf
| Author | SHA1 | Date | |
|---|---|---|---|
| f10b9311bf | |||
| c39f2eb068 | |||
| 3a08268c12 | |||
| d87ed6d454 | |||
| 10d48ca47d | |||
| 536bdc4cb9 | |||
| 5099bdcb79 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -163,8 +163,11 @@ GitHub.sublime-settings
|
|||||||
.history
|
.history
|
||||||
|
|
||||||
|
|
||||||
|
static-copy
|
||||||
static
|
static
|
||||||
|
static/*
|
||||||
staticfiles
|
staticfiles
|
||||||
media
|
media
|
||||||
tmp
|
tmp
|
||||||
logs
|
logs
|
||||||
|
static/testdir
|
||||||
@ -17,31 +17,17 @@ import django
|
|||||||
|
|
||||||
django.setup()
|
django.setup()
|
||||||
|
|
||||||
|
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from channels.routing import ProtocolTypeRouter, URLRouter
|
from channels.routing import ProtocolTypeRouter, URLRouter
|
||||||
from whitenoise import WhiteNoise
|
|
||||||
from channels.auth import AuthMiddlewareStack
|
from channels.auth import AuthMiddlewareStack
|
||||||
from api import routing
|
|
||||||
from inventory.notifications.sse import NotificationSSEApp
|
from inventory.notifications.sse import NotificationSSEApp
|
||||||
from django.urls import re_path
|
from django.urls import re_path
|
||||||
from django.core.asgi import get_asgi_application
|
from django.core.asgi import get_asgi_application
|
||||||
from django.contrib.staticfiles.handlers import ASGIStaticFilesHandler
|
|
||||||
from pathlib import Path
|
|
||||||
# application = ProtocolTypeRouter(
|
|
||||||
# {
|
|
||||||
# "http": get_asgi_application(),
|
|
||||||
# # "websocket": AuthMiddlewareStack(URLRouter(routing.websocket_urlpatterns)),
|
|
||||||
# }
|
|
||||||
# )
|
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "car_inventory.settings")
|
|
||||||
django.setup()
|
|
||||||
|
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
|
||||||
|
# BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
app = get_asgi_application()
|
app = get_asgi_application()
|
||||||
|
|
||||||
# app = WhiteNoise(app, root=str(BASE_DIR / 'staticfiles'))
|
|
||||||
|
|
||||||
application = ProtocolTypeRouter(
|
application = ProtocolTypeRouter(
|
||||||
{
|
{
|
||||||
"http": AuthMiddlewareStack(
|
"http": AuthMiddlewareStack(
|
||||||
@ -50,7 +36,7 @@ application = ProtocolTypeRouter(
|
|||||||
path("sse/notifications/", NotificationSSEApp()),
|
path("sse/notifications/", NotificationSSEApp()),
|
||||||
re_path(
|
re_path(
|
||||||
r"", app
|
r"", app
|
||||||
), # All other routes go to Django
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
@ -58,5 +44,5 @@ application = ProtocolTypeRouter(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if django.conf.settings.DEBUG:
|
# if django.conf.settings.DEBUG:
|
||||||
application = ASGIStaticFilesHandler(app)
|
# application = ASGIStaticFilesHandler(app)
|
||||||
@ -5,7 +5,7 @@ from django.urls import path, include
|
|||||||
from schema_graph.views import Schema
|
from schema_graph.views import Schema
|
||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
from django.conf.urls.i18n import i18n_patterns
|
from django.conf.urls.i18n import i18n_patterns
|
||||||
from inventory.notifications.sse import NotificationSSEApp
|
# from inventory.notifications.sse import NotificationSSEApp
|
||||||
|
|
||||||
# import debug_toolbar
|
# import debug_toolbar
|
||||||
# from two_factor.urls import urlpatterns as tf_urls
|
# from two_factor.urls import urlpatterns as tf_urls
|
||||||
@ -33,5 +33,7 @@ urlpatterns += i18n_patterns(
|
|||||||
# path('', include(tf_urls)),
|
# path('', include(tf_urls)),
|
||||||
)
|
)
|
||||||
|
|
||||||
# if not settings.DEBUG:
|
if settings.DEBUG:
|
||||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
urlpatterns += static(settings.STATIC_URL, document_root = settings.STATIC_ROOT)
|
||||||
|
|
||||||
|
|||||||
@ -1,82 +1,3 @@
|
|||||||
# import json
|
|
||||||
# from django.contrib.auth.models import AnonymousUser
|
|
||||||
# from django.contrib.auth import get_user_model
|
|
||||||
# from django.db import close_old_connections
|
|
||||||
# from urllib.parse import parse_qs
|
|
||||||
# from channels.db import database_sync_to_async
|
|
||||||
# from inventory.models import Notification
|
|
||||||
# import asyncio
|
|
||||||
|
|
||||||
# @database_sync_to_async
|
|
||||||
# def get_notifications(user, last_id):
|
|
||||||
# return Notification.objects.filter(
|
|
||||||
# user=user, id__gt=last_id, is_read=False
|
|
||||||
# ).order_by("created")
|
|
||||||
|
|
||||||
# class NotificationSSEApp:
|
|
||||||
# async def __call__(self, scope, receive, send):
|
|
||||||
# if scope["type"] != "http":
|
|
||||||
# return
|
|
||||||
|
|
||||||
# query_string = parse_qs(scope["query_string"].decode())
|
|
||||||
# last_id = int(query_string.get("last_id", [0])[0])
|
|
||||||
|
|
||||||
# # Get user from scope if using AuthMiddlewareStack
|
|
||||||
# user = scope.get("user", AnonymousUser())
|
|
||||||
# if not user.is_authenticated:
|
|
||||||
# await send({
|
|
||||||
# "type": "http.response.start",
|
|
||||||
# "status": 403,
|
|
||||||
# "headers": [(b"content-type", b"text/plain")],
|
|
||||||
# })
|
|
||||||
# await send({
|
|
||||||
# "type": "http.response.body",
|
|
||||||
# "body": b"Unauthorized",
|
|
||||||
# })
|
|
||||||
# return
|
|
||||||
|
|
||||||
# await send({
|
|
||||||
# "type": "http.response.start",
|
|
||||||
# "status": 200,
|
|
||||||
# "headers": [
|
|
||||||
# (b"content-type", b"text/event-stream"),
|
|
||||||
# (b"cache-control", b"no-cache"),
|
|
||||||
# (b"x-accel-buffering", b"no"),
|
|
||||||
# ]
|
|
||||||
# })
|
|
||||||
|
|
||||||
# try:
|
|
||||||
# while True:
|
|
||||||
# close_old_connections()
|
|
||||||
|
|
||||||
# notifications = await get_notifications(user, last_id)
|
|
||||||
# for notification in notifications:
|
|
||||||
# data = {
|
|
||||||
# "id": notification.id,
|
|
||||||
# "message": notification.message,
|
|
||||||
# "created": notification.created.isoformat(),
|
|
||||||
# "is_read": notification.is_read,
|
|
||||||
# }
|
|
||||||
|
|
||||||
# event_str = (
|
|
||||||
# f"id: {notification.id}\n"
|
|
||||||
# f"event: notification\n"
|
|
||||||
# f"data: {json.dumps(data)}\n\n"
|
|
||||||
# )
|
|
||||||
|
|
||||||
# await send({
|
|
||||||
# "type": "http.response.body",
|
|
||||||
# "body": event_str.encode("utf-8"),
|
|
||||||
# "more_body": True
|
|
||||||
# })
|
|
||||||
|
|
||||||
# last_id = notification.id
|
|
||||||
|
|
||||||
# await asyncio.sleep(2)
|
|
||||||
|
|
||||||
# except asyncio.CancelledError:
|
|
||||||
# pass
|
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
from django.contrib.auth.models import AnonymousUser
|
from django.contrib.auth.models import AnonymousUser
|
||||||
|
|||||||
@ -1003,10 +1003,10 @@ def create_po_item_upload(sender, instance, created, **kwargs):
|
|||||||
if instance.po_status == "fulfilled" or instance.po_status == 'approved':
|
if instance.po_status == "fulfilled" or instance.po_status == 'approved':
|
||||||
for item in instance.get_itemtxs_data()[0]:
|
for item in instance.get_itemtxs_data()[0]:
|
||||||
dealer = models.Dealer.objects.get(entity=instance.entity)
|
dealer = models.Dealer.objects.get(entity=instance.entity)
|
||||||
if item.bill_model.is_paid():
|
if item.bill_model and item.bill_model.is_paid():
|
||||||
models.PoItemsUploaded.objects.get_or_create(
|
models.PoItemsUploaded.objects.get_or_create(
|
||||||
dealer=dealer, po=instance, item=item, status=instance.po_status
|
dealer=dealer, po=instance, item=item, status=instance.po_status
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# @receiver(post_save, sender=models.Staff)
|
# @receiver(post_save, sender=models.Staff)
|
||||||
|
|||||||
@ -342,6 +342,11 @@ urlpatterns = [
|
|||||||
views.CarDetailView.as_view(),
|
views.CarDetailView.as_view(),
|
||||||
name="car_detail",
|
name="car_detail",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"<slug:dealer_slug>/cars/<slug:slug>/estimate/",
|
||||||
|
views.create_estimate_for_car,
|
||||||
|
name="create_estimate_for_car",
|
||||||
|
),
|
||||||
path("cars/<slug:slug>/history/", views.car_history, name="car_history"),
|
path("cars/<slug:slug>/history/", views.car_history, name="car_history"),
|
||||||
path(
|
path(
|
||||||
"<slug:dealer_slug>/cars/<slug:slug>/update/",
|
"<slug:dealer_slug>/cars/<slug:slug>/update/",
|
||||||
|
|||||||
@ -1329,7 +1329,9 @@ def get_finance_data(estimate, dealer):
|
|||||||
additional_services = car.get_additional_services()
|
additional_services = car.get_additional_services()
|
||||||
discounted_price = Decimal(car.marked_price) - discount
|
discounted_price = Decimal(car.marked_price) - discount
|
||||||
vat_amount = discounted_price * vat.rate
|
vat_amount = discounted_price * vat.rate
|
||||||
|
total_services_amount=additional_services.get("total")
|
||||||
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_services_amount_=additional_services.get("total_")
|
||||||
total_vat = vat_amount + total_services_vat
|
total_vat = vat_amount + total_services_vat
|
||||||
return {
|
return {
|
||||||
"car": car,
|
"car": car,
|
||||||
@ -1340,9 +1342,16 @@ def get_finance_data(estimate, dealer):
|
|||||||
"discount_amount": discount,
|
"discount_amount": discount,
|
||||||
"additional_services": additional_services,
|
"additional_services": additional_services,
|
||||||
"final_price": discounted_price + vat_amount,
|
"final_price": discounted_price + vat_amount,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"total_services_vat": total_services_vat,
|
"total_services_vat": total_services_vat,
|
||||||
|
"total_services_amount":total_services_amount,
|
||||||
|
"total_services_amount_":total_services_amount_,
|
||||||
|
|
||||||
"total_vat": total_vat,
|
"total_vat": total_vat,
|
||||||
"grand_total": discounted_price + total_vat + additional_services.get("total"),
|
"grand_total": discounted_price + total_vat + additional_services.get("total"),
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# totals = self.calculate_totals()
|
# totals = self.calculate_totals()
|
||||||
|
|||||||
@ -4656,7 +4656,7 @@ def sales_list_view(request, dealer_slug):
|
|||||||
search_query = request.GET.get('q', None)
|
search_query = request.GET.get('q', None)
|
||||||
if search_query:
|
if search_query:
|
||||||
qs = qs.filter(
|
qs = qs.filter(
|
||||||
Q(order_number__icontains=search_query)|
|
Q(customer__phone_number__icontains=search_query)|
|
||||||
Q(customer__customer_name__icontains=search_query)
|
Q(customer__customer_name__icontains=search_query)
|
||||||
).distinct()
|
).distinct()
|
||||||
|
|
||||||
@ -5092,6 +5092,7 @@ class EstimateDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
|
|||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
||||||
estimate = kwargs.get("object")
|
estimate = kwargs.get("object")
|
||||||
|
|
||||||
if estimate.get_itemtxs_data():
|
if estimate.get_itemtxs_data():
|
||||||
# calculator = CarFinanceCalculator(estimate)
|
# calculator = CarFinanceCalculator(estimate)
|
||||||
# finance_data = calculator.get_finance_data()
|
# finance_data = calculator.get_finance_data()
|
||||||
@ -5099,6 +5100,8 @@ class EstimateDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
|
|||||||
|
|
||||||
invoice_obj = InvoiceModel.objects.all().filter(ce_model=estimate).first()
|
invoice_obj = InvoiceModel.objects.all().filter(ce_model=estimate).first()
|
||||||
kwargs["data"] = finance_data
|
kwargs["data"] = finance_data
|
||||||
|
kwargs["customer_obj"]=estimate.customer.customer_set.first()
|
||||||
|
kwargs['dealer_info']=dealer
|
||||||
|
|
||||||
kwargs["invoice"] = invoice_obj
|
kwargs["invoice"] = invoice_obj
|
||||||
try:
|
try:
|
||||||
@ -5119,7 +5122,8 @@ class EstimatePrintView(EstimateDetailView):
|
|||||||
It reuses the data-fetching logic from EstimateDetailView but
|
It reuses the data-fetching logic from EstimateDetailView but
|
||||||
uses a dedicated, stripped-down print template.
|
uses a dedicated, stripped-down print template.
|
||||||
"""
|
"""
|
||||||
template_name = "sales/estimates/estimate_preview.html"
|
|
||||||
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
|
|
||||||
@ -5130,13 +5134,16 @@ class EstimatePrintView(EstimateDetailView):
|
|||||||
# lang = request.GET.get('lang', 'ar')
|
# lang = request.GET.get('lang', 'ar')
|
||||||
|
|
||||||
|
|
||||||
template_path = "sales/estimates/estimate_preview.html"
|
if request.GET.get('lang')=='en':
|
||||||
|
template_path = "sales/estimates/estimate_preview_en.html"
|
||||||
|
else:
|
||||||
|
template_path = "sales/estimates/estimate_preview_ar.html"
|
||||||
|
|
||||||
|
|
||||||
html_string = render_to_string(template_path, context)
|
html_string = render_to_string(template_path, context)
|
||||||
|
|
||||||
|
base_url = request.build_absolute_uri('/')
|
||||||
pdf_file = HTML(string=html_string).write_pdf()
|
pdf_file = HTML(string=html_string, base_url=base_url).write_pdf()
|
||||||
|
|
||||||
|
|
||||||
response = HttpResponse(pdf_file, content_type='application/pdf')
|
response = HttpResponse(pdf_file, content_type='application/pdf')
|
||||||
@ -5522,7 +5529,7 @@ class InvoiceListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
|||||||
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
|
||||||
entity = dealer.entity
|
entity = dealer.entity
|
||||||
staff = getattr(self.request.user, "staff", None)
|
staff = getattr(self.request.user, "staff", None)
|
||||||
qs = []
|
qs=None
|
||||||
try:
|
try:
|
||||||
if any(
|
if any(
|
||||||
[
|
[
|
||||||
@ -5871,7 +5878,6 @@ class InvoicePreviewView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
|
|||||||
|
|
||||||
model = InvoiceModel
|
model = InvoiceModel
|
||||||
context_object_name = "invoice"
|
context_object_name = "invoice"
|
||||||
template_name = "sales/invoices/invoice_preview.html"
|
|
||||||
permission_required = ["django_ledger.view_invoicemodel"]
|
permission_required = ["django_ledger.view_invoicemodel"]
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
@ -5881,8 +5887,37 @@ class InvoicePreviewView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
|
|||||||
# calculator = CarFinanceCalculator(invoice)
|
# calculator = CarFinanceCalculator(invoice)
|
||||||
finance_data = get_finance_data(invoice,dealer)
|
finance_data = get_finance_data(invoice,dealer)
|
||||||
kwargs["data"] = finance_data
|
kwargs["data"] = finance_data
|
||||||
kwargs["dealer"] = dealer
|
kwargs["dealer_info"] = dealer
|
||||||
|
kwargs["customer_obj"]=invoice.customer.customer_set.first()
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
|
||||||
|
self.object = self.get_object()
|
||||||
|
context = self.get_context_data(object=self.object)
|
||||||
|
|
||||||
|
|
||||||
|
# lang = request.GET.get('lang', 'ar')
|
||||||
|
|
||||||
|
|
||||||
|
if request.GET.get('lang')=='en':
|
||||||
|
template_path = "sales/invoices/invoice_preview_en.html"
|
||||||
|
elif request.GET.get('lang')=='ar':
|
||||||
|
template_path = "sales/invoices/invoice_preview_ar.html"
|
||||||
|
else:
|
||||||
|
# just for preview not for download
|
||||||
|
return render(request,'sales/invoices/invoice_preview.html',context)
|
||||||
|
|
||||||
|
|
||||||
|
html_string = render_to_string(template_path, context)
|
||||||
|
|
||||||
|
base_url = request.build_absolute_uri('/')
|
||||||
|
pdf_file = HTML(string=html_string, base_url=base_url).write_pdf()
|
||||||
|
|
||||||
|
|
||||||
|
response = HttpResponse(pdf_file, content_type='application/pdf')
|
||||||
|
response['Content-Disposition'] = f'attachment; filename="invoice_{self.object.invoice_number}.pdf"'
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
# payments
|
# payments
|
||||||
@ -6221,10 +6256,10 @@ class LeadListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
|||||||
| Q(last_name__icontains=query)
|
| Q(last_name__icontains=query)
|
||||||
| Q(id_car_make__name__icontains=query)
|
| Q(id_car_make__name__icontains=query)
|
||||||
| Q(id_car_model__name__icontains=query)
|
| Q(id_car_model__name__icontains=query)
|
||||||
| Q(email__icontains=query)
|
|
||||||
| Q(phone_number__icontains=query)
|
| Q(phone_number__icontains=query)
|
||||||
| Q(next_action__icontains=query)
|
| Q(next_action__icontains=query)
|
||||||
| Q(staff__name__icontains=query)
|
| Q(staff__first_name__icontains=query)
|
||||||
|
| Q(staff__last_name__icontains=query)
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.request.is_dealer: # or self.request.is_manager:
|
if self.request.is_dealer: # or self.request.is_manager:
|
||||||
@ -10238,7 +10273,8 @@ def payment_callback(request, dealer_slug):
|
|||||||
# return render(request, "payment_failed.html", {"message": message})
|
# return render(request, "payment_failed.html", {"message": message})
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
async def sse_stream(request): # 👈 Mark as async!
|
async def sse_stream(request):
|
||||||
|
import asyncio
|
||||||
def event_generator():
|
def event_generator():
|
||||||
last_id = int(request.GET.get("last_id", 0))
|
last_id = int(request.GET.get("last_id", 0))
|
||||||
|
|
||||||
@ -10878,19 +10914,23 @@ def InventoryItemCreateView(request, dealer_slug):
|
|||||||
serie = request.POST.get("serie")
|
serie = request.POST.get("serie")
|
||||||
trim = request.POST.get("trim")
|
trim = request.POST.get("trim")
|
||||||
year = request.POST.get("year")
|
year = request.POST.get("year")
|
||||||
exterior = models.ExteriorColors.objects.get(
|
exterior = request.POST.get("exterior")
|
||||||
pk=request.POST.get("exterior")
|
interior = request.POST.get("interior")
|
||||||
)
|
|
||||||
interior = models.InteriorColors.objects.get(
|
|
||||||
pk=request.POST.get("interior")
|
|
||||||
)
|
|
||||||
|
|
||||||
make_name = models.CarMake.objects.get(pk=make)
|
make_name = models.CarMake.objects.get(pk=make)
|
||||||
model_name = models.CarModel.objects.get(pk=model)
|
model_name = models.CarModel.objects.get(pk=model)
|
||||||
serie_name = models.CarSerie.objects.get(pk=serie)
|
serie_name = models.CarSerie.objects.get(pk=serie)
|
||||||
trim_name = models.CarTrim.objects.get(pk=trim)
|
trim_name = models.CarTrim.objects.get(pk=trim)
|
||||||
|
exterior_name = models.ExteriorColors.objects.get(
|
||||||
|
pk=request.POST.get("exterior")
|
||||||
|
)
|
||||||
|
interior_name = models.InteriorColors.objects.get(
|
||||||
|
pk=request.POST.get("interior")
|
||||||
|
)
|
||||||
|
|
||||||
|
inventory_name = f"{make_name.name} || {model_name.name} || {serie_name.name} || {trim_name.name} || {year} || {exterior_name.name} || {interior_name.name}"
|
||||||
|
display_name = f"{make_name.name} {model_name.name} {serie_name.name} {trim_name.name} {year} {exterior_name.name}"
|
||||||
|
|
||||||
inventory_name = f"{make_name.name} || {model_name.name} || {serie_name.name} || {trim_name.name} || {year} || {exterior.name} || {interior.name}"
|
|
||||||
if (
|
if (
|
||||||
inventory := entity.get_items_inventory()
|
inventory := entity.get_items_inventory()
|
||||||
.filter(name=inventory_name)
|
.filter(name=inventory_name)
|
||||||
@ -10898,17 +10938,27 @@ def InventoryItemCreateView(request, dealer_slug):
|
|||||||
):
|
):
|
||||||
messages.error(request, _("Inventory item already exists"))
|
messages.error(request, _("Inventory item already exists"))
|
||||||
return response
|
return response
|
||||||
|
|
||||||
uom = entity.get_uom_all().filter(name="Unit").first()
|
uom = entity.get_uom_all().filter(name="Unit").first()
|
||||||
if not uom:
|
if not uom:
|
||||||
uom = entity.create_uom(name="Unit", unit_abbr="unit")
|
uom = entity.create_uom(name="Unit", unit_abbr="unit")
|
||||||
entity.create_item_inventory(
|
item = entity.create_item_inventory(
|
||||||
name=inventory_name,
|
name=display_name,
|
||||||
uom_model=uom,
|
uom_model=uom,
|
||||||
item_type=ItemModel.ITEM_TYPE_MATERIAL,
|
item_type=ItemModel.ITEM_TYPE_MATERIAL,
|
||||||
inventory_account=account,
|
inventory_account=account,
|
||||||
coa_model=coa,
|
coa_model=coa,
|
||||||
)
|
)
|
||||||
|
item.additional_info.update(
|
||||||
|
{
|
||||||
|
"make": make,
|
||||||
|
"model": model,
|
||||||
|
"serie": serie,
|
||||||
|
"trim": trim,
|
||||||
|
"year": year,
|
||||||
|
"exterior": exterior,
|
||||||
|
"interior": interior,
|
||||||
|
})
|
||||||
|
item.save()
|
||||||
messages.success(request, _("Inventory item created successfully"))
|
messages.success(request, _("Inventory item created successfully"))
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@ -11005,6 +11055,9 @@ class PurchaseOrderDetailView(LoginRequiredMixin, PermissionRequiredMixin, Detai
|
|||||||
for i in po_items_qs.values("po_total_amount", "po_item_status")
|
for i in po_items_qs.values("po_total_amount", "po_item_status")
|
||||||
if i["po_item_status"] != "cancelled"
|
if i["po_item_status"] != "cancelled"
|
||||||
)
|
)
|
||||||
|
items = [{"total": x.total_amount, "q": x.quantity} for x in po_model.get_itemtxs_data()[0].all()]
|
||||||
|
po_quantity = sum(item["q"] for item in items)
|
||||||
|
context['po_quantity']=po_quantity
|
||||||
return context
|
return context
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
@ -11035,9 +11088,8 @@ class PurchaseOrderDetailView(LoginRequiredMixin, PermissionRequiredMixin, Detai
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
base_url = request.build_absolute_uri('/')
|
||||||
# Use WeasyPrint to generate the PDF
|
pdf = HTML(string=html_string, base_url=base_url).write_pdf()
|
||||||
pdf = HTML(string=html_string).write_pdf()
|
|
||||||
|
|
||||||
response = HttpResponse(pdf, content_type="application/pdf")
|
response = HttpResponse(pdf, content_type="application/pdf")
|
||||||
response["Content-Disposition"] = f'attachment; filename="PO_{self.object.po_number}.pdf"'
|
response["Content-Disposition"] = f'attachment; filename="PO_{self.object.po_number}.pdf"'
|
||||||
@ -11223,18 +11275,14 @@ def upload_cars(request, dealer_slug, pk=None):
|
|||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
if item:
|
if item:
|
||||||
data = [x.strip() for x in item.item_model.name.split("||")]
|
# data = [x.strip() for x in item.item_model.name.split("||")]
|
||||||
make = models.CarMake.objects.filter(is_sa_import=True).get(
|
make = models.CarMake.objects.get(pk=item.addition_info.get("make"))
|
||||||
name=data[0]
|
model = models.CarModel.objects.get(pk=item.addition_info.get("model"))
|
||||||
)
|
trim = models.CarTrim.objects.get(pk=item.addition_info.get("trim"))
|
||||||
model = make.carmodel_set.get(name=data[1])
|
serie = models.CarSerie.objects.get(pk=item.addition_info.get("serie"))
|
||||||
trim = models.CarTrim.objects.filter(
|
year = item.addition_info.get("year")
|
||||||
name=data[3], id_car_serie__id_car_model=model.id_car_model
|
exterior = models.ExteriorColors.objects.get(pk=item.addition_info.get("exterior"))
|
||||||
).first()
|
interior = models.InteriorColors.objects.get(pk=item.addition_info.get("interior"))
|
||||||
serie = trim.id_car_serie
|
|
||||||
year = data[4]
|
|
||||||
exterior = models.ExteriorColors.objects.get(name=data[5])
|
|
||||||
interior = models.InteriorColors.objects.get(name=data[6])
|
|
||||||
receiving_date = timezone.now()
|
receiving_date = timezone.now()
|
||||||
vendor_model = item.bill_model.vendor
|
vendor_model = item.bill_model.vendor
|
||||||
vendor = models.Vendor.objects.get(vendor_model=vendor_model)
|
vendor = models.Vendor.objects.get(vendor_model=vendor_model)
|
||||||
|
|||||||
@ -35,7 +35,8 @@
|
|||||||
<div class="row my-5">
|
<div class="row my-5">
|
||||||
<div class="card rounded ">
|
<div class="card rounded ">
|
||||||
<div class="card-header ">
|
<div class="card-header ">
|
||||||
<p class="mb-0">{{ _("Group Details") }}</p>
|
<p class="mb-2">{{ _("Group Details") }}</p>
|
||||||
|
<a class="btn btn-phoenix-secondary " href="{% url 'group_list' request.dealer.slug %}">{% trans "Group List" %}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|||||||
@ -87,9 +87,13 @@
|
|||||||
didOpen: (toast) => {
|
didOpen: (toast) => {
|
||||||
toast.onmouseenter = Swal.stopTimer;
|
toast.onmouseenter = Swal.stopTimer;
|
||||||
toast.onmouseleave = Swal.resumeTimer;
|
toast.onmouseleave = Swal.resumeTimer;
|
||||||
} });
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
{% with last_notif=notifications_|last %}
|
||||||
|
let lastNotificationId = {{ last_notif.id|default:0 }};
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
let lastNotificationId = {{ notifications_.last.id|default:0 }};
|
|
||||||
let seenNotificationIds = new Set();
|
let seenNotificationIds = new Set();
|
||||||
let counter = document.getElementById('notification-counter');
|
let counter = document.getElementById('notification-counter');
|
||||||
let notificationsContainer = document.getElementById('notifications-container');
|
let notificationsContainer = document.getElementById('notifications-container');
|
||||||
@ -100,7 +104,6 @@
|
|||||||
let initialUnreadCount = {{ notifications_.count|default:0 }};
|
let initialUnreadCount = {{ notifications_.count|default:0 }};
|
||||||
updateCounter(initialUnreadCount);
|
updateCounter(initialUnreadCount);
|
||||||
|
|
||||||
|
|
||||||
fetchInitialNotifications();
|
fetchInitialNotifications();
|
||||||
|
|
||||||
function fetchInitialNotifications() {
|
function fetchInitialNotifications() {
|
||||||
@ -108,29 +111,22 @@
|
|||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.notifications && data.notifications.length > 0) {
|
if (data.notifications && data.notifications.length > 0) {
|
||||||
|
|
||||||
lastNotificationId = data.notifications[0].id;
|
lastNotificationId = data.notifications[0].id;
|
||||||
|
|
||||||
seenNotificationIds = new Set();
|
seenNotificationIds = new Set();
|
||||||
|
|
||||||
let unreadCount = 0;
|
let unreadCount = 0;
|
||||||
|
|
||||||
data.notifications.forEach(notification => {
|
data.notifications.forEach(notification => {
|
||||||
seenNotificationIds.add(notification.id);
|
seenNotificationIds.add(notification.id);
|
||||||
if (!notification.is_read) {
|
if (!notification.is_read) unreadCount++;
|
||||||
unreadCount++;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
renderNotifications(data.notifications);
|
renderNotifications(data.notifications);
|
||||||
|
|
||||||
updateCounter(unreadCount);
|
updateCounter(unreadCount);
|
||||||
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
connectSSE();
|
|
||||||
}, 5000);
|
|
||||||
}
|
}
|
||||||
|
// Always connect SSE after initial load
|
||||||
|
setTimeout(() => {
|
||||||
|
connectSSE();
|
||||||
|
}, 1000);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Error fetching initial notifications:', error);
|
console.error('Error fetching initial notifications:', error);
|
||||||
@ -143,12 +139,12 @@
|
|||||||
eventSource.close();
|
eventSource.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ✅ FIXED URL HERE
|
||||||
eventSource = new EventSource("/sse/notifications/?last_id=" + lastNotificationId);
|
eventSource = new EventSource("/sse/notifications/?last_id=" + lastNotificationId);
|
||||||
|
|
||||||
eventSource.addEventListener('notification', function(e) {
|
eventSource.addEventListener('notification', function(e) {
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(e.data);
|
const data = JSON.parse(e.data);
|
||||||
|
|
||||||
if (seenNotificationIds.has(data.id)) return;
|
if (seenNotificationIds.has(data.id)) return;
|
||||||
seenNotificationIds.add(data.id);
|
seenNotificationIds.add(data.id);
|
||||||
|
|
||||||
@ -158,6 +154,11 @@
|
|||||||
|
|
||||||
updateCounter('increment');
|
updateCounter('increment');
|
||||||
|
|
||||||
|
if (!notificationsContainer) {
|
||||||
|
console.warn("Notification container missing, can't render SSE event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const notificationElement = createNotificationElement(data);
|
const notificationElement = createNotificationElement(data);
|
||||||
notificationsContainer.insertAdjacentHTML('afterbegin', notificationElement);
|
notificationsContainer.insertAdjacentHTML('afterbegin', notificationElement);
|
||||||
|
|
||||||
@ -168,7 +169,7 @@
|
|||||||
|
|
||||||
Toast.fire({
|
Toast.fire({
|
||||||
icon: 'info',
|
icon: 'info',
|
||||||
html:`${data.message}`
|
html: `${data.message}`
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -220,7 +221,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCounter(action) {
|
function updateCounter(action) {
|
||||||
@ -231,12 +232,14 @@
|
|||||||
if (notificationCountDiv) {
|
if (notificationCountDiv) {
|
||||||
notificationCountDiv.innerHTML = `
|
notificationCountDiv.innerHTML = `
|
||||||
<span class="badge bg-danger rounded-pill" id="notification-counter" style="position: absolute; top: 8px; right: 3px; font-size: 0.50rem;">0</span>
|
<span class="badge bg-danger rounded-pill" id="notification-counter" style="position: absolute; top: 8px; right: 3px; font-size: 0.50rem;">0</span>
|
||||||
`;
|
`;
|
||||||
counter = document.getElementById('notification-counter');
|
counter = document.getElementById('notification-counter');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!counter) return;
|
||||||
|
|
||||||
let currentCount = parseInt(counter.textContent) || 0;
|
let currentCount = parseInt(counter.textContent) || 0;
|
||||||
|
|
||||||
if (action === 'increment') {
|
if (action === 'increment') {
|
||||||
@ -294,7 +297,7 @@
|
|||||||
notificationCard.closest('.notification-card').classList.add('fade-out');
|
notificationCard.closest('.notification-card').classList.add('fade-out');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
notificationCard.closest('.notification-card').remove();
|
notificationCard.closest('.notification-card').remove();
|
||||||
}, 200);
|
}, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -125,7 +125,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
||||||
<td class="name align-middle white-space-nowrap ps-0 px-1">
|
<td class="name align-middle white-space-nowrap px-1">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<div>
|
<div>
|
||||||
<a class="fs-8 fw-bold"
|
<a class="fs-8 fw-bold"
|
||||||
@ -144,7 +144,7 @@
|
|||||||
<td class="date align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 text-body-tertiary">
|
<td class="date align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 text-body-tertiary">
|
||||||
{{ org.created|date }}
|
{{ org.created|date }}
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle white-space-nowrap text-end pe-0 ps-4">
|
<td class="align-middle white-space-nowrap text-end pe-2 ps-4">
|
||||||
{% if perms.inventory.change_organization or perms.inventory.delete_organization %}
|
{% if perms.inventory.change_organization or perms.inventory.delete_organization %}
|
||||||
<div class="btn-reveal-trigger position-static">
|
<div class="btn-reveal-trigger position-static">
|
||||||
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10"
|
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10"
|
||||||
|
|||||||
@ -19,9 +19,9 @@
|
|||||||
{% if po_model.po_status == 'fulfilled' %}
|
{% if po_model.po_status == 'fulfilled' %}
|
||||||
<div class="ms-2">
|
<div class="ms-2">
|
||||||
<a class="btn btn-phoenix-primary my-2 mx-2"
|
<a class="btn btn-phoenix-primary my-2 mx-2"
|
||||||
href="{{ request.path }}?format=pdf&lang=en"><i class="fa-solid fa-arrow-down me-1"></i>{% trans 'Download PO ENG' %}</a>
|
href="{{ request.path }}?format=pdf&lang=en"><i class="fa-solid fa-arrow-down me-1"></i>{% trans 'Download PO EN' %}</a>
|
||||||
<a class="btn btn-phoenix-primary my-2"
|
<a class="btn btn-phoenix-primary my-2"
|
||||||
href="{{ request.path }}?format=pdf&lang=ar"><i class="fa-solid fa-arrow-down me-1"></i>{% trans 'Download PO ARB' %}</a>
|
href="{{ request.path }}?format=pdf&lang=ar"><i class="fa-solid fa-arrow-down me-1"></i>{% trans 'Download PO AR' %}</a>
|
||||||
</diV>
|
</diV>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{% load tenhal_tag %}
|
{% load tenhal_tag %}
|
||||||
{% load custom_filters %}
|
{% load custom_filters %}
|
||||||
|
{% load i18n static custom_filters num2words_tags %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="ar" dir="rtl">
|
<html lang="ar" dir="rtl">
|
||||||
<head>
|
<head>
|
||||||
@ -109,50 +109,94 @@
|
|||||||
|
|
||||||
/* Footer Styles */
|
/* Footer Styles */
|
||||||
.document-footer {
|
.document-footer {
|
||||||
|
position: relative;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
color: #888;
|
color: #888;
|
||||||
border-top: 1px solid #ddd;
|
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
margin-top: 30px;
|
margin: 0 20mm;
|
||||||
|
|
||||||
}
|
}
|
||||||
.footer-flex {
|
.footer-flex {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
.footer-logo {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.footer-logo img {
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
.footer-logo p {
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.footer-powered p {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
.footer-powered span {
|
||||||
|
font-weight: lighter;
|
||||||
|
}
|
||||||
|
.footer-powered a {
|
||||||
|
color: #112e40;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="document-header">
|
<div class="document-header">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>{{ dealer.name }}</h1>
|
||||||
|
|
||||||
|
<address>
|
||||||
|
العنوان : {{ dealer.address }}<br>
|
||||||
|
البريد الإلكتروني : {{ dealer.user.email }}<br>
|
||||||
|
الهاتف : {{ dealer.phone_number }}<br>
|
||||||
|
رقم السجل التجاري : {{ dealer.crn }} | رقم ضريبة القيمة المضافة : {{ dealer.vrn }}
|
||||||
|
</address>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="dealer-logo ">
|
||||||
|
{% if dealer.logo %}
|
||||||
|
<img class="rounded-soft"
|
||||||
|
style="max-width:100px;
|
||||||
|
max-height:100px"
|
||||||
|
src="{{dealer.logo.url|default:'' }}"
|
||||||
|
alt="Dealer Logo" />
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h1>أمر شراء</h1>
|
<h1>أمر شراء</h1>
|
||||||
<h2 style="font-size: 18px;">{{ po_model.po_number }}</h2>
|
<h2 style="font-size: 18px;">{{ po_model.po_number }}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<h1>{{ dealer.name }}</h1>
|
|
||||||
<address>
|
|
||||||
العنوان: {{ dealer.address }}<br>
|
|
||||||
البريد الإلكتروني: {{ dealer.user.email }}<br>
|
|
||||||
الهاتف: {{ dealer.phone_number }}<br>
|
|
||||||
رقم السجل التجاري: {{ dealer.crn }} | رقم ضريبة القيمة المضافة: {{ dealer.vrn }}
|
|
||||||
</address>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="document-details">
|
<div class="document-details">
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<h2>التفاصيل:</h2>
|
<h2>التفاصيل:</h2>
|
||||||
<p><span class="label">رقم أمر الشراء:</span> {{ po_model.po_number }}</p>
|
<p><span class="label">رقم أمر الشراء : </span> {{ po_model.po_number }}</p>
|
||||||
<p><span class="label">تاريخ الإصدار:</span> {{ po_model.date_fulfilled|date:"Y/m/d" }}</p>
|
<p><span class="label">تاريخ الإصدار : </span> {{ po_model.date_fulfilled|date:"Y/m/d" }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<h2>يُرسل إلى:</h2>
|
<h2>يُرسل إلى:</h2>
|
||||||
<p><span class="label">المورد:</span> {{ vendor.vendor_name }}</p>
|
<p><span class="label">المورد : </span> {{ vendor.vendor_name }}</p>
|
||||||
<p><span class="label">البريد الإلكتروني:</span> {{ vendor.email }}</p>
|
<p><span class="label">البريد الإلكتروني : </span> {{ vendor.email }}</p>
|
||||||
<p><span class="label">الهاتف:</span> {{ vendor.phone }}</p>
|
<p><span class="label">الهاتف : </span> {{ vendor.phone }}</p>
|
||||||
<p><span class="label">العنوان:</span> {{ vendor.address_1 }}</p>
|
<p><span class="label">العنوان : </span> {{ vendor.address_1 }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
@ -170,13 +214,24 @@
|
|||||||
|
|
||||||
<div class="document-details" style="margin-top: 10px; border-top: 1px solid #ddd; padding-top: 10px;">
|
<div class="document-details" style="margin-top: 10px; border-top: 1px solid #ddd; padding-top: 10px;">
|
||||||
<div class="section text-right" style="width: 100%;">
|
<div class="section text-right" style="width: 100%;">
|
||||||
<p class="h4"><span class="label">المبلغ الإجمالي:</span> {{ po_total_amount|floatformat:'2g' }}<span class="icon-saudi_riyal"></span></p>
|
<p class="h4"><span class="label">المبلغ الإجمالي : </span> {{ po_total_amount|currency_format }}<span class="icon-saudi_riyal"></span></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<hr style="border-bottom:1px solid #ccc; ">
|
||||||
|
|
||||||
<div class="document-footer footer-flex">
|
<div class="document-footer">
|
||||||
<p>© <strong>هيكل</strong> {% now "Y" %} جميع الحقوق محفوظة.</p>
|
<div class="footer-logo">
|
||||||
<p><strong>تنحل</strong>مدعوم من</p>
|
<img src="{% static 'images/logos/logo-d-pdf.png' %}" alt="Logo" />
|
||||||
|
<p>
|
||||||
|
<span>Haikal</span> | <span>هيكل</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer-powered">
|
||||||
|
<p>
|
||||||
|
<span>Powered by </span>
|
||||||
|
<a href="https://tenhal.sa"><span>TENHAL</span> | <span>تنحل</span></a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -103,22 +103,49 @@
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Footer Styles */
|
/* Footer Styles */
|
||||||
.document-footer {
|
.document-footer {
|
||||||
|
position: relative;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
color: #888;
|
color: #888;
|
||||||
border-top: 1px solid #ddd;
|
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
margin-top: 30px;
|
margin: 0 20mm;
|
||||||
|
|
||||||
|
}
|
||||||
|
.footer-flex {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.footer-logo {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.footer-logo img {
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
.footer-logo p {
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.footer-powered p {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
.footer-powered span {
|
||||||
|
font-weight: lighter;
|
||||||
|
}
|
||||||
|
.footer-powered a {
|
||||||
|
color: #112e40;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-flex {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -126,12 +153,25 @@
|
|||||||
<div>
|
<div>
|
||||||
<h1>{{ dealer.name }}</h1>
|
<h1>{{ dealer.name }}</h1>
|
||||||
<address>
|
<address>
|
||||||
Address: {{ dealer.address}}<br>
|
Address : {{ dealer.address}}<br>
|
||||||
Email: {{ dealer.user.email }}<br>
|
Email : {{ dealer.user.email }}<br>
|
||||||
Phone: {{dealer.phone_number }}<br>
|
Phone : {{dealer.phone_number }}<br>
|
||||||
CRN: {{dealer.crn}} | VRN: {{dealer.vrn}}
|
CRN : {{dealer.crn}} | VRN : {{dealer.vrn}}
|
||||||
</address>
|
</address>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="dealer-logo ">
|
||||||
|
{% if dealer.logo %}
|
||||||
|
<img class="rounded-soft"
|
||||||
|
style="max-width:100px;
|
||||||
|
max-height:100px"
|
||||||
|
src="{{dealer.logo.url|default:'' }}"
|
||||||
|
alt="Dealer Logo" />
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h1>PURCHASE ORDER</h1>
|
<h1>PURCHASE ORDER</h1>
|
||||||
<h2 style="font-size: 18px;">{{ po_model.po_number }}</h2>
|
<h2 style="font-size: 18px;">{{ po_model.po_number }}</h2>
|
||||||
@ -141,15 +181,15 @@
|
|||||||
<div class="document-details">
|
<div class="document-details">
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<h2>BILL TO:</h2>
|
<h2>BILL TO:</h2>
|
||||||
<p><span class="label">Vendor: {{vendor.vendor_name}}</span> </p>
|
<p><span class="label">Vendor : {{vendor.vendor_name}}</span> </p>
|
||||||
<p><span class="label">Email: {{vendor.email}}</span> </p>
|
<p><span class="label">Email : {{vendor.email}}</span> </p>
|
||||||
<p><span class="label">Phone: {{vendor.phone}}</span> </p>
|
<p><span class="label">Phone : {{vendor.phone}}</span> </p>
|
||||||
<p><span class="label">Address: {{vendor.address_1}}</span> </p>
|
<p><span class="label">Address : {{vendor.address_1}}</span> </p>
|
||||||
</div>
|
</div>
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<h2>DETAILS:</h2>
|
<h2>DETAILS:</h2>
|
||||||
<p><span class="label">PO Number:</span> {{ po_model.po_number }}</p>
|
<p><span class="label">PO Number : </span> {{ po_model.po_number }}</p>
|
||||||
<p><span class="label">Issue Date:</span> {{ po_model.date_fulfilled|date:"F j, Y" }}</p>
|
<p><span class="label">Issue Date : </span> {{ po_model.date_fulfilled|date:"F j, Y" }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
@ -161,13 +201,24 @@
|
|||||||
<div class="document-details" style="margin-top: 30px;">
|
<div class="document-details" style="margin-top: 30px;">
|
||||||
|
|
||||||
<div class="section text-right">
|
<div class="section text-right">
|
||||||
<p class="h4"><span class="label">Total Amount:</span> {{ po_total_amount|floatformat:'2g' }}<span class="icon-saudi_riyal"></span></p>
|
<p class="h4"><span class="label">Total Amount : </span> {{ po_total_amount|currency_format }}<span class="icon-saudi_riyal"></span></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<hr style="border-bottom:1px solid #ccc; ">
|
||||||
|
|
||||||
<div class="document-footer footer-flex">
|
<div class="document-footer">
|
||||||
<p>© {% now "Y" %} All rights reserved <strong>Haikal</strong> </p>
|
<div class="footer-logo">
|
||||||
<p>Powered By <strong>Tenhal</strong></p>
|
<img src="{% static 'images/logos/logo-d-pdf.png' %}" alt="Logo" />
|
||||||
|
<p>
|
||||||
|
<span>Haikal</span> | <span>هيكل</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer-powered">
|
||||||
|
<p>
|
||||||
|
<span>Powered by </span>
|
||||||
|
<a href="https://tenhal.sa"><span>TENHAL</span> | <span>تنحل</span></a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
<tr class="has-text-centered bg-body-highlight">
|
<tr class="has-text-centered bg-body-highlight">
|
||||||
<th>البند</th>
|
<th>البند</th>
|
||||||
<th>سعر الوحدة</th>
|
<th>سعر الوحدة</th>
|
||||||
<th>كمية أمر الشراء</th>
|
<th>الكمية</th>
|
||||||
<th>المبلغ</th>
|
<th>المبلغ</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -14,7 +14,7 @@
|
|||||||
{% for item in po_items_list %}
|
{% for item in po_items_list %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ item.item_model }}</td>
|
<td>{{ item.item_model }}</td>
|
||||||
<td class="has-text-centered">{{ item.po_unit_cost }}</td>
|
<td class="has-text-centered">{{ item.po_unit_cost|currency_format }}</td>
|
||||||
<td class="has-text-centered">{{ item.po_quantity }}</td>
|
<td class="has-text-centered">{{ item.po_quantity }}</td>
|
||||||
<td class="has-text-centered">
|
<td class="has-text-centered">
|
||||||
<span class="icon-saudi_riyal"></span>{{ item.po_total_amount | currency_format }}
|
<span class="icon-saudi_riyal"></span>{{ item.po_total_amount | currency_format }}
|
||||||
@ -26,12 +26,12 @@
|
|||||||
<tfoot>
|
<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
||||||
|
<td>إجمالي مبلغ أمر الشراء</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td class="has-text-left">إجمالي مبلغ أمر الشراء</td>
|
<td class="has-text-left">{{po_quantity}}</td>
|
||||||
<td class="has-text-weight-bold has-text-centered">
|
<td class="has-text-weight-bold has-text-centered">
|
||||||
<span class="icon-saudi_riyal"></span>{{ po_model.po_amount | currency_format }}
|
<span class="icon-saudi_riyal"></span>{{ po_model.po_amount | currency_format }}
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</tfoot>
|
</tfoot>
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
{% for item in po_items_list %}
|
{% for item in po_items_list %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ item.item_model }}</td>
|
<td>{{ item.item_model }}</td>
|
||||||
<td class="has-text-centered">{{ item.po_unit_cost }}</td>
|
<td class="has-text-centered">{{ item.po_unit_cost|currency_format}}</td>
|
||||||
<td class="has-text-centered">{{ item.po_quantity }}</td>
|
<td class="has-text-centered">{{ item.po_quantity }}</td>
|
||||||
<td class="has-text-centered">
|
<td class="has-text-centered">
|
||||||
<span class="icon-saudi_riyal"></span>{{ item.po_total_amount | currency_format }}
|
<span class="icon-saudi_riyal"></span>{{ item.po_total_amount | currency_format }}
|
||||||
@ -26,12 +26,14 @@
|
|||||||
<tfoot>
|
<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
||||||
<td></td>
|
<td>Total PO Amount</td>
|
||||||
<td class="has-text-right">Total PO Amount</td>
|
<td class="has-text-right"></td>
|
||||||
|
|
||||||
|
<td>{{po_quantity}}</td>
|
||||||
|
|
||||||
<td class="has-text-weight-bold has-text-centered">
|
<td class="has-text-weight-bold has-text-centered">
|
||||||
<span class="icon-saudi_riyal"></span>{{ po_model.po_amount | currency_format }}
|
<span class="icon-saudi_riyal"></span>{{ po_model.po_amount | currency_format }}
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</tfoot>
|
</tfoot>
|
||||||
|
|||||||
@ -134,11 +134,17 @@
|
|||||||
{% if perms.django_ledger.change_estimatemodel %}
|
{% if perms.django_ledger.change_estimatemodel %}
|
||||||
<a href="{% url 'send_email' request.dealer.slug estimate.pk %}"
|
<a href="{% url 'send_email' request.dealer.slug estimate.pk %}"
|
||||||
class="btn btn-phoenix-primary me-2"><span class="fa-regular fa-paper-plane me-sm-2"></span><span class="d-none d-sm-inline-block">{% trans 'Send Quotation' %}</span></a>
|
class="btn btn-phoenix-primary me-2"><span class="fa-regular fa-paper-plane me-sm-2"></span><span class="d-none d-sm-inline-block">{% trans 'Send Quotation' %}</span></a>
|
||||||
<a href="{% url 'estimate_print' request.dealer.slug estimate.pk %}"
|
<a href="{% url 'estimate_print' request.dealer.slug estimate.pk %}?lang=en"
|
||||||
class="btn btn-phoenix-secondary"
|
class="btn btn-phoenix-secondary"
|
||||||
target="_blank">
|
target="_blank">
|
||||||
<span class="d-none d-sm-inline-block"><i class="fas fa-print me-2"></i>{% trans 'Print' %}</span>
|
<span class="d-none d-sm-inline-block"><i class="fas fa-print me-2"></i>{% trans 'Print EN' %}</span>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{% url 'estimate_print' request.dealer.slug estimate.pk %}?lang=ar"
|
||||||
|
class="btn btn-phoenix-secondary"
|
||||||
|
target="_blank">
|
||||||
|
<span class="d-none d-sm-inline-block"><i class="fas fa-print me-2"></i>{% trans 'Print AR' %}</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if estimate.sale_orders.first %}
|
{% if estimate.sale_orders.first %}
|
||||||
<!--if sale order exist-->
|
<!--if sale order exist-->
|
||||||
|
|||||||
@ -1,264 +0,0 @@
|
|||||||
{% load i18n static custom_filters num2words_tags %}
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="ar" dir="rtl">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>{% trans "Quotation" %}</title>
|
|
||||||
<style>
|
|
||||||
/* General Body and Font Styles */
|
|
||||||
body {
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #333;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Page Layout and Margins for PDF */
|
|
||||||
@page {
|
|
||||||
size: A4;
|
|
||||||
margin: 20mm;
|
|
||||||
@top-left {
|
|
||||||
content: "صفحة " counter(page) " من " counter(pages);
|
|
||||||
font-size: 10px;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Header Styles */
|
|
||||||
.document-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
border-bottom: 2px solid #333;
|
|
||||||
padding-bottom: 15px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
.document-header .logo {
|
|
||||||
max-width: 150px;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
.document-header h1 {
|
|
||||||
font-size: 24px;
|
|
||||||
margin: 0;
|
|
||||||
color: #0056b3; /* A professional blue */
|
|
||||||
}
|
|
||||||
.document-header address {
|
|
||||||
text-align: right;
|
|
||||||
font-style: normal;
|
|
||||||
font-size: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Document Details Section */
|
|
||||||
.document-details {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
.document-details .section {
|
|
||||||
width: 48%;
|
|
||||||
}
|
|
||||||
.document-details h2 {
|
|
||||||
font-size: 14px;
|
|
||||||
border-bottom: 1px solid #ccc;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
.document-details p {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
.document-details .label {
|
|
||||||
font-weight: bold;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Table Styles */
|
|
||||||
.table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
.table th, .table td {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
padding: 8px;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
.table th {
|
|
||||||
background-color: #f2f2f2;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.table tfoot td {
|
|
||||||
border-top: 2px solid #333;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.text-right {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.text-left {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
.text-center {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Footer Styles */
|
|
||||||
.document-footer {
|
|
||||||
text-align: center;
|
|
||||||
font-size: 10px;
|
|
||||||
color: #888;
|
|
||||||
border-top: 1px solid #ddd;
|
|
||||||
padding-top: 15px;
|
|
||||||
margin-top: 30px;
|
|
||||||
}
|
|
||||||
.footer-flex {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="document-header">
|
|
||||||
<div>
|
|
||||||
<h1>{{ request.dealer.name }}</h1>
|
|
||||||
<address>
|
|
||||||
العنوان: {{ request.dealer.address }}<br>
|
|
||||||
البريد الإلكتروني: {{ request.dealer.user.email }}<br>
|
|
||||||
الهاتف: {{ request.dealer.phone_number }}<br>
|
|
||||||
رقم السجل التجاري: {{ request.dealer.crn }} | الرقم الضريبي: {{ request.dealer.vrn }}
|
|
||||||
</address>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h1>عرض سعر</h1>
|
|
||||||
<h2 style="font-size: 18px;">{{ estimate.estimate_number }}</h2>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="document-details">
|
|
||||||
<div class="section">
|
|
||||||
<h2>{{ estimate.customer.customer_name }}: إلى</h2>
|
|
||||||
<p><span class="label">العميل: {{ estimate.customer.customer_name }}</span></p>
|
|
||||||
<p><span class="label">البريد الإلكتروني: {{ estimate.customer.email |default:"N/A"}}</span></p>
|
|
||||||
<p><span class="label">الهاتف: {{ estimate.customer.phone_number|default:"N/A" }}</span></p>
|
|
||||||
<p><span class="label">العنوان: {{ estimate.customer.address_1|default:"N/A" }}</span></p>
|
|
||||||
</div>
|
|
||||||
<div class="section text-left">
|
|
||||||
<h2>التفاصيل:</h2>
|
|
||||||
<p><span class="label">رقم عرض السعر:</span> {{ estimate.estimate_number }}</p>
|
|
||||||
<p><span class="label">تاريخ الإصدار:</span> {{ estimate.date_approved|date:"Y/m/d" }}</p>
|
|
||||||
<p><span class="label">طريقة الدفع:</span> {{ estimate.get_terms_display }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-lg-12">
|
|
||||||
<div class="table-responsive">
|
|
||||||
<div class="d-flex justify-content-between">
|
|
||||||
<span class="fs-9 fw-thin">تفاصيل السيارة</span>
|
|
||||||
</div>
|
|
||||||
<table class="table table-sm table-bordered m-1">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">الصانع</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">الموديل</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">السلسلة</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">الفئة</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">السنة</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">رقم الهيكل</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">الكمية</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">سعر الوحدة</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">الخصم</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">الضريبة</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">الإجمالي</span>
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_make.name }}</td>
|
|
||||||
<td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_model.name }}</td>
|
|
||||||
<td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_serie.name }}</td>
|
|
||||||
<td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_trim.name }}</td>
|
|
||||||
<td class="text-center fs-10 align-content-center">{{ data.car.year }}</td>
|
|
||||||
<td class="ps-1 fs-10 align-content-center">{{ data.car.vin }}</td>
|
|
||||||
<td class="text-center fs-10 align-content-center">1</td>
|
|
||||||
<td class="text-center fs-10 align-content-center">{{ data.car.marked_price|floatformat:2 }}</td>
|
|
||||||
<td class="text-center fs-10 align-content-center">{{ data.discount_amount|floatformat:2 }}</td>
|
|
||||||
<td class="text-center fs-10 align-content-center">{{ data.vat_amount|floatformat:2 }}</td>
|
|
||||||
<td class="text-center fs-10 align-content-center">{{ data.final_price|floatformat:2 }}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if data.additional_services %}
|
|
||||||
<div class="col-lg-12">
|
|
||||||
<div class="table-responsive">
|
|
||||||
<div class="d-flex justify-content-between">
|
|
||||||
<span class="fs-9 fw-thin">الخدمات الإضافية</span>
|
|
||||||
</div>
|
|
||||||
<table class="table table-sm table-bordered m-1">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="text-center fs-10 align-content-center">النوع</th>
|
|
||||||
<th class="text-center fs-10 align-content-center">القيمة</th>
|
|
||||||
<th class="text-center fs-10 align-content-center">ضريبة الخدمة</th>
|
|
||||||
<th class="text-center fs-10 align-content-center">الإجمالي</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for service in data.additional_services.services %}
|
|
||||||
<tr>
|
|
||||||
<td class="ps-1 text-center fs-10 align-content-center">{{ service.0.name }}</td>
|
|
||||||
<td class="ps-1 text-center fs-10 align-content-center">{{ service.0.price|floatformat:2 }}</td>
|
|
||||||
<td class="ps-1 text-center fs-10 align-content-center">{{ service.1|floatformat:2 }}</td>
|
|
||||||
<td class="ps-1 text-center fs-10 align-content-center">{{ service.0.price_|floatformat:2 }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="document-details" style="margin-top: 30px;">
|
|
||||||
<div class="section text-left">
|
|
||||||
<p><span class="label">إجمالي ضريبة القيمة المضافة:</span> {{ data.total_vat|floatformat:'2g' }}</p>
|
|
||||||
<p><span class="label">الإجمالي الكلي:</span> {{ data.grand_total|floatformat:'2g' }}</p>
|
|
||||||
<p><span class="label">كتابةً:</span> {{ data.grand_total|num_to_words }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="document-footer footer-flex">
|
|
||||||
<p>© {% now "Y" %} جميع الحقوق محفوظة <strong>هيكل</strong></p>
|
|
||||||
<p>بواسطة <strong>تنحل</strong></p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
357
templates/sales/estimates/estimate_preview_ar.html
Normal file
357
templates/sales/estimates/estimate_preview_ar.html
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
{% load i18n static custom_filters num2words_tags %}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ar" dir="rtl">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>عرض سعر</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* General Body and Font Styles */
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Page Layout and Margins for PDF */
|
||||||
|
@page {
|
||||||
|
size: A4;
|
||||||
|
margin: 20mm;
|
||||||
|
@top-left {
|
||||||
|
content: "صفحة " counter(page) " من " counter(pages);
|
||||||
|
font-size: 10px;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header Styles */
|
||||||
|
.document-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 2px solid #333;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.document-header .logo {
|
||||||
|
max-width: 150px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.document-header h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
margin: 0;
|
||||||
|
color: #0056b3;
|
||||||
|
}
|
||||||
|
.document-header address {
|
||||||
|
text-align: right;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Document Details Section */
|
||||||
|
.document-details {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
.document-details .section {
|
||||||
|
width: 48%;
|
||||||
|
}
|
||||||
|
.document-details h2 {
|
||||||
|
font-size: 14px;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
.document-details p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.document-details .label {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Table Styles */
|
||||||
|
.table {
|
||||||
|
width: 80%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 20px auto; /* Centering the table */
|
||||||
|
}
|
||||||
|
.table th, .table td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 8px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.table th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.table tfoot td {
|
||||||
|
border-top: 2px solid #333;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.text-right {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.text-left {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.text-center {
|
||||||
|
text-align: center;2px solid #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive and layout helpers */
|
||||||
|
.table-container {
|
||||||
|
width: 100%;
|
||||||
|
overflow-x: auto;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.table-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
.table-header span {
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: lighter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer Styles */
|
||||||
|
.document-footer {
|
||||||
|
position: relative;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 10px;
|
||||||
|
color: #888;
|
||||||
|
|
||||||
|
padding-top: 15px;
|
||||||
|
margin: 0 20mm;
|
||||||
|
|
||||||
|
}
|
||||||
|
.footer-flex {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.footer-logo {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.footer-logo img {
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
.footer-logo p {
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.footer-powered p {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
.footer-powered span {
|
||||||
|
font-weight: lighter;
|
||||||
|
}
|
||||||
|
.footer-powered a {
|
||||||
|
color: #112e40;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="document-header">
|
||||||
|
<div>
|
||||||
|
<h1>{{ dealer_info.name }}</h1>
|
||||||
|
<address>
|
||||||
|
العنوان : {{ dealer_info.address }}<br>
|
||||||
|
البريد الإلكتروني : {{ dealer_info.user.email }}<br>
|
||||||
|
الهاتف : {{ dealer_info.phone_number }}<br>
|
||||||
|
رقم السجل التجاري : {{dealer_info.crn }}<br>
|
||||||
|
الرقم الضريبي : {{ dealer_info.vrn }}
|
||||||
|
</address>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="dealer-logo ">
|
||||||
|
{% if dealer_info.logo %}
|
||||||
|
<img class="rounded-soft"
|
||||||
|
style="max-width:100px;
|
||||||
|
max-height:100px"
|
||||||
|
src="{{dealer_info.logo.url|default:'' }}"
|
||||||
|
alt="Dealer Logo" />
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>عرض سعر</h1>
|
||||||
|
<h2 style="font-size: 18px;">{{ estimate.estimate_number }}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="document-details">
|
||||||
|
<div class="section">
|
||||||
|
<h2>{{ customer_obj.full_name }}: إلى</h2>
|
||||||
|
<p><span class="label">العميل : {{ customer_obj.full_name }}</span></p>
|
||||||
|
<p><span class="label">البريد الإلكتروني : {{ customer_obj.email |default:"N/A"}}</span></p>
|
||||||
|
<p><span class="label">الهاتف : {{ customer_obj.phone_number|default:"N/A" }}</span></p>
|
||||||
|
<p><span class="label">العنوان : {{ customer_obj.address|default:"N/A" }}</span></p>
|
||||||
|
</div>
|
||||||
|
<div class="section text-left">
|
||||||
|
<h2>التفاصيل:</h2>
|
||||||
|
<p><span class="label">رقم عرض السعر : </span> {{estimate.estimate_number }}</p>
|
||||||
|
<p><span class="label">تاريخ الإصدار : </span> {{ estimate.date_approved|date:"Y/m/d" }}</p>
|
||||||
|
<p><span class="label">طريقة الدفع : </span> {{ estimate.get_terms_display }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-header">
|
||||||
|
<span>تفاصيل السيارة</span>
|
||||||
|
</div>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الصانع</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الموديل</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>السلسلة</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الفئة</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>السنة</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>رقم الهيكل</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">{{ data.car.id_car_make.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.id_car_model.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.id_car_serie.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.id_car_trim.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.year }}</td>
|
||||||
|
<td class="text-center">{{ data.car.vin }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-header">
|
||||||
|
<span>التفاصيل المالية</span>
|
||||||
|
</div>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الكمية</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>سعر الوحدة</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الخصم</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الضريبة</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الإجمالي</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">1</td>
|
||||||
|
<td class="text-center">{{ data.car.marked_price|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ data.discount_amount|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ data.vat_amount|currency_format }}</td>
|
||||||
|
<td class="text-center">{{ data.final_price|currency_format }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if data.additional_services %}
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-header">
|
||||||
|
<span>الخدمات الإضافية</span>
|
||||||
|
</div>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">النوع</th>
|
||||||
|
<th class="text-center">القيمة</th>
|
||||||
|
<th class="text-center">ضريبة الخدمة</th>
|
||||||
|
<th class="text-center">الإجمالي</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for service in data.additional_services.services %}
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">{{ service.0.name }}</td>
|
||||||
|
<td class="text-center">{{ service.0.price|currency_format }}</td>
|
||||||
|
<td class="text-center">{{ service.1|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ service.0.price_|currency_format}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center"></td>
|
||||||
|
<td class="text-center">{{ data.total_services_amount|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ data.total_services_vat|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ data.total_services_amount_|currency_format}}</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="document-details" style="margin-top: 30px; ">
|
||||||
|
<div class="section text-left">
|
||||||
|
<p><span class="label">إجمالي ضريبة القيمة المضافة : </span> {{ data.total_vat|currency_format }}</p>
|
||||||
|
<p><span class="label">الإجمالي الكلي : </span> {{ data.grand_total|currency_format}}</p>
|
||||||
|
<p><span class="label">كتابةً : </span> {{ data.grand_total|num_to_words }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr style="border-bottom:1px solid #ccc; ">
|
||||||
|
|
||||||
|
<div class="document-footer">
|
||||||
|
<div class="footer-logo">
|
||||||
|
<img src="{% static 'images/logos/logo-d-pdf.png' %}" alt="Logo" />
|
||||||
|
<p>
|
||||||
|
<span>Haikal</span> | <span>هيكل</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer-powered">
|
||||||
|
<p>
|
||||||
|
<span>Powered by </span>
|
||||||
|
<a href="https://tenhal.sa"><span>TENHAL</span> | <span>تنحل</span></a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
357
templates/sales/estimates/estimate_preview_en.html
Normal file
357
templates/sales/estimates/estimate_preview_en.html
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
{% load static custom_filters num2words_tags %}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Quotation</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* General Body and Font Styles */
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Page Layout and Margins for PDF */
|
||||||
|
@page {
|
||||||
|
size: A4;
|
||||||
|
margin: 20mm;
|
||||||
|
@top-left {
|
||||||
|
content: "صفحة " counter(page) " من " counter(pages);
|
||||||
|
font-size: 10px;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header Styles */
|
||||||
|
.document-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 2px solid #333;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.document-header .logo {
|
||||||
|
max-width: 150px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.document-header h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
margin: 0;
|
||||||
|
color: #0056b3;
|
||||||
|
}
|
||||||
|
.document-header address {
|
||||||
|
text-align: right;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Document Details Section */
|
||||||
|
.document-details {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
.document-details .section {
|
||||||
|
width: 48%;
|
||||||
|
}
|
||||||
|
.document-details h2 {
|
||||||
|
font-size: 14px;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
.document-details p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.document-details .label {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Table Styles */
|
||||||
|
.table {
|
||||||
|
width: 80%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 20px auto; /* Centering the table */
|
||||||
|
}
|
||||||
|
.table th, .table td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 8px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.table th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.table tfoot td {
|
||||||
|
border-top: 2px solid #333;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.text-right {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.text-left {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.text-center {
|
||||||
|
text-align: center;2px solid #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive and layout helpers */
|
||||||
|
.table-container {
|
||||||
|
width: 100%;
|
||||||
|
overflow-x: auto;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.table-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
.table-header span {
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: lighter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer Styles */
|
||||||
|
.document-footer {
|
||||||
|
position: relative;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 10px;
|
||||||
|
color: #888;
|
||||||
|
|
||||||
|
padding-top: 15px;
|
||||||
|
margin: 0 20mm;
|
||||||
|
|
||||||
|
}
|
||||||
|
.footer-flex {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.footer-logo {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.footer-logo img {
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
.footer-logo p {
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.footer-powered p {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
.footer-powered span {
|
||||||
|
font-weight: lighter;
|
||||||
|
}
|
||||||
|
.footer-powered a {
|
||||||
|
color: #112e40;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="document-header">
|
||||||
|
<div>
|
||||||
|
<h1>{{ dealer_info.name }}</h1>
|
||||||
|
<address>
|
||||||
|
Address : {{ dealer_info.address }}<br>
|
||||||
|
Email : {{ dealer_info.user.email }}<br>
|
||||||
|
Phone : {{ dealer_info.phone_number }}<br>
|
||||||
|
Commercial Registration No. : {{dealer_info.crn }}<br>
|
||||||
|
VAT No. : {{ dealer_info.vrn }}
|
||||||
|
</address>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="dealer-logo ">
|
||||||
|
{% if dealer_info.logo %}
|
||||||
|
<img class="rounded-soft"
|
||||||
|
style="max-width:100px;
|
||||||
|
max-height:100px"
|
||||||
|
src="{{dealer_info.logo.url|default:'' }}"
|
||||||
|
alt="Dealer Logo" />
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>Quotation</h1>
|
||||||
|
<h2 style="font-size: 18px;">{{ estimate.estimate_number }}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="document-details">
|
||||||
|
<div class="section">
|
||||||
|
<h2>To: {{ customer_obj.full_name }}</h2>
|
||||||
|
<p><span class="label">Customer : {{ customer_obj.full_name }}</span></p>
|
||||||
|
<p><span class="label">Email : {{ customer_obj.email |default:"N/A"}}</span></p>
|
||||||
|
<p><span class="label">Phone : {{ customer_obj.phone_number|default:"N/A" }}</span></p>
|
||||||
|
<p><span class="label">Address : {{ customer_obj.address|default:"N/A" }}</span></p>
|
||||||
|
</div>
|
||||||
|
<div class="section text-right">
|
||||||
|
<h2>Details:</h2>
|
||||||
|
<p><span class="label">Quotation Number : </span> {{ estimate.estimate_number }}</p>
|
||||||
|
<p><span class="label">Issue Date : </span> {{ estimate.date_approved|date:"Y/m/d" }}</p>
|
||||||
|
<p><span class="label">Payment Method : </span> {{ estimate.get_terms_display }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-header">
|
||||||
|
<span>Car Details</span>
|
||||||
|
</div>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Make</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Model</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Series</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Trim</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Year</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>VIN</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">{{ data.car.id_car_make.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.id_car_model.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.id_car_serie.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.id_car_trim.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.year }}</td>
|
||||||
|
<td class="text-center">{{ data.car.vin }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-header">
|
||||||
|
<span>Financial Details</span>
|
||||||
|
</div>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Quantity</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Unit Price</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Discount</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>VAT</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Total</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">1</td>
|
||||||
|
<td class="text-center">{{ data.car.marked_price|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ data.discount_amount|currency_format }}</td>
|
||||||
|
<td class="text-center">{{ data.vat_amount|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ data.final_price|currency_format}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if data.additional_services %}
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-header">
|
||||||
|
<span>Additional Services</span>
|
||||||
|
</div>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">Type</th>
|
||||||
|
<th class="text-center">Value</th>
|
||||||
|
<th class="text-center">Service VAT</th>
|
||||||
|
<th class="text-center">Total</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for service in data.additional_services.services %}
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">{{ service.0.name }}</td>
|
||||||
|
<td class="text-center">{{ service.0.price|currency_format }}</td>
|
||||||
|
<td class="text-center">{{ service.1|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ service.0.price_|currency_format}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center"></td>
|
||||||
|
<td class="text-center">{{ data.total_services_amount|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ data.total_services_vat|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ data.total_services_amount_|currency_format }}</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="document-details" style="margin-top: 30px; ">
|
||||||
|
<div class="section text-right">
|
||||||
|
<p><span class="label">Total VAT : </span> {{ data.total_vat|currency_format}}</p>
|
||||||
|
<p><span class="label">Grand Total : </span> {{ data.grand_total|currency_format }}</p>
|
||||||
|
<p><span class="label">In words : </span> {{ data.grand_total|num_to_words }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr style="border-bottom:1px solid #ccc; ">
|
||||||
|
|
||||||
|
<div class="document-footer">
|
||||||
|
<div class="footer-logo">
|
||||||
|
<img src="{% static 'images/logos/logo-d-pdf.png' %}" alt="Logo" />
|
||||||
|
<p>
|
||||||
|
<span>Haikal</span> | <span>هيكل</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer-powered">
|
||||||
|
<p>
|
||||||
|
<span>Powered by </span>
|
||||||
|
<a href="https://tenhal.sa"><span>TENHAL</span> | <span>تنحل</span></a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -144,6 +144,16 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'invoice_preview' request.dealer.slug invoice.pk %}"
|
<a href="{% url 'invoice_preview' request.dealer.slug invoice.pk %}"
|
||||||
class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-regular fa-eye"></i> {% trans 'Preview' %}</span></a>
|
class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-regular fa-eye"></i> {% trans 'Preview' %}</span></a>
|
||||||
|
<a href="{% url 'invoice_preview' request.dealer.slug invoice.pk %}?lang=en"
|
||||||
|
class="btn btn-phoenix-secondary"
|
||||||
|
target="_blank">
|
||||||
|
<span class="d-none d-sm-inline-block"><i class="fas fa-print me-2"></i>{% trans 'Print EN' %}</span>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'invoice_preview' request.dealer.slug invoice.pk %}?lang=ar"
|
||||||
|
class="btn btn-phoenix-secondary"
|
||||||
|
target="_blank">
|
||||||
|
<span class="d-none d-sm-inline-block"><i class="fas fa-print me-2"></i>{% trans 'Print AR' %}</span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ invoice.amount_owned }}
|
{{ invoice.amount_owned }}
|
||||||
|
|||||||
@ -14,9 +14,9 @@
|
|||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
{% comment %} <div class="col-auto">
|
||||||
<div class="d-flex">{% include 'partials/search_box.html' %}</div>
|
<div class="d-flex">{% include 'partials/search_box.html' %}</div>
|
||||||
</div>
|
</div> {% endcomment %}
|
||||||
</div>
|
</div>
|
||||||
<div class="table-responsive px-1 scrollbar">
|
<div class="table-responsive px-1 scrollbar">
|
||||||
<table class="table align-items-center table-flush">
|
<table class="table align-items-center table-flush">
|
||||||
|
|||||||
@ -1,367 +1,333 @@
|
|||||||
{% load i18n static custom_filters num2words_tags %}
|
{% load i18n static custom_filters num2words_tags %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="ar" dir="rtl">
|
<html lang="ar">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<title>{% trans "Invoice Preview" %}</title>
|
||||||
<title>{% trans "Invoice" %}</title>
|
|
||||||
<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">
|
|
||||||
<link href="{% static 'css/custom.css' %}" type="text/css" rel="stylesheet">
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap"
|
|
||||||
rel="stylesheet">
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: 'Roboto', sans-serif;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.invoice-container {
|
<style>
|
||||||
width: 210mm;
|
/* General Body and Font Styles */
|
||||||
min-height: 297mm;
|
body {
|
||||||
padding: 10mm;
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
margin: 10mm auto;
|
font-size: 14px;
|
||||||
background: white;
|
color: #333;
|
||||||
border-radius: 5px;
|
background-color: #f7f7f7;
|
||||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
|
margin: 0;
|
||||||
display: flex;
|
padding: 20px;
|
||||||
flex-direction: column;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.invoice-content {
|
/* Container for the document content */
|
||||||
flex-grow: 1;
|
.document-container {
|
||||||
}
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 40px;
|
||||||
|
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.invoice-header {
|
/* Header Styles */
|
||||||
text-align: center;
|
.document-header {
|
||||||
border-bottom: 2px solid #dee2e6;
|
display: flex;
|
||||||
padding-bottom: 10px;
|
justify-content: space-between;
|
||||||
margin-bottom: 20px;
|
align-items: center;
|
||||||
}
|
border-bottom: 2px solid #333;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.document-header .logo {
|
||||||
|
max-width: 150px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.document-header h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
margin: 0;
|
||||||
|
color: #0056b3;
|
||||||
|
}
|
||||||
|
.document-header h2 {
|
||||||
|
font-size: 18px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.document-header address {
|
||||||
|
text-align: right;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.qr-code {
|
/* Document Details Section */
|
||||||
text-align: center;
|
.document-details {
|
||||||
margin-top: 10px;
|
display: flex;
|
||||||
}
|
justify-content: space-between;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
.document-details .section {
|
||||||
|
width: 48%;
|
||||||
|
}
|
||||||
|
.document-details h2 {
|
||||||
|
font-size: 14px;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
.document-details p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.document-details .label {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
.qr-code img {
|
/* Table Styles */
|
||||||
width: 3cm;
|
.table {
|
||||||
height: 3cm;
|
width: 100%;
|
||||||
border-radius: 0.3333333333rem;
|
border-collapse: collapse;
|
||||||
}
|
margin: 20px 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.table th, .table td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 8px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.table th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.table tfoot td {
|
||||||
|
border-top: 2px solid #333;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.text-right {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.text-left {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.text-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.invoice-details, .invoice-table {
|
/* Responsive and layout helpers */
|
||||||
font-size: 14px;
|
.table-container {
|
||||||
}
|
width: 100%;
|
||||||
|
overflow-x: auto;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.table-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
.table-header span {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
.invoice-table th {
|
/* Footer Styles */
|
||||||
background-color: #f8f9fa;
|
.document-footer {
|
||||||
font-weight: 600;
|
text-align: center;
|
||||||
}
|
font-size: 10px;
|
||||||
|
color: #888;
|
||||||
.invoice-total {
|
border-top: 1px solid #ddd;
|
||||||
text-align: right;
|
padding-top: 15px;
|
||||||
font-size: 16px;
|
margin-top: 30px;
|
||||||
font-weight: 600;
|
}
|
||||||
margin-top: 10px;
|
.footer-logo img {
|
||||||
}
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
.footer-note {
|
}
|
||||||
margin-top: auto;
|
.footer-logo p {
|
||||||
padding-top: 10mm;
|
font-size: 9px;
|
||||||
font-size: 13px;
|
font-weight: bold;
|
||||||
display: flex;
|
margin: 5px 0 0;
|
||||||
justify-content: space-between;
|
}
|
||||||
align-items: center;
|
.footer-powered p {
|
||||||
border-top: 2px solid #dee2e6; /* Add a top border to separate from content */
|
font-size: 11px;
|
||||||
}
|
margin: 0;
|
||||||
|
}
|
||||||
.logo-img img {
|
.footer-powered span {
|
||||||
width: 10mm;
|
font-weight: lighter;
|
||||||
height: 10mm;
|
}
|
||||||
}
|
.footer-powered a {
|
||||||
</style>
|
color: #112e40;
|
||||||
</head>
|
text-decoration: none;
|
||||||
<body>
|
font-size: 9px;
|
||||||
<div class="row p-2">
|
}
|
||||||
<div class="col-2">
|
</style>
|
||||||
<button class="btn btn-sm btn-phoenix-danger w-100"
|
</head>
|
||||||
onclick="window.history.back()">الرجوع / Back</button>
|
<body>
|
||||||
|
<div class="document-container">
|
||||||
|
<div class="document-header">
|
||||||
|
<div>
|
||||||
|
<h1>{{ dealer_info.name }}</h1>
|
||||||
|
<address>
|
||||||
|
العنوان : {{ dealer_info.address }}<br>
|
||||||
|
البريد الإلكتروني : {{ dealer_info.user.email }}<br>
|
||||||
|
الهاتف : {{ dealer_info.phone_number }}<br>
|
||||||
|
رقم السجل التجاري : {{dealer_info.crn }} | الرقم الضريبي : {{ dealer_info.vrn }}
|
||||||
|
</address>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-2">
|
<div>
|
||||||
<button class="btn btn-sm btn-phoenix-primary w-100" id="download-pdf">تحميل / Download</button>
|
<h1>عرض سعر</h1>
|
||||||
|
<h2>{{ estimate.estimate_number }}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-8"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="invoice-container" id="invoice-content">
|
|
||||||
<div class="invoice-content">
|
<div class="document-details">
|
||||||
<div class="invoice-header">
|
<div class="section">
|
||||||
<h5 class="fs-5">
|
<h2>{{ estimate.customer.customer_name }}: إلى</h2>
|
||||||
<span>Invoice</span> / <span>فاتورة</span>
|
<p><span class="label">العميل : {{ customer_obj.full_name }}</span></p>
|
||||||
</h5>
|
<p><span class="label">البريد الإلكتروني : {{ customer_obj.email |default:"N/A"}}</span></p>
|
||||||
</div>
|
<p><span class="label">الهاتف : {{ customer_obj.phone_number|default:"N/A" }}</span></p>
|
||||||
<div class="invoice-details p-1">
|
<p><span class="label">العنوان : {{ customer_obj.address|default:"N/A" }}</span></p>
|
||||||
<div class="d-flex justify-content-around align-items-end">
|
|
||||||
<div class="d-flex justify-content-start align-items-center">
|
|
||||||
<div class="qr-code">
|
|
||||||
<img src="{% static 'qr_code/Marwan_qr.png' %}" alt="QR Code">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="dealer-logo ">
|
|
||||||
{% if request.dealer.logo %}
|
|
||||||
<img class="rounded-soft"
|
|
||||||
style="max-width:150px;
|
|
||||||
max-height:150px"
|
|
||||||
src="{{ request.dealer.logo.url|default:'' }}"
|
|
||||||
alt="Dealer Logo" />
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<table class="table table-sm table-responsive border-gray-50">
|
|
||||||
<tr>
|
|
||||||
<td class="ps-1">
|
|
||||||
<strong>Dealership Name</strong>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">{{ request.dealer.name }}</td>
|
|
||||||
<td class="text-end">
|
|
||||||
<strong>اسم الوكالة</strong>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="ps-1">
|
|
||||||
<strong>Dealership Address</strong>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">{{ request.dealer.address }}</td>
|
|
||||||
<td class="text-end">
|
|
||||||
<strong>عنوان الوكالة</strong>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="ps-1">
|
|
||||||
<strong>Phone</strong>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">{{ request.dealer.phone_number }}</td>
|
|
||||||
<td class="text-end">
|
|
||||||
<strong>جوال</strong>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<strong>VAT Number</strong>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">{{ request.dealer.vrn }}</td>
|
|
||||||
<td class="text-end">
|
|
||||||
<strong>الرقم الضريبي</strong>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<table class="table table-sm table-bordered border-gray-50 ">
|
|
||||||
<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_approved| date:"Y/m/d" }}</td>
|
|
||||||
<td class="text-end p-1">
|
|
||||||
<strong>التاريخ</strong>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="ps-1">
|
|
||||||
<strong>Customer Name</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>Email</strong>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">{{ invoice.customer.email |default:"N/A" }}</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 class="d-flex justify-content-between">
|
|
||||||
<span class="fs-9 fw-thin">Car Details</span>
|
|
||||||
<span class="fs-9 fw-thin">تفاصيل السيارة</span>
|
|
||||||
</div>
|
|
||||||
<div class="invoice-table p-1">
|
|
||||||
<table class="table table-sm table-bordered m-1">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">Make</span> / <span class="fs-10">الصانع</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">Model</span> / <span class="fs-10">الموديل</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">Series</span> / <span class="fs-10">السلسلة</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">Trim</span> / <span class="fs-10">الفئة</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">Year</span> / <span class="fs-10">السنة</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">VIN</span> / <span class="fs-10">رقم الهيكل</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">Quantity</span> / <span class="fs-10">الكمية</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">Unit Price</span> / <span class="fs-10">سعر الوحدة</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">Discount</span> / <span class="fs-10">الخصم</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">VAT</span> / <span class="fs-10">الضريبة</span>
|
|
||||||
</th>
|
|
||||||
<th class="text-wrap text-center align-content-center">
|
|
||||||
<span class="fs-10">Total</span> / <span class="fs-10">الإجمالي</span>
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_make.name }}</td>
|
|
||||||
<td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_model.name }}</td>
|
|
||||||
<td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_serie.name }}</td>
|
|
||||||
<td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_trim.name }}</td>
|
|
||||||
<td class="text-center fs-10 align-content-center">{{ data.car.year }}</td>
|
|
||||||
<td class="ps-1 fs-10 align-content-center">{{ data.car.vin }}</td>
|
|
||||||
<td class="text-center fs-10 align-content-center">1</td>
|
|
||||||
<td class="text-center fs-10 align-content-center">{{ data.car.marked_price |floatformat:2 }}</td>
|
|
||||||
<td class="text-center fs-10 align-content-center">{{ data.discount_amount |floatformat:2 }}</td>
|
|
||||||
<td class="text-center fs-10 align-content-center">{{ data.vat_amount|floatformat:2 }}</td>
|
|
||||||
<td class="text-center fs-10 align-content-center">{{ data.final_price|floatformat:2 }}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex justify-content-between">
|
|
||||||
<span class="fs-9 fw-thin">Additional Services</span>
|
|
||||||
<span class="fs-9 fw-thin">الخدمات الإضافية</span>
|
|
||||||
</div>
|
|
||||||
{% if data.additional_services %}
|
|
||||||
<div class="invoice-table p-1">
|
|
||||||
<table class="table table-sm table-bordered m-1">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="text-center fs-10 align-content-center">Type / النوع</th>
|
|
||||||
<th class="text-center fs-10 align-content-center">Price / السعر</th>
|
|
||||||
<th class="text-center fs-10 align-content-center">Service VAT / ضريبة الخدمة</th>
|
|
||||||
<th class="text-center fs-10 align-content-center">
|
|
||||||
<span class="fs-10">Total</span> / <span class="fs-10">الإجمالي</span>
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for service in data.additional_services.services %}
|
|
||||||
<tr>
|
|
||||||
<td class="ps-1 text-start fs-10 align-content-center">{{ service.0.name }}</td>
|
|
||||||
<td class="ps-1 text-center fs-10 align-content-center">{{ service.0.price|floatformat }}</td>
|
|
||||||
<td class="ps-1 text-center fs-10 align-content-center">{{ service.1|floatformat }}</td>
|
|
||||||
<td class="ps-1 text-center fs-10 align-content-center">{{ service.0.price_|floatformat }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<div class="invoice-total 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">Total VAT</strong>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">
|
|
||||||
<span class="fs-9">{{ data.total_vat|floatformat }} <span class="icon-saudi_riyal"></span></span>
|
|
||||||
</td>
|
|
||||||
<td class="text-end">
|
|
||||||
<strong class="fs-9">إجمالي ضريبة القيمة المضافة</strong>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="text-start ps-1">
|
|
||||||
<strong class="fs-9">Grand Total</strong>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">
|
|
||||||
<span class="fs-9">{{ data.grand_total|floatformat }} <span class="icon-saudi_riyal"></span></span>
|
|
||||||
</td>
|
|
||||||
<td class="text-end">
|
|
||||||
<strong class="fs-9">الإجمالي الكلي</strong>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="text-end" colspan="3">
|
|
||||||
<span class="fs-9 fw-bold">كتابةً: </span><span class="fs-9">{{ data.grand_total|num_to_words }} <span class="icon-saudi_riyal"></span></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="footer-note">
|
<div class="section text-left">
|
||||||
<div class="logo-img text-center">
|
<h2>التفاصيل:</h2>
|
||||||
<img src="{% static 'images/logos/logo-d-pdf.png' %}" alt="Logo" />
|
<p><span class="label">رقم عرض السعر : </span> {{ estimate.estimate_number }}</p>
|
||||||
<p class="fs-9 fw-bold">
|
<p><span class="label">تاريخ الإصدار : </span> {{ estimate.date_approved|date:"Y/m/d" }}</p>
|
||||||
<span>Haikal</span> | <span>هيكل</span>
|
<p><span class="label">طريقة الدفع : </span> {{ estimate.get_terms_display }}</p>
|
||||||
</p>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-header">
|
||||||
|
<span>تفاصيل السيارة</span>
|
||||||
|
</div>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الصانع</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الموديل</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>السلسلة</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الفئة</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>السنة</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>رقم الهيكل</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">{{ data.car.id_car_make.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.id_car_model.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.id_car_serie.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.id_car_trim.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.year }}</td>
|
||||||
|
<td class="text-center">{{ data.car.vin }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-header">
|
||||||
|
<span>التفاصيل المالية</span>
|
||||||
|
</div>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الكمية</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>سعر الوحدة</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الخصم</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الضريبة</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الإجمالي</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">1</td>
|
||||||
|
<td class="text-center">{{ data.car.marked_price|floatformat:2 }}</td>
|
||||||
|
<td class="text-center">{{ data.discount_amount|floatformat:2 }}</td>
|
||||||
|
<td class="text-center">{{ data.vat_amount|floatformat:2 }}</td>
|
||||||
|
<td class="text-center">{{ data.final_price|floatformat:2 }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if data.additional_services %}
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-header">
|
||||||
|
<span>الخدمات الإضافية</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="fs-11">
|
<table class="table">
|
||||||
<span class="fw-thin">Powered by </span>
|
<thead>
|
||||||
<a class="text-decoration-none fs-9"
|
<tr>
|
||||||
href="https://tenhal.sa"
|
<th class="text-center">النوع</th>
|
||||||
style="color: #112e40"><span>TENHAL</span> | <span>تنحل</span></a>
|
<th class="text-center">القيمة</th>
|
||||||
|
<th class="text-center">ضريبة الخدمة</th>
|
||||||
|
<th class="text-center">الإجمالي</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for service in data.additional_services.services %}
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">{{ service.0.name }}</td>
|
||||||
|
<td class="text-center">{{ service.0.price|floatformat:2 }}</td>
|
||||||
|
<td class="text-center">{{ service.1|floatformat:2 }}</td>
|
||||||
|
<td class="text-center">{{ service.0.price_|floatformat:2 }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center"></td>
|
||||||
|
<td class="text-center">{{ data.total_services_amount|floatformat:'2g'}}</td>
|
||||||
|
<td class="text-center">{{ data.total_services_vat|floatformat:'2g'}}</td>
|
||||||
|
<td class="text-center">{{ data.total_services_amount_|floatformat:'2g' }}</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="document-details" style="margin-top: 30px; ">
|
||||||
|
<div class="section text-left">
|
||||||
|
<p><span class="label">إجمالي ضريبة القيمة المضافة : </span> {{ data.total_vat|floatformat:'2g' }}</p>
|
||||||
|
<p><span class="label">الإجمالي الكلي : </span> {{ data.grand_total|floatformat:'2g' }}</p>
|
||||||
|
<p><span class="label">كتابةً : </span> {{ data.grand_total|num_to_words }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr style="border-bottom:1px solid #ccc; ">
|
||||||
|
|
||||||
|
<div class="document-footer">
|
||||||
|
<div class="footer-logo">
|
||||||
|
<img src="{% static 'images/logos/logo-d-pdf.png' %}" alt="Logo" />
|
||||||
|
<p>
|
||||||
|
<span>Haikal</span> | <span>هيكل</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer-powered">
|
||||||
|
<p>
|
||||||
|
<span>Powered by </span>
|
||||||
|
<a href="https://tenhal.sa"><span>TENHAL</span> | <span>تنحل</span></a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="{% static 'vendors/bootstrap/bootstrap.min.js' %}"></script>
|
</div>
|
||||||
<script src="{% static 'js/html2pdf.bundle.min.js' %}"></script>
|
</body>
|
||||||
<script>
|
|
||||||
document.getElementById('download-pdf').addEventListener('click', function () {
|
|
||||||
html2pdf().from(document.getElementById('invoice-content')).set({
|
|
||||||
margin: 0,
|
|
||||||
filename: "{{ invoice.invoice_number }}_{{ invoice.customer.customer_name }}_{{invoice.date_approved|date:'Y-m-d' }}.pdf",
|
|
||||||
image: { type: 'jpeg', quality: 0.98 },
|
|
||||||
html2canvas: { scale: 3 },
|
|
||||||
jsPDF: { unit: 'mm', format: 'a3', orientation: 'portrait' }
|
|
||||||
}).save();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
359
templates/sales/invoices/invoice_preview_ar.html
Normal file
359
templates/sales/invoices/invoice_preview_ar.html
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
{% load static custom_filters num2words_tags %}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ar" dir="rtl">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
|
||||||
|
<title>فاتورة</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* General Body and Font Styles */
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Page Layout and Margins for PDF */
|
||||||
|
|
||||||
|
@page {
|
||||||
|
size: A4;
|
||||||
|
margin: 20mm;
|
||||||
|
@top-left {
|
||||||
|
content: "صفحة " counter(page) " من " counter(pages);
|
||||||
|
font-size: 10px;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header Styles */
|
||||||
|
.document-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 2px solid #333;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.document-header .logo {
|
||||||
|
max-width: 150px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.document-header h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
margin: 0;
|
||||||
|
color: #0056b3;
|
||||||
|
}
|
||||||
|
.document-header address {
|
||||||
|
text-align: right;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Document Details Section */
|
||||||
|
.document-details {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
.document-details .section {
|
||||||
|
width: 48%;
|
||||||
|
}
|
||||||
|
.document-details h2 {
|
||||||
|
font-size: 14px;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
.document-details p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.document-details .label {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Table Styles */
|
||||||
|
.table {
|
||||||
|
width: 80%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 20px auto; /* Centering the table */
|
||||||
|
}
|
||||||
|
.table th, .table td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 8px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.table th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.table tfoot td {
|
||||||
|
border-top: 2px solid #333;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.text-right {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.text-left {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.text-center {
|
||||||
|
text-align: center;2px solid #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive and layout helpers */
|
||||||
|
.table-container {
|
||||||
|
width: 100%;
|
||||||
|
overflow-x: auto;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.table-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
.table-header span {
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: lighter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer Styles */
|
||||||
|
.document-footer {
|
||||||
|
position: relative;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 10px;
|
||||||
|
color: #888;
|
||||||
|
|
||||||
|
padding-top: 15px;
|
||||||
|
margin: 0 20mm;
|
||||||
|
|
||||||
|
}
|
||||||
|
.footer-flex {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.footer-logo {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.footer-logo img {
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
.footer-logo p {
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.footer-powered p {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
.footer-powered span {
|
||||||
|
font-weight: lighter;
|
||||||
|
}
|
||||||
|
.footer-powered a {
|
||||||
|
color: #112e40;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="document-header">
|
||||||
|
<div>
|
||||||
|
<h1>{{ dealer_info.name }}</h1>
|
||||||
|
<address>
|
||||||
|
العنوان : {{ dealer_info.address }}<br>
|
||||||
|
البريد الإلكتروني : {{ dealer_info.user.email }}<br>
|
||||||
|
الهاتف : {{ dealer_info.phone_number }}<br>
|
||||||
|
رقم السجل التجاري : {{dealer_info.crn }}<br>
|
||||||
|
الرقم الضريبي : {{ dealer_info.vrn }}
|
||||||
|
</address>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="dealer-logo ">
|
||||||
|
{% if dealer_info.logo %}
|
||||||
|
<img class="rounded-soft"
|
||||||
|
style="max-width:100px;
|
||||||
|
max-height:100px"
|
||||||
|
src="{{dealer_info.logo.url|default:'' }}"
|
||||||
|
alt="Dealer Logo" />
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>فاتورة</h1>
|
||||||
|
<h2 style="font-size: 18px;">{{ invoice.invoice_number }}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="document-details">
|
||||||
|
<div class="section">
|
||||||
|
<h2>{{ customer_obj.full_name }}: إلى</h2>
|
||||||
|
<p><span class="label">العميل : {{ customer_obj.full_name }}</span></p>
|
||||||
|
<p><span class="label">البريد الإلكتروني : {{ customer_obj.email |default:"N/A"}}</span></p>
|
||||||
|
<p><span class="label">الهاتف : {{ customer_obj.phone_number|default:"N/A" }}</span></p>
|
||||||
|
<p><span class="label">العنوان : {{ customer_obj.address|default:"N/A" }}</span></p>
|
||||||
|
</div>
|
||||||
|
<div class="section text-left">
|
||||||
|
<h2>التفاصيل:</h2>
|
||||||
|
<p><span class="label">رقم عرض السعر : </span> {{ invoice.invoice_number }}</p>
|
||||||
|
<p><span class="label">تاريخ الإصدار : </span> {{ invoice.date_approved|date:"Y/m/d" }}</p>
|
||||||
|
<p><span class="label">طريقة الدفع : </span> {{ invoice.get_terms_display }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-header">
|
||||||
|
<span>تفاصيل السيارة</span>
|
||||||
|
</div>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الصانع</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الموديل</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>السلسلة</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الفئة</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>السنة</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>رقم الهيكل</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">{{ data.car.id_car_make.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.id_car_model.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.id_car_serie.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.id_car_trim.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.year }}</td>
|
||||||
|
<td class="text-center">{{ data.car.vin }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-header">
|
||||||
|
<span>التفاصيل المالية</span>
|
||||||
|
</div>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الكمية</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>سعر الوحدة</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الخصم</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الضريبة</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>الإجمالي</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">1</td>
|
||||||
|
<td class="text-center">{{ data.car.marked_price|currency_format }}</td>
|
||||||
|
<td class="text-center">{{ data.discount_amount|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ data.vat_amount|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ data.final_price|currency_format }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if data.additional_services %}
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-header">
|
||||||
|
<span>الخدمات الإضافية</span>
|
||||||
|
</div>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">النوع</th>
|
||||||
|
<th class="text-center">القيمة</th>
|
||||||
|
<th class="text-center">ضريبة الخدمة</th>
|
||||||
|
<th class="text-center">الإجمالي</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for service in data.additional_services.services %}
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">{{ service.0.name }}</td>
|
||||||
|
<td class="text-center">{{ service.0.price|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ service.1|currency_format }}</td>
|
||||||
|
<td class="text-center">{{ service.0.price_|currency_format}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center"></td>
|
||||||
|
<td class="text-center">{{ data.total_services_amount|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ data.total_services_vat|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ data.total_services_amount_|currency_format }}</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="document-details" style="margin-top: 30px; ">
|
||||||
|
<div class="section text-left">
|
||||||
|
<p><span class="label">إجمالي ضريبة القيمة المضافة : </span> {{ data.total_vat|currency_format }}</p>
|
||||||
|
<p><span class="label">الإجمالي الكلي : </span> {{ data.grand_total|currency_format}}</p>
|
||||||
|
<p><span class="label">كتابةً : </span> {{ data.grand_total|num_to_words }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr style="border-bottom:1px solid #ccc; ">
|
||||||
|
|
||||||
|
<div class="document-footer">
|
||||||
|
<div class="footer-logo">
|
||||||
|
<img src="{% static 'images/logos/logo-d-pdf.png' %}" alt="Logo" />
|
||||||
|
<p>
|
||||||
|
<span>Haikal</span> | <span>هيكل</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer-powered">
|
||||||
|
<p>
|
||||||
|
<span>Powered by </span>
|
||||||
|
<a href="https://tenhal.sa"><span>TENHAL</span> | <span>تنحل</span></a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
357
templates/sales/invoices/invoice_preview_en.html
Normal file
357
templates/sales/invoices/invoice_preview_en.html
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
{% load static custom_filters num2words_tags %}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Invoice</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* General Body and Font Styles */
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Page Layout and Margins for PDF */
|
||||||
|
@page {
|
||||||
|
size: A4;
|
||||||
|
margin: 20mm;
|
||||||
|
@top-left {
|
||||||
|
content: "صفحة " counter(page) " من " counter(pages);
|
||||||
|
font-size: 10px;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header Styles */
|
||||||
|
.document-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 2px solid #333;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.document-header .logo {
|
||||||
|
max-width: 150px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.document-header h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
margin: 0;
|
||||||
|
color: #0056b3;
|
||||||
|
}
|
||||||
|
.document-header address {
|
||||||
|
text-align: right;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Document Details Section */
|
||||||
|
.document-details {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
.document-details .section {
|
||||||
|
width: 48%;
|
||||||
|
}
|
||||||
|
.document-details h2 {
|
||||||
|
font-size: 14px;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
.document-details p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.document-details .label {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Table Styles */
|
||||||
|
.table {
|
||||||
|
width: 80%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 20px auto; /* Centering the table */
|
||||||
|
}
|
||||||
|
.table th, .table td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 8px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.table th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.table tfoot td {
|
||||||
|
border-top: 2px solid #333;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.text-right {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.text-left {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.text-center {
|
||||||
|
text-align: center;2px solid #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive and layout helpers */
|
||||||
|
.table-container {
|
||||||
|
width: 100%;
|
||||||
|
overflow-x: auto;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.table-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
.table-header span {
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: lighter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer Styles */
|
||||||
|
.document-footer {
|
||||||
|
position: relative;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 10px;
|
||||||
|
color: #888;
|
||||||
|
|
||||||
|
padding-top: 15px;
|
||||||
|
margin: 0 20mm;
|
||||||
|
|
||||||
|
}
|
||||||
|
.footer-flex {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.footer-logo {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.footer-logo img {
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
.footer-logo p {
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.footer-powered p {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
.footer-powered span {
|
||||||
|
font-weight: lighter;
|
||||||
|
}
|
||||||
|
.footer-powered a {
|
||||||
|
color: #112e40;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="document-header">
|
||||||
|
<div>
|
||||||
|
<h1>{{ dealer_info.name }}</h1>
|
||||||
|
<address>
|
||||||
|
Address : {{ dealer_info.address }}<br>
|
||||||
|
Email : {{ dealer_info.user.email }}<br>
|
||||||
|
Phone : {{ dealer_info.phone_number }}<br>
|
||||||
|
Commercial Registration No. : {{dealer_info.crn }}<br>
|
||||||
|
VAT No. : {{ dealer_info.vrn }}
|
||||||
|
</address>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="dealer-logo ">
|
||||||
|
{% if dealer_info.logo %}
|
||||||
|
<img class="rounded-soft"
|
||||||
|
style="max-width:100px;
|
||||||
|
max-height:100px"
|
||||||
|
src="{{dealer_info.logo.url|default:'' }}"
|
||||||
|
alt="Dealer Logo" />
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>Invoice</h1>
|
||||||
|
<h2 style="font-size: 18px;">{{ invoice.invoice_number }}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="document-details">
|
||||||
|
<div class="section">
|
||||||
|
<h2>To: {{ customer_obj.full_name }}</h2>
|
||||||
|
<p><span class="label">Customer : {{ customer_obj.full_name }}</span></p>
|
||||||
|
<p><span class="label">Email : {{ customer_obj.email |default:"N/A"}}</span></p>
|
||||||
|
<p><span class="label">Phone : {{ customer_obj.phone_number|default:"N/A" }}</span></p>
|
||||||
|
<p><span class="label">Address : {{ customer_obj.address|default:"N/A" }}</span></p>
|
||||||
|
</div>
|
||||||
|
<div class="section text-right">
|
||||||
|
<h2>Details:</h2>
|
||||||
|
<p><span class="label">Quotation Number : </span> {{ invoice.invoice_number }}</p>
|
||||||
|
<p><span class="label">Issue Date : </span> {{ invoice.date_approved|date:"Y/m/d" }}</p>
|
||||||
|
<p><span class="label">Payment Method : </span> {{ invoiceget_terms_display }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-header">
|
||||||
|
<span>Car Details</span>
|
||||||
|
</div>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Make</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Model</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Series</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Trim</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Year</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>VIN</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">{{ data.car.id_car_make.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.id_car_model.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.id_car_serie.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.id_car_trim.name }}</td>
|
||||||
|
<td class="text-center">{{ data.car.year }}</td>
|
||||||
|
<td class="text-center">{{ data.car.vin }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-header">
|
||||||
|
<span>Financial Details</span>
|
||||||
|
</div>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Quantity</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Unit Price</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Discount</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>VAT</span>
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
<span>Total</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">1</td>
|
||||||
|
<td class="text-center">{{ data.car.marked_price|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ data.discount_amount|currency_format }}</td>
|
||||||
|
<td class="text-center">{{ data.vat_amount|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ data.final_price|currency_format }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if data.additional_services %}
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table-header">
|
||||||
|
<span>Additional Services</span>
|
||||||
|
</div>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">Type</th>
|
||||||
|
<th class="text-center">Value</th>
|
||||||
|
<th class="text-center">Service VAT</th>
|
||||||
|
<th class="text-center">Total</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for service in data.additional_services.services %}
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">{{ service.0.name }}</td>
|
||||||
|
<td class="text-center">{{ service.0.price|currency_format }}</td>
|
||||||
|
<td class="text-center">{{ service.1|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ service.0.price_|currency_format}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center"></td>
|
||||||
|
<td class="text-center">{{ data.total_services_amount|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ data.total_services_vat|currency_format}}</td>
|
||||||
|
<td class="text-center">{{ data.total_services_amount_|currency_format }}</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="document-details" style="margin-top: 30px; ">
|
||||||
|
<div class="section text-right">
|
||||||
|
<p><span class="label">Total VAT : </span> {{ data.total_vat|currency_format}}</p>
|
||||||
|
<p><span class="label">Grand Total : </span> {{ data.grand_total|currency_format}}</p>
|
||||||
|
<p><span class="label">In words : </span> {{ data.grand_total|num_to_words }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr style="border-bottom:1px solid #ccc; ">
|
||||||
|
|
||||||
|
<div class="document-footer">
|
||||||
|
<div class="footer-logo">
|
||||||
|
<img src="{% static 'images/logos/logo-d-pdf.png' %}" alt="Logo" />
|
||||||
|
<p>
|
||||||
|
<span>Haikal</span> | <span>هيكل</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer-powered">
|
||||||
|
<p>
|
||||||
|
<span>Powered by </span>
|
||||||
|
<a href="https://tenhal.sa"><span>TENHAL</span> | <span>تنحل</span></a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -15,9 +15,9 @@
|
|||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
{% comment %} <div class="col-auto">
|
||||||
<div class="d-flex">{% include 'partials/search_box.html' %}</div>
|
<div class="d-flex">{% include 'partials/search_box.html' %}</div>
|
||||||
</div>
|
</div> {% endcomment %}
|
||||||
</div>
|
</div>
|
||||||
<div class="table-responsive scrollbar mx-n1 px-1">
|
<div class="table-responsive scrollbar mx-n1 px-1">
|
||||||
<table class="table align-items-center table-flush">
|
<table class="table align-items-center table-flush">
|
||||||
|
|||||||
2
templates/vendors/vendors_list.html
vendored
2
templates/vendors/vendors_list.html
vendored
@ -101,7 +101,7 @@
|
|||||||
<a class="fs-8 fw-bold"
|
<a class="fs-8 fw-bold"
|
||||||
href="{% url 'vendor_detail' request.dealer.slug vendor.slug %}">{{ vendor.arabic_name }}</a>
|
href="{% url 'vendor_detail' request.dealer.slug vendor.slug %}">{{ vendor.arabic_name }}</a>
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<p class="mb-0 text-body-highlight fw-semibold fs-9 me-2">{{ vendor.name }}</p>
|
<p class="mb-0 text-body-highlight fw-semibold fs-9 me-2">{{ vendor.name|title }}</p>
|
||||||
<!--<span class="badge badge-phoenix badge-phoenix-primary">{{ vendor.vendor_model.uuid }}</span>-->
|
<!--<span class="badge badge-phoenix badge-phoenix-primary">{{ vendor.vendor_model.uuid }}</span>-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user