add management commands for invoice due date

This commit is contained in:
ismail 2025-08-06 19:35:55 +03:00
parent 65d7e8c685
commit 87dabb97cc
8 changed files with 226 additions and 65 deletions

View File

@ -0,0 +1,134 @@
import logging
from datetime import timedelta
from django.urls import reverse
from django.conf import settings
from django.utils import timezone
from inventory.tasks import send_email
from django.core.management.base import BaseCommand
from django.template.loader import render_to_string
from django.utils.translation import gettext_lazy as _
from django.contrib.contenttypes.models import ContentType
from django_ledger.models import InvoiceModel,EstimateModel
from inventory.models import ExtraInfo,Notification,CustomGroup
logger = logging.getLogger(__name__)
class Command(BaseCommand):
help = "Handles invoices due date reminders"
def handle(self, *args, **options):
self.stdout.write("Starting invoices due date reminders..")
# 1. Send expiration reminders
self.invocie_expiration_reminders()
# self.invoice_past_due()
# # 2. Deactivate expired plans
# self.deactivate_expired_plans()
# # 3. Clean up old incomplete orders
# self.cleanup_old_orders()
# self.stdout.write("Reminders completed!")
def invocie_expiration_reminders(self):
"""Queue email reminders for expiring plans"""
reminder_days = getattr(settings, 'INVOICE_PAST_DUE_REMIND', [3, 7, 14])
today = timezone.now().date()
for days in reminder_days:
target_date = today + timedelta(days=days)
expiring_plans = InvoiceModel.objects.filter(
date_due=target_date
).select_related('customer','ce_model')
for inv in expiring_plans:
# dealer = inv.customer.customer_set.first().dealer
subject = f"Your invoice is due in {days} days"
message = render_to_string('emails/invoice_past_due_reminder.txt', {
'customer_name': inv.customer.customer_name,
'invoice_number': inv.invoice_number,
'amount_due': inv.amount_due,
'days_past_due': inv.due_in_days(),
'SITE_NAME': settings.SITE_NAME
})
send_email(
'noreply@yourdomain.com',
inv.customer.email,
subject,
message,
)
self.stdout.write(f"Queuing {expiring_plans} reminders for {target_date}")
def invoice_past_due(self):
"""Queue email reminders for expiring plans"""
today = timezone.now().date()
expiring_plans = InvoiceModel.objects.filter(
date_due__lte = today
).select_related('customer','ce_model')
# Send email
for inv in expiring_plans:
dealer = inv.customer.customer_set.first().dealer
subject = f"Your invoice is past due"
message = render_to_string('emails/invoice_past_due.txt', {
'customer_name': inv.customer.customer_name,
'invoice_number': inv.invoice_number,
'amount_due': inv.amount_due,
'days_past_due': (today - inv.date_due).days,
'SITE_NAME': settings.SITE_NAME
})
# send notification to accountatnt
recipients = (
CustomGroup.objects.filter(dealer=dealer, name="Accountant")
.first()
.group.user_set.exclude(email=dealer.user.email)
.distinct()
)
for rec in recipients:
Notification.objects.create(
user=rec,
message=_(
"""
Invoice {invoice_number} is past due,please your
<a href="{url}" target="_blank">View</a>.
"""
).format(
invoice_number=inv.invoice_number,
url=reverse(
"invoice_detail",
kwargs={"dealer_slug": dealer.slug, "entity_slug": dealer.entity.slug, "pk": inv.pk},
),
),
)
# send email to customer
send_email(
'noreply@yourdomain.com',
inv.customer.email,
subject,
message,
)
self.stdout.write(f"Queuing {expiring_plans} reminders for {today}")
# def deactivate_expired_plans(self):
# """Deactivate plans that have expired (synchronous)"""
# expired_plans = UserPlan.objects.filter(
# active=True,
# expire__lt=timezone.now().date()
# )
# count = expired_plans.update(active=False)
# self.stdout.write(f"Deactivated {count} expired plans")
# def cleanup_old_orders(self):
# """Delete incomplete orders older than 30 days"""
# cutoff = timezone.now() - timedelta(days=30)
# count, _ = Order.objects.filter(
# created__lt=cutoff,
# status=Order.STATUS.NEW
# ).delete()
# self.stdout.write(f"Cleaned up {count} old incomplete orders")

