This commit is contained in:
Faheedkhan 2025-07-01 12:31:16 +03:00
commit e441983674
18 changed files with 182 additions and 134 deletions

View File

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

View File

@ -143,7 +143,6 @@ class DealerSlugMiddleware:
return None
if dealer_slug.lower() != request.dealer.slug.lower():
print(dealer_slug)
logger.warning(f"Dealer slug mismatch: {dealer_slug} != {request.dealer.slug}")
raise Http404("Dealer slug mismatch")

View File

@ -904,15 +904,28 @@ def create_po_item_upload(sender,instance,created,**kwargs):
models.PoItemsUploaded.objects.create(dealer=dealer,po=instance, item=item, status="fulfilled")
##########################################################
######################Notification########################
##########################################################
@receiver(post_save, sender=PurchaseOrderModel)
def create_po_fulfilled_notification(sender,instance,created,**kwargs):
if instance.po_status == "fulfilled":
dealer = models.Dealer.objects.get(entity=instance.entity)
accountants = models.CustomGroup.objects.filter(dealer=dealer,name="Inventory").first().group.user_set.exclude(email=dealer.user.email)
for accountant in accountants:
models.Notification.objects.create(
user=accountant,
message=f"""
New Purchase Order {instance.po_number} has been added to dealer {instance.dealer.name}.
<a href="{instance.get_absolute_url()}" target="_blank">View</a>
""",
)
@receiver(post_save, sender=models.Car)
def car_created_notification(sender, instance, created, **kwargs):
if created:
accountants = models.CustomGroup.objects.filter(dealer=instance.dealer,name="Accountant").first().group.user_set.exclude(email=instance.dealer.user.email)
accountants = models.CustomGroup.objects.filter(dealer=instance.dealer,name__in=["Manager","Accountant"]).first().group.user_set.all()
for accountant in accountants:
models.Notification.objects.create(
user=accountant,
@ -971,13 +984,18 @@ def lead_created_notification(sender, instance, created, **kwargs):
<a href="{reverse('lead_detail',kwargs={'dealer_slug':instance.dealer.slug,'slug':instance.slug})}" target="_blank">View</a>
""",
)
@receiver(post_save, sender=models.Lead)
def lead_created_notification(sender, instance, created, **kwargs):
if created:
models.Notification.objects.create(
user=instance.staff.user,
message=f"""
New Lead has been added.
<a href="{reverse('lead_detail',kwargs={'dealer_slug':instance.dealer.slug,'slug':instance.slug})}" target="_blank">View</a>
""",
)
# @receiver(post_save, sender=models.Lead)
# def lead_created_notification(sender, instance, created, **kwargs):
# if created:
# models.Notification.objects.create(
# user=instance.staff.user,
# message=f"""
# New Lead has been added.
# <a href="{reverse('lead_detail',kwargs={'dealer_slug':instance.dealer.slug,'slug':instance.slug})}" target="_blank">View</a>
# """,
# )
# send notification after car is sold {manager,dealer}
# after po review send notification to {manager} to approve po
# after estimate review send notification to {manager} to approve estimate

View File

@ -207,11 +207,7 @@ urlpatterns = [
path("notifications/stream/", views.sse_stream, name="sse_stream"),
path("notifications/fetch/", views.fetch_notifications, name="fetch_notifications"),
path(
"notifications/",
views.NotificationListView.as_view(),
name="notifications_history",
),
path("notifications/list/", views.NotificationListView.as_view(), name="notifications_history"),
path(
"notifications/<int:notification_id>/mark_as_read/",
@ -1086,17 +1082,17 @@ urlpatterns = [
#########
# Purchase Order
path(
"<slug:dealer_slug>/purchase_orders/",
"<slug:dealer_slug>/<slug:entity_slug>/purchase_orders/",
views.PurchaseOrderListView.as_view(),
name="purchase_order_list",
),
path(
"<slug:dealer_slug>/purchase_orders/new/",
"<slug:dealer_slug>/purchase_orders/<slug:entity_slug>/new/",
views.PurchaseOrderCreateView,
name="purchase_order_create",
),
path(
"<slug:dealer_slug>/purchase_orders/<uuid:pk>/detail/",
"<slug:dealer_slug>/purchase_orders/<slug:entity_slug>/<uuid:pk>/detail/",
views.PurchaseOrderDetailView.as_view(),
name="purchase_order_detail",
),

View File

@ -3499,6 +3499,20 @@ class BankAccountCreateView(
kwargs["entity_slug"] = entity.slug
kwargs["user_model"] = entity.admin
return kwargs
def get_form(self, form_class=None):
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
form = super().get_form(form_class)
account_qs = dealer.entity.get_all_accounts().filter(
role__in=[
roles.ASSET_CA_CASH,
roles.LIABILITY_CL_ACC_PAYABLE,
roles.LIABILITY_LTL_MORTGAGE_PAYABLE
])
form.fields['account_model'].queryset = account_qs
return form
def get_success_url(self):
return reverse_lazy("bank_account_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"]})
@ -3567,7 +3581,18 @@ class BankAccountUpdateView(
kwargs["entity_slug"] = entity.slug # Get entity_slug from URL
kwargs["user_model"] = entity.admin # Get user_model from the request
return kwargs
def get_form(self, form_class=None):
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
form = super().get_form(form_class)
account_qs = dealer.entity.get_all_accounts().filter(
role__in=[
roles.ASSET_CA_CASH,
roles.LIABILITY_CL_ACC_PAYABLE,
roles.LIABILITY_LTL_MORTGAGE_PAYABLE
])
form.fields['account_model'].queryset = account_qs
return form
def get_success_url(self):
return reverse_lazy(
"bank_account_detail",
@ -6320,14 +6345,19 @@ class ItemExpenseCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateV
permission_required = ["django_ledger.add_itemmodel"]
def get_form_kwargs(self):
dealer = get_user_type(self.request)
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
kwargs = super().get_form_kwargs()
kwargs["entity_slug"] = dealer.entity.slug
kwargs["user_model"] = dealer.entity.admin
return kwargs
# def get_form(self,form_class=None):
# dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
# form = super().get_form(form_class)
# form.fields["uom"].queryset = dealer.entity.get_uom_all()
# return form
def form_valid(self, form):
dealer = get_user_type(self.request)
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
form.instance.entity = dealer.entity
return super().form_valid(form)
def get_success_url(self):
@ -6880,15 +6910,15 @@ class BillModelCreateView(CreateView):
return {"date_draft": get_localdate()}
def get_form(self, form_class=None):
dealer = get_user_type(self.request)
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
return BillModelCreateForm(entity_model=dealer.entity, **self.get_form_kwargs())
def form_valid(self, form):
dealer = get_user_type(self.request)
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
bill_model: BillModel = form.save(commit=False)
ledger_model, bill_model = bill_model.configure(
entity_slug=dealer.entity.slug,
user_model=self.request.user,
entity_slug=dealer.entity,
user_model=dealer.entity.admin,
commit_ledger=True,
)
@ -8836,7 +8866,7 @@ def payment_callback(request,dealer_slug):
return render(request, "payment_failed.html", {"message": message})
def sse_stream(request):
def sse_stream(request):
def event_stream():
last_id = request.GET.get("last_id", 0)
while True:
@ -8895,7 +8925,7 @@ def mark_all_notifications_as_read(request):
@login_required
def notifications_history(request):
models.Notification.objects.filter(user=request.user, is_read=False).update(
read=True
is_read=True
)
return JsonResponse({"status": "success"})
@ -9216,18 +9246,23 @@ def permenant_delete_account(request,dealer_slug, content_type, slug):
#####################################################################
def PurchaseOrderCreateView(request, dealer_slug):
def PurchaseOrderCreateView(request, dealer_slug,entity_slug):
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
entity = dealer.entity
if request.method == "POST":
po = entity.create_purchase_order(po_title=request.POST.get("po_title"))
po.entity = entity
po.save()
try:
po = entity.create_purchase_order(po_title=request.POST.get("po_title"))
po.entity = entity
po.save()
except ValidationError as e:
messages.error(request, str(e))
return redirect("purchase_order_create", dealer_slug=dealer.slug, entity_slug=entity.slug)
messages.success(request, _("Purchase order created successfully"))
return redirect("purchase_order_detail", dealer_slug=dealer.slug, pk=po.pk)
return redirect("purchase_order_detail", dealer_slug=dealer.slug, entity_slug=entity.slug, pk=po.pk)
form = PurchaseOrderModelCreateForm(
entity_slug=entity.slug, user_model=entity.admin
entity_slug=entity.slug,
user_model=entity.admin,
)
return render(request, "purchase_orders/po_form.html", {"form": form})
@ -9346,14 +9381,12 @@ class PurchaseOrderDetailView(PurchaseOrderModelDetailViewBase):
context_object_name = "po_model"
def get_queryset(self):
dealer = get_user_type(self.request)
self.queryset = PurchaseOrderModel.objects.for_entity(
entity_slug=dealer.entity.slug, user_model=dealer.entity.admin
).select_related("entity", "ce_model")
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
self.queryset = dealer.entity.get_purchase_orders().select_related("entity", "ce_model")
return super().get_queryset()
def get_context_data(self, **kwargs):
dealer = get_user_type(self.request)
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
context = super().get_context_data(**kwargs)
context["entity_slug"] = dealer.entity.slug
return context
@ -9367,77 +9400,76 @@ class PurchaseOrderListView(LoginRequiredMixin, PermissionRequiredMixin, ListVie
permission_required = ["inventory.view_carfinance"]
def get_queryset(self):
dealer = get_user_type(self.request)
entity = dealer.entity
return self.model.objects.filter(entity=entity)
def get_queryset(self):
dealer = get_user_type(self.request)
entity = dealer.entity
queryset = self.model.objects.filter(entity=entity)
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
return self.model.objects.filter(entity=dealer.entity)
query = self.request.GET.get('q') # This is generic: looks for 'q' from GET
# def get_queryset(self):
# dealer = get_user_type(self.request)
# entity = dealer.entity
# queryset = self.model.objects.filter(entity=entity)
if query:
# Start with an empty Q object for the search filters
search_filters = Q()
# query = self.request.GET.get('q') # This is generic: looks for 'q' from GET
# 1. Try to parse the query as a date
parsed_date = None
date_formats = [
'%Y-%m-%d', # 2023-10-26
'%m/%d/%Y', # 10/26/2023
'%d-%m-%Y', # 26-10-2023
'%B %d, %Y', # October 26, 2023
'%b %d, %Y', # Oct 26, 2023
'%Y/%m/%d', # 2023/10/26
'%Y-%m', # 2023-10 (for year-month search)
'%Y',
'%b %d',
'%B %d' # 2023 (for year search)
]
# if query:
# # Start with an empty Q object for the search filters
# search_filters = Q()
for fmt in date_formats:
try:
# For '%Y-%m' and '%Y', we only care about year/month, not exact day
if fmt == '%Y-%m':
parsed_date = datetime.strptime(query, fmt)
search_filters |= Q(created__year=parsed_date.year, created__month=parsed_date.month)
break
elif fmt == '%Y':
parsed_date = datetime.strptime(query, fmt)
search_filters |= Q(created__year=parsed_date.year)
break
else:
parsed_date = datetime.strptime(query, fmt).date()
search_filters |= Q(created__date=parsed_date) # Matches exact date part of datetime field
break # Found a match, no need to try other formats
except ValueError:
continue # Try next format
# # 1. Try to parse the query as a date
# parsed_date = None
# date_formats = [
# '%Y-%m-%d', # 2023-10-26
# '%m/%d/%Y', # 10/26/2023
# '%d-%m-%Y', # 26-10-2023
# '%B %d, %Y', # October 26, 2023
# '%b %d, %Y', # Oct 26, 2023
# '%Y/%m/%d', # 2023/10/26
# '%Y-%m', # 2023-10 (for year-month search)
# '%Y',
# '%b %d',
# '%B %d' # 2023 (for year search)
# ]
# 2. Add text-based search filters (always apply these)
# Combine them with OR operator
text_filters = (
Q(po_number__icontains=query) |
Q(po_title__icontains=query) |
Q(po_status__icontains=query) |
Q(created__icontains=query)
# for fmt in date_formats:
# try:
# # For '%Y-%m' and '%Y', we only care about year/month, not exact day
# if fmt == '%Y-%m':
# parsed_date = datetime.strptime(query, fmt)
# search_filters |= Q(created__year=parsed_date.year, created__month=parsed_date.month)
# break
# elif fmt == '%Y':
# parsed_date = datetime.strptime(query, fmt)
# search_filters |= Q(created__year=parsed_date.year)
# break
# else:
# parsed_date = datetime.strptime(query, fmt).date()
# search_filters |= Q(created__date=parsed_date) # Matches exact date part of datetime field
# break # Found a match, no need to try other formats
# except ValueError:
# continue # Try next format
)
# # 2. Add text-based search filters (always apply these)
# # Combine them with OR operator
# text_filters = (
# Q(po_number__icontains=query) |
# Q(po_title__icontains=query) |
# Q(po_status__icontains=query) |
# Q(created__icontains=query)
# )
# # If a date was successfully parsed, combine with text filters
# if parsed_date:
# # Use a combined Q object. This means it will search for
# # (date_match OR po_number_match OR po_title_match)
# queryset = queryset.filter(search_filters | text_filters).distinct()
# else:
# # If no date was parsed, only apply text filters
# queryset = queryset.filter(text_filters).distinct()
# return queryset
# If a date was successfully parsed, combine with text filters
if parsed_date:
# Use a combined Q object. This means it will search for
# (date_match OR po_number_match OR po_title_match)
queryset = queryset.filter(search_filters | text_filters).distinct()
else:
# If no date was parsed, only apply text filters
queryset = queryset.filter(text_filters).distinct()
return queryset
def get_context_data(self, **kwargs):
dealer = get_user_type(self.request)
@ -9451,7 +9483,7 @@ class PurchaseOrderUpdateView(PurchaseOrderModelUpdateViewBase):
context_object_name = "po_model"
def get_context_data(self, itemtxs_formset=None, **kwargs):
dealer = self.request.dealer
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
context = super().get_context_data(**kwargs)
context["entity_slug"] = dealer.entity.slug
po_model: PurchaseOrderModel = self.object

View File

@ -185,7 +185,7 @@
<td class="align-items-start white-space-nowrap pe-2">
{% if bill_item.po_model_id %}
<a class="btn btn-sm btn-phoenix-primary"
href="{% url 'purchase_order_detail' request.dealer.slug bill_item.po_model_id %}">
href="{% url 'purchase_order_detail' request.dealer.slug request.dealer.entity.slug bill_item.po_model_id %}">
{% trans 'View PO' %}
</a>
{% endif %}

View File

@ -72,7 +72,7 @@
{% currency_symbol %}{{ f.instance.po_total_amount | currency_format }}
</span>
<a class="btn btn-sm btn-phoenix-info mt-1"
href="{% url 'purchase_order_detail' dealer_slug f.instance.po_model_id %}">
href="{% url 'purchase_order_detail' dealer_slug entity_slug f.instance.po_model_id %}">
{% trans 'View PO' %}
</a>
</div>

View File

@ -14,7 +14,7 @@
<div class="d-flex">
<div class="me-3 flex-1 mt-2">
<h4 class="fs-9 text-body-emphasis">{{ _("System")}}:</h4>
{% if not notification.is_read %}
{% if notification.is_read %}
<p class="fs-9 text-body-highlight"><span class="far fa-envelope text-success-dark fs-8 me-1"></span><span class="me-1">{{ notification.message|safe }}</span> <span class="ms-2 text-body-tertiary text-opacity-85 fw-bold fs-10 text-end">{{ notification.created|timesince }}</span></p>
{% else %}
<p class="fs-9 text-body-highlight"><span class="far fa-envelope-open text-danger-dark fs-8 me-1"></span><span>{{ notification.message|safe }}</span> <span class="ms-2 text-body-tertiary text-opacity-85 fw-bold fs-10 text-end">{{ notification.created|timesince }}</span></p>
@ -48,7 +48,5 @@
<p>No notifications found.</p>
{% endif %}
{% endblock %}

View File

@ -37,7 +37,7 @@
</div>
<div class="col-6 col-md-4 col-xxl-2 text-center border-translucent border-start-xxl border-end-xxl-0 border-bottom-xxl-0 border-end border-bottom pb-4 pb-xxl-0 ">
<span class="uil fs-5 lh-1 uil-receipt-alt text-secondary"></span>
<a href="{% url 'purchase_order_list' request.dealer.slug %}"><h4 class="fs-6 pt-3">{{ purchase_orders }}</h4></a>
<a href="{% url 'purchase_order_list' request.dealer.slug request.dealer.entity.slug %}"><h4 class="fs-6 pt-3">{{ purchase_orders }}</h4></a>
<p class="fs-9 mb-0">{{ _("Purchase Orders")}}</p>
</div>
</div>

View File

@ -108,8 +108,6 @@
<button type="submit" class="btn btn-primary me-2">
<i class="fas fa-save me-1"></i>{% trans "Save Changes" %}
</button>
<a href="{% url 'group_detail' request.dealer.slug group.pk %}" class="btn btn-phoenix-secondary "><i class="fa-solid fa-ban me-1"></i> {% trans "Cancel"|capfirst %}</a>
</div>
</div>
</div>

View File

@ -45,13 +45,15 @@
</div>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'upload_cars' request.dealer.slug %}">
<div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-file-import"></span></span><span class="nav-link-text">{% trans "Bulk Upload"|capfirst %}</span>
</div>
</a>
{% if perms.inventory.add_car %}
<li class="nav-item">
<a class="nav-link" href="{% url 'upload_cars' request.dealer.slug %}">
<div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-file-import"></span></span><span class="nav-link-text">{% trans "Bulk Upload"|capfirst %}</span>
</div>
</a>
</li>
{% endif %}
</ul>
</div>
</div>
@ -262,7 +264,7 @@
{% endif %}
<li class="nav-item">
<a class="nav-link" href="{% url 'purchase_order_list' request.dealer.slug %}">
<a class="nav-link" href="{% url 'purchase_order_list' request.dealer.slug request.dealer.entity.slug %}">
<div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-warehouse"></span></span><span class="nav-link-text">{% trans "purchase Orders"|capfirst %}</span>
</div>

View File

@ -44,7 +44,7 @@
<div class="row">
<div class="col-md-6">
<p><strong>{{ _("Bank Account Name") }}:</strong> {{ bank_account.name }}</p>
<p><strong>{{ _("Cash Account") }}:</strong> {{ bank_account.cash_account }}</p>
<p><strong>{{ _("Cash Account") }}:</strong> {{ bank_account }}</p>
</div>
<div class="col-md-6">
<p><strong>{{ _("Amount") }}:</strong> {{ bank_account.amount }}</p>

View File

@ -228,7 +228,7 @@
{% else %}
<div class="card border-0 shadow-sm text-center py-5">
<div class="card-body">
<a href="{% url 'purchase_order_create' request.dealer.slug %}" class="text-decoration-none">
<a href="{% url 'purchase_order_create' request.dealer.slug request.dealer.entity.slug %}" class="text-decoration-none">
<span class="text-muted mb-3 d-inline-block">{% icon "ic:baseline-add-circle-outline" 48 %}</span>
<h3 class="h4 text-muted">{% trans 'New Purchase Order' %}</h3>
</a>

View File

@ -17,7 +17,7 @@
</div>
<a class="btn btn-phoenix-primary w-100 py-2"
href="{% url 'purchase_order_list' request.dealer.slug %}">
href="{% url 'purchase_order_list' request.dealer.slug request.dealer.entity.slug %}">
<i class="fas fa-list me-2"></i>{% trans 'PO List' %}
</a>
</div>

View File

@ -57,7 +57,7 @@
<button class="btn btn-phoenix-primary" data-bs-toggle="modal" data-bs-target="#POModal"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-receipt"></i> {% trans 'View Purchase Order' %}</span></button>
<a href="{% url 'purchase_order_list' request.dealer.slug %}" class="btn btn-phoenix-secondary">Back to List</a>
<a href="{% url 'purchase_order_list' request.dealer.slug request.dealer.entity.slug %}" class="btn btn-phoenix-secondary">Back to List</a>
</div>
</div>

View File

@ -19,7 +19,7 @@
{{ _("Purchase Orders") |capfirst }}
</h2>
<div>
<a href="{% url 'purchase_order_create' request.dealer.slug %}"
<a href="{% url 'purchase_order_create' request.dealer.slug request.dealer.entity.slug %}"
class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{{ _("Create New PO") }}</a>
</div>
</div>
@ -65,7 +65,7 @@
<div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a href="{% url 'purchase_order_detail' request.dealer.slug po.pk %}" class="dropdown-item text-success-dark">{% trans 'Purchase Order Detail' %}</a>
<a href="{% url 'purchase_order_detail' request.dealer.slug request.dealer.entity.slug po.pk %}" class="dropdown-item text-success-dark">{% trans 'Purchase Order Detail' %}</a>
{% if po.po_status == 'fulfilled' %}
<a href="{% url 'view_items_inventory' dealer_slug=request.dealer.slug entity_slug=entity_slug po_pk=po.pk %}" class="dropdown-item text-success-dark">{% trans 'Add Inventory Items' %}</a>
{% else %}

View File

@ -26,9 +26,9 @@
<button type="submit"
class="btn btn-phoenix-success w-100 my-2">{% trans 'Save PO' %}
</button>
<a href="{% url 'purchase_order_detail' request.dealer.slug po_model.uuid %}"
<a href="{% url 'purchase_order_detail' request.dealer.slug request.dealer.entity.slug po_model.uuid %}"
class="btn btn-phoenix-secondary w-100 my-2">{% trans 'Back to PO Detail' %}</a>
<a href="{% url 'purchase_order_list' request.dealer.slug %}"
<a href="{% url 'purchase_order_list' request.dealer.slug request.dealer.entity.slug %}"
class="btn btn-phoenix-info
info w-100 my-2">{% trans 'PO List' %}</a>
</div>

View File

@ -65,7 +65,9 @@
{% elif estimate.status == 'in_review' %}
<span class="badge text-bg-info">{% trans "In Review" %}</span>
{% elif estimate.status == 'approved' %}
<span class="badge text-bg-success">{% trans "Approved" %}</span>
{% if perms.django_ledger.change_estimatemodel %}
<span class="badge text-bg-success">{% trans "Approved" %}</span>
{% endif %}
{% elif estimate.status == 'completed' %}
<span class="badge text-bg-success">{% trans "Completed" %}</span>
{% elif estimate.status == 'canceled' %}
@ -83,15 +85,17 @@
{% if estimate.sale_orders.first %}
<!--if sale order exist-->
<a href="{% url 'invoice_create' request.dealer.slug estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-receipt"></i> {% trans 'Create Invoice' %}</span></a>
<a href="{% url 'order_detail' request.dealer.slug estimate.sale_orders.first.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{{ _("Preview Sale Order") }}</span></a>
{% else %}
<a href="{% url 'create_sale_order' request.dealer.slug estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-file-import"></i> {% trans 'Create Sale Order' %}</span></a>
{% comment %} {% endcomment %}
{% if perms.djagno_ledger.add_invoice %}
<a href="{% url 'invoice_create' request.dealer.slug estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-receipt"></i> {% trans 'Create Invoice' %}</span></a>
{% endif %}
<a href="{% url 'order_detail' request.dealer.slug estimate.sale_orders.first.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{{ _("Preview Sale Order") }}</span></a>
{% else %}
<a href="{% url 'create_sale_order' request.dealer.slug estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-file-import"></i> {% trans 'Create Sale Order' %}</span></a>
{% comment %} {% endcomment %}
{% endif %}
{% elif estimate.status == 'completed' %}
<a href="{% url 'order_detail' request.dealer.slug estimate.sale_orders.first.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{{ _("Preview Sale Order") }}</span></a>
<a href="{% url 'invoice_detail' request.dealer.slug estimate.invoicemodel_set.first.pk %}" class="btn btn-phoenix-primary btn-sm" type="button"><i class="fa-solid fa-receipt"></i>