This commit is contained in:
gitea 2025-02-26 16:01:58 +00:00
parent 12d480659e
commit 91ef0da13b
9 changed files with 103 additions and 46 deletions

View File

@ -52,8 +52,12 @@ class InjectDealerMiddleware:
def __call__(self, request): def __call__(self, request):
try: try:
dealer = get_user_type(request) request.is_dealer = False
request.user.dealer = dealer request.is_staff = False
if hasattr(request.user, "dealer"):
request.is_dealer = True
if hasattr(request.user, "staffmember"):
request.is_staff = True
except Exception as e: except Exception as e:
pass pass
response = self.get_response(request) response = self.get_response(request)

View File

@ -0,0 +1,14 @@
# Generated by Django 4.2.17 on 2025-02-26 13:54
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '0049_alter_lead_status_alter_leadstatushistory_new_status_and_more'),
('inventory', '0050_remove_carreservation_reserved_for'),
]
operations = [
]

View File

@ -955,11 +955,11 @@ class Staff(models.Model, LocalizedNameMixin):
objects = StaffUserManager() objects = StaffUserManager()
@property @property
def get_user(self): def user(self):
return self.staff_member.user return self.staff_member.user
@property @property
def get_groups(self): def groups(self):
return [x.customgroup for x in self.user.groups.all()] return [x.customgroup for x in self.user.groups.all()]
@ -1266,6 +1266,8 @@ class Lead(models.Model):
def get_latest_schedule(self): def get_latest_schedule(self):
return self.schedules.order_by('-scheduled_at').first() return self.schedules.order_by('-scheduled_at').first()
def get_latest_schedules(self):
return self.schedules.filter(scheduled_at__gt=now()).exclude(status='Canceled').order_by('-scheduled_at')[:5]
class Schedule(models.Model): class Schedule(models.Model):
PURPOSE_CHOICES = [ PURPOSE_CHOICES = [

View File

@ -122,6 +122,11 @@ urlpatterns = [
views.schedule_lead, views.schedule_lead,
name="schedule_lead", name="schedule_lead",
), ),
path(
"crm/leads/schedule/<int:pk>/cancel/",
views.schedule_cancel,
name="schedule_cancel",
),
path( path(
"crm/leads/<int:pk>/transfer/", "crm/leads/<int:pk>/transfer/",
views.lead_transfer, views.lead_transfer,

View File

@ -96,12 +96,11 @@ def send_email(from_, to_, subject, message):
def get_user_type(request): def get_user_type(request):
dealer = "" if request.is_dealer:
if hasattr(request.user, "dealer"): return request.user.dealer
dealer = request.user.dealer elif request.is_staff:
elif hasattr(request.user, "staffmember"): return request.user.staffmember.staff.dealer
dealer = request.user.staffmember.staff.dealer return None
return dealer
def get_dealer_from_instance(instance): def get_dealer_from_instance(instance):

View File

@ -2632,12 +2632,11 @@ class LeadListView(ListView):
def get_queryset(self): def get_queryset(self):
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
print(dealer) qs = models.Lead.objects.filter(dealer=dealer)
if self.request.is_dealer:
return qs
staffmember = getattr(self.request.user, "staffmember", None) staffmember = getattr(self.request.user, "staffmember", None)
if staffmember: if staffmember and getattr(staffmember, "staff", None):
qs = models.Lead.objects.filter(dealer=dealer)
if staffmember.staff.staff_type == models.StaffTypes.MANAGER:
return qs
return qs.filter(staff=staffmember.staff) return qs.filter(staff=staffmember.staff)
return models.Lead.objects.none() return models.Lead.objects.none()
@ -3842,3 +3841,11 @@ def DealerSettingsView(request,pk):
form.fields['bill_prepaid_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.ASSET_CA_PREPAID) form.fields['bill_prepaid_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.ASSET_CA_PREPAID)
form.fields['bill_unearned_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.LIABILITY_CL_ACC_PAYABLE) form.fields['bill_unearned_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.LIABILITY_CL_ACC_PAYABLE)
return render(request, 'account/user_settings.html', {'form': form}) return render(request, 'account/user_settings.html', {'form': form})
def schedule_cancel(request,pk):
schedule = get_object_or_404(models.Schedule, pk=pk)
schedule.status = "Canceled"
schedule.save()
response = HttpResponse()
response.status_code = 200
return response

View File

@ -137,21 +137,46 @@
<td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="">{{ lead.email }}</a></td> <td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="">{{ lead.email }}</a></td>
<td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="tel:{{ lead.phone_number }}">{{ lead.phone_number }}</a></td> <td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="tel:{{ lead.phone_number }}">{{ lead.phone_number }}</a></td>
<td class="align-middle white-space-nowrap fw-semibold"> <td class="align-middle white-space-nowrap fw-semibold">
{% if lead.get_latest_schedule %} <div class="accordion" id="accordionExample">
{{lead.get_latest_schedule.scheduled_type}} at <br> <div class="accordion-item">
<a href="{% url 'appointment:get_user_appointments' %}"> <h2 class="accordion-header" id="headingTwo">
{% if lead.get_latest_schedule.scheduled_type == "Call" %} <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
<span class="badge badge-phoenix badge-phoenix-primary text-primary {% if lead.get_latest_schedule.schedule_past_date %}badge-phoenix-danger text-danger{% endif %} fw-semibold"><span class="text-primary {% if lead.get_latest_schedule.schedule_past_date %}text-danger{% endif %}" data-feather="phone"></span> View Schedules ({{lead.get_latest_schedules.count}})
{{ lead.get_latest_schedule.scheduled_at }}</span> </button>
{% elif lead.get_latest_schedule.scheduled_type == "Meeting" %} </h2>
<span class="badge badge-phoenix badge-phoenix-success text-success fw-semibold"><span class="text-success" data-feather="calendar"></span> <div class="accordion-collapse collapse" id="collapseTwo" aria-labelledby="headingTwo" data-bs-parent="#accordionExample">
{{ lead.get_latest_schedule.scheduled_at }}</span> <div class="accordion-body pt-0">
{% elif lead.get_latest_schedule.scheduled_type == "Email" %} <div class="d-flex flex-column gap-2">
<span class="badge badge-phoenix badge-phoenix-warning text-warning fw-semibold"><span class="text-warning" data-feather="email"></span> <table><tbody>
{{ lead.get_latest_schedule.scheduled_at }}</span> {% for schedule in lead.get_latest_schedules %}
{% endif %} <tr class="schedule-{{ schedule.pk }}">
</a> <td class="align-middle white-space-nowrap">
{% endif %} {% if schedule.scheduled_type == "Call" %}
<a href="{% url 'appointment:get_user_appointments' %}">
<span class="badge badge-phoenix badge-phoenix-primary text-primary {% if schedule.schedule_past_date %}badge-phoenix-danger text-danger{% endif %} fw-semibold"><span class="text-primary {% if schedule.schedule_past_date %}text-danger{% endif %}" data-feather="phone"></span>
{{ schedule.scheduled_at }}</span></a>
{% elif schedule.scheduled_type == "Meeting" %}
<a href="{% url 'appointment:get_user_appointments' %}">
<span class="badge badge-phoenix badge-phoenix-success text-success fw-semibold"><span class="text-success" data-feather="calendar"></span>
{{ schedule.scheduled_at }}</span></a>
{% elif schedule.scheduled_type == "Email" %}
<a href="{% url 'appointment:get_user_appointments' %}">
<span class="badge badge-phoenix badge-phoenix-warning text-warning fw-semibold"><span class="text-warning" data-feather="email"></span>
{{ schedule.scheduled_at }}</span></a>
{% endif %}
</td>
<td>
<a style="cursor: pointer;" hx-delete="{% url 'schedule_cancel' schedule.pk %}" hx-target=".schedule-{{ schedule.pk }}" hx-confirm="Are you sure you want to cancel this schedule?"><i class="fa-solid fa-ban text-danger"></i></a>
</td>
{% endfor %}
</tr>
<tr><td><small><a href="{% url 'appointment:get_user_appointments' %}">View All ...</a></small></td></tr>
</tbody></table>
</div>
</div>
</div>
</div>
</div>
</td> </td>
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.staff|upper }}</td> <td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.staff|upper }}</td>
<td class="align-middle white-space-nowrap fw-semibold text-body-highlight">{{ lead.source|upper }}</td> <td class="align-middle white-space-nowrap fw-semibold text-body-highlight">{{ lead.source|upper }}</td>
@ -179,7 +204,7 @@
{% endif %} {% endif %}
</td> </td>
<td class="align-middle white-space-nowrap text-end"> <td class="align-middle white-space-nowrap text-end">
{% if user == lead.staff.user %} {% if user == lead.staff.user or request.is_dealer %}
<div class="btn-reveal-trigger position-static"> <div class="btn-reveal-trigger position-static">
<button <button
class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10"

