update
This commit is contained in:
parent
91ef0da13b
commit
86d3c3d586
2
.gitignore
vendored
2
.gitignore
vendored
@ -6,6 +6,8 @@ __pycache__
|
||||
**/*__pycache__
|
||||
db.sqlite
|
||||
db.sqlite3
|
||||
db.sqlite3.backup
|
||||
db.sqlite*
|
||||
media
|
||||
car_inventory/settings.py
|
||||
scripts/dsrpipe.py
|
||||
|
||||
@ -944,7 +944,7 @@ class StaffTypes(models.TextChoices):
|
||||
|
||||
class Staff(models.Model, LocalizedNameMixin):
|
||||
staff_member = models.OneToOneField(StaffMember, on_delete=models.CASCADE, related_name="staff")
|
||||
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="staff")
|
||||
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="staff")
|
||||
name = models.CharField(max_length=255, verbose_name=_("Name"))
|
||||
arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
|
||||
phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number"))
|
||||
@ -1225,6 +1225,8 @@ class Lead(models.Model):
|
||||
def __str__(self):
|
||||
return f"{self.first_name} {self.last_name}"
|
||||
|
||||
def get_user_model(self):
|
||||
return User.objects.get(email=self.email) or None
|
||||
@property
|
||||
def is_converted(self):
|
||||
return bool(self.customer)
|
||||
@ -1247,20 +1249,20 @@ class Lead(models.Model):
|
||||
customer = entity.get_customers().filter(email=self.email).first()
|
||||
if entity and not customer:
|
||||
customer = entity.create_customer(
|
||||
customer_model_kwargs={
|
||||
"customer_name": self.full_name,
|
||||
"address_1": self.address,
|
||||
"phone": self.phone_number,
|
||||
"email": self.email,
|
||||
}
|
||||
)
|
||||
|
||||
customer.additional_info = {}
|
||||
commit=False,
|
||||
customer_model_kwargs={
|
||||
"customer_name": self.full_name,
|
||||
"address_1": self.address,
|
||||
"phone": self.phone_number,
|
||||
"email": self.email,
|
||||
}
|
||||
)
|
||||
|
||||
customer.additional_info.update({"info":self.to_dict()})
|
||||
customer.additional_info.update({"stage":"qualified"})
|
||||
customer.additional_info.update({"type":"customer"})
|
||||
customer.save()
|
||||
self.customer = customer
|
||||
self.status = Status.QUALIFIED
|
||||
customer.save()
|
||||
self.save()
|
||||
return customer
|
||||
|
||||
@ -1760,7 +1762,7 @@ class SaleOrder(models.Model):
|
||||
('cash', 'Cash'),
|
||||
('finance', 'Finance'),
|
||||
('lease', 'Lease'),
|
||||
])
|
||||
])
|
||||
comments = models.TextField(blank=True, null=True)
|
||||
formatted_order_id = models.CharField(max_length=10, unique=True, editable=False)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
@ -666,9 +666,13 @@ def create_ledger_vendor(sender, instance, created, **kwargs):
|
||||
@receiver(post_save, sender=models.CustomerModel)
|
||||
def create_customer_user(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
first_name = instance.additional_info.get("customer_info").get("first_name")
|
||||
last_name = instance.additional_info.get("customer_info").get("last_name")
|
||||
user = User.objects.create(
|
||||
username=instance.email,
|
||||
email=instance.email,
|
||||
first_name=first_name if first_name else '',
|
||||
last_name=last_name if last_name else '',
|
||||
)
|
||||
instance.additional_info.update({"user_info": to_dict(user)})
|
||||
user.set_unusable_password()
|
||||
|
||||
@ -74,11 +74,11 @@ urlpatterns = [
|
||||
"customers/create/", views.CustomerCreateView, name="customer_create"
|
||||
),
|
||||
path(
|
||||
"customers/<str:pk>/update/",
|
||||
"customers/<uuid:pk>/update/",
|
||||
views.CustomerUpdateView,
|
||||
name="customer_update",
|
||||
),
|
||||
path("customers/<str:pk>/delete/", views.delete_customer, name="customer_delete"),
|
||||
path("customers/<uuid:pk>/delete/", views.delete_customer, name="customer_delete"),
|
||||
path(
|
||||
"customers/<str:customer_id>/opportunities/create/",
|
||||
views.OpportunityCreateView.as_view(),
|
||||
|
||||
@ -247,7 +247,6 @@ def get_financial_values(model):
|
||||
additional_services = []
|
||||
|
||||
for i in data:
|
||||
print(i)
|
||||
if i.item_model.additional_info["additional_services"]:
|
||||
additional_services.extend(
|
||||
[
|
||||
|
||||
@ -10,7 +10,7 @@ from calendar import month_name
|
||||
from pyzbar.pyzbar import decode
|
||||
from urllib.parse import urlparse, urlunparse
|
||||
#####################################################################
|
||||
|
||||
from django.db.models.deletion import RestrictedError
|
||||
# Django
|
||||
from django.db.models import Q
|
||||
from django.conf import settings
|
||||
@ -1250,7 +1250,6 @@ class CustomerDetailView(LoginRequiredMixin, DetailView):
|
||||
context["total"] = total
|
||||
return context
|
||||
|
||||
|
||||
def add_note_to_customer(request, customer_id):
|
||||
customer = get_object_or_404(CustomerModel, pk=customer_id)
|
||||
if request.method == "POST":
|
||||
@ -1312,9 +1311,9 @@ def CustomerCreateView(request):
|
||||
"email": form.cleaned_data["email"],
|
||||
}
|
||||
)
|
||||
customer.additional_info = {}
|
||||
customer.additional_info["customer_info"] = customer_dict
|
||||
customer.additional_info["type"] = "customer"
|
||||
# customer.additional_info = {}
|
||||
customer.additional_info.update({"customer_info": customer_dict})
|
||||
customer.additional_info.update({"type": "customer"})
|
||||
customer.save()
|
||||
|
||||
messages.success(request, _("Customer created successfully."))
|
||||
@ -1375,11 +1374,15 @@ def CustomerUpdateView(request, pk):
|
||||
|
||||
|
||||
|
||||
|
||||
@login_required
|
||||
def delete_customer(request, pk):
|
||||
customer = get_object_or_404(models.Customer, pk=pk)
|
||||
customer.delete()
|
||||
customer = get_object_or_404(models.CustomerModel, pk=pk)
|
||||
user = User.objects.get(email=customer.email)
|
||||
customer.active = False
|
||||
user.is_active = False
|
||||
customer.save()
|
||||
user.save()
|
||||
|
||||
messages.success(request, _("Customer deleted successfully."))
|
||||
return redirect("customer_list")
|
||||
|
||||
@ -1581,10 +1584,11 @@ class UserCreateView(
|
||||
|
||||
email = form.cleaned_data["email"]
|
||||
password = "Tenhal@123"
|
||||
|
||||
user = User.objects.create_user(username=form.cleaned_data["name"], email=email, password=password)
|
||||
user.is_staff = True
|
||||
user.save()
|
||||
staff_member = StaffMember.objects.create(user=user)
|
||||
staff_member = StaffMember.objects.create(user=user)
|
||||
for service in form.cleaned_data["service_offered"]:
|
||||
staff_member.services_offered.add(service)
|
||||
staff = form.save(commit=False)
|
||||
@ -1639,9 +1643,9 @@ class UserUpdateView(
|
||||
return super().form_valid(form)
|
||||
|
||||
def UserDeleteview(request, pk):
|
||||
user = get_object_or_404(models.Staff, pk=pk)
|
||||
user.staff_member.delete()
|
||||
user.delete()
|
||||
staff = get_object_or_404(models.Staff, pk=pk)
|
||||
staff.staff_member.delete()
|
||||
staff.delete()
|
||||
messages.success(request, _("User deleted successfully."))
|
||||
return redirect("user_list")
|
||||
|
||||
@ -1767,9 +1771,14 @@ def OrganizationUpdateView(request,pk):
|
||||
# success_message = "Organization deleted successfully."
|
||||
def OrganizationDeleteView(request, pk):
|
||||
organization = get_object_or_404(CustomerModel, pk=pk)
|
||||
organization.delete()
|
||||
messages.success(request, _("Organization deleted successfully."))
|
||||
return redirect("organization_list")
|
||||
try:
|
||||
User.objects.get(email=organization.email).delete()
|
||||
organization.delete()
|
||||
messages.success(request, _("Organization deleted successfully."))
|
||||
except Exception as e:
|
||||
print("unable to delete user", e)
|
||||
messages.error(request,_("Unable to delete organization"))
|
||||
return redirect("organization_list")
|
||||
|
||||
class RepresentativeListView(LoginRequiredMixin, ListView):
|
||||
model = models.Representative
|
||||
@ -2157,7 +2166,7 @@ def create_estimate(request,pk=None):
|
||||
form = forms.EstimateModelCreateForm(
|
||||
entity_slug=entity.slug, user_model=entity.admin
|
||||
)
|
||||
form.fields["customer"].queryset = entity.get_customers().filter(active=True)
|
||||
form.fields["customer"].queryset = entity.get_customers().filter(active=True,additional_info__type="customer")
|
||||
|
||||
if pk:
|
||||
opportunity = models.Opportunity.objects.get(pk=pk)
|
||||
@ -2181,7 +2190,8 @@ def create_estimate(request,pk=None):
|
||||
}
|
||||
for x in car_list
|
||||
],
|
||||
"opportunity_id": pk if pk else None
|
||||
"opportunity_id": pk if pk else None,
|
||||
"customer_count": entity.get_customers().count()
|
||||
}
|
||||
|
||||
return render(request, "sales/estimates/estimate_form.html", context)
|
||||
@ -2686,28 +2696,40 @@ def lead_create(request):
|
||||
if form.is_valid():
|
||||
instance = form.save(commit=False)
|
||||
dealer = get_user_type(request)
|
||||
instance.dealer = dealer
|
||||
# staff = None
|
||||
# if hasattr(request.user, "staffmember"):
|
||||
# staff = request.user.staffmember.staff
|
||||
# instance.staff = staff
|
||||
instance.dealer = dealer
|
||||
instance.staff = form.cleaned_data.get("staff")
|
||||
|
||||
|
||||
# creating customer in ledger
|
||||
customer = dealer.entity.get_customers().filter(email=instance.email).first()
|
||||
if not customer:
|
||||
customer = dealer.entity.create_customer(
|
||||
commit=False,
|
||||
customer_model_kwargs={
|
||||
"customer_name": instance.full_name,
|
||||
"address_1": instance.address,
|
||||
"phone": instance.phone_number,
|
||||
"email": instance.email,
|
||||
"sales_tax_rate": 0.15,
|
||||
"sales_tax_rate": 0.15,
|
||||
}
|
||||
)
|
||||
customer.additional_info.update({'stage': 'lead'})
|
||||
customer.save()
|
||||
customer_info = {
|
||||
"first_name": instance.first_name,
|
||||
"last_name": instance.last_name,
|
||||
"address": instance.address,
|
||||
"phone_number": str(instance.phone_number),
|
||||
"email": instance.email,
|
||||
}
|
||||
customer.additional_info.update({"customer_info": customer_info })
|
||||
customer.additional_info.update({"type":"lead"})
|
||||
customer.save()
|
||||
instance.customer = customer
|
||||
# try:
|
||||
# user = User.objects.get(email=customer.email)
|
||||
# user.first_name = instance.first_name
|
||||
# user.last_name = instance.last_name
|
||||
# user.save()
|
||||
# except Exception as e:
|
||||
# print(e)
|
||||
instance.save()
|
||||
messages.success(request, "Lead created successfully!")
|
||||
return redirect("lead_list")
|
||||
@ -2732,6 +2754,11 @@ class LeadUpdateView(UpdateView):
|
||||
@login_required
|
||||
def LeadDeleteView(request,pk):
|
||||
lead = get_object_or_404(models.Lead, pk=pk)
|
||||
try:
|
||||
User.objects.get(email=lead.customer.email).delete()
|
||||
lead.customer.delete()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
lead.delete()
|
||||
messages.success(request, "Lead deleted successfully!")
|
||||
return redirect("lead_list")
|
||||
@ -2809,11 +2836,11 @@ def lead_convert(request, pk):
|
||||
|
||||
@login_required
|
||||
def schedule_lead(request, pk):
|
||||
if not hasattr(request.user,"staffmember"):
|
||||
if not request.is_staff:
|
||||
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)
|
||||
if request.method == "POST":
|
||||
form = forms.ScheduleForm(request.POST)
|
||||
@ -2821,13 +2848,13 @@ def schedule_lead(request, pk):
|
||||
instance = form.save(commit=False)
|
||||
instance.lead = lead
|
||||
instance.scheduled_by = request.user
|
||||
instance.customer = lead.customer
|
||||
|
||||
# Create AppointmentRequest
|
||||
service = Service.objects.filter(name=instance.scheduled_type).first()
|
||||
if not service:
|
||||
messages.error(request, "Service not found!")
|
||||
return redirect("lead_list")
|
||||
staff_member = request.user.staffmember
|
||||
return redirect("lead_list")
|
||||
|
||||
try:
|
||||
appointment_request = AppointmentRequest.objects.create(
|
||||
@ -2835,7 +2862,7 @@ def schedule_lead(request, pk):
|
||||
start_time=instance.scheduled_at.time(),
|
||||
end_time=(instance.scheduled_at + instance.duration).time(),
|
||||
service=service,
|
||||
staff_member=staff_member,
|
||||
staff_member=request.user.staffmember,
|
||||
)
|
||||
except ValidationError as e:
|
||||
messages.error(request, str(e))
|
||||
@ -3426,6 +3453,10 @@ class OrderListView(ListView):
|
||||
template_name = "sales/orders/order_list.html"
|
||||
context_object_name = "orders"
|
||||
|
||||
def get_queryset(self):
|
||||
dealer = get_user_type(self.request)
|
||||
qs = super().get_queryset()
|
||||
return qs.filter(estimate__entity=dealer.entity)
|
||||
|
||||
# email
|
||||
@login_required
|
||||
|
||||
@ -104,7 +104,7 @@
|
||||
<script src="{% static 'vendors/dayjs/dayjs.min.js' %}"></script>
|
||||
<script src="{% static 'js/phoenix.js' %}"></script>
|
||||
<script src="{% static 'js/apexcharts.js' %}"></script>
|
||||
<script src="{% static 'vendors/echarts/echarts.min.js' %}"></script>
|
||||
{% comment %} <script src="{% static 'vendors/echarts/echarts.min.js' %}"></script> {% endcomment %}
|
||||
<script src="{% static 'js/crm-analytics.js' %}"></script>
|
||||
<script src="{% static 'js/travel-agency-dashboard.js' %}"></script>
|
||||
<script src="{% static 'js/crm-dashboard.js' %}"></script>
|
||||
|
||||
@ -140,11 +140,11 @@
|
||||
<div class="accordion" id="accordionExample">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingTwo">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse{{lead.pk}}" aria-expanded="false" aria-controls="collapseTwo">
|
||||
View Schedules ({{lead.get_latest_schedules.count}})
|
||||
</button>
|
||||
</h2>
|
||||
<div class="accordion-collapse collapse" id="collapseTwo" aria-labelledby="headingTwo" data-bs-parent="#accordionExample">
|
||||
<div class="accordion-collapse collapse" id="collapse{{lead.pk}}" aria-labelledby="headingTwo" data-bs-parent="#accordionExample">
|
||||
<div class="accordion-body pt-0">
|
||||
<div class="d-flex flex-column gap-2">
|
||||
<table><tbody>
|
||||
|
||||
@ -50,6 +50,11 @@
|
||||
<div class="d-flex align-items-center px-1 py-1 bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div><span>{{ _("Address")|capfirst }}</span>
|
||||
</div>
|
||||
</th>
|
||||
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="company" style="width:15%;">
|
||||
<div class="d-inline-flex flex-center">
|
||||
<div class="d-flex align-items-center px-1 py-1 bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div><span>{{ _("Active")|capfirst }}</span>
|
||||
</div>
|
||||
</th>
|
||||
<th class="sort align-middle ps-4 pe-5 text-uppercase" scope="col" data-sort="date" style="width:15%;">
|
||||
{{ _("Create date") }}</th>
|
||||
<th class="sort text-end align-middle pe-0 ps-4" scope="col"></th>
|
||||
@ -76,6 +81,13 @@
|
||||
<td class="contact align-middle white-space-nowrap ps-4 border-end border-translucent fw-semibold text-body-highlight">{{ customer.additional_info.customer_info.national_id }}</td>
|
||||
<td class="company align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 border-end border-translucent fw-semibold text-body-highlight">
|
||||
{{ customer.address_1 }}</td>
|
||||
<td class="date align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 text-body-tertiary">
|
||||
{% if customer.active %}
|
||||
<span class="badge badge-phoenix badge-phoenix-success"><i class="fas fa-check"></i> {{customer.active}}</span>
|
||||
{% else %}
|
||||
<span class="badge badge-phoenix badge-phoenix-danger"><i class="fas fa-times"></i> {{customer.active}}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="date align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 text-body-tertiary">{{ customer.created|date }}</td>
|
||||
<td class="align-middle white-space-nowrap text-end pe-0 ps-4">
|
||||
<a href="{% url 'customer_update' customer.pk %}" class="btn btn-sm btn-phoenix-primary me-2" data-url="{% url 'customer_update' customer.pk %}">
|
||||
|
||||
@ -18,12 +18,10 @@
|
||||
{% include 'partials/form_errors.html' %}
|
||||
<div class="d-flex flex-column">
|
||||
<div class="d-flex flex-column flex-sm-grow-1 p-0">
|
||||
|
||||
<div class="row g-4">
|
||||
<h3 class="mb-3">{% trans 'Add Car' %}</h3>
|
||||
|
||||
<!-- VIN -->
|
||||
<div class="col-lg-4 col-xl-6">
|
||||
<div class="col-lg-12 col-xl-6">
|
||||
<div class="card bg-body mb-3">
|
||||
<div class="card-body">
|
||||
<div class="form-floating">
|
||||
@ -46,7 +44,7 @@
|
||||
</div>
|
||||
|
||||
<div class="row mt-2">
|
||||
<div class="col-6">
|
||||
<div class="col-md-6">
|
||||
<div class="form-floating">
|
||||
<span class="text-success fw-bold" id="year-check"></span>
|
||||
<input type="number"
|
||||
@ -56,7 +54,7 @@
|
||||
<label for="{{ form.year.id_for_label }}">{% trans 'Year' %}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="serie-row" class="col-6">
|
||||
<div id="serie-row" class="col-md-6">
|
||||
<div class="form-floating">
|
||||
<select class="form-select form-select-sm"
|
||||
id="{{ form.id_car_serie.id_for_label }}"
|
||||
@ -68,14 +66,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
<div class="col-6" id="make-row">
|
||||
<div class="col-md-6" id="make-row">
|
||||
<div class="form-floating">
|
||||
<span class="text-success fw-bold" id="make-check"></span>
|
||||
{{ form.id_car_make|add_class:"form-select form-select-sm" }}
|
||||
<label for="{{ form.id_car_make.id_for_label }}">{% trans 'make'|capfirst %}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6" id="trim-row">
|
||||
<div class="col-md-6" id="trim-row">
|
||||
<div class="form-floating">
|
||||
<select class="form-select form-select-sm"
|
||||
id="{{ form.id_car_trim.id_for_label }}"
|
||||
@ -87,7 +85,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
<div class="col-6" id="model-row">
|
||||
<div class="col-md-6" id="model-row">
|
||||
<div class="form-floating">
|
||||
<span class="text-success fw-bold" id="model-check"></span>
|
||||
<select class="form-select form-select-sm"
|
||||
@ -122,7 +120,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-lg-4 col-xl-6">
|
||||
<div class="col-xl-6">
|
||||
<div class="row">
|
||||
|
||||
<!--Vendor Field-->
|
||||
|
||||
@ -1,149 +1,138 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% block title %}{% trans "Organizations" %}{% endblock title %}
|
||||
{% block organizations %}<a class="nav-link active">{% trans "Organizations" %}</a>{% endblock %}
|
||||
{% block title %}
|
||||
{% trans 'Organizations' %}
|
||||
{% endblock %}
|
||||
{% block organizations %}
|
||||
<a class="nav-link active">{% trans 'Organizations' %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section class="pt-5 pb-9">
|
||||
<section class="pt-5 pb-9">
|
||||
<div class="row">
|
||||
<h2 class="mb-4">{% trans 'Organizations' %}</h2>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<h2 class="mb-4">{% trans "Organizations" %}</h2>
|
||||
|
||||
<div class="row g-3 justify-content-between mb-4">
|
||||
<div class="col-auto">
|
||||
<div class="d-md-flex justify-content-between">
|
||||
<div>
|
||||
<a href="{% url 'organization_create' %}" class="btn btn-sm btn-phoenix-primary"><span class="fas fa-plus me-2"></span>{% trans "add organization"|capfirst %}</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="d-flex">
|
||||
<div class="search-box me-2">
|
||||
<form method="get" class="d-inline-block position-relative">
|
||||
<input name="q" class="form-control search-input search" type="search" placeholder="{{ _('Enter Organization name') }}" aria-label="Search" value="{{ request.GET.q }}"/>
|
||||
<span class="fas fa-search search-box-icon"></span>
|
||||
{% if request.GET.q %}
|
||||
<a href="{% url request.resolver_match.view_name %}" class="btn btn-outline-danger ms-1">
|
||||
<i class="bi bi-x-lg"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-3 justify-content-between mb-4">
|
||||
<div class="col-auto">
|
||||
<div class="d-md-flex justify-content-between">
|
||||
<div>
|
||||
<a href="{% url 'organization_create' %}" class="btn btn-sm btn-phoenix-primary"><span class="fas fa-plus me-2"></span>{% trans 'add organization'|capfirst %}</a>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive scrollbar mx-n1 px-1">
|
||||
|
||||
<table class="table table-hover fs-9 mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" data-sort="name" style="width:25%;">{{ _("Name")|capfirst }}</th>
|
||||
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="name" style="width:15%;">
|
||||
<div class="d-inline-flex flex-center">
|
||||
<div class="d-flex align-items-center px-1 py-1 bg-success-subtle rounded me-2"><span class="fs-7 text-success-dark far fa-file-alt"></span></div><span>{% trans "CRN" %}</span>
|
||||
</div>
|
||||
</th>
|
||||
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="phone" style="width:15%; min-width: 180px;">
|
||||
<div class="d-inline-flex flex-center">
|
||||
<div class="d-flex align-items-center px-1 py-1 bg-primary-subtle rounded me-2"><span class="fs-7 text-primary-dark fas fa-money-check-alt"></span></div><span>{% trans "VRN" %}</span>
|
||||
</div>
|
||||
</th>
|
||||
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="contact" style="width:15%;">
|
||||
<div class="d-inline-flex flex-center">
|
||||
<div class="d-flex align-items-center px-1 py-1 bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="phone"></span></div><span>{% trans "Phone" %}</span>
|
||||
</div>
|
||||
</th>
|
||||
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="company" style="width:15%;">
|
||||
<div class="d-inline-flex flex-center">
|
||||
<div class="d-flex align-items-center px-1 py-1 bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div><span>{% trans 'Address' %}</span>
|
||||
</div>
|
||||
</th>
|
||||
<th class="sort align-middle ps-4 pe-5 text-uppercase" scope="col" data-sort="date" style="width:15%;">
|
||||
{{ _("Create date") }}</th>
|
||||
<th class="sort text-end align-middle pe-0 ps-4" scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="list" id="leal-tables-body">
|
||||
|
||||
{% for org in organizations %}
|
||||
<!-- Delete Modal -->
|
||||
<div class="modal fade" id="deleteModal"
|
||||
data-bs-backdrop="static"
|
||||
data-bs-keyboard="false"
|
||||
tabindex="-1"
|
||||
aria-labelledby="deleteModalLabel"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="deleteModalLabel">
|
||||
|
||||
{% trans "Delete Vendor" %}
|
||||
<span data-feather="alert-circle"></span>
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<p class="mb-0 text-danger fw-bold">
|
||||
{% trans "Are you sure you want to delete this Organization?" %}
|
||||
</p>
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">
|
||||
{% trans "No" %}
|
||||
</button>
|
||||
<a type="button" class="btn btn-danger btn-sm" href="{% url 'organization_delete' org.pk %}">
|
||||
{% trans "Yes" %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
||||
|
||||
<td class="name align-middle white-space-nowrap ps-0">
|
||||
<div class="d-flex align-items-center">
|
||||
<div><a class="fs-8 fw-bold" href="{% url 'organization_detail' org.pk %}">{{ org.customer_name }}</a>
|
||||
<div class="d-flex align-items-center">
|
||||
<p class="mb-0 text-body-highlight fw-semibold fs-9 me-2"></p><span class="badge badge-phoenix badge-phoenix-primary">{{ org.customer_name}}</span>
|
||||
<img src="{{ org.additional_info.organization_info.logo }}" width="80" height="80" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="email align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent">{{ org.additional_info.organization_info.crn }}</td>
|
||||
<td class="phone align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent">{{ org.additional_info.organization_info.vrn }}</td>
|
||||
<td class="phone align-middle white-space-nowrap ps-4 border-end border-translucent fw-semibold text-body-highlight"><a class="text-body-highlight" href="tel:{{ org.phone }}">{{ org.phone }}</a></td>
|
||||
<td class="company align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 border-end border-translucent fw-semibold text-body-highlight">
|
||||
{{ org.address_1 }}</td>
|
||||
<td class="date align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 text-body-tertiary">{{ org.created|date }}</td>
|
||||
<td class="align-middle white-space-nowrap text-end pe-0 ps-4">
|
||||
<div class="btn-reveal-trigger position-static">
|
||||
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
|
||||
<div class="dropdown-menu dropdown-menu-end py-2"><a href="{% url 'organization_update' org.pk %}" class="dropdown-item text-success-dark">
|
||||
{% trans "Edit" %}
|
||||
</a>
|
||||
<div class="dropdown-divider"></div><button class="dropdown-item text-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">{% trans "Delete" %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
<div class="col-auto">
|
||||
<div class="d-flex">
|
||||
<div class="search-box me-2">
|
||||
<form method="get" class="d-inline-block position-relative">
|
||||
<input name="q" class="form-control search-input search" type="search" placeholder="{{ _('Enter Organization name') }}" aria-label="Search" value="{{ request.GET.q }}" />
|
||||
<span class="fas fa-search search-box-icon"></span>
|
||||
{% if request.GET.q %}
|
||||
<a href="{% url request.resolver_match.view_name %}" class="btn btn-outline-danger ms-1"><i class="bi bi-x-lg"></i></a>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive scrollbar mx-n1 px-1">
|
||||
<table class="table table-hover fs-9 mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort white-space-nowrap align-middle text-uppercase ps-0" scope="col" data-sort="name" style="width:25%;">{{ _('Name')|capfirst }}</th>
|
||||
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="name" style="width:15%;">
|
||||
<div class="d-inline-flex flex-center">
|
||||
<div class="d-flex align-items-center px-1 py-1 bg-success-subtle rounded me-2">
|
||||
<span class="fs-7 text-success-dark far fa-file-alt"></span>
|
||||
</div><span>{% trans 'CRN' %}</span>
|
||||
</div>
|
||||
</th>
|
||||
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="phone" style="width:15%; min-width: 180px;">
|
||||
<div class="d-inline-flex flex-center">
|
||||
<div class="d-flex align-items-center px-1 py-1 bg-primary-subtle rounded me-2">
|
||||
<span class="fs-7 text-primary-dark fas fa-money-check-alt"></span>
|
||||
</div><span>{% trans 'VRN' %}</span>
|
||||
</div>
|
||||
</th>
|
||||
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="contact" style="width:15%;">
|
||||
<div class="d-inline-flex flex-center">
|
||||
<div class="d-flex align-items-center px-1 py-1 bg-info-subtle rounded me-2">
|
||||
<span class="text-info-dark" data-feather="phone"></span>
|
||||
</div><span>{% trans 'Phone' %}</span>
|
||||
</div>
|
||||
</th>
|
||||
<th class="sort align-middle ps-4 pe-5 text-uppercase border-end border-translucent" scope="col" data-sort="company" style="width:15%;">
|
||||
<div class="d-inline-flex flex-center">
|
||||
<div class="d-flex align-items-center px-1 py-1 bg-warning-subtle rounded me-2">
|
||||
<span class="text-warning-dark" data-feather="grid"></span>
|
||||
</div><span>{% trans 'Address' %}</span>
|
||||
</div>
|
||||
</th>
|
||||
<th class="sort align-middle ps-4 pe-5 text-uppercase" scope="col" data-sort="date" style="width:15%;">{{ _('Create date') }}</th>
|
||||
<th class="sort text-end align-middle pe-0 ps-4" scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="list" id="leal-tables-body">
|
||||
{% for org in organizations %}
|
||||
<!-- Delete Modal -->
|
||||
<div class="modal fade" id="deleteModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="deleteModalLabel">
|
||||
{% trans 'Delete Vendor' %}
|
||||
<span data-feather="alert-circle"></span>
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<p class="mb-0 text-danger fw-bold">
|
||||
{% trans 'Are you sure you want to delete this Organization?' %}
|
||||
</p>
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">{% trans 'No' %}</button>
|
||||
<a type="button" class="btn btn-danger btn-sm" href="{% url 'organization_delete' org.pk %}">{% trans 'Yes' %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
||||
<td class="name align-middle white-space-nowrap ps-0">
|
||||
<div class="d-flex align-items-center">
|
||||
<div>
|
||||
<a class="fs-8 fw-bold" href="{% url 'organization_detail' org.pk %}">{{ org.customer_name }}</a>
|
||||
<div class="d-flex align-items-center">
|
||||
<p class="mb-0 text-body-highlight fw-semibold fs-9 me-2"></p><span class="badge badge-phoenix badge-phoenix-primary">{{ org.customer_name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="email align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent">{{ org.additional_info.organization_info.crn }}</td>
|
||||
<td class="phone align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent">{{ org.additional_info.organization_info.vrn }}</td>
|
||||
<td class="phone align-middle white-space-nowrap ps-4 border-end border-translucent fw-semibold text-body-highlight">
|
||||
<a class="text-body-highlight" href="tel:{{ org.phone }}">{{ org.phone }}</a>
|
||||
</td>
|
||||
<td class="company align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 border-end border-translucent fw-semibold text-body-highlight">{{ org.address_1 }}</td>
|
||||
<td class="date align-middle white-space-nowrap text-body-tertiary text-opacity-85 ps-4 text-body-tertiary">{{ org.created|date }}</td>
|
||||
<td class="align-middle white-space-nowrap text-end pe-0 ps-4">
|
||||
<div class="btn-reveal-trigger position-static">
|
||||
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10" type="button" data-bs-toggle="dropdown" data-boundary="window" aria-haspopup="true" aria-expanded="false" data-bs-reference="parent"><span class="fas fa-ellipsis-h fs-10"></span></button>
|
||||
<div class="dropdown-menu dropdown-menu-end py-2">
|
||||
<a href="{% url 'organization_update' org.pk %}" class="dropdown-item text-success-dark">{% trans 'Edit' %}</a>
|
||||
<div class="dropdown-divider"></div><button class="dropdown-item text-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">{% trans 'Delete' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="d-flex justify-content-center">
|
||||
{% if is_paginated %}
|
||||
{% include 'partials/pagination.html' %}
|
||||
{% include 'partials/pagination.html' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
@ -4,18 +4,40 @@
|
||||
|
||||
{% block title %}{{ _("Create Quotation") }}{% endblock title %}
|
||||
|
||||
{% block customCSS %}
|
||||
<style>
|
||||
.disabled{
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
{% endblock customCSS %}
|
||||
{% block content %}
|
||||
<div class="row mt-4">
|
||||
<div class="row mt-4">
|
||||
{% if not items %}
|
||||
<div class="alert alert-outline-warning d-flex align-items-center" role="alert">
|
||||
<i class="fa-solid fa-circle-info fs-6"></i>
|
||||
<p class="mb-0 flex-1">{{ _("Please add at least one car before creating a quotation.") }}</p>
|
||||
<button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if not customer_count %}
|
||||
<div class="alert alert-outline-warning d-flex align-items-center" role="alert">
|
||||
<i class="fa-solid fa-circle-info fs-6"></i>
|
||||
<p class="mb-0 flex-1"> {{ _("Please add at least one customer before creating a quotation.") }}</p>
|
||||
<button class="btn-close" type="button" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<form id="mainForm" method="post" class="needs-validation {% if not items or not customer_count %}disabled{% endif %}">
|
||||
<h3 class="text-center"><i class="fa-regular fa-file-lines"></i> {% trans "Create Quotation" %}</h3>
|
||||
<form id="mainForm" method="post" class="needs-validation">
|
||||
{% csrf_token %}
|
||||
<div class="row g-3">
|
||||
<div class="row g-3 col-10">
|
||||
{{ form|crispy }}
|
||||
<div class="row mt-5">
|
||||
<div id="formrow">
|
||||
<h3 class="text-start"><i class="fa-solid fa-car-side"></i> {{ _("Cars") }}</h3>
|
||||
<div class="form-row row g-3 mb-3 mt-5">
|
||||
<div class="mb-2 col-sm-4">
|
||||
<div class="mb-2 col-sm-4 col-md-6 col-lg-4">
|
||||
<select class="form-control item" name="item[]" required>
|
||||
{% for item in items %}
|
||||
<option style="background-color: rgb({{ item.color }});" value="{{ item.hash }}">{{ item.make }} {{item.model}} {{item.serie}} {{item.trim}} {{item.color_name}} ({{item.hash_count}})</option>
|
||||
@ -24,10 +46,10 @@
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-2 col-sm-2">
|
||||
<div class="mb-2 col-sm-4 col-md-3">
|
||||
<input class="form-control quantity" type="number" placeholder="Quantity" name="quantity[]" required>
|
||||
</div>
|
||||
<div class="mb-2 col-sm-1">
|
||||
<div class="mb-2 col-sm-3 col-md-3">
|
||||
<button class="btn btn-sm btn-danger removeBtn"><i class="fa-solid fa-trash"></i> {{ _("Remove") }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Order Number" %}</th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Customer" %}</th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "For Quotation" %}</th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col"></th>
|
||||
<th class="sort white-space-nowrap align-middle" scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="list">
|
||||
|
||||
@ -32,6 +32,10 @@
|
||||
<td class="align-middle product white-space-nowrap py-0">
|
||||
<a href="{% url 'invoice_detail' journal.ledger.invoicemodel.pk %}"><i class="fa-solid fa-receipt"></i> {{ journal.ledger.invoicemodel }}</a>
|
||||
</td>
|
||||
{% elif journal.ledger.billmodel %}
|
||||
<td class="align-middle product white-space-nowrap py-0">
|
||||
<a href="{% url 'bill_detail' journal.ledger.billmodel.pk %}"><i class="fa-solid fa-money-bill"></i> {{ journal.ledger.billmodel }}</a>
|
||||
</td>
|
||||
{% else %}
|
||||
<td class="align-middle product white-space-nowrap py-0"></td>
|
||||
{% endif %}
|
||||
|
||||
@ -27,8 +27,13 @@
|
||||
|
||||
<form class="row g-3 mb-9" method="post" class="form" novalidate>
|
||||
{% csrf_token %}
|
||||
{{ redirect_field }}
|
||||
{{ form|crispy }}
|
||||
{{ redirect_field }}
|
||||
{{ form.name|as_crispy_field }}
|
||||
{{ form.arabic_name|as_crispy_field }}
|
||||
{{ form.email|as_crispy_field }}
|
||||
{{ form.phone_number|as_crispy_field }}
|
||||
{{ form.staff_type|as_crispy_field }}
|
||||
{{ form.service_offered|as_crispy_field }}
|
||||
{% for error in form.errors %}
|
||||
<div class="text-danger">{{ error }}</div>
|
||||
{% endfor %}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user