add management commands for invoice due date
This commit is contained in:
parent
65d7e8c685
commit
87dabb97cc
134
inventory/management/commands/invoices_due_date_reminder.py
Normal file
134
inventory/management/commands/invoices_due_date_reminder.py
Normal 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")
|
||||
@ -2197,7 +2197,7 @@ class DealerUpdateView(
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse("dealer_detail", kwargs={"slug": self.object.slug})
|
||||
|
||||
|
||||
class StaffDetailView(LoginRequiredMixin, DetailView):
|
||||
"""
|
||||
Represents a detailed view for a Dealer model.
|
||||
@ -2218,7 +2218,7 @@ class StaffDetailView(LoginRequiredMixin, DetailView):
|
||||
model = models.Staff
|
||||
template_name = "staff/staff_detail.html"
|
||||
context_object_name = "staff"
|
||||
|
||||
|
||||
|
||||
|
||||
def dealer_vat_rate_update(request, slug):
|
||||
@ -6890,7 +6890,7 @@ class OpportunityCreateView(
|
||||
template_name = "crm/opportunities/opportunity_form.html"
|
||||
success_message = _("Opportunity created successfully.")
|
||||
permission_required = ["inventory.add_opportunity"]
|
||||
|
||||
|
||||
def get_initial(self):
|
||||
initial = super().get_initial()
|
||||
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"
|
||||
success_message = _("Opportunity updated successfully.")
|
||||
permission_required = ["inventory.change_opportunity"]
|
||||
|
||||
|
||||
|
||||
def get_form(self, form_class=None):
|
||||
form = super().get_form(form_class)
|
||||
@ -7018,7 +7018,7 @@ class OpportunityStageUpdateView(
|
||||
form_class = forms.OpportunityStageForm
|
||||
success_message = _("Opportunity Stage updated successfully.")
|
||||
permission_required = ["inventory.change_opportunity"]
|
||||
|
||||
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy(
|
||||
@ -7051,7 +7051,7 @@ class OpportunityDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailV
|
||||
template_name = "crm/opportunities/opportunity_detail.html"
|
||||
context_object_name = "opportunity"
|
||||
permission_required = ["inventory.view_opportunity"]
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
dealer = get_object_or_404(models.Dealer, slug=self.kwargs.get("dealer_slug"))
|
||||
context = super().get_context_data(**kwargs)
|
||||
@ -7144,7 +7144,7 @@ class OpportunityListView(LoginRequiredMixin, PermissionRequiredMixin, ListView)
|
||||
staff = self.request.staff
|
||||
queryset = models.Opportunity.objects.filter(dealer=dealer, lead__staff=staff)
|
||||
|
||||
|
||||
|
||||
|
||||
# Stage filter
|
||||
stage = self.request.GET.get("stage")
|
||||
@ -7424,7 +7424,7 @@ class ItemServiceListView(LoginRequiredMixin, PermissionRequiredMixin, ListView)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class ItemExpenseCreateView(LoginRequiredMixin, PermissionRequiredMixin,SuccessMessageMixin, CreateView):
|
||||
"""
|
||||
Represents a view for creating item expense entries.
|
||||
@ -7518,7 +7518,7 @@ class ItemExpenseUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateV
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class ItemExpenseListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
||||
"""
|
||||
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")
|
||||
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
|
||||
|
||||
|
||||
print(order)
|
||||
if payment_status == "paid":
|
||||
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["entity_slug"] = dealer.entity.slug
|
||||
context["vendors"] = vendors
|
||||
|
||||
|
||||
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')
|
||||
|
||||
# # Calculate summary data for the filtered results
|
||||
|
||||
|
||||
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_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)
|
||||
|
||||
header=[
|
||||
'Make',
|
||||
'VIN',
|
||||
'Model',
|
||||
'Year',
|
||||
'Serie',
|
||||
'Trim',
|
||||
'Mileage',
|
||||
'Stock Type',
|
||||
'Created Date',
|
||||
'Sold Date',
|
||||
'Cost Price',
|
||||
'Marked Price',
|
||||
'Discount Amount',
|
||||
'Selling Price',
|
||||
'Tax Amount',
|
||||
'Invoice Number',
|
||||
'Make',
|
||||
'VIN',
|
||||
'Model',
|
||||
'Year',
|
||||
'Serie',
|
||||
'Trim',
|
||||
'Mileage',
|
||||
'Stock Type',
|
||||
'Created Date',
|
||||
'Sold Date',
|
||||
'Cost Price',
|
||||
'Marked Price',
|
||||
'Discount Amount',
|
||||
'Selling Price',
|
||||
'Tax Amount',
|
||||
'Invoice Number',
|
||||
]
|
||||
writer.writerow(header)
|
||||
|
||||
@ -11007,11 +11007,9 @@ class RecallDetailView(DetailView):
|
||||
return context
|
||||
|
||||
|
||||
|
||||
def RecallFilterView(request):
|
||||
context = {'make_data': models.CarMake.objects.all()}
|
||||
if request.method == "POST":
|
||||
print(request.POST)
|
||||
make = request.POST.get('make')
|
||||
model = request.POST.get('model')
|
||||
serie = request.POST.get('serie')
|
||||
|
||||
10
templates/emails/invoice_past_due.txt
Normal file
10
templates/emails/invoice_past_due.txt
Normal 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
|
||||
11
templates/emails/invoice_past_due_reminder.txt
Normal file
11
templates/emails/invoice_past_due_reminder.txt
Normal 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
|
||||
|
||||
@ -492,7 +492,7 @@
|
||||
{% if request.is_dealer %}
|
||||
<h6 class="mt-2 text-body-emphasis">{{ user.dealer.get_local_name }}</h6>
|
||||
{% 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 %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load tenhal_tag %}
|
||||
{% block title %}
|
||||
{{ _("Car Sale Report") |capfirst }}
|
||||
{% endblock title %}
|
||||
@ -8,7 +9,7 @@
|
||||
{% block content%}
|
||||
|
||||
<style>
|
||||
|
||||
|
||||
.summary-card {
|
||||
border: 1px solid var(--card-border);
|
||||
border-radius: .5rem;
|
||||
@ -34,9 +35,9 @@
|
||||
.summary-card .card-text {
|
||||
font-size: 2.25rem;
|
||||
font-weight: 700;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<div class="container-fluid report-container">
|
||||
@ -98,8 +99,8 @@
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="card summary-card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{% trans 'Total Revenue' %}<i class="fas fa-dollar-sign ms-2"></i></h5>
|
||||
<p class="card-text">{{ total_revenue|floatformat:2 }}</p>
|
||||
<h5 class="card-title">{% trans 'Total Revenue' %}<span class="icon-saudi_riyal"></span></h5>
|
||||
<p class="card-text">{{ total_revenue|floatformat:2 }} <span class="icon-saudi_riyal"></span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -107,7 +108,7 @@
|
||||
<div class="card summary-card">
|
||||
<div class="card-body">
|
||||
<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>
|
||||
@ -115,7 +116,7 @@
|
||||
<div class="card summary-card">
|
||||
<div class="card-body">
|
||||
<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>
|
||||
@ -174,14 +175,14 @@
|
||||
<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.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.invoice.date_paid|date|default_if_none:"-" }}</td>
|
||||
<td class="fs-9">{{ car.finances.cost_price }}</td>
|
||||
<td class="fs-9">{{ car.finances.marked_price }}</td>
|
||||
<td class="fs-9">{{ car.finances.discount_amount }}</td>
|
||||
<td class="fs-9">{{ car.finances.selling_price }}</td>
|
||||
<td class="fs-9">{{ car.finances.vat_amount }}</td>
|
||||
<td class="fs-9">{{ car.finances.cost_price }} <span class="icon-saudi_riyal"></span></td>
|
||||
<td class="fs-9">{{ car.finances.marked_price }} <span class="icon-saudi_riyal"></span></td>
|
||||
<td class="fs-9">{{ car.finances.discount_amount }} <span class="icon-saudi_riyal"></span></td>
|
||||
<td class="fs-9">{{ car.finances.selling_price }} <span class="icon-saudi_riyal"></span></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>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
@ -252,13 +252,14 @@
|
||||
<td class="align-middle text-body-tertiary fw-semibold">{{ item.total }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
|
||||
<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 text-start text-danger fw-semibold">
|
||||
<form action="{% url 'update_estimate_discount' request.dealer.slug estimate.pk %}"
|
||||
method="post">
|
||||
{% csrf_token %}
|
||||
{% if estimate.is_draft %}
|
||||
<form action="{% url 'update_estimate_discount' request.dealer.slug estimate.pk %}"
|
||||
method="post">
|
||||
{% csrf_token %}
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="number"
|
||||
class="form-control"
|
||||
@ -266,10 +267,13 @@
|
||||
value="{{ data.total_discount }}"
|
||||
step="0.01"
|
||||
style="width: 1px">
|
||||
<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>
|
||||
</div>
|
||||
</form>
|
||||
<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>
|
||||
</div>
|
||||
</form>
|
||||
{% else %}
|
||||
{{ data.total_discount }} <span class="icon-saudi_riyal"></span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<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>
|
||||
<br>
|
||||
{% endfor %}
|
||||
{% if estimate.is_draft %}
|
||||
<button class="btn btn-phoenix-primary btn-xs ms-auto"
|
||||
type="button"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#additionalModal">
|
||||
<span class="fas fa-plus me-1"></span>{{ _("Add") }}
|
||||
</button>
|
||||
type="button"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#additionalModal">
|
||||
<span class="fas fa-plus me-1"></span>{{ _("Add") }}
|
||||
</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="bg-body-secondary total-sum">
|
||||
@ -345,7 +351,7 @@ document.addEventListener('htmx:afterSwap', initEstimateFunctions);
|
||||
|
||||
function initEstimateFunctions() {
|
||||
// Initialize calculateTotals if estimate table exists
|
||||
|
||||
|
||||
|
||||
// Initialize form action setter if form exists
|
||||
const confirmForm = document.getElementById('confirmForm');
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
{% load custom_filters %}
|
||||
{% load tenhal_tag %}
|
||||
{% block title %}{{ page_title }} - {{ sale_order.formatted_order_id }}{% endblock %}
|
||||
{% block content %}
|
||||
<div class="container mt-4">
|
||||
@ -17,9 +18,9 @@
|
||||
<!-- Basic Information -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-4">
|
||||
<h4>{% trans "Customer Information" %}</h4>
|
||||
<h4 class="mb-3">{% trans "Customer Information" %}</h4>
|
||||
<p>
|
||||
<strong>{% trans "Name" %}:</strong> {{ sale_order.full_name }}
|
||||
<strong>{% trans "Name" %}:</strong> {{ sale_order.full_name|title }}
|
||||
<br>
|
||||
{% if sale_order.customer %}
|
||||
<strong>{% trans "Contact" %}:</strong> {{ sale_order.customer.phone_number }}
|
||||
@ -29,7 +30,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h4>{% trans "Order Details" %}</h4>
|
||||
<h4 class="mb-3">{% trans "Order Details" %}</h4>
|
||||
<p>
|
||||
<strong>{% trans "Order Date" %}:</strong> {{ sale_order.order_date|date }}
|
||||
<br>
|
||||
@ -187,7 +188,7 @@
|
||||
<strong>{% trans "Amount Paid" %}:</strong>
|
||||
</td>
|
||||
<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>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -195,7 +196,7 @@
|
||||
<strong>{% trans "Balance Due" %}:</strong>
|
||||
</td>
|
||||
<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>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -203,7 +204,7 @@
|
||||
<strong>{% trans "Amount Unearned" %}:</strong>
|
||||
</td>
|
||||
<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>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -211,7 +212,7 @@
|
||||
<strong>{% trans "Amount Receivable" %}:</strong>
|
||||
</td>
|
||||
<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>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user