View File

@ -403,13 +403,13 @@
</div> </div>
</div> </div>
</li> </li>
{% if user.is_authenticated and user.dealer or user.staff %} {% if user.is_authenticated and request.is_dealer or request.is_staff %}
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link lh-1 pe-0" id="navbarDropdownUser" role="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-haspopup="true" aria-expanded="false"> <a class="nav-link lh-1 pe-0" id="navbarDropdownUser" role="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-haspopup="true" aria-expanded="false">
<div class="avatar avatar-l"> <div class="avatar avatar-l">
{% if user.dealer.logo %} {% if user.dealer.logo %}
<img class="rounded-circle" src="{{ user.dealer.logo.url }}" alt="" /> <img class="rounded-circle" src="{{ user.dealer.logo.url }}" alt="" />
{% elif user.staff.dealer.logo %} {% elif user.staff.dealer.logo %}
<img class="rounded-circle" src="{{ user.staff.dealer.logo.url }}" alt="" /> <img class="rounded-circle" src="{{ user.staff.dealer.logo.url }}" alt="" />
{% else %} {% else %}
<span class="fa fa-user text-body-tertiary" style="width: 32px;"></span> <span class="fa fa-user text-body-tertiary" style="width: 32px;"></span>
@ -430,16 +430,17 @@
<span class="fa fa-user text-body-tertiary" style="width: 32px;"></span> <span class="fa fa-user text-body-tertiary" style="width: 32px;"></span>
{% endif %} {% endif %}
</div> </div>
{% if user.dealer %}
{% if request.is_dealer %}
<h6 class="mt-2 text-body-emphasis">{{ user.dealer.get_local_name }}</h6> <h6 class="mt-2 text-body-emphasis">{{ user.dealer.get_local_name }}</h6>
{% else %} {% else %}
<h6 class="mt-2 text-body-emphasis">{{ user.staff.get_local_name }}</h6> <h6 class="mt-2 text-body-emphasis">{{ user.staffmember.staff.get_local_name }}</h6>
{% endif %} {% endif %}
</div> </div>
</div> </div>
<div class="overflow-auto scrollbar" style="height: 10rem;"> <div class="overflow-auto scrollbar" style="height: 10rem;">
<ul class="nav d-flex flex-column mb-2 pb-1"> <ul class="nav d-flex flex-column mb-2 pb-1">
{% if user.dealer %} {% if request.is_dealer %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link px-3 d-block" href="{% url 'dealer_detail' user.dealer.pk %}"> <span class="me-2 text-body align-bottom" data-feather="user"></span><span>{% translate 'profile'|capfirst %}</span></a> <a class="nav-link px-3 d-block" href="{% url 'dealer_detail' user.dealer.pk %}"> <span class="me-2 text-body align-bottom" data-feather="user"></span><span>{% translate 'profile'|capfirst %}</span></a>
</li> </li>
@ -448,7 +449,7 @@
<a class="nav-link px-3 d-block" href="{% url 'appointment:user_profile' request.user.id %}"> <span class="me-2 text-body align-bottom" data-feather="user"></span><span>{% translate 'profile'|capfirst %}</span></a> <a class="nav-link px-3 d-block" href="{% url 'appointment:user_profile' request.user.id %}"> <span class="me-2 text-body align-bottom" data-feather="user"></span><span>{% translate 'profile'|capfirst %}</span></a>
</li> </li>
{% endif %} {% endif %}
{% if user.dealer %} {% if request.is_dealer %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link px-3 d-block" href="{% url 'user_list' %}"><span class="me-2 text-body align-bottom" data-feather="users"></span>{{ _("Staff & Group") }}</a> <a class="nav-link px-3 d-block" href="{% url 'user_list' %}"><span class="me-2 text-body align-bottom" data-feather="users"></span>{{ _("Staff & Group") }}</a>
</li> </li>
@ -457,7 +458,7 @@
</li> </li>
{% endif %} {% endif %}
<li class="nav-item"> <li class="nav-item">
{% if user.dealer %} {% if request.is_dealer %}
<a class="nav-link px-3 d-block" href="{% url 'dealer_settings' user.dealer.pk %}"> <span class="me-2 text-body align-bottom" data-feather="settings"></span>Settings &amp; Privacy </a> <a class="nav-link px-3 d-block" href="{% url 'dealer_settings' user.dealer.pk %}"> <span class="me-2 text-body align-bottom" data-feather="settings"></span>Settings &amp; Privacy </a>
{% endif %} {% endif %}
</li> </li>