Compare commits

..

No commits in common. "20e1811fc76442cb14da300fa2b719149dc11bc5" and "094deebf5829c8236019b50448b7e7ba0e659554" have entirely different histories.

26 changed files with 146 additions and 222 deletions

View File

@ -2448,7 +2448,12 @@ class Opportunity(models.Model):
null=True, null=True,
blank=True, blank=True,
) )
probability = models.PositiveIntegerField(validators=[validate_probability],null=True, blank=True)
amount = models.DecimalField(
max_digits=10,
decimal_places=2,
verbose_name=_("Amount"),
)
expected_revenue = models.DecimalField( expected_revenue = models.DecimalField(
max_digits=10, max_digits=10,
decimal_places=2, decimal_places=2,
@ -2456,6 +2461,8 @@ class Opportunity(models.Model):
blank=True, blank=True,
null=True, null=True,
) )
vehicle_of_interest_make = models.CharField(max_length=50, blank=True, null=True)
vehicle_of_interest_model = models.CharField(max_length=100, blank=True, null=True)
expected_close_date = models.DateField(blank=True, null=True) expected_close_date = models.DateField(blank=True, null=True)
created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created")) created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created"))
updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated")) updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated"))
@ -2516,6 +2523,8 @@ class Opportunity(models.Model):
return objects return objects
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if self.amount:
self.expected_revenue = self.amount * self.probability / 100
opportinity_for = "" opportinity_for = ""
if self.lead.lead_type == "customer": if self.lead.lead_type == "customer":
self.customer = self.lead.customer self.customer = self.lead.customer

View File

@ -1129,6 +1129,7 @@ class ChartOfAccountModelCreateView(ChartOfAccountModelModelBaseViewMixIn, Creat
}, },
) )
class ChartOfAccountModelUpdateView(ChartOfAccountModelModelBaseViewMixIn, UpdateView): class ChartOfAccountModelUpdateView(ChartOfAccountModelModelBaseViewMixIn, UpdateView):
context_object_name = "coa_model" context_object_name = "coa_model"
slug_url_kwarg = "coa_slug" slug_url_kwarg = "coa_slug"

View File

