update on the plans and more

This commit is contained in:
ismail 2025-07-27 16:42:02 +03:00
parent 1fd00af6ac
commit 85515bd272
21 changed files with 379 additions and 94 deletions

View File

@ -1,15 +1,15 @@
from inventory import views
from django.conf import settings
from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings
from django.conf.urls.i18n import i18n_patterns
from inventory import views
# from debug_toolbar.toolbar import debug_toolbar_urls
from inventory.notifications.sse import NotificationSSEApp
# import debug_toolbar
from schema_graph.views import Schema
from django.conf.urls.static import static
from django.conf.urls.i18n import i18n_patterns
from inventory.notifications.sse import NotificationSSEApp
# import debug_toolbar
# from two_factor.urls import urlpatterns as tf_urls
# from debug_toolbar.toolbar import debug_toolbar_urls
urlpatterns = [
# path('__debug__/', include(debug_toolbar.urls)),

View File

@ -1603,7 +1603,7 @@ class PermissionForm(forms.ModelForm):
"django_ledger.invoicemodel",
"django_ledger.vendormodel",
"django_ledger.journalentrymodel"
"django_ledger.purchaseordermodel", # TODO add purchase order
"django_ledger.purchaseordermodel",
]
permissions = cache.get(

View File

@ -0,0 +1,28 @@
from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
import datetime
from inventory.models import Dealer
from plans.models import Plan, Order,PlanPricing
User = get_user_model()
class Command(BaseCommand):
help = ""
def handle(self, *args, **options):
dealer = Dealer.objects.get(user__email="dealer6@example.com")
user = dealer.user
user.userplan.expire = datetime.datetime.now().date()
user.userplan.save()
pp = PlanPricing.objects.get(plan__name="Basic")
order = Order.objects.create(
user=user,
plan=pp.plan,
pricing=pp.pricing,
amount=pp.price,
currency="SA",
tax=15,
status=1,
)
order.complete_order()
print(user.userplan)

View File

@ -0,0 +1,72 @@
from django.core.management.base import BaseCommand
from django.utils import timezone
from django.conf import settings
from django.template.loader import render_to_string
from plans.models import UserPlan, Order
from datetime import timedelta
from django.utils.translation import activate, get_language
from django_q.tasks import async_task
import logging
from inventory.tasks import send_bilingual_reminder, handle_email_result
logger = logging.getLogger(__name__)
class Command(BaseCommand):
help = "Handles subscription plan maintenance tasks"
def handle(self, *args, **options):
self.stdout.write("Starting plans maintenance...")
# 1. Send expiration reminders
self.send_expiration_reminders()
# 2. Deactivate expired plans
self.deactivate_expired_plans()
# 3. Clean up old incomplete orders
self.cleanup_old_orders()
self.stdout.write("Maintenance completed!")
def send_expiration_reminders(self):
"""Queue email reminders for expiring plans"""
reminder_days = getattr(settings, 'PLANS_EXPIRATION_REMIND', [3, 7, 14])
today = timezone.now().date()
for days in reminder_days:
target_date = today + timedelta(days=days)
expiring_plans = UserPlan.objects.filter(
active=True,
expire=target_date
).select_related('user', 'plan')
self.stdout.write(f"Queuing {days}-day reminders for {expiring_plans.count()} plans")
for user_plan in expiring_plans:
# Queue email task
async_task(
send_bilingual_reminder,
user_plan.user_id,
user_plan.plan_id,
user_plan.expire,
days,
hook=handle_email_result
)
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

@ -321,7 +321,6 @@ class BasePurchaseOrderActionActionView(
f"User {user_username} attempting to call action '{self.action_name}' "
f"on Purchase Order ID: {po_model.pk} (Entity: {entity_slug})."
)
print(self.action_name)
if self.action_name == "mark_as_fulfilled":
try:
if po_model.can_fulfill():

View File

@ -24,6 +24,7 @@ from . import models
from django.utils.timezone import now
from django.db import transaction
from django_q.tasks import async_task
from plans.signals import order_completed, activate_user_plan
# logging
import logging
@ -1153,3 +1154,10 @@ def bill_model_after_approve_notification(sender, instance, created, **kwargs):
please complete the bill payment.
""",
)
def handle_upgrade(sender, order, **kwargs):
logger.info(f"User {order.user} upgraded to {order.plan}")
order_completed.connect(handle_upgrade)

View File

@ -1,11 +1,18 @@
import logging
from plans.models import Plan
from django.conf import settings
from django.db import transaction
from django_ledger.io import roles
from django_q.tasks import async_task
from django.core.mail import send_mail
from appointment.models import StaffMember
from django.utils.translation import activate
from django.contrib.auth import get_user_model
from allauth.account.models import EmailAddress
from django.core.mail import EmailMultiAlternatives
from inventory.models import DealerSettings, Dealer
from django.template.loader import render_to_string
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import User, Group, Permission
@ -1151,14 +1158,6 @@ def create_user_dealer(email, password, name, arabic_name, phone, crn, vrn, addr
user.set_password(password)
user.save()
#TODO remove this later
EmailAddress.objects.create(
user=user,
email=user.email,
verified=True,
primary=True
)
group = Group.objects.create(name=f"{user.pk}-Admin")
user.groups.add(group)
for perm in Permission.objects.filter(
@ -1195,3 +1194,64 @@ def create_user_dealer(email, password, name, arabic_name, phone, crn, vrn, addr
# instance.user.groups.add(group)
# transaction.on_commit(run)
def send_bilingual_reminder(user_id, plan_id, expiration_date, days_until_expire):
"""Send bilingual email reminder using Django-Q"""
try:
user = User.objects.get(id=user_id)
plan = Plan.objects.get(id=plan_id)
# Determine user language preference
user_language = getattr(user, 'language', settings.LANGUAGE_CODE)
activate(user_language)
# Context data
context = {
'user': user,
'plan': plan,
'expiration_date': expiration_date,
'days_until_expire': days_until_expire,
'SITE_NAME': settings.SITE_NAME,
'RENEWAL_URL': "url" ,#settings.RENEWAL_URL,
'direction': 'rtl' if user_language.startswith('ar') else 'ltr'
}
# Subject with translation
subject_en = f"Your {plan.name} subscription expires in {days_until_expire} days"
subject_ar = f"اشتراكك في {plan.name} ينتهي خلال {days_until_expire} أيام"
# Render templates
text_content = render_to_string([
f'emails/expiration_reminder_{user_language}.txt',
'emails/expiration_reminder.txt'
], context)
html_content = render_to_string([
f'emails/expiration_reminder_{user_language}.html',
'emails/expiration_reminder.html'
], context)
# Create email
email = EmailMultiAlternatives(
subject=subject_ar if user_language.startswith('ar') else subject_en,
body=text_content,
from_email=settings.DEFAULT_FROM_EMAIL,
to=[user.email]
)
email.attach_alternative(html_content, "text/html")
email.send()
return f"Sent to {user.email} in {user_language}"
except Exception as e:
logger.error(f"Email failed: {str(e)}")
raise
def handle_email_result(task):
"""Callback for email results"""
if task.success:
logger.info(f"Email task succeeded: {task.result}")
else:
logger.error(f"Email task failed: {task.result}")

View File

@ -701,7 +701,7 @@ urlpatterns = [
),
path(
"<slug:dealer_slug>/ledgers/<slug:entity_slug>/delete/<uuid:ledger_pk>/",
views.LedgerModelDeleteView.as_view(),
views.LedgerModelDeleteView,
name="ledger-delete",
),
path(

View File

@ -3979,7 +3979,7 @@ class BankAccountDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailV
def get_queryset(self):
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
query = self.request.GET.get("q")
qs = self.model.objects.filter(entity=dealer.entity)
qs = self.model.objects.filter(entity_model=dealer.entity)
if query:
qs = apply_search_filters(qs, query)
return qs
@ -4022,8 +4022,8 @@ class BankAccountUpdateView(
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
entity = dealer.entity
kwargs = super().get_form_kwargs()
kwargs["entity_slug"] = entity.slug # Get entity_slug from URL
kwargs["user_model"] = entity.admin # Get user_model from the request
kwargs["entity_slug"] = entity.slug
kwargs["user_model"] = entity.admin
return kwargs
def get_form(self, form_class=None):
@ -4037,7 +4037,6 @@ class BankAccountUpdateView(
]
)
form.fields["account_model"].queryset = account_qs
return form
def get_success_url(self):
@ -8893,7 +8892,7 @@ class LedgerModelDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailV
permission_required = "django_ledger.view_ledgermodel"
class LedgerModelCreateView(LedgerModelCreateViewBase):
class LedgerModelCreateView(LedgerModelCreateViewBase,SuccessMessageMixin):
"""
Handles the creation of LedgerModel entities.
@ -8909,6 +8908,7 @@ class LedgerModelCreateView(LedgerModelCreateViewBase):
template_name = "ledger/ledger/ledger_form.html"
permission_required = ["django_ledger.add_ledgermodel"]
success_message = _("Ledger created successfully")
def get_form(self, form_class=None):
return LedgerModelCreateForm(
@ -8918,10 +8918,11 @@ class LedgerModelCreateView(LedgerModelCreateViewBase):
)
def form_valid(self, form):
form.field["entity"] = self.request.dealer.entity
form.fields["entity"] = self.request.dealer.entity
return super().form_valid(form)
def get_success_url(self):
messages.success(self.request, self.success_message)
return reverse(
"ledger_list",
kwargs={
@ -8955,34 +8956,47 @@ class LedgerModelModelActionView(LedgerModelModelActionViewBase):
)
class LedgerModelDeleteView(LedgerModelDeleteViewBase, SuccessMessageMixin):
"""
Handles the deletion of a Ledger model instance.
Provides functionality for rendering a confirmation template and deleting a
ledger instance from the system. Extends functionality for managing success
messages and redirections upon successful deletion.
@login_required
@permission_required("django_ledger.delete_ledgermodel", raise_exception=True)
def LedgerModelDeleteView(request, dealer_slug,entity_slug,ledger_pk):
ledger = LedgerModel.objects.filter(pk=ledger_pk).first()
if request.method == "POST":
ledger.delete()
messages.success(request, _("Ledger deleted successfully"))
return redirect("ledger_list", dealer_slug=dealer_slug, entity_slug=entity_slug)
return render(request,"ledger/ledger/ledger_delete.html",{"ledger_model":ledger})
# class LedgerModelDeleteView(DeleteView, SuccessMessageMixin):
# """
# Handles the deletion of a Ledger model instance.
:ivar template_name: Path to the template used for rendering the delete
confirmation view.
:type template_name: str
:ivar success_message: Success message displayed upon successful deletion
of the ledger instance.
:type success_message: str
"""
# Provides functionality for rendering a confirmation template and deleting a
# ledger instance from the system. Extends functionality for managing success
# messages and redirections upon successful deletion.
template_name = "ledger/ledger/ledger_delete.html"
success_message = _("Ledger deleted successfully")
permission_required = ["django_ledger.delete_ledgermodel"]
# :ivar template_name: Path to the template used for rendering the delete
# confirmation view.
# :type template_name: str
# :ivar success_message: Success message displayed upon successful deletion
# of the ledger instance.
# :type success_message: str
# """
def get_success_url(self):
return reverse(
"ledger_list",
kwargs={
"dealer_slug": self.kwargs["dealer_slug"],
"entity_slug": self.kwargs["entity_slug"],
},
)
# template_name = "ledger/ledger/ledger_delete.html"
# pk_url_kwarg = 'ledger_pk'
# context_object_name = 'ledger_model'
# success_message = _("Ledger deleted successfully")
# permission_required = ["django_ledger.delete_ledgermodel"]
# def get_success_url(self):
# return reverse(
# "ledger_list",
# kwargs={
# "dealer_slug": self.kwargs["dealer_slug"],
# "entity_slug": self.kwargs["entity_slug"],
# },
# )
class JournalEntryListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
@ -9076,7 +9090,7 @@ class JournalEntryCreateView(
@login_required
@permission_required("django_ledger.delete_journalentrymodel", raise_exception=True)
def JournalEntryDeleteView(request, pk):
def JournalEntryDeleteView(request,dealer_slug, pk):
"""
Handles the deletion of a specific journal entry. This view facilitates
the deletion of a journal entry identified by its primary key (pk). If the
@ -9097,10 +9111,10 @@ def JournalEntryDeleteView(request, pk):
ledger = journal_entry.ledger
if not journal_entry.can_delete():
messages.error(request, _("Journal Entry cannot be deleted"))
return redirect("journalentry_list", pk=ledger.pk)
return redirect("journalentry_list",dealer_slug=dealer_slug, pk=ledger.pk)
journal_entry.delete()
messages.success(request, "Journal Entry deleted")
return redirect("journalentry_list", pk=ledger.pk)
return redirect("journalentry_list",dealer_slug=dealer_slug, pk=ledger.pk)
return render(
request,
"ledger/journal_entry/journal_entry_delete.html",
@ -9330,39 +9344,91 @@ def payment_callback(request, dealer_slug):
payment_id = request.GET.get("id")
history = models.PaymentHistory.objects.filter(transaction_id=payment_id).first()
payment_status = request.GET.get("status")
order = Order.objects.filter(user=dealer.user, status=1).first()
order = Order.objects.filter(user=dealer.user, status=1).first() # Status 1 = NEW
if payment_status == "paid":
# Get or create billing info (optional step)
billing_info, created = BillingInfo.objects.get_or_create(
user=dealer.user,
tax_number=dealer.vrn,
name=dealer.arabic_name,
street=dealer.address,
zipcode=dealer.entity.zip_code if dealer.entity.zip_code else " ",
city=dealer.entity.city if dealer.entity.city else " ",
country=dealer.entity.country if dealer.entity.country else " ",
defaults={
'tax_number': dealer.vrn,
'name': dealer.arabic_name,
'street': dealer.address,
'zipcode': dealer.entity.zip_code or " ",
'city': dealer.entity.city or " ",
'country': dealer.entity.country or " ",
}
)
if created:
userplan = UserPlan.objects.create(
user=request.user,
plan=order.plan,
active=True,
)
userplan.initialize()
order.complete_order()
history.status = "paid"
history.save()
invoice = order.get_invoices().first()
return render(
request, "payment_success.html", {"order": order, "invoice": invoice}
)
try:
# COMPLETE THE ORDER - This handles plan activation/upgrade
order.complete_order() # Critical step: activates the plan
# Update payment history
history.status = "paid"
history.save()
# Retrieve invoice
invoice = order.get_invoices().first()
return render(
request,
"payment_success.html",
{"order": order, "invoice": invoice}
)
except Exception as e:
# Handle activation errors (log, notify admin, etc.)
logger.error(f"Plan activation failed: {str(e)}")
history.status = "failed"
history.save()
return render(request, "payment_failed.html", {"message": "Plan activation error"})
elif payment_status == "failed":
history.status = "failed"
history.save()
return render(request, "payment_failed.html", {"message": message})
return render(request, "payment_failed.html", {"message": message})
# Handle unexpected status
return render(request, "payment_failed.html", {"message": "Unknown payment status"})
# def payment_callback(request, dealer_slug):
# message = request.GET.get("message")
# dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
# payment_id = request.GET.get("id")
# history = models.PaymentHistory.objects.filter(transaction_id=payment_id).first()
# payment_status = request.GET.get("status")
# order = Order.objects.filter(user=dealer.user, status=1).first()
# if payment_status == "paid":
# billing_info, created = BillingInfo.objects.get_or_create(
# user=dealer.user,
# tax_number=dealer.vrn,
# name=dealer.arabic_name,
# street=dealer.address,
# zipcode=dealer.entity.zip_code if dealer.entity.zip_code else " ",
# city=dealer.entity.city if dealer.entity.city else " ",
# country=dealer.entity.country if dealer.entity.country else " ",
# )
# if created:
# userplan = UserPlan.objects.create(
# user=request.user,
# plan=order.plan,
# active=True,
# )
# userplan.initialize()
# order.complete_order()
# history.status = "paid"
# history.save()
# invoice = order.get_invoices().first()
# return render(
# request, "payment_success.html", {"order": order, "invoice": invoice}
# )
# elif payment_status == "failed":
# history.status = "failed"
# history.save()
# return render(request, "payment_failed.html", {"message": message})
@login_required

View File

@ -1,9 +1,17 @@
{% extends "account/email/base_message.txt" %}
{% load account %}
{% load i18n %}
{% load account i18n %}
{% block content %}{% autoescape off %}{% user_display user as user_display %}{% blocktranslate with site_name=current_site.name site_domain=current_site.domain %}You're receiving this email because user {{ user_display }} has given your email address to register an account on {{ site_domain }}.{% endblocktranslate %}
{% block content %}{% autoescape off %}{% user_display user as user_display %}
{% blocktranslate with site_domain=current_site.domain %}تتلقى هذا البريد لأن {{ user_display }} استخدم بريدك للتسجيل في {{ site_domain }}.{% endblocktranslate %}
{% if code %}{% blocktranslate %}Your email verification code is listed below. Please enter it in your open browser window.{% endblocktranslate %}
{% if code %}
{% blocktranslate %}أدخل رمز التحقق في المتصفح:{% endblocktranslate %}
{{ code }}{% else %}{% blocktranslate %}To confirm this is correct, go to {{ activate_url }}{% endblocktranslate %}{% endif %}{% endautoescape %}{% endblock content %}
{{ code }}
{% blocktranslate %}ينتهي صلاحية هذا الرمز خلال {{ code_expiration }} دقيقة.{% endblocktranslate %}
{% else %}
{% blocktranslate %}أكد هذا التسجيل بالزيارة:{% endblocktranslate %}
{{ activate_url }}
{% endif %}{% endautoescape %}{% endblock content %}

View File

@ -27,6 +27,7 @@
<h3 class="mb-4">{% trans "Change Password" %}</h3>
</div>
<form method="post"
hx-boost="false"
action="{% url 'account_change_password' %}"
class="form needs-validation"
novalidate>

View File

@ -181,9 +181,9 @@ document.addEventListener('htmx:afterRequest', function(evt) {
return alert("Error: Could Not Find Resource");
}
if (evt.detail.successful != true) {
console.log(evt)
console.log(evt.detail.xhr.statusText)
/* Notify of an unexpected error, & print error to console */
notify("error", "Unexpected Error");
notify("error", `Unexpected Error ,${evt.detail.xhr.statusText}`);
}
});
document.body.addEventListener('htmx:beforeSwap', function(evt) {

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<body style="font-family: 'Segoe UI', Tahoma, sans-serif; direction: rtl;">
<p>مرحباً {{ user.get_full_name }}،</p>
<p>
اشتراكك في <strong>{{ plan.name }}</strong> سينتهي خلال
{{ days_until_expire }} يوم في {{ expiration_date|date:"j F Y" }}.
</p>
<p>
<a href="{{ RENEWAL_URL }}">جدد اشتراكك الآن</a> لمواصلة الخدمة.
</p>
<p>مع أطيب التحيات،<br>
فريق {{ SITE_NAME }}</p>
</body>
</html>

View File

@ -0,0 +1,8 @@
مرحباً {{ user.get_full_name }}،
اشتراكك في {{ plan.name }} سينتهي خلال {{ days_until_expire }} يوم في {{ expiration_date|date:"j F Y" }}.
جدد اشتراكك الآن: {{ RENEWAL_URL }}
مع أطيب التحيات،
فريق {{ SITE_NAME }}

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<body style="font-family: Arial, sans-serif; direction: {{ direction }};">
<p>Hello {{ user.get_full_name }},</p>
<p>Your <strong>{{ plan.name }}</strong> subscription will expire
in {{ days_until_expire }} days on {{ expiration_date|date:"F j, Y" }}.</p>
<p><a href="{{ RENEWAL_URL }}">Renew now</a> to continue service.</p>
<p>Best regards,<br>
The {{ SITE_NAME }} Team</p>
</body>
</html>

View File

@ -0,0 +1,8 @@
Hello {{ user.get_full_name }},
Your {{ plan.name }} subscription will expire in {{ days_until_expire }} days on {{ expiration_date|date:"F j, Y" }}.
Renew now: {{ RENEWAL_URL }}
Best regards,
{{ SITE_NAME }} Team

View File

@ -6,7 +6,7 @@
{{ _("Add New Expense") }}
{% endblock title %}
{% block content %}
<!---->
<div class="row justify-content-center mt-5 mb-3">
@ -19,7 +19,6 @@
</h3>
</div>
<div class="card-body bg-light-subtle">
<form method="post" action="">
{% csrf_token %}
{{ form|crispy }}
@ -29,11 +28,7 @@
<button class="btn btn-lg btn-phoenix-primary md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'item_expense_list' request.dealer.slug %}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
</form>
</div>
</div>
</div>

View File

@ -5,7 +5,7 @@
{{ _("Create Bill") }}
{% endblock title %}
{% block content %}
<div class="row mt-4">
<div class="row mt-4" hx-boost="true">
<h3 class="text-center">{% trans "Create Bill" %}<span class="fas fa-money-bills ms-2 text-primary"></span></h3>
<form id="mainForm" method="post" class="needs-validation">
{% csrf_token %}
@ -15,7 +15,7 @@
<button class="btn btn-sm btn-phoenix-success me-2" type="submit">
<i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}
</button>
<a href="{{ request.META.HTTP_REFERER }}"
<a href="{% url 'bill_list' request.dealer.slug %}"
class="btn btn-sm btn-phoenix-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
</form>

View File

@ -5,7 +5,7 @@
{% block content %}
<div class="row justify-content-center">
<div class="col-md-6">
<form action="{% url 'journalentry_delete' journal_entry.pk %}"
<form action="{% url 'journalentry_delete' request.dealer.slug journal_entry.pk %}"
method="post">
{% csrf_token %}
<div class="card">
@ -13,7 +13,7 @@
<h5 class="card-title fw-light">Are you sure you want to delete?</h5>
</div>
<div class="card-body text-center">
<a href="{% url 'journalentry_list' journal_entry.ledger.pk %}"
<a href="{% url 'journalentry_list' request.dealer.slug journal_entry.ledger.pk %}"
class="btn btn-phoenix-primary me-2">{% trans 'Go Back' %}</a>
<button type="submit" class="btn btn-phoenix-danger">{% trans 'Delete' %}</button>
</div>

View File

@ -27,7 +27,7 @@
{% for transaction in transactions %}
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td>{{ forloop.counter }}</td>
<td class="align-middle product white-space-nowrap py-0">{{ transaction.created|date }}</td>
<td class="align-middle product white-space-nowrap py-0">{{ transaction.created|date }}</td>
<td class="align-middle product white-space-nowrap">{{ transaction.account.name }}</td>
<td class="align-middle product white-space-nowrap">{{ transaction.account.code }}</td>
<td class="align-middle product white-space-nowrap text-success">

View File

@ -5,7 +5,7 @@
{% block content %}
<div class="row justify-content-center">
<div class="col-md-6">
<form action="{% url 'ledger-delete' entity_slug=view.kwargs.entity_slug ledger_pk=ledger_model.uuid %}"
<form action="{% url 'ledger-delete' dealer_slug=request.dealer.slug entity_slug=request.dealer.entity.slug ledger_pk=ledger_model.uuid %}"
method="post">
{% csrf_token %}
<div class="card">
@ -13,7 +13,7 @@
<h5 class="card-title fw-light">{{ ledger_model.get_delete_message }}</h5>
</div>
<div class="card-body text-center">
<a href="{% url 'ledger_list' %}" class="btn btn-phoenix-primary me-2">{% trans 'Go Back' %}</a>
<a href="{% url 'ledger_list' request.dealer.slug request.dealer.entity.slug %}" class="btn btn-phoenix-primary me-2">{% trans 'Go Back' %}</a>
<button type="submit" class="btn btn-phoenix-danger">{% trans 'Delete' %}</button>
</div>
</div>