update the note in lead and vendor disable

This commit is contained in:
ismail 2025-05-20 18:17:13 +03:00
parent faf4eba38a
commit 5c4ea15fdf
12 changed files with 243 additions and 110 deletions

View File

@ -0,0 +1,19 @@
# Generated by Django 5.1.7 on 2025-05-20 12:45
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0002_vendor_active'),
]
operations = [
migrations.AlterField(
model_name='opportunity',
name='customer',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to='inventory.customer'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 5.1.7 on 2025-05-20 12:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0003_alter_opportunity_customer'),
]
operations = [
migrations.AddField(
model_name='opportunity',
name='slug',
field=models.SlugField(blank=True, help_text='Unique slug for the opportunity.', null=True, unique=True, verbose_name='Slug'),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 5.1.7 on 2025-05-20 13:45
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0004_opportunity_slug'),
]
operations = [
migrations.AddField(
model_name='notes',
name='dealer',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='notes', to='inventory.dealer'),
preserve_default=False,
),
]

View File

@ -1447,7 +1447,8 @@ class Lead(models.Model):
def full_name(self):
return f"{self.first_name} {self.last_name}"
def convert_to_customer(self):
self.status = Status.QUALIFIED
self.status = Status.NEGOTIATION
self.is_converted = True
self.save()
return self.get_customer_model()
def get_status(self):
@ -1587,7 +1588,7 @@ class Opportunity(models.Model):
Dealer, on_delete=models.CASCADE, related_name="opportunities"
)
customer = models.ForeignKey(
CustomerModel, on_delete=models.CASCADE, related_name="opportunities",null=True,blank=True
Customer, on_delete=models.CASCADE, related_name="opportunities",null=True,blank=True
)
car = models.ForeignKey(
Car, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_("Car")
@ -1611,15 +1612,22 @@ class Opportunity(models.Model):
created = models.DateTimeField(auto_now_add=True, verbose_name=_("Created"))
updated = models.DateTimeField(auto_now=True, verbose_name=_("Updated"))
estimate = models.OneToOneField(EstimateModel, related_name="opportunity",on_delete=models.SET_NULL,null=True,blank=True)
slug = models.SlugField(null=True, blank=True, unique=True,verbose_name=_("Slug"),
help_text=_("Unique slug for the opportunity."))
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(f"opportunity {self.customer.first_name} {self.customer.last_name}")
super(Opportunity, self).save(*args, **kwargs)
class Meta:
verbose_name = _("Opportunity")
verbose_name_plural = _("Opportunities")
def __str__(self):
return f"Opportunity for {self.customer.customer_name}"
return f"Opportunity for {self.customer.first_name} {self.customer.last_name}"
class Notes(models.Model):
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="notes")
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.UUIDField()
content_object = GenericForeignKey("content_type", "object_id")

View File