@ -4360,8 +4360,7 @@ class AccountListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
def get_queryset(self): def get_queryset(self):
query = self.request.GET.get("q") query = self.request.GET.get("q")
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
coa = ChartOfAccountModel.objects.get(entity=dealer.entity,pk=self.kwargs["coa_pk"]) or self.request.entity.get_default_coa() accounts = dealer.entity.get_all_accounts()
accounts = coa.get_coa_accounts()
return apply_search_filters(accounts, query) return apply_search_filters(accounts, query)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -4411,20 +4410,9 @@ class AccountCreateView(
permission_required = ["django_ledger.add_accountmodel"] permission_required = ["django_ledger.add_accountmodel"]
def form_valid(self, form): def form_valid(self, form):
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
instance = form.save(commit=False)
coa = ChartOfAccountModel.objects.get(entity=dealer.entity,pk=self.kwargs["coa_pk"]) or self.request.entity.get_default_coa()
# coa.insert_account(account_model=instance)
account = coa.entity.create_account(
coa_model=coa,
code=instance.code,
name=instance.name,
role=instance.role,
balance_type=_(instance.balance_type),
active=True,
)
form.instance.entity_model = dealer.entity form.instance.entity_model = dealer.entity
form.instance.coa_model = coa form.instance.coa_model = dealer.entity.get_default_coa()
form.instance.depth = 0 form.instance.depth = 0
form.instance.path = form.instance.code form.instance.path = form.instance.code
return super().form_valid(form) return super().form_valid(form)
@ -4432,15 +4420,13 @@ class AccountCreateView(
def get_form_kwargs(self): def get_form_kwargs(self):
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
kwargs = super().get_form_kwargs() kwargs = super().get_form_kwargs()
coa = ChartOfAccountModel.objects.get(entity=dealer.entity,pk=self.kwargs["coa_pk"]) or self.request.entity.get_default_coa() kwargs["coa_model"] = dealer.entity.get_default_coa()
kwargs["coa_model"] = coa
return kwargs return kwargs
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)
entity = get_user_type(self.request).entity entity = get_user_type(self.request).entity
coa = ChartOfAccountModel.objects.get(entity=entity,pk=self.kwargs["coa_pk"]) or self.request.entity.get_default_coa() form.initial["coa_model"] = entity.get_default_coa()
form.initial["coa_model"] = coa
return form return form
def get_success_url(self): def get_success_url(self):
@ -4450,13 +4436,12 @@ class AccountCreateView(
def get_context_data(self,**kwargs): def get_context_data(self,**kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context["url_kwargs"] = self.kwargs context["url_kwargs"] = self.kwargs
coa_pk = context["url_kwargs"]["coa_pk"] coa_pk = context["url_kwargs"]["coa_pk"]
try: try:
context["coa_model"] = ChartOfAccountModel.objects.get(entity=self.request.entity,pk=coa_pk) kwargs["coa_model"] = ChartOfAccountModel.objects.get(pk=coa_pk) or self.request.entity.get_default_coa()
except Exception: except Exception:
context["coa_model"] = self.request.entity.get_default_coa() kwargs["coa_model"] = self.request.entity.get_default_coa()
return context return context
class AccountDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView): class AccountDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
""" """
Represents the detailed view for an account with additional context data related to account Represents the detailed view for an account with additional context data related to account
@ -4555,11 +4540,7 @@ class AccountUpdateView(
form.fields["_ref_node_id"].widget = HiddenInput() form.fields["_ref_node_id"].widget = HiddenInput()
form.fields["_position"].widget = HiddenInput() form.fields["_position"].widget = HiddenInput()
return form return form
def form_valid(self, form):
form.instance.coa_model = ChartOfAccountModel.objects.get(pk=self.kwargs['coa_pk']) or self.request.entity.get_default_coa()
return super().form_valid(form)
def get_success_url(self): def get_success_url(self):
return reverse_lazy( return reverse_lazy(
"account_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"],"coa_pk":self.kwargs["coa_pk"]} "account_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"],"coa_pk":self.kwargs["coa_pk"]}
@ -4570,9 +4551,9 @@ class AccountUpdateView(
context["url_kwargs"] = self.kwargs context["url_kwargs"] = self.kwargs
coa_pk = context["url_kwargs"]["coa_pk"] coa_pk = context["url_kwargs"]["coa_pk"]
try: try:
context["coa_model"] = ChartOfAccountModel.objects.get(pk=coa_pk) or self.request.entity.get_default_coa() kwargs["coa_model"] = ChartOfAccountModel.objects.get(pk=coa_pk) or self.request.entity.get_default_coa()
except Exception: except Exception:
context["coa_model"] = self.request.entity.get_default_coa() kwargs["coa_model"] = self.request.entity.get_default_coa()
return context return context
@login_required @login_required
@permission_required("django_ledger.delete_accountmodel") @permission_required("django_ledger.delete_accountmodel")
@ -6769,26 +6750,12 @@ def delete_note(request, dealer_slug, pk):
:return: An HTTP redirection to the lead detail page of the corresponding note's lead. :return: An HTTP redirection to the lead detail page of the corresponding note's lead.
:rtype: HttpResponseRedirect :rtype: HttpResponseRedirect
""" """
try: note = get_object_or_404(models.Notes, pk=pk, created_by=request.user)
note = get_object_or_404(models.Notes, pk=pk, created_by=request.user) lead_pk = note.content_object.pk
print(note) lead = models.Lead.objects.get(pk=lead_pk)
if isinstance(note.content_object, models.Lead): note.delete()
url = "lead_detail" messages.success(request, _("Note deleted successfully."))
slug = note.content_object.slug return redirect("lead_detail", dealer_slug=dealer_slug, slug=lead.slug)
if hasattr(note.content_object, "opportunity"):
url = "opportunity_detail"
slug = note.content_object.opportunity.slug
elif isinstance(note.content_object, models.Opportunity):
url = "opportunity_detail"
slug = note.content_object.slug
note.delete()
messages.success(request, _("Note deleted successfully."))
except Exception as e:
print("Errroooorrr: ",e)
print(url)
print(dealer_slug)
return redirect(url, dealer_slug=dealer_slug,slug=slug)
@login_required @login_required
@ -6870,9 +6837,9 @@ def schedule_event(request, dealer_slug, content_type, slug):
dealer = get_object_or_404(models.Dealer, slug=dealer_slug) dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
obj = get_object_or_404(model, slug=slug) obj = get_object_or_404(model, slug=slug)
# if not request.is_staff: if not request.is_staff:
# messages.error(request, _("You do not have permission to schedule.")) messages.error(request, _("You do not have permission to schedule."))
# return redirect(f"{content_type}_detail", dealer_slug=dealer_slug, slug=slug) return redirect(f"{content_type}_detail", dealer_slug=dealer_slug, slug=slug)
if request.method == "POST": if request.method == "POST":
from django_q.models import Schedule as DjangoQSchedule from django_q.models import Schedule as DjangoQSchedule
@ -7373,6 +7340,7 @@ class OpportunityDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailV
form.fields["stage"].widget.attrs["hx-get"] = url form.fields["stage"].widget.attrs["hx-get"] = url
form.fields["stage"].initial = self.object.stage form.fields["stage"].initial = self.object.stage
context["status_form"] = form context["status_form"] = form
context["lead_notes"] = models.Notes.objects.filter( context["lead_notes"] = models.Notes.objects.filter(
content_type__model="lead", object_id=self.object.id content_type__model="lead", object_id=self.object.id
).order_by("-created") ).order_by("-created")
@ -10220,9 +10188,8 @@ def add_note(request, dealer_slug, content_type, slug):
@require_http_methods(["POST"]) @require_http_methods(["POST"])
@permission_required("inventory.change_notes", raise_exception=True) @permission_required("inventory.change_notes", raise_exception=True)
def update_note(request, dealer_slug, pk): def update_note(request, dealer_slug, pk):
print(pk)
note = get_object_or_404(models.Notes, pk=pk) note = get_object_or_404(models.Notes, pk=pk)
# lead = get_object_or_404(models.Lead, pk=note.content_object.id) lead = get_object_or_404(models.Lead, pk=note.content_object.id)
dealer = get_object_or_404(models.Dealer, slug=dealer_slug) dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
if request.method == "POST": if request.method == "POST":
note.note = request.POST.get("note") note.note = request.POST.get("note")
@ -11454,10 +11421,7 @@ def staff_password_reset_view(request, dealer_slug, user_pk):
if request.method == 'POST': if request.method == 'POST':
form = forms.CustomSetPasswordForm(staff.user, request.POST) form = forms.CustomSetPasswordForm(staff.user, request.POST)
if form.is_valid(): if form.is_valid():
print(form.cleaned_data['new_password1'])
print(form.cleaned_data['new_password2'])
form.save() form.save()
messages.success(request, _('Your password has been set. You may go ahead and log in now.')) messages.success(request, _('Your password has been set. You may go ahead and log in now.'))
return redirect('user_detail',dealer_slug=dealer_slug,slug=staff.slug) return redirect('user_detail',dealer_slug=dealer_slug,slug=staff.slug)
@ -11698,12 +11662,12 @@ def ticket_update(request, ticket_id):
}) })
# class ChartOfAccountModelListView(ChartOfAccountModelListViewBase): class ChartOfAccountModelListView(ChartOfAccountModelListViewBase):
# template_name = 'chart_of_accounts/coa_list.html' template_name = 'chart_of_accounts/coa_list.html'
# permission_required = 'django_ledger.view_chartofaccountmodel' permission_required = 'django_ledger.view_chartofaccountmodel'
class ChartOfAccountModelCreateView(ChartOfAccountModelCreateViewBase): class ChartOfAccountModelCreateView(ChartOfAccountModelCreateViewBase):
template_name = 'chart_of_accounts/coa_create.html' template_name = 'chart_of_accounts/coa_create.html'
permission_required = 'django_ledger.add_chartofaccountmodel' permission_required = 'django_ledger.add_chartofaccountmodel'
class ChartOfAccountModelListView(ChartOfAccountModelListViewBase): class ChartOfAccountModelListView(ChartOfAccountModelListViewBase):
template_name = 'chart_of_accounts/coa_list.html' template_name = 'chart_of_accounts/coa_list.html'
permission_required = 'django_ledger.view_chartofaccountmodel' permission_required = 'django_ledger.view_chartofaccountmodel'