View File

@ -2197,7 +2197,7 @@ class DealerUpdateView(
def get_success_url(self): def get_success_url(self):
return reverse("dealer_detail", kwargs={"slug": self.object.slug}) return reverse("dealer_detail", kwargs={"slug": self.object.slug})
class StaffDetailView(LoginRequiredMixin, DetailView): class StaffDetailView(LoginRequiredMixin, DetailView):
""" """
Represents a detailed view for a Dealer model. Represents a detailed view for a Dealer model.
@ -2218,7 +2218,7 @@ class StaffDetailView(LoginRequiredMixin, DetailView):
model = models.Staff model = models.Staff
template_name = "staff/staff_detail.html" template_name = "staff/staff_detail.html"
context_object_name = "staff" context_object_name = "staff"
def dealer_vat_rate_update(request, slug): def dealer_vat_rate_update(request, slug):
@ -6890,7 +6890,7 @@ class OpportunityCreateView(
template_name = "crm/opportunities/opportunity_form.html" template_name = "crm/opportunities/opportunity_form.html"
success_message = _("Opportunity created successfully.") success_message = _("Opportunity created successfully.")
permission_required = ["inventory.add_opportunity"] permission_required = ["inventory.add_opportunity"]
def get_initial(self): def get_initial(self):
initial = super().get_initial() initial = super().get_initial()
dealer = get_object_or_404(models.Dealer, slug=self.kwargs.get("dealer_slug")) dealer = get_object_or_404(models.Dealer, slug=self.kwargs.get("dealer_slug"))
@ -6966,7 +6966,7 @@ class OpportunityUpdateView(
template_name = "crm/opportunities/opportunity_form.html" template_name = "crm/opportunities/opportunity_form.html"
success_message = _("Opportunity updated successfully.") success_message = _("Opportunity updated successfully.")
permission_required = ["inventory.change_opportunity"] permission_required = ["inventory.change_opportunity"]
def get_form(self, form_class=None): def get_form(self, form_class=None):
form = super().get_form(form_class) form = super().get_form(form_class)
@ -7018,7 +7018,7 @@ class OpportunityStageUpdateView(
form_class = forms.OpportunityStageForm form_class = forms.OpportunityStageForm
success_message = _("Opportunity Stage updated successfully.") success_message = _("Opportunity Stage updated successfully.")
permission_required = ["inventory.change_opportunity"] permission_required = ["inventory.change_opportunity"]
def get_success_url(self): def get_success_url(self):
return reverse_lazy( return reverse_lazy(
@ -7051,7 +7051,7 @@ class OpportunityDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailV
template_name = "crm/opportunities/opportunity_detail.html" template_name = "crm/opportunities/opportunity_detail.html"
context_object_name = "opportunity" context_object_name = "opportunity"
permission_required = ["inventory.view_opportunity"] permission_required = ["inventory.view_opportunity"]
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
dealer = get_object_or_404(models.Dealer, slug=self.kwargs.get("dealer_slug")) dealer = get_object_or_404(models.Dealer, slug=self.kwargs.get("dealer_slug"))
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -7144,7 +7144,7 @@ class OpportunityListView(LoginRequiredMixin, PermissionRequiredMixin, ListView)
staff = self.request.staff staff = self.request.staff
queryset = models.Opportunity.objects.filter(dealer=dealer, lead__staff=staff) queryset = models.Opportunity.objects.filter(dealer=dealer, lead__staff=staff)
# Stage filter # Stage filter
stage = self.request.GET.get("stage") stage = self.request.GET.get("stage")
@ -7424,7 +7424,7 @@ class ItemServiceListView(LoginRequiredMixin, PermissionRequiredMixin, ListView)
class ItemExpenseCreateView(LoginRequiredMixin, PermissionRequiredMixin,SuccessMessageMixin, CreateView): class ItemExpenseCreateView(LoginRequiredMixin, PermissionRequiredMixin,SuccessMessageMixin, CreateView):
""" """
Represents a view for creating item expense entries. Represents a view for creating item expense entries.
@ -7518,7 +7518,7 @@ class ItemExpenseUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateV
class ItemExpenseListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): class ItemExpenseListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
""" """
Handles the display of a list of item expenses. Handles the display of a list of item expenses.
@ -9517,7 +9517,7 @@ def payment_callback(request, dealer_slug):
payment_status = request.GET.get("status") payment_status = request.GET.get("status")
logger.info(f"Received payment callback for dealer_slug: {dealer_slug}, payment_id: {payment_id}, status: {payment_status}") logger.info(f"Received payment callback for dealer_slug: {dealer_slug}, payment_id: {payment_id}, status: {payment_status}")
order = Order.objects.filter(user=dealer.user, status=1).first() # Status 1 = NEW order = Order.objects.filter(user=dealer.user, status=1).first() # Status 1 = NEW
print(order) print(order)
if payment_status == "paid": if payment_status == "paid":
logger.info(f"Payment successful for transaction ID {payment_id}. Processing order completion.") logger.info(f"Payment successful for transaction ID {payment_id}. Processing order completion.")
@ -10400,7 +10400,7 @@ class PurchaseOrderListView(LoginRequiredMixin, PermissionRequiredMixin, ListVie
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context["entity_slug"] = dealer.entity.slug context["entity_slug"] = dealer.entity.slug
context["vendors"] = vendors context["vendors"] = vendors
return context return context
@ -10881,7 +10881,7 @@ def car_sale_report_view(request, dealer_slug):
years = models.Car.objects.filter(dealer=dealer, status='sold').values_list('year', flat=True).distinct().order_by('-year') years = models.Car.objects.filter(dealer=dealer, status='sold').values_list('year', flat=True).distinct().order_by('-year')
# # Calculate summary data for the filtered results # # Calculate summary data for the filtered results
total_revenue = cars_sold.aggregate(total_revenue=Sum('finances__marked_price'))['total_revenue'] or 0 total_revenue = cars_sold.aggregate(total_revenue=Sum('finances__marked_price'))['total_revenue'] or 0
# total_vat = cars_sold.aggregate(total_vat=Sum('finances__vat_amount'))['total_vat'] or 0 # total_vat = cars_sold.aggregate(total_vat=Sum('finances__vat_amount'))['total_vat'] or 0
total_discount = cars_sold.aggregate(total_discount=Sum('finances__discount_amount'))['total_discount'] or 0 total_discount = cars_sold.aggregate(total_discount=Sum('finances__discount_amount'))['total_discount'] or 0
@ -10921,22 +10921,22 @@ def car_sale_report_csv_export(request,dealer_slug):
writer = csv.writer(response) writer = csv.writer(response)
header=[ header=[
'Make', 'Make',
'VIN', 'VIN',
'Model', 'Model',
'Year', 'Year',
'Serie', 'Serie',
'Trim', 'Trim',
'Mileage', 'Mileage',
'Stock Type', 'Stock Type',
'Created Date', 'Created Date',
'Sold Date', 'Sold Date',
'Cost Price', 'Cost Price',
'Marked Price', 'Marked Price',
'Discount Amount', 'Discount Amount',
'Selling Price', 'Selling Price',
'Tax Amount', 'Tax Amount',
'Invoice Number', 'Invoice Number',
] ]
writer.writerow(header) writer.writerow(header)
@ -11007,11 +11007,9 @@ class RecallDetailView(DetailView):
return context return context
def RecallFilterView(request): def RecallFilterView(request):
context = {'make_data': models.CarMake.objects.all()} context = {'make_data': models.CarMake.objects.all()}
if request.method == "POST": if request.method == "POST":
print(request.POST)
make = request.POST.get('make') make = request.POST.get('make')
model = request.POST.get('model') model = request.POST.get('model')
serie = request.POST.get('serie') serie = request.POST.get('serie')

View File

@ -0,0 +1,10 @@
Hello {{ customer_name }},
This is a friendly reminder that your invoice for {{ invoice_number }} is now {{ days_past_due }} days past due.
Please settle your outstanding balance of {{ amount_due }} .
If you have already paid, please disregard this notice.
Best regards,
{{ SITE_NAME }} Team

View File

@ -0,0 +1,11 @@
Hello {{ customer_name }},
This is a friendly reminder that your invoice for {{ invoice_number }} is due in {{ days_past_due }} days.
Please settle your outstanding balance of {{ amount_due }} before the due date to avoid any late fees.
If you have already paid, please disregard this notice.
Best regards,
{{ SITE_NAME }} Team

View File

@ -492,7 +492,7 @@
{% if request.is_dealer %} {% if request.is_dealer %}
<h6 class="mt-2 text-body-emphasis">{{ user.dealer.get_local_name }}</h6> <h6 class="mt-2 text-body-emphasis">{{ user.dealer.get_local_name }}</h6>
{% else %} {% else %}
<h6 class="mt-2 text-body-emphasis">{{ user.staffmember.staff.get_local_name }}</h6> <h6 class="mt-2 text-body-emphasis">{{ user.staff.get_local_name }}</h6>
{% endif %} {% endif %}
</div> </div>
</div> </div>

View File

@ -1,6 +1,7 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load i18n %} {% load i18n %}
{% load static %} {% load static %}
{% load tenhal_tag %}
{% block title %} {% block title %}
{{ _("Car Sale Report") |capfirst }} {{ _("Car Sale Report") |capfirst }}
{% endblock title %} {% endblock title %}
@ -8,7 +9,7 @@
{% block content%} {% block content%}
<style> <style>
.summary-card { .summary-card {
border: 1px solid var(--card-border); border: 1px solid var(--card-border);
border-radius: .5rem; border-radius: .5rem;
@ -34,9 +35,9 @@
.summary-card .card-text { .summary-card .card-text {
font-size: 2.25rem; font-size: 2.25rem;
font-weight: 700; font-weight: 700;
} }
</style> </style>
<div class="container-fluid report-container"> <div class="container-fluid report-container">
@ -98,8 +99,8 @@
<div class="col-md-6 col-lg-3"> <div class="col-md-6 col-lg-3">
<div class="card summary-card"> <div class="card summary-card">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">{% trans 'Total Revenue' %}<i class="fas fa-dollar-sign ms-2"></i></h5> <h5 class="card-title">{% trans 'Total Revenue' %}<span class="icon-saudi_riyal"></span></h5>
<p class="card-text">{{ total_revenue|floatformat:2 }}</p> <p class="card-text">{{ total_revenue|floatformat:2 }} <span class="icon-saudi_riyal"></span></p>
</div> </div>
</div> </div>
</div> </div>
@ -107,7 +108,7 @@
<div class="card summary-card"> <div class="card summary-card">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">{% trans 'Total VAT Amount' %}<i class="fas fa-percent ms-2"></i></h5> <h5 class="card-title">{% trans 'Total VAT Amount' %}<i class="fas fa-percent ms-2"></i></h5>
<p class="card-text">{{ 10000|floatformat:2 }}</p> <p class="card-text">{{ 10000|floatformat:2 }} <span class="icon-saudi_riyal"></span></p>
</div> </div>
</div> </div>
</div> </div>
@ -115,7 +116,7 @@
<div class="card summary-card"> <div class="card summary-card">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">{% trans 'Total Discount Amount' %}<i class="fas fa-tag ms-2"></i></h5> <h5 class="card-title">{% trans 'Total Discount Amount' %}<i class="fas fa-tag ms-2"></i></h5>
<p class="card-text">{{ total_discount|floatformat:2 }}</p> <p class="card-text">{{ total_discount|floatformat:2 }} <span class="icon-saudi_riyal"></span></p>
</div> </div>
</div> </div>
</div> </div>
@ -174,14 +175,14 @@
<td class="fs-9">{{ car.id_car_serie.name }}</td> <td class="fs-9">{{ car.id_car_serie.name }}</td>
<td class="fs-9">{{ car.id_car_trim.name }}</td> <td class="fs-9">{{ car.id_car_trim.name }}</td>
<td class="fs-9">{{ car.mileage }}</td> <td class="fs-9">{{ car.mileage }}</td>
<td class="fs-9">{{ car.stock_type }}</td> <td class="fs-9">{{ car.stock_type|capfirst }}</td>
<td class="fs-9">{{ car.created_at|date }}</td> <td class="fs-9">{{ car.created_at|date }}</td>
<td class="fs-9">{{ car.invoice.date_paid|date|default_if_none:"-" }}</td> <td class="fs-9">{{ car.invoice.date_paid|date|default_if_none:"-" }}</td>
<td class="fs-9">{{ car.finances.cost_price }}</td> <td class="fs-9">{{ car.finances.cost_price }} <span class="icon-saudi_riyal"></span></td>
<td class="fs-9">{{ car.finances.marked_price }}</td> <td class="fs-9">{{ car.finances.marked_price }} <span class="icon-saudi_riyal"></span></td>
<td class="fs-9">{{ car.finances.discount_amount }}</td> <td class="fs-9">{{ car.finances.discount_amount }} <span class="icon-saudi_riyal"></span></td>
<td class="fs-9">{{ car.finances.selling_price }}</td> <td class="fs-9">{{ car.finances.selling_price }} <span class="icon-saudi_riyal"></span></td>
<td class="fs-9">{{ car.finances.vat_amount }}</td> <td class="fs-9">{{ car.finances.vat_amount }} <span class="icon-saudi_riyal"></span></td>
<td class="fs-9">{{ car.invoice.invoice_number }}</td> <td class="fs-9">{{ car.invoice.invoice_number }}</td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@ -252,13 +252,14 @@
<td class="align-middle text-body-tertiary fw-semibold">{{ item.total }}</td> <td class="align-middle text-body-tertiary fw-semibold">{{ item.total }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
<tr class="bg-body-secondary total-sum"> <tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="7">{% trans "Discount Amount" %}</td> <td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="7">{% trans "Discount Amount" %}</td>
<td class="align-middle text-start text-danger fw-semibold"> <td class="align-middle text-start text-danger fw-semibold">
<form action="{% url 'update_estimate_discount' request.dealer.slug estimate.pk %}" {% if estimate.is_draft %}
method="post"> <form action="{% url 'update_estimate_discount' request.dealer.slug estimate.pk %}"
{% csrf_token %} method="post">
{% csrf_token %}
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<input type="number" <input type="number"
class="form-control" class="form-control"
@ -266,10 +267,13 @@
value="{{ data.total_discount }}" value="{{ data.total_discount }}"
step="0.01" step="0.01"
style="width: 1px"> style="width: 1px">
<span class="input-group-text"><span class="icon-saudi_riyal"></span></span> <span class="input-group-text"><span class="icon-saudi_riyal"></span></span>
<button type="submit" class="btn btn-sm btn-phoenix-primary ms-n2">{% trans "Update" %}</button> <button type="submit" class="btn btn-sm btn-phoenix-primary ms-n2">{% trans "Update" %}</button>
</div> </div>
</form> </form>
{% else %}
{{ data.total_discount }} <span class="icon-saudi_riyal"></span>
{% endif %}
</td> </td>
</tr> </tr>
<tr class="bg-body-secondary total-sum"> <tr class="bg-body-secondary total-sum">
@ -285,12 +289,14 @@
<small><span class="fw-semibold">+ {{ service.name }} - {{ service.price_|floatformat }}<span class="icon-saudi_riyal"></span></span></small> <small><span class="fw-semibold">+ {{ service.name }} - {{ service.price_|floatformat }}<span class="icon-saudi_riyal"></span></span></small>
<br> <br>
{% endfor %} {% endfor %}
{% if estimate.is_draft %}
<button class="btn btn-phoenix-primary btn-xs ms-auto" <button class="btn btn-phoenix-primary btn-xs ms-auto"
type="button" type="button"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#additionalModal"> data-bs-target="#additionalModal">
<span class="fas fa-plus me-1"></span>{{ _("Add") }} <span class="fas fa-plus me-1"></span>{{ _("Add") }}
</button> </button>
{% endif %}
</td> </td>
</tr> </tr>
<tr class="bg-body-secondary total-sum"> <tr class="bg-body-secondary total-sum">
@ -345,7 +351,7 @@ document.addEventListener('htmx:afterSwap', initEstimateFunctions);
function initEstimateFunctions() { function initEstimateFunctions() {
// Initialize calculateTotals if estimate table exists // Initialize calculateTotals if estimate table exists
// Initialize form action setter if form exists // Initialize form action setter if form exists
const confirmForm = document.getElementById('confirmForm'); const confirmForm = document.getElementById('confirmForm');

View File

@ -1,6 +1,7 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load i18n %} {% load i18n %}
{% load custom_filters %} {% load custom_filters %}
{% load tenhal_tag %}
{% block title %}{{ page_title }} - {{ sale_order.formatted_order_id }}{% endblock %} {% block title %}{{ page_title }} - {{ sale_order.formatted_order_id }}{% endblock %}
{% block content %} {% block content %}
<div class="container mt-4"> <div class="container mt-4">
@ -17,9 +18,9 @@
<!-- Basic Information --> <!-- Basic Information -->
<div class="row mb-4"> <div class="row mb-4">
<div class="col-md-4"> <div class="col-md-4">
<h4>{% trans "Customer Information" %}</h4> <h4 class="mb-3">{% trans "Customer Information" %}</h4>
<p> <p>
<strong>{% trans "Name" %}:</strong> {{ sale_order.full_name }} <strong>{% trans "Name" %}:</strong> {{ sale_order.full_name|title }}
<br> <br>
{% if sale_order.customer %} {% if sale_order.customer %}
<strong>{% trans "Contact" %}:</strong> {{ sale_order.customer.phone_number }} <strong>{% trans "Contact" %}:</strong> {{ sale_order.customer.phone_number }}
@ -29,7 +30,7 @@
</p> </p>
</div> </div>
<div class="col-md-4"> <div class="col-md-4">
<h4>{% trans "Order Details" %}</h4> <h4 class="mb-3">{% trans "Order Details" %}</h4>
<p> <p>
<strong>{% trans "Order Date" %}:</strong> {{ sale_order.order_date|date }} <strong>{% trans "Order Date" %}:</strong> {{ sale_order.order_date|date }}
<br> <br>
@ -187,7 +188,7 @@
<strong>{% trans "Amount Paid" %}:</strong> <strong>{% trans "Amount Paid" %}:</strong>
</td> </td>
<td style="padding-left: 0.5rem;"> <td style="padding-left: 0.5rem;">
<span class="currency">{{ CURRENCY }}</span>{{ sale_order.invoice.amount_paid|floatformat:2 }} <span class="icon-saudi_riyal"></span>{{ sale_order.invoice.amount_paid|floatformat:2 }}
</td> </td>
</tr> </tr>
<tr> <tr>
@ -195,7 +196,7 @@
<strong>{% trans "Balance Due" %}:</strong> <strong>{% trans "Balance Due" %}:</strong>
</td> </td>
<td style="padding-left: 0.5rem;"> <td style="padding-left: 0.5rem;">
<span class="currency">{{ CURRENCY }}</span>{{ sale_order.invoice.amount_due|floatformat:2 }} <span class="icon-saudi_riyal"></span>{{ sale_order.invoice.amount_due|floatformat:2 }}
</td> </td>
</tr> </tr>
<tr> <tr>
@ -203,7 +204,7 @@
<strong>{% trans "Amount Unearned" %}:</strong> <strong>{% trans "Amount Unearned" %}:</strong>
</td> </td>
<td style="padding-left: 0.5rem;"> <td style="padding-left: 0.5rem;">
<span class="currency">{{ CURRENCY }}</span>{{ sale_order.invoice.amount_unearned|floatformat:2 }} <span class="icon-saudi_riyal"></span>{{ sale_order.invoice.amount_unearned|floatformat:2 }}
</td> </td>
</tr> </tr>
<tr> <tr>
@ -211,7 +212,7 @@
<strong>{% trans "Amount Receivable" %}:</strong> <strong>{% trans "Amount Receivable" %}:</strong>
</td> </td>
<td style="padding-left: 0.5rem;"> <td style="padding-left: 0.5rem;">
<span class="currency">{{ CURRENCY }}</span>{{ sale_order.invoice.amount_receivable|floatformat:2 }} <span class="icon-saudi_riyal"></span>{{ sale_order.invoice.amount_receivable|floatformat:2 }}
</td> </td>
</tr> </tr>
</tbody> </tbody>