@ -83,6 +83,11 @@ urlpatterns = [
views.CustomerDetailView.as_view(),
name="customer_detail",
),
path(
"customers/<slug:slug>/add-note/",
views.add_note_to_customer,
name="add_note_to_customer",
),
path(
"customers/<slug:slug>/update/",
views.CustomerUpdateView.as_view(),
@ -94,11 +99,6 @@ urlpatterns = [
views.OpportunityCreateView.as_view(),
name="create_opportunity",
),
path(
"customers/<slug:slug>/add-note/",
views.add_note_to_customer,
name="add_note_to_customer",
),
path("crm/leads/create/", views.lead_create, name="lead_create"),
path(
"crm/leads/<slug:slug>/view/", views.LeadDetailView.as_view(), name="lead_detail"
@ -109,13 +109,21 @@ urlpatterns = [
path("crm/leads/", views.LeadListView.as_view(), name="lead_list"),
path(
"crm/leads/<int:pk>/update/", views.LeadUpdateView.as_view(), name="lead_update"
"crm/leads/<slug:slug>/update/", views.LeadUpdateView.as_view(), name="lead_update"
),
path("crm/leads/<slug:slug>/delete/", views.LeadDeleteView, name="lead_delete"),
path("crm/leads/<int:pk>/lead-convert/", views.lead_convert, name="lead_convert"),
path("crm/leads/<int:pk>/add-note/", views.add_note_to_lead, name="add_note_to_lead"),
path('crm/leads/<int:pk>/update-note/', views.update_note, name='update_note_to_lead'),
path("crm/leads/<slug:slug>/lead-convert/", views.lead_convert, name="lead_convert"),
path("crm/leads/<int:pk>/delete-note/", views.delete_note, name="delete_note_to_lead"),
path(
"crm/<int:pk>/update-note/",
views.update_note,
name="update_note",
),
path(
"crm/<str:content_type>/<slug:slug>/add-note/",
views.add_note,
name="add_note",
),
path(
"crm/<int:pk>/update-task/",
views.update_task,
@ -152,13 +160,12 @@ urlpatterns = [
name="schedule_cancel",
),
path(
"crm/leads/<int:pk>/transfer/",
"crm/leads/<slug:slug>/transfer/",
views.lead_transfer,
name="lead_transfer",
),
path(
"crm/opportunities/<int:pk>/add_note/",
"crm/opportunities/<slug:slug>/add_note/",
views.add_note_to_opportunity,
name="add_note_to_opportunity",
),
@ -168,17 +175,22 @@ urlpatterns = [
name="opportunity_create",
),
path(
"crm/opportunities/<int:pk>/create/",
"crm/opportunities/<slug:slug>/create/",
views.OpportunityCreateView.as_view(),
name="lead_opportunity_create",
),
path(
"crm/opportunities/<slug:slug>/create/",
views.OpportunityCreateView.as_view(),
name="opportunity_create",
),
path(
"crm/opportunities/<int:pk>/",
"crm/opportunities/<slug:slug>/",
views.OpportunityDetailView.as_view(),
name="opportunity_detail",
),
path(
"crm/opportunities/<int:pk>/edit/",
"crm/opportunities/<slug:slug>/edit/",
views.OpportunityUpdateView.as_view(),
name="update_opportunity",
),
@ -193,7 +205,7 @@ urlpatterns = [
name="delete_opportunity",
),
path(
"crm/opportunities/<int:pk>/opportunity_update_status/",
"crm/opportunities/<slug:slug>/opportunity_update_status/",
views.opportunity_update_status,
name="opportunity_update_status",
),

View File

@ -22,7 +22,7 @@ from django.http.response import StreamingHttpResponse
# Django
from django.db.models import Q
from django.conf import settings
from django.db import transaction
from django.db import IntegrityError, transaction
from django.db.models import Func
from django.contrib import messages
from django.http import Http404, JsonResponse, HttpResponseForbidden
@ -1953,7 +1953,7 @@ class CustomerDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
@login_required
def add_note_to_customer(request, pk):
def add_note_to_customer(request, slug):
"""
This function allows authenticated users to add a note to a specific customer. The
note creation is handled by a form, which is validated after submission. If the form
@ -1970,7 +1970,7 @@ def add_note_to_customer(request, pk):
POST request, it renders the note form template with context including
the form and customer.
"""
customer = get_object_or_404(models.Customer, pk=pk)
customer = get_object_or_404(models.Customer, slug=slug)
if request.method == "POST":
form = forms.NoteForm(request.POST)
if form.is_valid():
@ -1979,7 +1979,7 @@ def add_note_to_customer(request, pk):
note.created_by = request.user
note.save()
return redirect("customer_detail", pk=customer.pk)
return redirect("customer_detail", slug=customer.slug)
else:
form = forms.NoteForm()
return render(
@ -2206,9 +2206,16 @@ class VendorCreateView(
success_message = _("Vendor created successfully")
def form_valid(self, form):
if vendor:= models.Vendor.objects.filter(email=form.instance.email).first():
if not vendor.active:
messages.error(self.request, _("Vendor Account with this email is Deactivated,Please Contact Admin"))
else:
messages.error(self.request, _("Vendor with this email already exists"))
return redirect("vendor_create")
dealer = get_user_type(self.request)
form.instance.dealer = dealer
form.instance.save()
return super().form_valid(form)
@ -4597,6 +4604,7 @@ class LeadDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
context["transfer_form"] = forms.LeadTransferForm()
context["activity_form"] = forms.ActivityForm()
context["staff_task_form"] = forms.StaffTaskForm()
context["note_form"] = forms.NoteForm()
return context
@ -4798,7 +4806,7 @@ def LeadDeleteView(request, slug):
@login_required
def add_note_to_lead(request, pk):
def add_note_to_lead(request, slug):
"""
Adds a note to a specific lead. This view is accessible only to authenticated
users. The function handles the POST request to create a new note associated
@ -4814,7 +4822,7 @@ def add_note_to_lead(request, pk):
note creation or renders the note form template for GET or invalid POST requests.
:rtype: HttpResponse
"""
lead = get_object_or_404(models.Lead, pk=pk)
lead = get_object_or_404(models.Lead, slug=slug)
if request.method == "POST":
form = forms.NoteForm(request.POST)
if form.is_valid():
@ -4830,7 +4838,7 @@ def add_note_to_lead(request, pk):
@login_required
def add_note_to_opportunity(request, pk):
def add_note_to_opportunity(request, slug):
"""
Add a note to a specific opportunity identified by its primary key.
@ -4844,7 +4852,7 @@ def add_note_to_opportunity(request, pk):
:type pk: int
:return: A redirect response to the detailed view of the opportunity.
"""
opportunity = get_object_or_404(models.Opportunity, pk=pk)
opportunity = get_object_or_404(models.Opportunity, slug=slug)
if request.method == "POST":
notes = request.POST.get("notes")
if not notes:
@ -4852,7 +4860,7 @@ def add_note_to_opportunity(request, pk):
else:
models.Notes.objects.create(content_object=opportunity, created_by=request.user,note=notes)
messages.success(request, _("Note added successfully"))
return redirect("opportunity_detail", pk=opportunity.pk)
return redirect("opportunity_detail", slug=opportunity.slug)
@login_required
@ -4910,14 +4918,15 @@ def delete_note(request, pk):
"""
note = get_object_or_404(models.Notes, pk=pk, created_by=request.user)
lead_pk = note.content_object.pk
lead = models.Lead.objects.get(pk=lead_pk)
note.delete()
messages.success(request, _("Note deleted successfully."))
return redirect("lead_detail", pk=lead_pk)
return redirect("lead_detail", slug=lead.slug)
@login_required
@permission_required("inventory.change_lead", raise_exception=True)
def lead_convert(request, pk):
def lead_convert(request, slug):
"""
Converts a lead into a customer and creates a corresponding opportunity.
@ -4934,20 +4943,20 @@ def lead_convert(request, pk):
:return: An HTTP response redirecting to the lead list view.
:rtype: HttpResponse
"""
lead = get_object_or_404(models.Lead, pk=pk)
lead = get_object_or_404(models.Lead, slug=slug)
dealer = get_user_type(request)
if hasattr(lead, "opportunity"):
messages.error(request, _("Lead is already converted to customer"))
else:
customer = lead.convert_to_customer()
models.Opportunity.objects.create(dealer=dealer,customer=customer,lead=lead,probability=50,stage=models.Stage.PROSPECT,staff=lead.staff,status=models.Status.QUALIFIED)
models.Opportunity.objects.create(dealer=dealer,customer=customer,lead=lead,probability=50,stage=models.Stage.NEGOTIATION,staff=lead.staff)
messages.success(request, _("Lead converted to customer successfully"))
return redirect("lead_list")
@login_required
@permission_required("inventory.add_lead", raise_exception=True)
def schedule_lead(request, pk):
def schedule_lead(request, slug):
"""
Handles the scheduling of a lead for an appointment.
@ -4970,7 +4979,7 @@ def schedule_lead(request, pk):
messages.error(request, _("You do not have permission to schedule lead"))
return redirect("lead_list")
dealer = get_user_type(request)
lead = get_object_or_404(models.Lead, pk=pk, dealer=dealer)
lead = get_object_or_404(models.Lead, slug=slug, dealer=dealer)
if request.method == "POST":
form = forms.ScheduleForm(request.POST)
if form.is_valid():
@ -4998,7 +5007,7 @@ def schedule_lead(request, pk):
)
except ValidationError as e:
messages.error(request, str(e))
return redirect("schedule_lead", pk=lead.pk)
return redirect("schedule_lead", slug=lead.slug)
client = get_object_or_404(User, email=lead.email)
# Create Appointment
@ -5022,7 +5031,7 @@ def schedule_lead(request, pk):
@login_required
@permission_required("inventory.change_lead", raise_exception=True)
def lead_transfer(request, pk):
def lead_transfer(request, slug):
"""
Handles the transfer of a lead to a different staff member. This view is accessible
only to authenticated users with the 'inventory.change_lead' permission. If the
@ -5034,7 +5043,7 @@ def lead_transfer(request, pk):
:param pk: The primary key of the lead to be transferred.
:return: An HTTP redirect response to the lead list view.
"""
lead = get_object_or_404(models.Lead, pk=pk)
lead = get_object_or_404(models.Lead, slug=slug)
if request.method == "POST":
form = forms.LeadTransferForm(request.POST)
if form.is_valid():
@ -5194,24 +5203,14 @@ class OpportunityCreateView(CreateView,SuccessMessageMixin, LoginRequiredMixin):
template_name = "crm/opportunities/opportunity_form.html"
success_message = "Opportunity created successfully."
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
def get_initial(self):
initial = super().get_initial()
dealer = get_user_type(self.request)
return context
# def get_form_kwargs(self):
# kwargs = super().get_form_kwargs()
# dealer = get_user_type(self.request)
# kwargs["car"].queryset = models.Car.objects.filter(dealer=dealer,)
# return kwargs
# def get_initial(self):
# initial = super().get_initial()
# if self.kwargs.get("pk", None):
# lead = models.Lead.objects.get(pk=self.kwargs.get("pk"))
# initial["customer"] = lead.customer
# return initial
if self.kwargs.get("slug", None):
lead = models.Lead.objects.get(slug=self.kwargs.get("slug"),dealer=dealer)
initial["lead"] = lead
initial['stage'] = models.Stage.PROPOSAL
return initial
def form_valid(self, form):
dealer = get_user_type(self.request)
@ -5252,7 +5251,7 @@ class OpportunityUpdateView(LoginRequiredMixin,SuccessMessageMixin, UpdateView):
success_message = "Opportunity updated successfully."
def get_success_url(self):
return reverse_lazy("opportunity_detail", kwargs={"pk": self.object.pk})
return reverse_lazy("opportunity_detail", kwargs={"slug": self.object.slug})
class OpportunityDetailView(LoginRequiredMixin, DetailView):
@ -5360,7 +5359,7 @@ def delete_opportunity(request, pk):
@login_required
def opportunity_update_status(request, pk):
def opportunity_update_status(request, slug):
"""
Update the status and/or stage of a specific Opportunity instance. This is a
view function, which is generally tied to a URL endpoint in a Django application.
@ -5385,7 +5384,7 @@ def opportunity_update_status(request, pk):
frontend behavior.
:rtype: HttpResponse
"""
opportunity = get_object_or_404(models.Opportunity, pk=pk)
opportunity = get_object_or_404(models.Opportunity, slug=slug)
status = request.GET.get("status")
stage = request.GET.get("stage")
if status:
@ -5394,7 +5393,7 @@ def opportunity_update_status(request, pk):
opportunity.stage = stage
opportunity.save()
messages.success(request,_("Opportunity status updated successfully"))
response = HttpResponse(redirect("opportunity_detail",pk=opportunity.pk))
response = HttpResponse(redirect("opportunity_detail",slug=opportunity.slug))
response['HX-Refresh'] = 'true'
return response
@ -7784,6 +7783,7 @@ def add_activity(request,content_type,slug):
else:
messages.error(request, _("Activity form is not valid"))
return redirect(f"{content_type}_detail", slug=slug)
def add_task(request,content_type,slug):
try:
model = apps.get_model(f'inventory.{content_type}')
@ -7824,4 +7824,43 @@ def update_task(request,pk):
tasks = models.Tasks.objects.filter(
content_type__model="lead", object_id=lead.id
)
return render(request,'crm/leads/lead_detail.html',{'lead':lead,'tasks':tasks})
return render(request,'crm/leads/lead_detail.html',{'lead':lead,'tasks':tasks})
def add_note(request,content_type,slug):
try:
model = apps.get_model(f'inventory.{content_type}')
except LookupError:
raise Http404("Model not found")
obj = get_object_or_404(model, slug=slug)
dealer = get_user_type(request)
if request.method == "POST":
form = forms.NoteForm(request.POST)
if form.is_valid():
note = form.save(commit=False)
note.dealer = dealer
note.content_object = obj
note.created_by = request.user
note.save()
messages.success(request, _("Note added successfully"))
else:
print(form.errors)
messages.error(request, _("Note form is not valid"))
return redirect(f"{content_type}_detail", slug=slug)
def update_note(request,pk):
note = get_object_or_404(models.Notes, pk=pk)
lead = get_object_or_404(models.Lead, pk=note.content_object.id)
dealer = get_user_type(request)
if request.method == "POST":
note.note = request.POST.get('note')
note.save()
messages.success(request, _("Note updated successfully"))
return redirect(f"lead_detail", slug=lead.slug)
else:
messages.error(request, _("Note form is not valid"))
notes = models.Notes.objects.filter(
content_type__model="lead", object_id=lead.id,dealer=dealer
)
return render(request,'crm/leads/lead_detail.html',{'lead':lead,'notes':notes})

View File

@ -230,7 +230,7 @@
<div class="modal fade" id="exampleModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<form class="modal-content" action="{% url 'lead_transfer' lead.pk %}" method="post">
<form class="modal-content" action="{% url 'lead_transfer' lead.slug %}" method="post">
{% csrf_token %}
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Reassign Lead To Another Employee</h5>
@ -301,10 +301,7 @@
<div class="tab-pane fade" id="tab-notes" role="tabpanel" aria-labelledby="notes-tab">
<div class="mb-1 d-flex align-items-center justify-content-between">
<h3 class="mb-4" id="scrollspyNotes">{{ _("Notes") }}</h3>
<a id="addBtn" href="#" class="btn btn-sm btn-phoenix-primary mb-3 btn-sm" data-url="{% url 'add_note_to_lead' lead.pk %}" data-bs-toggle="modal" data-bs-target="#noteModal" data-note-title="{{ _("Add") }}<i class='fa fa-plus-circle text-success ms-2'></i>">
<span class="fas fa-plus me-1"></span>
{% trans 'Add Note' %}
</a>
<button class="btn btn-phoenix-primary btn-sm" type="button" onclick="reset_form()" data-bs-toggle="modal" data-bs-target="#noteModal"><span class="fas fa-plus me-1"></span>{{ _("Add Note") }}</button>
</div>
<div class="border-top border-bottom border-translucent" id="leadDetailsTable">
@ -331,9 +328,18 @@
<td class="align-middle text-body-tertiary text-start white-space-nowrap">{{ note.created|naturalday|capfirst }}</td>
<td class="align-middle text-end white-space-nowrap pe-0 action py-2">
{% if note.created_by == request.user %}
<a id="updateBtn" href="#" class="btn btn-sm btn-phoenix-primary me-2" data-url="{% url 'update_note_to_lead' note.pk %}" data-bs-toggle="modal" data-bs-target="#noteModal" data-note-title="{{ _("Update") }}<i class='fas fa-pen-square text-primary ms-2'></i>">
<i class="fas fa-pen"></i>
</a>
<a id="updateBtn"
href="#"
onclick="updateNote(this)"
class="btn btn-sm btn-phoenix-primary me-2"
data-pk="{{ note.pk }}"
data-note="{{ note.note|escapejs }}"
data-url="{% url 'update_note' note.pk %}"
data-bs-toggle="modal"
data-bs-target="#noteModal"
data-note-title="{{ _('Update') }}<i class='fas fa-pen-square text-primary ms-2'></i>">
{{ _("Update") }}
</a>
<button class="btn btn-phoenix-danger btn-sm delete-btn"
data-url="{% url 'delete_note_to_lead' note.pk %}"
data-message="Are you sure you want to delete this note?"
@ -535,7 +541,7 @@
</div>
{% include 'modal/delete_modal.html' %}
<!-- add update Modal -->
<div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" aria-hidden="true">
{% comment %} <div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" aria-hidden="true">
<div class="modal-dialog modal-md">
<div class="modal-content">
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
@ -549,7 +555,7 @@
</div>
</div>
</div>
</div>
</div> {% endcomment %}
<!-- activity Modal -->
{% include "components/activity_modal.html" with content_type="lead" slug=lead.slug %}
@ -559,7 +565,7 @@
<div class="modal-dialog modal-md">
<div class="modal-content">
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
<h4 class="modal-title" id="noteModalLabel">{% trans 'Task' %}</h4>
<h4 class="modal-title" id="taskModalLabel">{% trans 'Task' %}</h4>
<button class="btn p-0 text-body-quaternary fs-6" data-bs-dismiss="modal" aria-label="Close">
<span class="fas fa-times"></span>
</button>
@ -574,34 +580,44 @@
</div>
</div>
</div>
<!-- note Modal -->
<div class="modal fade" id="noteModal" tabindex="-1" aria-labelledby="noteModalLabel" aria-hidden="true">
<div class="modal-dialog modal-md">
<div class="modal-content">
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
<h4 class="modal-title" id="noteModalLabel">{% trans 'Note' %}</h4>
<button class="btn p-0 text-body-quaternary fs-6" data-bs-dismiss="modal" aria-label="Close">
<span class="fas fa-times"></span>
</button>
</div>
<div class="modal-body">
<form action="{% url 'add_note' 'lead' lead.slug %}" method="post" class="add_note_form">
{% csrf_token %}
{{ note_form|crispy }}
<button type="submit" class="btn btn-success w-100">{% trans 'Save' %}</button>
</form>
</div>
</div>
</div>
</div>
{% endblock content %}
{% block customJS %}
<script>
function updateNote(e) {
let url = e.getAttribute('data-url')
let note = e.getAttribute('data-note')
document.querySelector('#id_note').value = note
let form = document.querySelector('.add_note_form')
form.action = url
}
function reset_form() {
document.querySelector('#id_note').value = ""
let form = document.querySelector('.add_note_form')
form.action = "{% url 'add_note' 'lead' lead.slug %}"
}
document.addEventListener("DOMContentLoaded", function () {
const noteModal = document.getElementById("noteModal");
const modalTitle = document.getElementById("noteModalLabel");
const modalBody = noteModal.querySelector(".modal-body");
noteModal.addEventListener("show.bs.modal", function (event) {
const button = event.relatedTarget;
const url = button.getAttribute("data-url");
const title = button.getAttribute("data-note-title");
fetch(url)
.then((response) => response.text())
.then((html) => {
modalBody.innerHTML = html;
modalTitle.innerHTML = title;
})
.catch((error) => {
modalBody.innerHTML = '<p class="text-danger">{% trans 'Error loading form. Please try again later' %}.</p>';
console.error("Error loading form:", error);
});
});
});
let Toast = Swal.mixin({
toast: true,
position: "top-end",
@ -723,5 +739,6 @@
titleText: msg
});
}
});
</script>
{% endblock customJS %}

View File

@ -240,7 +240,7 @@
</td> {% endcomment %}
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">
{% if lead.opportunity %}
<a href="{% url 'opportunity_detail' lead.opportunity.id %}">
<a href="{% url 'opportunity_detail' lead.opportunity.slug %}">
<span class="badge badge-phoenix badge-phoenix-success">Opportunity {{ lead.opportunity.lead}} <i class="fa-solid fa-arrow-up-right-from-square"></i></span>
</a>
{% endif %}
@ -260,15 +260,15 @@
</button>
<div class="dropdown-menu dropdown-menu-end py-2">
{% if perms.inventory.change_lead %}
<a href="{% url 'lead_update' lead.id %}" class="dropdown-item text-success-dark">{% trans "Edit" %}</a>
<a href="{% url 'lead_update' lead.slug %}" class="dropdown-item text-success-dark">{% trans "Edit" %}</a>
{% endif %}
<button class="dropdown-item text-primary" onclick="openActionModal('{{ lead.id }}', '{{ lead.action }}', '{{ lead.next_action }}', '{{ lead.next_action_date|date:"Y-m-d\TH:i" }}')">
<button class="dropdown-item text-primary" onclick="openActionModal('{{ lead.pk }}', '{{ lead.action }}', '{{ lead.next_action }}', '{{ lead.next_action_date|date:"Y-m-d\TH:i" }}')">
{% trans "Update Actions" %}
</button>
<a href="{% url 'send_lead_email' lead.id %}" class="dropdown-item text-success-dark">{% trans "Send Email" %}</a>
<a href="{% url 'schedule_lead' lead.id %}" class="dropdown-item text-success-dark">{% trans "Schedule Event" %}</a>
<a href="{% url 'send_lead_email' lead.slug %}" class="dropdown-item text-success-dark">{% trans "Send Email" %}</a>
<a href="{% url 'schedule_lead' lead.slug %}" class="dropdown-item text-success-dark">{% trans "Schedule Event" %}</a>
{% if not lead.opportunity %}
<a href="{% url 'lead_convert' lead.id %}" class="dropdown-item text-success-dark">{% trans "Convert" %}</a>
<a href="{% url 'lead_opportunity_create' lead.slug %}" class="dropdown-item text-success-dark">{% trans "Convert to Opportunity" %}</a>
{% endif %}
<div class="dropdown-divider"></div>
{% if perms.inventory.delete_lead %}

View File

@ -3,7 +3,7 @@
{% if form.instance.pk %}
<form method="post" action="{% url 'update_note_to_lead' note.pk %}" enctype="multipart/form-data">
{% else %}
<form method="post" action="{% url 'add_note_to_lead' lead.pk %}" enctype="multipart/form-data">
<form method="post" action="{% url 'add_note_to_lead' lead.slug %}" enctype="multipart/form-data">
{% endif %}
{% csrf_token %}

View File

@ -18,7 +18,7 @@
<a class="dropdown-item" href="{% url 'estimate_create_from_opportunity' opportunity.pk %}">{{ _("Create Quotation")}}</a>
{% endif %}
</li>
<li><a class="dropdown-item" href="{% url 'update_opportunity' opportunity.pk %}">Update Opportunity</a></li>
<li><a class="dropdown-item" href="{% url 'update_opportunity' opportunity.slug %}">Update Opportunity</a></li>
<li><a class="dropdown-item text-danger" href="">Delete Opportunity</a></li>
</ul>
</div>
@ -79,7 +79,7 @@
</div>
</div>
</div>
<div class="card">
{% comment %} <div class="card">
<div class="card-body">
<h4 class="mb-5">{{ _("Other Information")}}</h4>
<div class="row g-3">
@ -101,7 +101,7 @@
</div>
</div>
</div>
</div>
</div> {% endcomment %}
</div>
</div>
<div class="col-xl-7 col-xxl-8">
@ -330,7 +330,7 @@
</div>
<div class="tab-pane fade" id="tab-notes" role="tabpanel" aria-labelledby="notes-tab">
<h2 class="mb-4">Notes</h2>
<form action="{% url 'add_note_to_opportunity' opportunity.pk %}" method="post">
<form action="{% url 'add_note_to_opportunity' opportunity.slug %}" method="post">
{% csrf_token %}
<textarea class="form-control mb-3" id="notes" rows="4" name="notes" required> </textarea>
<button type="submit" class="btn btn-primary mb-3">Add Note</button>
@ -366,7 +366,7 @@
<button class="btn btn-link p-0 ms-3 fs-9 text-primary fw-bold text-decoration-none"><span class="fas fa-sort me-1 fw-extra-bold fs-10"></span>Sorting</button>
</div>
<div class="col-auto">
<a href="{% url 'schedule_lead' opportunity.lead.id %}" class="btn btn-primary"><span class="fa-solid fa-plus me-2"></span>Add Meeting </a>
<a href="{% url 'schedule_lead' opportunity.lead.slug %}" class="btn btn-primary"><span class="fa-solid fa-plus me-2"></span>Add Meeting </a>
</div>
</div>
<div class="row g-3">
@ -394,7 +394,7 @@
</div>
<div class="col-auto">
<a href="{% url 'schedule_lead' opportunity.lead.id %}" class="btn btn-primary"><span class="fa-solid fa-plus me-2"></span>Add Call</a>
<a href="{% url 'schedule_lead' opportunity.lead.slug %}" class="btn btn-primary"><span class="fa-solid fa-plus me-2"></span>Add Call</a>
</div>
</div>
<div class="border-top border-bottom border-translucent" id="leadDetailsTable" data-list='{"valueNames":["name","description","create_date","create_by","last_activity"],"page":5,"pagination":true}'>
@ -553,5 +553,5 @@
</div>
</div>
</div>
{% include "components/activity_modal.html" with content_type="opportunity" pk=opportunity.pk %}
{% include "components/activity_modal.html" with content_type="opportunity" slug=opportunity.slug %}
{% endblock %}

View File

@ -96,10 +96,10 @@
</div>
<div class="d-flex gap-2">
<a class="btn btn-sm btn-phoenix-primary" href="{% url 'opportunity_detail' opportunity.pk %}">
<a class="btn btn-sm btn-phoenix-primary" href="{% url 'opportunity_detail' opportunity.slug %}">
{{ _("View Details") }} <i class="fa-solid fa-eye ms-2"></i>
</a>
<a class="btn btn-sm btn-phoenix-success" href="{% url 'update_opportunity' opportunity.pk %}">
<a class="btn btn-sm btn-phoenix-success" href="{% url 'update_opportunity' opportunity.slug %}">
{{ _("Update") }} <i class="fa-solid fa-pen ms-2"></i>
</a>
</div>

View File

@ -1,6 +1,6 @@
{% load i18n static crispy_forms_filters %}
<form method="post" action="{% url 'add_note_to_customer' customer.pk %}" enctype="multipart/form-data">
<form method="post" action="{% url 'add_note_to_customer' customer.slug %}" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-sm btn-success w-100">{{ _("Add") }}</button>