Binary file not shown.

Before

Width:  |  Height:  |  Size: 334 KiB

View File

@ -13,7 +13,7 @@
<p class="text-body-tertiary">{{ _("Are you sure you want to sign out?") }}</p> <p class="text-body-tertiary">{{ _("Are you sure you want to sign out?") }}</p>
</div> </div>
<div class="d-grid"> <div class="d-grid">
<form method="post" action="{% url 'account_logout' %}"> <form hx-boost="false" method="post" action="{% url 'account_logout' %}">
{% csrf_token %} {% csrf_token %}
{{ redirect_field }} {{ redirect_field }}
<div class="d-grid gap-2 mt-3"> <div class="d-grid gap-2 mt-3">

View File

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

View File

@ -24,8 +24,7 @@
<h3 class="text-body-highlight">{% trans 'Car Dealership Registration' %}</h3> <h3 class="text-body-highlight">{% trans 'Car Dealership Registration' %}</h3>
<p class="text-body-tertiary fs-9">{% trans 'Create your dealership account today' %}</p> <p class="text-body-tertiary fs-9">{% trans 'Create your dealership account today' %}</p>
</div> </div>
<div class="mx-auto mt-4 text-center">
</div>
<form method="post" action="{% url 'account_signup' %}" class="needs-validation"> <form method="post" action="{% url 'account_signup' %}" class="needs-validation">
{% csrf_token %} {% csrf_token %}
<div class="card theme-wizard"> <div class="card theme-wizard">

View File

@ -87,7 +87,13 @@
<img src="{% static 'spinner.svg' %}" width="100" height="100" alt=""> <img src="{% static 'spinner.svg' %}" width="100" height="100" alt="">
</div> </div>
<div id="main_content" <div id="main_content"
class="fade-me-in"> class="fade-me-in"
hx-boost="false"
hx-target="#main_content"
hx-select="#main_content"
hx-swap="outerHTML transition:true"
hx-select-oob="#toast-container"
hx-history-elt>
{% block customCSS %}{% endblock %} {% block customCSS %}{% endblock %}
{% block content %} {% block content %}
{% endblock content %} {% endblock content %}

View File

@ -1,6 +1,6 @@
{% load django_ledger %} {% load django_ledger %}
{% load i18n %} {% load i18n %}
<div id="djl-bill-card-widget" class=""> <div id="djl-bill-card-widget" class="" hx-boost="false">
{% if not create_bill %} {% if not create_bill %}
{% if style == 'dashboard' %} {% if style == 'dashboard' %}
<!-- Dashboard Style Card --> <!-- Dashboard Style Card -->
@ -54,7 +54,7 @@
<a href="{% url 'django_ledger:bill-detail' entity_slug=entity_slug bill_pk=bill.uuid %}" <a href="{% url 'django_ledger:bill-detail' entity_slug=entity_slug bill_pk=bill.uuid %}"
class="btn btn-sm btn-phoenix-primary me-md-2">{% trans 'View' %}</a> class="btn btn-sm btn-phoenix-primary me-md-2">{% trans 'View' %}</a>
{% if perms.django_ledger.change_billmodel %} {% if perms.django_ledger.change_billmodel %}
<a <a hx-boost="true"
href="{% url 'django_ledger:bill-update' entity_slug=entity_slug bill_pk=bill.uuid %}" href="{% url 'django_ledger:bill-update' entity_slug=entity_slug bill_pk=bill.uuid %}"
class="btn btn-sm btn-phoenix-warning me-md-2">{% trans 'Update' %}</a> class="btn btn-sm btn-phoenix-warning me-md-2">{% trans 'Update' %}</a>
{% if bill.can_pay %} {% if bill.can_pay %}
@ -203,7 +203,7 @@
<!-- Update Button --> <!-- Update Button -->
{% if perms.django_ledger.change_billmodel %} {% if perms.django_ledger.change_billmodel %}
{% if "update" not in request.path %} {% if "update" not in request.path %}
<a <a hx-boost="true"
href="{% url 'bill-update' dealer_slug=dealer_slug entity_slug=entity_slug bill_pk=bill.uuid %}"> href="{% url 'bill-update' dealer_slug=dealer_slug entity_slug=entity_slug bill_pk=bill.uuid %}">
<button class="btn btn-phoenix-primary"> <button class="btn btn-phoenix-primary">
<i class="fas fa-edit me-2"></i>{% trans 'Update' %} <i class="fas fa-edit me-2"></i>{% trans 'Update' %}

