910 lines
55 KiB
HTML
910 lines
55 KiB
HTML
{% extends 'base.html' %}
|
|
{% load i18n static humanize %}
|
|
{% load crispy_forms_tags %}
|
|
{% block title %}
|
|
{{ _("Opportunity Detail") }}
|
|
{% endblock title %}
|
|
{% block content %}
|
|
<div class="row align-items-center justify-content-between g-3 mb-4 mt-4">
|
|
<div class="col-12 col-md-auto">
|
|
<h2 class="mb-0">{{ _("Opportunity details") }}</h2>
|
|
</div>
|
|
<div class="col-12 col-md-auto d-flex">
|
|
<div>
|
|
<button class="btn px-3 btn-phoenix-secondary"
|
|
type="button"
|
|
data-bs-toggle="dropdown"
|
|
data-boundary="window"
|
|
aria-haspopup="true"
|
|
aria-expanded="false"
|
|
data-bs-reference="parent">
|
|
<span class="fa-solid fa-ellipsis"></span>
|
|
</button>
|
|
<ul class="dropdown-menu dropdown-menu-end p-0" style="z-index: 9999;">
|
|
<li>
|
|
{% if opportunity.estimate %}
|
|
{% if perms.django_ledger.view_estimatemodel %}
|
|
<a class="dropdown-item"
|
|
href="{% url 'estimate_detail' request.dealer.slug opportunity.estimate.pk %}">{{ _("View Quotation") }}</a>
|
|
{% endif %}
|
|
{% else %}
|
|
{% if perms.django_ledger.add_estimatemodel and not opportunity.estimate %}
|
|
<a class="dropdown-item"
|
|
type="button"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#estimateModal">{% trans "Create Estimate" %}</a>
|
|
{% endif %}
|
|
{% endif %}
|
|
</li>
|
|
{% if perms.inventory.change_opportunity %}
|
|
<li>
|
|
<a class="dropdown-item"
|
|
href="{% url 'update_opportunity' request.dealer.slug opportunity.slug %}">{% trans "Update Opportunity" %}</a>
|
|
</li>
|
|
<li>
|
|
<a class="dropdown-item"
|
|
type="button"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#updateStageModal">{% trans "Update Stage" %}</a>
|
|
</li>
|
|
{% endif %}
|
|
{% if perms.inventory.delete_opportunity %}
|
|
<li>
|
|
<a class="dropdown-item text-danger" href="">{% trans "Delete Opportunity" %}</a>
|
|
</li>
|
|
{% endif %}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row g-4 g-xl-6 other-information">
|
|
<div class="col-xl-5 col-xxl-4">
|
|
<div class="sticky-leads-sidebar">
|
|
<div class="card mb-3">
|
|
<div class="card-body">
|
|
<div class="row align-items-center g-3">
|
|
<div class="col-12 col-sm-auto flex-1">
|
|
{% if opportunity.car %}
|
|
<h3 class="fw-bolder mb-2 line-clamp-1">
|
|
<span class="d-inline-block lh-sm me-1"
|
|
data-feather="check-circle"
|
|
style="height:16px;
|
|
width:16px"></span> {{ opportunity.car.id_car_make.get_local_name }} - {{ opportunity.car.id_car_model.get_local_name }} - {{ opportunity.car.year }}
|
|
</h3>
|
|
{% endif %}
|
|
<div class="d-flex align-items-center mb-4">
|
|
{% if opportunity.car.marked_price %}
|
|
<span class="">{% trans "Marked Price: " %}</span>
|
|
<h5 class="mb-0 me-4">
|
|
{{ opportunity.car.marked_price }} <span class="fw-light"><span class="icon-saudi_riyal"></span></span>
|
|
</h5>
|
|
{% endif %}
|
|
</div>
|
|
<div class="d-md-flex d-xl-block align-items-center justify-content-between mb-5">
|
|
<div class="d-flex align-items-center mb-3 mb-md-0 mb-xl-3">
|
|
<div class="avatar avatar-xl me-3">
|
|
{% if opportunity.car.id_car_make.logo %}
|
|
<img class="rounded"
|
|
src="{{ opportunity.car.id_car_make.logo.url }}"
|
|
alt="" />
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div>
|
|
{% if opportunity.customer %}
|
|
<h5>{{ opportunity.customer|capfirst }}</h5>
|
|
<div class="">
|
|
<div class="text-body-secondary text-decoration-none">
|
|
{% trans "Individual" %}<span class="fa-solid text-body-secondary fs-9 ms-2"></span>
|
|
</div>
|
|
{% else %}
|
|
<h5>{{ opportunity.organization|capfirst }}</h5>
|
|
<div class="">
|
|
<div class="text-body-secondary text-decoration-none">
|
|
{% trans "Organization" %}<span class="fa-solid text-body-secondary fs-9 ms-2"></span>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<span class="badge badge-phoenix badge-phoenix-primary">{% trans "STAGE" %}</span> : <span class="badge badge-phoenix badge-phoenix-success me-2">{{ opportunity.get_stage_display }}</span><span class="badge badge-phoenix badge-phoenix-danger me-2">{{ opportunity.get_status_display }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="progress mb-2" style="height:5px">
|
|
<div class="progress-bar bg-primary-lighter"
|
|
data-bs-theme="light"
|
|
role="progressbar"
|
|
style="width: {{ opportunity.probability }}%"
|
|
aria-valuenow="25"
|
|
aria-valuemin="0"
|
|
aria-valuemax="100"></div>
|
|
</div>
|
|
<div class="d-flex align-items-center justify-content-between">
|
|
<p class="mb-0">{{ opportunity.get_status_display }}</p>
|
|
<div>
|
|
<span class="d-inline-block lh-sm me-1"
|
|
data-feather="clock"
|
|
style="height:16px;
|
|
width:16px"></span><span class="d-inline-block lh-sm">{{ opportunity.created|naturaltime|capfirst }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card mb-3">
|
|
<div class="card-body">
|
|
<img class="w-100"
|
|
src="{% static 'images/car_images/' %}{{ opportunity.car.get_hash }}.png"
|
|
alt="{{ car.vin }}" />
|
|
</div>
|
|
</div>
|
|
<div class="card mb-3">
|
|
<div class="card-body">
|
|
<h4 class="mb-5 d-flex align-items-center">
|
|
<span class="d-inline-block lh-sm me-1"
|
|
data-feather="link"
|
|
style="height:16px;
|
|
width:16px"></span> {{ _("Upcoming Events") }}
|
|
</h4>
|
|
<div class="row g-3">
|
|
<div class="col-12 overflow-auto" style="max-height: 200px;">
|
|
<ul class="list-group list-group-flush">
|
|
{% for event in schedules %}
|
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
<div class="d-flex align-items-center">
|
|
<span class="badge rounded-pill bg-phoenix-primary text-primary me-2 fs-9">{{ event.scheduled_type|capfirst }}</span>
|
|
<span class="fs-9">{{ event.purpose }}</span>
|
|
</div>
|
|
<div class="fs-9">{{ event.scheduled_at|naturaltime|capfirst }}</div>
|
|
</li>
|
|
{% empty %}
|
|
<li class="list-group-item text-center fs-9">{{ _("No upcoming events") }}</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h4 class="mb-5 d-flex align-items-center">
|
|
<span class="d-inline-block lh-sm me-1"
|
|
data-feather="link"
|
|
style="height:16px;
|
|
width:16px"></span> {{ _("Related Records") }}
|
|
</h4>
|
|
<div class="row g-3">
|
|
<div class="col-12">
|
|
<div class="mb-4">
|
|
<div class="d-flex flex-wrap justify-content-between mb-2">
|
|
<h5 class="mb-0 text-body-highlight me-2">{{ _("Estimate") }}</h5>
|
|
</div>
|
|
{% if opportunity.estimate %}
|
|
<a class="dropdown-item"
|
|
href="{% url 'estimate_detail' request.dealer.slug opportunity.estimate.pk %}">{{ _("View Quotation") }}</a>
|
|
{% else %}
|
|
<p>{{ _("No Estimate") }}</p>
|
|
{% endif %}
|
|
</div>
|
|
<div class="mb-4">
|
|
<div class="d-flex flex-wrap justify-content-between mb-2">
|
|
<h5 class="mb-0 text-body-highlight me-2">{{ _("Invoice") }}</h5>
|
|
</div>
|
|
{% if opportunity.estimate.invoicemodel_set.all %}
|
|
<a class="dropdown-item"
|
|
href="{% url 'invoice_detail' request.dealer.slug request.entity.slug opportunity.estimate.invoicemodel_set.first.pk %}">{{ _("View Invoice") }}</a>
|
|
{% else %}
|
|
<p>{{ _("No Invoice") }}</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card mt-3">
|
|
<div class="card-body">
|
|
<h4 class="mb-5 d-flex align-items-center">
|
|
<span class="d-inline-block lh-sm me-1"
|
|
data-feather="clock"
|
|
style="height:16px;
|
|
width:16px"></span> {{ _("System Information") }}
|
|
</h4>
|
|
<div class="row g-3">
|
|
<div class="col-12">
|
|
<div class="mb-4">
|
|
<div class="d-flex flex-wrap justify-content-between mb-2">
|
|
<h5 class="mb-0 text-body-highlight me-2">{{ _("Created ") }}</h5>
|
|
</div>
|
|
{{ opportunity.created|naturalday|capfirst }}
|
|
</div>
|
|
<div class="mb-4">
|
|
<div class="d-flex flex-wrap justify-content-between mb-2">
|
|
<h5 class="mb-0 text-body-highlight me-2">{{ _("Last Updated") }}</h5>
|
|
</div>
|
|
</div>
|
|
{{ opportunity.updated }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-xl-7 col-xxl-8">
|
|
{% comment %} <div class="card mb-5">
|
|
<div class="card-body">
|
|
<div class="row g-4 g-xl-1 g-xxl-3 justify-content-between">
|
|
<div class="col-sm-auto">
|
|
<div class="d-sm-block d-inline-flex d-md-flex flex-xl-column flex-xxl-row align-items-center align-items-xl-start align-items-xxl-center">
|
|
<div class="d-flex bg-primary-subtle rounded flex-center me-3 mb-sm-3 mb-md-0 mb-xl-3 mb-xxl-0"
|
|
style="width:32px;
|
|
height:32px">
|
|
<span class="text-primary-dark"
|
|
data-feather="layout"
|
|
style="width:24px;
|
|
height:24px"></span>
|
|
</div>
|
|
<div>
|
|
<p class="fw-bold mb-1">{{ _("Quotation Amount") }}</p>
|
|
<h4 class="fw-bolder text-nowrap">
|
|
{% if opportunity.estimate %}{{ opportunity.estimate.get_invoiced_amount.invoice_amount_paid__sum }}{% endif %}
|
|
</h4>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-sm-auto">
|
|
<div class="d-sm-block d-inline-flex d-md-flex flex-xl-column flex-xxl-row align-items-center align-items-xl-start align-items-xxl-center border-start-sm ps-sm-5 border-translucent">
|
|
<div class="d-flex bg-success-subtle rounded flex-center me-3 mb-sm-3 mb-md-0 mb-xl-3 mb-xxl-0"
|
|
style="width:32px;
|
|
height:32px">
|
|
<span class="text-success-dark icon-saudi_riyal"
|
|
style="width:24px;
|
|
height:24px"></span>
|
|
</div>
|
|
<div>
|
|
<p class="fw-bold mb-1">{{ _("Amount") }}</p>
|
|
<h4 class="fw-bolder text-nowrap">{{ opportunity.amount }}</h4>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div> {% endcomment %}
|
|
<div class="px-xl-4 mb-7">
|
|
<div class="row mx-0 mx-sm-3 mx-lg-0 px-lg-0">
|
|
|
|
<div class="col-sm-12 col-xxl-6 border-bottom border-translucent py-3">
|
|
<table class="w-100 table-stats">
|
|
<tr>
|
|
<th></th>
|
|
<th></th>
|
|
<th></th>
|
|
</tr>
|
|
<tr>
|
|
<td class="py-2">
|
|
<div class="d-inline-flex align-items-center">
|
|
<div class="d-flex bg-primary-subtle rounded-circle flex-center me-3"
|
|
style="width:24px;
|
|
height:24px">
|
|
<span class="text-primary-dark"
|
|
data-feather="phone"
|
|
style="width:16px;
|
|
height:16px"></span>
|
|
</div>
|
|
<p class="fw-bold mb-0">{{ _("Phone Number") }}</p>
|
|
</div>
|
|
</td>
|
|
<td class="py-2 d-none d-sm-block pe-sm-2">:</td>
|
|
<td class="py-2">
|
|
<a class="ps-6 ps-sm-0 fw-semibold mb-0 pb-3 pb-sm-0 text-body"
|
|
href="tel:{{ opportunity.customer.phone_number }}">{{ opportunity.customer.phone_number }}</a>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="py-2">
|
|
<div class="d-flex align-items-center">
|
|
<div class="d-flex bg-warning-subtle rounded-circle flex-center me-3"
|
|
style="width:24px;
|
|
height:24px">
|
|
<span class="text-warning-dark"
|
|
data-feather="mail"
|
|
style="width:16px;
|
|
height:16px"></span>
|
|
</div>
|
|
<p class="fw-bold mb-0">{{ _("Email") }}</p>
|
|
</div>
|
|
</td>
|
|
<td class="py-2 d-none d-sm-block pe-sm-2">:</td>
|
|
<td class="py-2">
|
|
<a class="ps-6 ps-sm-0 fw-semibold mb-0 text-body"
|
|
href="mailto:{{ opportunity.customer.email }}">{{ opportunity.customer.email }}</a>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="col-sm-12 col-xxl-6 border-end-xxl border-bottom border-bottom-xxl-0 py-3 border-translucent">
|
|
<table class="w-100 table-stats">
|
|
<tr>
|
|
<th></th>
|
|
<th></th>
|
|
<th></th>
|
|
</tr>
|
|
<tr>
|
|
<td class="py-2">
|
|
<div class="d-inline-flex align-items-center">
|
|
<div class="d-flex bg-success-subtle rounded-circle flex-center me-3"
|
|
style="width:24px;
|
|
height:24px">
|
|
<span class="text-success-dark"
|
|
data-feather="users"
|
|
style="width:16px;
|
|
height:16px"></span>
|
|
</div>
|
|
<p class="fw-bold mb-0">{{ _("Contact Name") }}</p>
|
|
</div>
|
|
</td>
|
|
<td class="py-2 d-none d-sm-block pe-sm-2">:</td>
|
|
<td class="py-2">
|
|
{% if opportunity.customer %}
|
|
<div class="ps-6 ps-sm-0 fw-semibold mb-0 pb-3 pb-sm-0">{{ opportunity.customer.full_name }}</div>
|
|
{% else %}
|
|
<div class="ps-6 ps-sm-0 fw-semibold mb-0 pb-3 pb-sm-0">{{ opportunity.organization }}</div>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="py-2">
|
|
<div class="d-flex align-items-center">
|
|
<div class="d-flex bg-info-subtle rounded-circle flex-center me-3"
|
|
style="width:24px;
|
|
height:24px">
|
|
<span class="text-info-dark"
|
|
data-feather="edit"
|
|
style="width:16px;
|
|
height:16px"></span>
|
|
</div>
|
|
<p class="fw-bold mb-0">{{ _("Assigned To") }}</p>
|
|
</div>
|
|
</td>
|
|
<td class="py-2 d-none d-sm-block pe-sm-2">:</td>
|
|
<td class="py-2">
|
|
{% if request.user.email == opportunity.staff.email %}
|
|
<div class="ps-6 ps-sm-0 fw-semibold mb-0">{% trans "You" %}</div>
|
|
{% else %}
|
|
<div class="ps-6 ps-sm-0 fw-semibold mb-0">{{ opportunity.staff.fullname }}</div>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="col-sm-12 col-xxl-6 py-3">
|
|
<table class="w-100 table-stats">
|
|
<tr>
|
|
<th></th>
|
|
<th></th>
|
|
<th></th>
|
|
</tr>
|
|
<tr>
|
|
<td class="py-2">
|
|
<div class="d-inline-flex align-items-center">
|
|
<div class="d-flex bg-info-subtle rounded-circle flex-center me-3"
|
|
style="width:24px;
|
|
height:24px">
|
|
<span class="text-info-dark"
|
|
data-feather="clock"
|
|
style="width:16px;
|
|
height:16px"></span>
|
|
</div>
|
|
<p class="fw-bold mb-0">{{ _("Create Date") }}</p>
|
|
</div>
|
|
</td>
|
|
<td class="py-2 d-none d-sm-block pe-sm-2">:</td>
|
|
<td class="py-2">
|
|
<div class="ps-6 ps-sm-0 fw-semibold mb-0 pb-3 pb-sm-0">{{ opportunity.created|naturaltime|capfirst }}</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="py-2">
|
|
<div class="d-flex align-items-center">
|
|
<div class="d-flex bg-warning-subtle rounded-circle flex-center me-3"
|
|
style="width:24px;
|
|
height:24px">
|
|
<span class="text-warning-dark"
|
|
data-feather="clock"
|
|
style="width:16px;
|
|
height:16px"></span>
|
|
</div>
|
|
<p class="fw-bold mb-0">{{ _("Expected Closing Date") }}</p>
|
|
</div>
|
|
</td>
|
|
<td class="py-2 d-none d-sm-block pe-sm-2">:</td>
|
|
<td class="py-2">
|
|
<div class="ps-6 ps-sm-0 fw-semibold mb-0">{{ opportunity.expected_close_date|date }}</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<ul class="nav nav-underline fs-9 deal-details scrollbar flex-nowrap w-100 pb-1 mb-6"
|
|
id="myTab"
|
|
role="tablist"
|
|
style="overflow-y: hidden">
|
|
<li class="nav-item text-nowrap me-2" role="presentation">
|
|
<a class="nav-link active"
|
|
id="tasks-tab"
|
|
data-bs-toggle="tab"
|
|
href="#tab-tasks"
|
|
role="tab"
|
|
aria-controls="tab-tasks"
|
|
aria-selected="true"> <span class="fa-solid fa-envelope me-2 tab-icon-color fs-8"></span>{{ _("Tasks") }}</a>
|
|
</li>
|
|
<li class="nav-item text-nowrap me-2" role="presentation">
|
|
<a class="nav-link"
|
|
id="notes-tab"
|
|
data-bs-toggle="tab"
|
|
href="#tab-notes"
|
|
role="tab"
|
|
aria-controls="tab-notes"
|
|
aria-selected="false"
|
|
tabindex="-1"> <span class="fa-solid fa-clipboard me-2 tab-icon-color"></span>{{ _("Notes") }}</a>
|
|
</li>
|
|
{% comment %} <li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link" id="meeting-tab" data-bs-toggle="tab" href="#tab-meeting" role="tab" aria-controls="tab-meeting" aria-selected="true"> <span class="fa-solid fa-video me-2 tab-icon-color"></span>{{ _("Meetings") }}</a></li> {% endcomment %}
|
|
{% comment %} <li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link" id="task-tab" data-bs-toggle="tab" href="#tab-task" role="tab" aria-controls="tab-task" aria-selected="true"> <span class="fa-solid fa-square-check me-2 tab-icon-color"></span>Task</a></li> {% endcomment %}
|
|
{% comment %} <li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link" id="call-tab" data-bs-toggle="tab" href="#tab-call" role="tab" aria-controls="tab-call" aria-selected="true"> <span class="fa-solid fa-phone me-2 tab-icon-color"></span>{{ _("Calls") }}</a></li> {% endcomment %}
|
|
{% comment %} <li class="nav-item text-nowrap me-2" role="presentation">
|
|
<a class="nav-link"
|
|
id="emails-tab"
|
|
data-bs-toggle="tab"
|
|
href="#tab-emails"
|
|
role="tab"
|
|
aria-controls="tab-emails"
|
|
aria-selected="true"> <span class="fa-solid fa-envelope me-2 tab-icon-color"></span>{{ _("Emails") }} </a>
|
|
</li> {% endcomment %}
|
|
<li class="nav-item text-nowrap me-2" role="presentation">
|
|
<a class="nav-link"
|
|
id="activity-tab"
|
|
data-bs-toggle="tab"
|
|
href="#tab-activity"
|
|
role="tab"
|
|
aria-controls="tab-activity"
|
|
aria-selected="false"
|
|
tabindex="-1"> <span class="fa-solid fa-chart-line me-2 tab-icon-color"></span>{{ _("Activity") }}</a>
|
|
</li>
|
|
{% comment %} <li class="nav-item text-nowrap me-2" role="presentation"><a class="nav-link" id="attachments-tab" data-bs-toggle="tab" href="#tab-attachments" role="tab" aria-controls="tab-attachments" aria-selected="true"> <span class="fa-solid fa-paperclip me-2 tab-icon-color"></span>Attachments</a></li> {% endcomment %}
|
|
</ul>
|
|
<div class="tab-content" id="myTabContent">
|
|
<div class="tab-pane fade active show"
|
|
id="tab-tasks"
|
|
role="tabpanel"
|
|
aria-labelledby="tasks-tab">
|
|
<div class="mb-1 d-flex justify-content-between align-items-center">
|
|
<h3 class="mb-0" id="scrollspyEmails">{{ _("Tasks") }}</h3>
|
|
{% if perms.inventory.change_opportunity %}
|
|
<button class="btn btn-phoenix-primary btn-sm"
|
|
type="button"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#scheduleModal">
|
|
<span class="fas fa-plus me-1"></span>{{ _("Add Task") }}
|
|
</button>
|
|
{% endif %}
|
|
</div>
|
|
<div>
|
|
<div class="border-top border-bottom border-translucent"
|
|
id="allEmailsTable"
|
|
data-list='{"valueNames":["subject","sent","date","source","status"],"page":7,"pagination":true}'>
|
|
<div class="table-responsive scrollbar mx-n1 px-1">
|
|
<table class="table fs-9 mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th class="white-space-nowrap fs-9 align-middle ps-0" style="width:26px;">
|
|
<div class="form-check mb-0 fs-8">
|
|
<input class="form-check-input"
|
|
type="checkbox"
|
|
data-bulk-select='{"body":"all-email-table-body"}' />
|
|
</div>
|
|
</th>
|
|
<th class="sort white-space-nowrap align-middle pe-3 ps-0 text-uppercase"
|
|
scope="col"
|
|
data-sort="subject"
|
|
style="width:31%;
|
|
min-width:350px">{% trans "Title" %}</th>
|
|
<th class="sort white-space-nowrap align-middle pe-3 ps-0 text-uppercase"
|
|
scope="col"
|
|
data-sort="subject"
|
|
style="width:31%;
|
|
min-width:350px">{% trans "Notes" %}</th>
|
|
{% comment %} <th class="sort align-middle pe-3 text-uppercase"
|
|
scope="col"
|
|
data-sort="sent"
|
|
style="width:15%;
|
|
min-width:130px">{% trans "Assigned to" %}</th> {% endcomment %}
|
|
<th class="sort align-middle text-start text-uppercase"
|
|
scope="col"
|
|
data-sort="date"
|
|
style="min-width:165px">{% trans "Due Date" %}</th>
|
|
<th class="sort align-middle text-start text-uppercase"
|
|
scope="col"
|
|
data-sort="date"
|
|
style="min-width:165px">{% trans "Completed" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="list taskTable" id="all-tasks-table-body">
|
|
{% for task in schedules %}
|
|
{% include "partials/task.html" %}
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% comment %} <div class="row align-items-center justify-content-between py-2 pe-0 fs-9">
|
|
<div class="col-auto d-flex">
|
|
<p class="mb-0 d-none d-sm-block me-3 fw-semibold text-body"
|
|
data-list-info="data-list-info"></p>
|
|
<a class="fw-semibold" href="" data-list-view="*">{% trans "View all" %}<span class="fas fa-angle-right ms-1" data-fa-transform="down-1"></span></a><a class="fw-semibold d-none" href="" data-list-view="less">View Less<span class="fas fa-angle-right ms-1" data-fa-transform="down-1"></span></a>
|
|
</div>
|
|
<div class="col-auto d-flex">
|
|
<button class="page-link" data-list-pagination="prev">
|
|
<span class="fas fa-chevron-left"></span>
|
|
</button>
|
|
<ul class="mb-0 pagination">
|
|
</ul>
|
|
<button class="page-link pe-0" data-list-pagination="next">
|
|
<span class="fas fa-chevron-right"></span>
|
|
</button>
|
|
</div>
|
|
</div> {% endcomment %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<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>
|
|
{% if perms.inventory.change_lead %}
|
|
<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>
|
|
{% endif %}
|
|
</div>
|
|
<div class="border-top border-bottom border-translucent"
|
|
id="leadDetailsTable">
|
|
<div class="table-responsive scrollbar mx-n1 px-1">
|
|
<table class="table fs-9 mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th class="align-middle pe-6 text-uppercase text-start"
|
|
scope="col"
|
|
style="width:40%">{{ _("Note") }}</th>
|
|
<th class="align-middle text-start text-uppercase white-space-nowrap"
|
|
scope="col"
|
|
style="width:40%">{{ _("Created On") }}</th>
|
|
<th class="align-middle text-start text-uppercase white-space-nowrap"
|
|
scope="col"
|
|
style="width:40%">{{ _("Last Updated") }}</th>
|
|
<th class="align-middle pe-0 text-end" scope="col" style="width:10%;"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="notesTable">
|
|
{% for note in opportunity.get_notes %}
|
|
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
|
<td class="align-middle text-start fw-bold text-body-tertiary ps-1">{{ note.note }}</td>
|
|
<td class="align-middle text-body-tertiary text-start white-space-nowrap">{{ note.created|naturalday|capfirst }}</td>
|
|
<td class="align-middle text-body-tertiary text-start white-space-nowrap">{{ note.updated|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="#"
|
|
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' request.dealer.slug 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' request.dealer.slug note.pk %}"
|
|
data-message="Are you sure you want to delete this note?"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#deleteModal">
|
|
<i class="fas fa-trash"></i>
|
|
</button>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="tab-pane fade"
|
|
id="tab-emails"
|
|
role="tabpanel"
|
|
aria-labelledby="emails-tab">
|
|
<h2 class="mb-4">Emails</h2>
|
|
{% if perms.inventory.change_opportunity %}
|
|
<div class="d-flex justify-content-end">
|
|
|
|
{% if opportunity.lead %}
|
|
<button class="btn btn-phoenix-primary btn-sm"
|
|
type="button"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#emailModal"
|
|
hx-get="{% url 'send_lead_email' request.dealer.slug opportunity.lead.slug %}"
|
|
hx-target="#emailModalBody"
|
|
hx-select=".email-form"
|
|
hx-swap="innerHTML">
|
|
<span class="fas fa-plus me-1"></span>{{ _("Send Email") }}
|
|
</button>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
<div>
|
|
<div class="scrollbar">
|
|
<ul class="nav nav-underline fs-9 flex-nowrap mb-1"
|
|
id="emailTab"
|
|
role="tablist">
|
|
<li class="nav-item me-3">
|
|
<a class="nav-link text-nowrap border-0 active"
|
|
id="mail-tab"
|
|
data-bs-toggle="tab"
|
|
href="#tab-mail"
|
|
aria-controls="mail-tab"
|
|
role="tab"
|
|
aria-selected="true">Mails ({{ opportunity.lead.get_emails|length }})<span class="text-body-tertiary fw-normal"></span></a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="tab-content" id="profileTabContent">
|
|
<div class="tab-pane fade show active"
|
|
id="tab-mail"
|
|
role="tabpanel"
|
|
aria-labelledby="mail-tab">
|
|
<div class="border-top border-bottom border-translucent"
|
|
id="allEmailsTable"
|
|
data-list='{"valueNames":["subject","sent","date","source","status"],"page":7,"pagination":true}'>
|
|
<div class="table-responsive scrollbar mx-n1 px-1">
|
|
<table class="table fs-9 mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th class="sort white-space-nowrap align-middle pe-3 ps-0 text-uppercase"
|
|
scope="col"
|
|
data-sort="subject"
|
|
style="width:31%;
|
|
min-width:350px">{% trans "Subject" %}</th>
|
|
<th class="sort align-middle pe-3 text-uppercase"
|
|
scope="col"
|
|
data-sort="sent"
|
|
style="width:15%;
|
|
min-width:130px">{% trans "Sent by" %}</th>
|
|
<th class="sort align-middle text-start text-uppercase"
|
|
scope="col"
|
|
data-sort="date"
|
|
style="min-width:15px">{% trans "Date" %}</th>
|
|
<th class="sort align-middle text-end text-uppercase"
|
|
scope="col"
|
|
data-sort="status"
|
|
style="width:15%;
|
|
min-width:100px">{% trans "Status" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="list" id="all-email-table-body">
|
|
{% for email in opportunity.lead.get_emails %}
|
|
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
|
<td class="subject order align-middle white-space-nowrap py-2 ps-0">
|
|
<a class="fw-semibold text-primary" href="#!">{{ email.subject }}</a>
|
|
<div class="fs-10 d-block">{{ email.to_email }}</div>
|
|
</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 }}</td>
|
|
<td class="status align-middle fw-semibold text-end py-2">
|
|
<span class="badge badge-phoenix fs-10 badge-phoenix-success">{% trans "sent" %}</span>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="row align-items-center justify-content-between py-2 pe-0 fs-9">
|
|
<div class="col-auto d-flex">
|
|
<p class="mb-0 d-none d-sm-block me-3 fw-semibold text-body"
|
|
data-list-info="data-list-info"></p>
|
|
<a class="fw-semibold" href="#!" data-list-view="*">{% trans "View all" %}<span class="fas fa-angle-right ms-1" data-fa-transform="down-1"></span></a><a class="fw-semibold d-none" href="#!" data-list-view="less">{% trans "View Less" %}<span class="fas fa-angle-right ms-1" data-fa-transform="down-1"></span></a>
|
|
</div>
|
|
<div class="col-auto d-flex">
|
|
<button class="page-link" data-list-pagination="prev">
|
|
<span class="fas fa-chevron-left"></span>
|
|
</button>
|
|
<ul class="mb-0 pagination">
|
|
</ul>
|
|
<button class="page-link pe-0" data-list-pagination="next">
|
|
<span class="fas fa-chevron-right"></span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="tab-pane fade"
|
|
id="tab-activity"
|
|
hx-get="{% url 'opportunity_detail' request.dealer.slug opportunity.slug %}"
|
|
hx-trigger="htmx:afterRequest from:"
|
|
hx-select="#tab-activity"
|
|
hx-target="this"
|
|
hx-swap="outerHTML"
|
|
role="tabpanel"
|
|
aria-labelledby="activity-tab">
|
|
<h2 class="mb-4">{% trans "Activity" %}</h2>
|
|
<div class="row align-items-center g-3 justify-content-between justify-content-start">
|
|
<div class="col-12 col-sm-auto">
|
|
<div class="search-box mb-2 mb-sm-0">
|
|
<form class="position-relative">
|
|
<input class="form-control search-input search"
|
|
type="search"
|
|
placeholder="Search Activity"
|
|
aria-label="Search" />
|
|
<span class="fas fa-search search-box-icon"></span>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
{% if perms.inventory.change_opportunity %}<div class="col-auto"></div>{% endif %}
|
|
</div>
|
|
{% for activity in opportunity.get_activities %}
|
|
<div class="border-bottom border-translucent py-4">
|
|
<div class="d-flex">
|
|
<div class="d-flex bg-primary-subtle rounded-circle flex-center me-3 bg-primary-subtle"
|
|
style="width:25px;
|
|
height:25px">
|
|
{% if activity.activity_type == "call" %}
|
|
<span class="fa-solid fa-phone text-warning fs-8"></span>
|
|
{% elif activity.activity_type == "email" %}
|
|
<span class="fa-solid fa-envelope text-info-light fs-8"></span>
|
|
{% elif activity.activity_type == "note" %}
|
|
<span class="fa-regular fa-sticky-note text-info-light fs-8"></span>
|
|
{% elif activity.activity_type == "task" %}
|
|
<span class="fa-solid fa-list-check text-success fs-8"></span>
|
|
{% elif activity.activity_type == "meeting" %}
|
|
<span class="fa-solid fa-users text-danger fs-8"></span>
|
|
{% elif activity.activity_type == "whatsapp" %}
|
|
<span class="fab fa-whatsapp text-success-dark fs-7"></span>
|
|
{% endif %}
|
|
</div>
|
|
<div class="flex-1">
|
|
<div class="d-flex justify-content-between flex-column flex-xl-row mb-2 mb-sm-0">
|
|
<div class="flex-1 me-2">
|
|
<h5 class="text-body-highlight lh-sm"></h5>
|
|
<p class="fs-9 mb-0">{{ activity.notes }}</p>
|
|
</div>
|
|
</div>
|
|
<div class="d-flex justify-content-between flex-column flex-xl-row mb-2 mb-sm-0">
|
|
<div class="flex-1 me-2">
|
|
<h5 class="text-body-highlight lh-sm"></h5>
|
|
{% if request.user.email == activity.created_by %}
|
|
<p class="fs-9 mb-0">
|
|
by <a class="ms-1" href="#!">You</a>
|
|
</p>
|
|
{% else %}
|
|
<p class="fs-9 mb-0">
|
|
by<a class="ms-1" href="#!">{{ activity.created_by }}</a>
|
|
</p>
|
|
{% endif %}
|
|
</div>
|
|
<div class="fs-9">
|
|
<span class="fa-regular fa-calendar-days text-primary me-2"></span><span class="fw-semibold">{{ activity.created|naturalday|capfirst }}</span>
|
|
</div>
|
|
</div>
|
|
<p class="fs-9 mb-0"></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal fade"
|
|
id="updateStageModal"
|
|
tabindex="-1"
|
|
aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<form method="post"
|
|
action="{% url 'update_opportunity_stage' request.dealer.slug opportunity.slug %}"
|
|
hx-post="{% url 'update_opportunity_stage' request.dealer.slug opportunity.slug %}"
|
|
hx-swap="none"
|
|
hx-on::after-request="location.reload()">
|
|
{% csrf_token %}
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="updateStageModalLabel">{{ _("Update Opportunity Stage") }}</h5>
|
|
<button class="btn btn-close p-1"
|
|
type="button"
|
|
data-bs-dismiss="modal"
|
|
aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">{{ stage_form|crispy }}</div>
|
|
<div class="modal-footer">
|
|
<button class="btn btn-phoenix-primary" type="submit">{{ _("Save") }}</button>
|
|
<button class="btn btn-phoenix-secondary"
|
|
type="button"
|
|
data-bs-dismiss="modal">{{ _("Cancel") }}</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% include 'modal/delete_modal.html' %}
|
|
<!-- email Modal -->
|
|
{% include "components/email_modal.html" %}
|
|
<!-- task Modal -->
|
|
{% include "components/task_modal.html" with content_type="opportunity" slug=opportunity.slug %}
|
|
<!-- note Modal -->
|
|
{% include "components/note_modal.html" with content_type="opportunity" slug=opportunity.slug %}
|
|
<!-- schedule Modal -->
|
|
{% include "components/schedule_modal.html" with content_type="opportunity" slug=opportunity.slug %}
|
|
|
|
<div class="modal fade"
|
|
id="estimateModal"
|
|
tabindex="-1"
|
|
aria-labelledby="estimateModalLabel"
|
|
aria-hidden="true">
|
|
<div class="modal-dialog modal-sm">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="estimateModalLabel">{% trans 'Create Estimate' %}</h5>
|
|
<button type="button"
|
|
class="btn-close"
|
|
data-bs-dismiss="modal"
|
|
aria-label="Close"></button>
|
|
</div>
|
|
<div id="estimateModalBody" class="main-modal-body" style="padding: 20px;">
|
|
<form action="{% url 'estimate_create_from_opportunity' request.dealer.slug opportunity.slug %}" method="post">
|
|
{% csrf_token %}
|
|
<p>{% trans 'Are you sure you want to create an estimate from this opportunity?' %}</p>
|
|
<button type="submit" class="btn btn-primary">{% trans 'Create Estimate' %}</button>
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans 'Cancel' %}</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% endblock %}
|
|
{% block customJS %}
|
|
<script>
|
|
document.body.addEventListener('htmx:afterSwap', function(evt) {
|
|
if (evt.detail.target.id === 'main_content') {
|
|
var modal = bootstrap.Modal.getInstance(document.getElementById('exampleModal'));
|
|
if (modal) {
|
|
modal.hide();
|
|
}
|
|
}
|
|
});
|
|
|
|
// Cleanup modal backdrop if needed
|
|
document.body.addEventListener('htmx:beforeSwap', function(evt) {
|
|
if (evt.detail.target.id === 'main_content') {
|
|
var backdrops = document.querySelectorAll('.modal-backdrop');
|
|
backdrops.forEach(function(backdrop) {
|
|
backdrop.remove();
|
|
});
|
|
}
|
|
});
|
|
|
|
</script>
|
|
{% endblock customJS %}
|