View File

@ -12,7 +12,7 @@
<div class="card-header bg-gradient py-4 border-0 rounded-top-4"> <div class="card-header bg-gradient py-4 border-0 rounded-top-4">
<h3 class="mb-0 fs-4 fw-bold text-center"> <h3 class="mb-0 fs-4 fw-bold text-center">
{% trans 'Create Chart of Accounts' %} {% trans 'Create Chart of Accounts' %}
<i class="fa-solid fa-chart-pie ms-2"></i> <i class="fa-solid fa-chart-pie ms-2"></i>
</h3> </h3>
</div> </div>
<div class="card-body p-4 p-md-5"> <div class="card-body p-4 p-md-5">

View File

@ -16,12 +16,11 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form id="noteForm" <form id="noteForm"
hx-boost="true"
action="{% url 'add_note' request.dealer.slug content_type slug %}" action="{% url 'add_note' request.dealer.slug content_type slug %}"
hx-select="#notesTable" hx-select="#notesTable"
hx-target="#notesTable" hx-target="#notesTable"
hx-on::after-request="{ resetSubmitButton(document.querySelector('.add_note_form button[type=submit]')); $('#noteModal').modal('hide'); }" hx-on::after-request="{ resetSubmitButton(document.querySelector('.add_note_form button[type=submit]')); $('#noteModal').modal('hide'); }"
hx-swap="outerHTML show:window.top" hx-swap="outerHTML"
method="post" method="post"
class="add_note_form"> class="add_note_form">
{% csrf_token %} {% csrf_token %}
@ -34,13 +33,12 @@
</div> </div>
<script> <script>
function updateNote(e) { function updateNote(e) {
let form = document.querySelector('#noteForm');
let url = e.getAttribute('data-url'); let url = e.getAttribute('data-url');
let note = e.getAttribute('data-note'); let note = e.getAttribute('data-note');
document.querySelector('#id_note').value = note; document.querySelector('#id_note').value = note;
let form = document.querySelector('#noteForm');
form.action = url; form.action = url;
htmx.process(form); htmx.process(form);
} }

View File

@ -16,13 +16,11 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form id="scheduleForm" <form id="scheduleForm"
hx-boost="true"
action="{% url 'schedule_event' request.dealer.slug content_type slug %}" action="{% url 'schedule_event' request.dealer.slug content_type slug %}"
hx-select=".taskTable" hx-select=".taskTable"
hx-target=".taskTable" hx-target=".taskTable"
hx-on::after-request="{ resetSubmitButton(document.querySelector('.add_schedule_form button[type=submit]')); $('#scheduleModal').modal('hide'); }" hx-on::after-request="{ resetSubmitButton(document.querySelector('.add_schedule_form button[type=submit]')); $('#scheduleModal').modal('hide'); }"
hx-swap="outerHTML" hx-swap="outerHTML"
hx-select-oob="#toast-container:outerHTML"
method="post" method="post"
class="add_schedule_form"> class="add_schedule_form">
{% csrf_token %} {% csrf_token %}

View File

@ -23,12 +23,13 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form id="taskForm" <form id="taskForm"
action="{% url 'add_task' request.dealer.slug content_type slug %}"
method="post" method="post"
class="add_task_form" class="add_task_form"
hx-post="{% url 'add_task' request.dealer.slug content_type slug %}" hx-post="{% url 'add_task' request.dealer.slug content_type slug %}"
hx-target="#your-content-container" hx-target="#your-content-container"
hx-swap="innerHTML" hx-swap="innerHTML"
> hx-boost="true">
{% csrf_token %} {% csrf_token %}
{{ staff_task_form|crispy }} {{ staff_task_form|crispy }}
<button type="submit" class="btn btn-phoenix-success w-100">{% trans 'Save' %}</button> <button type="submit" class="btn btn-phoenix-success w-100">{% trans 'Save' %}</button>

View File

@ -324,7 +324,11 @@
<div class="tab-content" id="myTabContent"> <div class="tab-content" id="myTabContent">
<div class="tab-pane fade" <div class="tab-pane fade"
id="tab-activity" id="tab-activity"
hx-get="{% url 'lead_detail' request.dealer.slug lead.slug %}"
hx-trigger="htmx:afterRequest from:#noteForm, htmx:afterRequest from:#scheduleForm"
hx-select="#tab-activity"
hx-target="this"
hx-swap="outerHTML"
role="tabpanel" role="tabpanel"
aria-labelledby="activity-tab"> aria-labelledby="activity-tab">
<div class="mb-1 d-flex justify-content-between align-items-center"> <div class="mb-1 d-flex justify-content-between align-items-center">
@ -615,7 +619,7 @@
<td class="sent align-middle white-space-nowrap text-start fw-bold text-body-tertiary py-2">{{ email.from_email }}</td> <td class="sent align-middle white-space-nowrap text-start fw-bold text-body-tertiary py-2">{{ email.from_email }}</td>
<td class="date align-middle white-space-nowrap text-body py-2">{{ email.created|naturalday }}</td> <td class="date align-middle white-space-nowrap text-body py-2">{{ email.created|naturalday }}</td>
<td class="align-middle white-space-nowrap ps-3"> <td class="align-middle white-space-nowrap ps-3">
<a class="text-body" href=""><span class="fa-solid fa-phone text-primary me-2"></span>{%trans "Call"%}</a> <a class="text-body" href=""><span class="fa-solid fa-phone text-primary me-2"></span>{%trans "Call"%</a>
</td> </td>
<td class="status align-middle fw-semibold text-end py-2"> <td class="status align-middle fw-semibold text-end py-2">
<span class="badge badge-phoenix fs-10 badge-phoenix-success">{%trans "sent"%}</span> <span class="badge badge-phoenix fs-10 badge-phoenix-success">{%trans "sent"%}</span>

View File

@ -9,6 +9,7 @@
<h5 class="card-header">{% trans "Send Mail" %}</h5> <h5 class="card-header">{% trans "Send Mail" %}</h5>
<div class="card-body"> <div class="card-body">
<form class="email-form d-flex flex-column h-100" <form class="email-form d-flex flex-column h-100"
hx-boost="true"
action="{% url 'send_lead_email' request.dealer.slug lead.slug %}" action="{% url 'send_lead_email' request.dealer.slug lead.slug %}"
method="post"> method="post">
{% csrf_token %} {% csrf_token %}
@ -48,7 +49,9 @@
<div class="d-flex justify-content-between align-items-center"> <div class="d-flex justify-content-between align-items-center">
<div class="d-flex gap-2"> <div class="d-flex gap-2">
{% comment %} <a href="{{ request.META.HTTP_REFERER }}" class="btn btn-phoenix-danger">Discard</a> {% endcomment %} {% comment %} <a href="{{ request.META.HTTP_REFERER }}" class="btn btn-phoenix-danger">Discard</a> {% endcomment %}
<a <a hx-boost="true"
hx-push-url='false'
hx-include="#message,#subject,#to"
href="{% url 'send_lead_email' request.dealer.slug lead.slug %}?status=draft" href="{% url 'send_lead_email' request.dealer.slug lead.slug %}?status=draft"
class="btn btn-phoenix-success">{% trans "Save as Draft" %}</a> class="btn btn-phoenix-success">{% trans "Save as Draft" %}</a>
<button class="btn btn-phoenix-primary fs-10" type="submit"> <button class="btn btn-phoenix-primary fs-10" type="submit">

View File

@ -15,7 +15,7 @@
</h3> </h3>
</div> </div>
<div class="card-body p-4 p-md-5"> <div class="card-body p-4 p-md-5">
<form <form hx-boost="false"
method="post" method="post"
enctype="multipart/form-data" enctype="multipart/form-data"
class="needs-validation" class="needs-validation"

View File

@ -5,7 +5,12 @@
<div class="navbar-vertical-content d-flex flex-column"> <div class="navbar-vertical-content d-flex flex-column">
<ul class="navbar-nav flex-column" <ul class="navbar-nav flex-column"
id="navbarVerticalNav" id="navbarVerticalNav"
> hx-boost="false"
hx-target="#main_content"
hx-select="#main_content"
hx-swap="outerHTML"
hx-select-oob="#toast-container"
hx-indicator="#spinner">
<li class="nav-item"> <li class="nav-item">
{% comment %} <p class="navbar-vertical-label text-primary fs-8 text-truncate">{{request.dealer|default:"Apps"}}</p> {% comment %} <p class="navbar-vertical-label text-primary fs-8 text-truncate">{{request.dealer|default:"Apps"}}</p>
@ -33,7 +38,7 @@
<li class="collapsed-nav-item-title d-none">{% trans "Inventory"|capfirst %}</li> <li class="collapsed-nav-item-title d-none">{% trans "Inventory"|capfirst %}</li>
{% if perms.inventory.add_car %} {% if perms.inventory.add_car %}
<li class="nav-item"> <li class="nav-item">
<a <a hx-boost="false"
id="btn-add-car" id="btn-add-car"
class="nav-link btn-add-car" class="nav-link btn-add-car"
href="{% url 'car_add' request.dealer.slug %}"> href="{% url 'car_add' request.dealer.slug %}">
@ -196,7 +201,7 @@
<li class="collapsed-nav-item-title d-none">{% trans 'sales'|capfirst %}</li> <li class="collapsed-nav-item-title d-none">{% trans 'sales'|capfirst %}</li>
{% if perms.django_ledger.add_estimatemodel %} {% if perms.django_ledger.add_estimatemodel %}
<li class="nav-item"> <li class="nav-item">
<a <a hx-boost="false"
class="nav-link" class="nav-link"
href="{% url 'estimate_create' request.dealer.slug %}"> href="{% url 'estimate_create' request.dealer.slug %}">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
@ -490,26 +495,11 @@
title="{% trans 'Logged in as ' %}{{ request.user.username }}"> title="{% trans 'Logged in as ' %}{{ request.user.username }}">
{% trans 'Hello, ' %}{{ name_to_display }} {% trans 'Hello, ' %}{{ name_to_display }}
</h6> </h6>
{% endwith %} {% endwith %}
</div> </div>
</div>
<div class="navbar-logo ">
<div class="d-flex align-items-center">
<small class="text-gray-600 ms-2 d-none d-sm-block fs-9"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
>
{% now "l, F j, Y g:i A" %}
</small>
</div>
</div> </div>
{% endif %} {% endif %}
<ul class="navbar-nav navbar-nav-icons flex-row gap-2"> <ul class="navbar-nav navbar-nav-icons flex-row gap-2" hx-boost="false">
<li class="nav-item"> <li class="nav-item">
<div class="theme-control-toggle fa-icon-wait"> <div class="theme-control-toggle fa-icon-wait">
<input class="form-check-input ms-0 theme-control-toggle-input" <input class="form-check-input ms-0 theme-control-toggle-input"
@ -561,7 +551,7 @@
{% endif %} {% endif %}
{% if user.is_authenticated and request.is_dealer or request.is_staff %} {% if user.is_authenticated and request.is_dealer or request.is_staff %}
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a <a hx-boost="false"
class="nav-link lh-1 pe-0" class="nav-link lh-1 pe-0"
id="navbarDropdownUser" id="navbarDropdownUser"
role="button" role="button"
@ -609,7 +599,7 @@
</li> </li>
{% else %} {% else %}
<li class="nav-item"> <li class="nav-item">
<a <a hx-boost="false"
class="nav-link px-3 d-block" class="nav-link px-3 d-block"
href="{% url 'staff_detail' request.dealer.slug request.staff.slug %}"> <span class="me-2 text-body align-bottom" data-feather="user"></span><span>{% translate 'profile'|capfirst %}</span></a> href="{% url 'staff_detail' request.dealer.slug request.staff.slug %}"> <span class="me-2 text-body align-bottom" data-feather="user"></span><span>{% translate 'profile'|capfirst %}</span></a>
</li> </li>
@ -643,7 +633,7 @@
{% endif %} {% endif %}
{% if request.is_staff %} {% if request.is_staff %}
<li class="nav-item"> <li class="nav-item">
<a <a hx-boost="false"
class="nav-link px-3 d-block" class="nav-link px-3 d-block"
href="{% url 'schedule_calendar' request.dealer.slug %}"> <span class="me-2 text-body align-bottom" data-feather="calendar"></span>{{ _("My Calendar") }}</a> href="{% url 'schedule_calendar' request.dealer.slug %}"> <span class="me-2 text-body align-bottom" data-feather="calendar"></span>{{ _("My Calendar") }}</a>
</li> </li>

View File

@ -170,7 +170,7 @@
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#mainModal" data-bs-target="#mainModal"
hx-get="{% url 'add_custom_card' request.dealer.slug car.slug %}" hx-get="{% url 'add_custom_card' request.dealer.slug car.slug %}"
hx-target="#mainModalBody" hx-target=".main-modal-body"
hx-swap="innerHTML">{% trans 'Add' %}</button> hx-swap="innerHTML">{% trans 'Add' %}</button>
{% endif %} {% endif %}
</td> </td>
@ -518,7 +518,7 @@
data-bs-dismiss="modal" data-bs-dismiss="modal"
aria-label="Close"></button> aria-label="Close"></button>
</div> </div>
<div id="mainModalBody" class="main-modal-body" style="padding: 20px;"> <div class="main-modal-body" style="padding: 20px;">
<!-- Content will be loaded here via AJAX --> <!-- Content will be loaded here via AJAX -->
</div> </div>
</div> </div>
@ -693,18 +693,5 @@
button.classList.add("d-none"); button.classList.add("d-none");
}); });
} }
document.addEventListener('htmx:afterRequest', e => {
console.log('PUT Success!')
});
document.addEventListener('htmx:beforeSwap', e => {
console.log('Before Swap!')
});
document.addEventListener('htmx:swapError', e => {
console.log('Swap Error!')
});
document.addEventListener('htmx:afterSwap', e => {
console.log('After Swap!')
});
</script> </script>
{% endblock %} {% endblock %}

View File

@ -25,7 +25,7 @@
{% endif %} {% endif %}
<!----> <!---->
<div class="row justify-content-center mt-5 mb-3 {% if not vendor_exists %}d-none{% endif %}" <div class="row justify-content-center mt-5 mb-3 {% if not vendor_exists %}d-none{% endif %}"
> hx-boost="false">
<div class="col-lg-8 col-md-10"> <div class="col-lg-8 col-md-10">
<div class="card shadow-sm border-0 rounded-3"> <div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3"> <div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">

View File

@ -5,7 +5,7 @@
{{ _("Create Bill") }} {{ _("Create Bill") }}
{% endblock title %} {% endblock title %}
{% block content %} {% block content %}
<div class="row mt-4"> <div class="row mt-4" hx-boost="true">
<h3 class="text-center"> <h3 class="text-center">
{% trans "Create Bill" %}<span class="fas fa-money-bills ms-2 text-primary"></span> {% trans "Create Bill" %}<span class="fas fa-money-bills ms-2 text-primary"></span>
</h3> </h3>

View File

@ -20,7 +20,7 @@
{% else %} {% else %}
{% trans "Add New Account" %} {% trans "Add New Account" %}
<i class="fa-solid fa-book ms-2"></i> <i class="fa-solid fa-book ms-2"></i>
{% endif %} {% endif %}
</h3> </h3>
</div> </div>
<div class="card-body p-4 p-md-5"> <div class="card-body p-4 p-md-5">

View File

@ -24,10 +24,8 @@
</div> </div>
<div class="modal-footer flex justify-content-center border-top-0"> <div class="modal-footer flex justify-content-center border-top-0">
<a id="deleteModalConfirm" <a id="deleteModalConfirm"
hx-boost="true"
hx-select-oob="#notesTable:outerHTML,#toast-container:outerHTML" hx-select-oob="#notesTable:outerHTML,#toast-container:outerHTML"
hx-on::after-request="{ $('#deleteModal').modal('hide'); }" hx-swap="none"
hx-swap="none show:#notesTable"
type="button" type="button"
class="btn btn-sm btn-phoenix-danger w-100" class="btn btn-sm btn-phoenix-danger w-100"
href="">{{ _("Delete") }}</a> href="">{{ _("Delete") }}</a>
@ -59,7 +57,6 @@
if (!deleteModal || !confirmDeleteBtn || !deleteModalMessage) return; if (!deleteModal || !confirmDeleteBtn || !deleteModalMessage) return;
const deleteUrl = this.getAttribute("data-url"); const deleteUrl = this.getAttribute("data-url");
console.log(deleteUrl)
const deleteMessage = this.getAttribute("data-message") || "Are you sure you want to delete this item?"; const deleteMessage = this.getAttribute("data-message") || "Are you sure you want to delete this item?";
// Update modal content // Update modal content
@ -71,13 +68,11 @@
htmx.process(confirmDeleteBtn); htmx.process(confirmDeleteBtn);
} }
// Show the modal // Show the modal
/*if (typeof bootstrap !== 'undefined') { /*if (typeof bootstrap !== 'undefined') {
const modal = new bootstrap.Modal(deleteModal); const modal = new bootstrap.Modal(deleteModal);
modal.show(); modal.show();
}*/ }*/
} }
} }
</script> </script>

View File

@ -1,108 +1,79 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load i18n %} {% load i18n %}
{% block title %}{% trans 'Order Details' %}{% endblock %} {% block title %}
{% trans 'Order Details' %}
{% endblock %}
{% block head %} {% block head %}
<script> <script>
$(function () { $(function () {
$('a.invoice-link').on('click', function (event) { $('a.invoice').click(function () {
event.preventDefault(); event.preventDefault();
window.open($(this).attr('href'), 'invoice_' + $(this).data('invoice-id'), 'width=860,resizable=1,location=0,status=0,titlebar=1'); window.open($(this).attr('href'), 'plans_invoice_{{ invoice.id }}', 'width=860,resizable=1,location=0,status=0,titlebar=1');
}); });
}); });
</script> </script>
{% endblock %} {% endblock %}
{% block body %} {% block body %}
<div class="max-w-4xl mx-auto"> <h1 class="mt-4">
<div class="flex items-center justify-between mb-6"> {% blocktrans with object.id as order_id and object.get_status_display as order_status %}Order #{{ order_id }}
<h1 class="text-3xl font-bold text-gray-800"> (status: {{ order_status }}){% endblocktrans %}
{% blocktrans with object.id as order_id %}Order #{{ order_id }}{% endblocktrans %} </h1>
</h1> {# You should provide displaying django messages in this template #}
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium {% with object as order %}
{% if object.status == object.STATUS.COMPLETED %}bg-green-100 text-green-800{% elif object.status == object.STATUS.PENDING %}bg-yellow-100 text-yellow-800{% else %}bg-gray-100 text-gray-800{% endif %}"> {% include "plans/order_detail_table.html" %}
<i class="fas {% if object.status == object.STATUS.COMPLETED %}fa-check-circle{% elif object.status == object.STATUS.PENDING %}fa-clock{% else %}fa-info-circle{% endif %} mr-2"></i> {% endwith %}
{{ object.get_status_display }}
</span>
</div>
{# Order Summary Section #}
<div class="rounded-xl shadow-sm overflow-hidden mb-6">
<div class="px-6 py-4">
<h2 class="text-xl font-semibold text-gray-800 mb-4">{% trans "Order Summary" %}</h2>
{% with object as order %}
{% include "plans/order_detail_table.html" %}
{% endwith %}
</div>
</div>
{# Printable Documents Section #}
{% if object.get_all_invoices.count %} {% if object.get_all_invoices.count %}
<div class="rounded-xl shadow-sm overflow-hidden mb-6"> <h2 class="mt-4">{% trans "Printable documents" %}</h2>
<div class="px-6 py-4"> <ul id="order_printable_documents">
<h2 class="text-xl font-semibold text-gray-800 mb-4"> {% for invoice in object.get_all_invoices %}
<i class="fas fa-file-pdf text-gray-400 mr-2"></i> {% trans "Printable documents" %}
</h2>
<ul class="space-y-2">
{% for invoice in object.get_all_invoices %}
<li> <li>
<a href="{{ invoice.get_absolute_url }}" data-invoice-id="{{ invoice.id }}" class="invoice-link text-blue-600 hover:text-blue-800 font-medium transition-colors duration-200"> <a href="{{ invoice.get_absolute_url }}" class="invoice">{{ invoice.get_type_display }} {{ invoice }}</a>
{{ invoice.get_type_display }} {{ invoice }}
</a>
</li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> {% endif %}
</div> <h2 class="mt-4">{% trans "Payment" %}</h2>
{% endif %} {% if object.completed %}
<p class="alert alert-phoenix-success mt-2">
{# Payment Section #} {% blocktrans with object.completed as completed %}
<div class="rounded-xl overflow-hidden mb-6"> Payment completed on: {{ completed }}
<div class="px-6 py-4"> {% endblocktrans %}
<h2 class="text-xl font-semibold text-gray-800 mb-4"> </p>
<i class="fas fa-credit-card text-gray-400 mr-2"></i> {% trans "Payment" %} {% else %}
</h2> {% if object.is_ready_for_payment %}
{% if object.completed %} {% block payment_method %}
<div class="bg-green-50 text-green-700 px-4 py-3 rounded-lg flex items-center"> <p class="mt-2">
<i class="fas fa-check-circle mr-3 text-lg"></i> Here should go bindings to your payment. We recommend using <a href="https://github.com/cypreess/django-getpaid">django-getpaid</a> for payment processing.
<p class="text-sm font-medium"> Use a fake payment below to simulate paying for an order:
{% blocktrans with object.completed as completed %}
Payment completed on: {{ completed|date:"F j, Y" }}
{% endblocktrans %}
</p> </p>
</div> <a class="btn btn-phoenix-success"
{% else %}
{% if object.is_ready_for_payment %}
<p class="text-gray-600 mb-4">
You can use a fake payment below to simulate paying for this order.
</p>
<a class="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-lg shadow-sm text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 transition-colors duration-200"
role="button" role="button"
href="{% url "fake_payments" pk=object.id %}"> href="{% url "fake_payments" pk=object.id %}">Pay using
<i class="fas fa-money-bill-wave mr-2"></i> FakePayments™ ;</a>
Pay using FakePayments&trade; {# An example code snippet for accepting payments using django-getpaid #}
</a> {# <form action="{% url "getpaid-new-payment" currency=object.currency %}" method="post"#}
{% else %} {# class="standard_form payment_form">#}
<div class="bg-yellow-50 text-yellow-700 px-4 py-3 rounded-lg flex items-center"> {# {% csrf_token %}#}
<i class="fas fa-exclamation-triangle mr-3 text-lg"></i> {# <ul>{{ payment_form.as_ul }}</ul>#}
<p class="text-sm font-medium"> {# <p><label>&nbsp;</label><input type="submit"
{% blocktrans %} value="{% trans "Pay the order" %}"
This order is expired. New payments cannot be initialized. Please make a new order if necessary. class="submit_button">#}
{% endblocktrans %} {# </p>#}
</p> {# </form>#}
</div> {% endblock %}
{% endif %} {% else %}
{% endif %} <p class="alert alert-phoenix-warning mt-2">
{% if object.status == object.STATUS.NOT_VALID %}
<div class="bg-red-50 text-red-700 px-4 py-3 rounded-lg mt-4 flex items-center">
<i class="fas fa-times-circle mr-3 text-lg"></i>
<p class="text-sm font-medium">
{% blocktrans %} {% blocktrans %}
This order could not be processed as it is not valid. Please contact customer service. This order is expired. It will accept an incoming payment made earlier, but new payment cannot be
{% endblocktrans %} initialized. Please make a new order if necessary.
{% endblocktrans %}
</p> </p>
</div>
{% endif %} {% endif %}
</div> {% endif %}
</div> {% if object.status == object.STATUS.NOT_VALID %}
</div> <p class="alert alert-phoenix-danger">
{% endblock %} {% blocktrans %}
This order could not be processed as it is not valid. Please contact with customer service.
{% endblocktrans %}
</p>
{% endif %}
{% endblock %}

View File

@ -104,7 +104,7 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
<div class="d-flex align-items-center gap-2"> <div class="d-flex align-items-center gap-2" hx-boost="false">
{% if estimate.status == 'draft' %} {% if estimate.status == 'draft' %}
{% if perms.django_ledger.change_estimatemodel %} {% if perms.django_ledger.change_estimatemodel %}
<button id="mark_as_sent_estimate" <button id="mark_as_sent_estimate"

View File

@ -87,7 +87,6 @@
{% endif %} {% endif %}
</div> </div>
{% else %} {% else %}
{% url 'estimate_create' request.dealer.slug as url %} {% include "empty-illustration-page.html" with value="invoice" url="#" %}
{% include "empty-illustration-page.html" with value="invoice" url=url %}
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View File

@ -119,7 +119,6 @@
</div> </div>
</section> </section>
{% else %} {% else %}
{% url 'estimate_create' request.dealer.slug as url %} {% include "empty-illustration-page.html" with value="sale order" url='#' %}
{% include "empty-illustration-page.html" with value="Sale Orders" url=url %}
{% endif %} {% endif %}
{% endblock %} {% endblock %}