Compare commits

...

5 Commits

Author SHA1 Message Date
88d0ff814b lead create bugs 2025-07-29 17:20:21 +03:00
8fd698c6c5 estimate-form 2025-07-29 16:43:25 +03:00
7a0079e25d update 2025-07-29 16:42:43 +03:00
85a0b8e827 Merge pull request 'default-image' (#151) from frontend into main
Reviewed-on: #151
2025-07-29 14:58:58 +03:00
b749f41a1d Merge pull request 'Default Images' (#150) from frontend into main
Reviewed-on: #150
2025-07-29 14:14:41 +03:00
15 changed files with 79 additions and 81 deletions

View File

@ -142,10 +142,11 @@ class StaffForm(forms.ModelForm):
queryset=CustomGroup.objects.all(),
required=True,
)
name = forms.CharField(
label=_("Full Name"))
class Meta:
model = Staff
fields = ["name", "arabic_name", "phone_number", "address", "logo", "group"]
fields = ["first_name","last_name","name", "arabic_name", "phone_number", "address", "logo", "group"]
# Dealer Form

View File

@ -223,7 +223,7 @@ class CarMake(models.Model, LocalizedNameMixin):
name = models.CharField(max_length=255, blank=True, null=True)
slug = models.SlugField(max_length=255, unique=True, blank=True, null=True)
arabic_name = models.CharField(max_length=255, blank=True, null=True)
logo = models.ImageField(_("logo"), upload_to="car_make", blank=True, null=True,default="user-logo.jpg")
logo = models.ImageField(_("logo"), upload_to="car_make", blank=True, null=True,default="user-logo.jpg")
is_sa_import = models.BooleanField(default=False)
car_type = models.SmallIntegerField(choices=CarType.choices, blank=True, null=True)
@ -1278,6 +1278,8 @@ class Staff(models.Model, LocalizedNameMixin):
StaffMember, on_delete=models.CASCADE, related_name="staff"
)
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="staff")
first_name = models.CharField(max_length=255, verbose_name=_("First Name"))
last_name = models.CharField(max_length=255, verbose_name=_("Last Name"))
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"))
@ -2000,6 +2002,8 @@ class Lead(models.Model):
.order_by("-updated")
.first()
)
def get_absolute_url(self):
return reverse("lead_detail", args=[self.dealer.slug,self.slug])
def save(self, *args, **kwargs):
if not self.slug:

View File

@ -914,7 +914,7 @@ class SearchCodeView(LoginRequiredMixin, View):
)
car = get_object_or_404(models.Car, vin=code)
logger.info(
f"Successfully found car (VIN: {code}, ID: {car.id}) based on scanned code for user: {request.user.username}."
f"Successfully found car (VIN: {code}, ID: {car.pk}) based on scanned code for user: {request.user.username}."
)
return JsonResponse(
{
@ -3405,6 +3405,7 @@ class UserCreateView(
return form
def form_valid(self, form):
staff = form.save(commit=False)
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
if dealer.is_staff_exceed_quota_limit:
messages.error(
@ -3426,14 +3427,13 @@ class UserCreateView(
return redirect("user_create", dealer_slug=dealer.slug)
password = "Tenhal@123"
user = User.objects.create_user(username=email, email=email, password=password)
user = User.objects.create_user(first_name=staff.first_name, last_name=staff.last_name, username=email, email=email, password=password)
user.is_staff = True
user.save()
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)
staff.staff_member = staff_member
staff.dealer = dealer
staff.save()
@ -6031,7 +6031,7 @@ def lead_create(request, dealer_slug):
f"lead created successfully for dealer {dealer_slug} by user:{user_username}"
)
messages.success(request, _("Lead created successfully"))
return redirect("lead_list", dealer_slug=dealer.slug)
return redirect("lead_detail",dealer_slug=dealer_slug,slug=instance.slug)
else:
logger.error(
f"error creating leading for dealer {dealer_slug} by user:{user_username}"

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -17,8 +17,8 @@
</h3>
</div>
<div class="card-body bg-light-subtle">
<form method="post" enctype="multipart/form-data" class="needs-validation" novalidate>
<form hx-boost="false" method="post" enctype="multipart/form-data" class="needs-validation" novalidate>
{% csrf_token %}
{{ form|crispy }}
<hr class="my-2">
@ -27,7 +27,7 @@
<a href="{% url 'dealer_detail' request.dealer.slug %}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
</form>
</div>
</div>

View File

@ -39,7 +39,6 @@
<div class="empty-state-container">
<!-- Empty State Illustration -->
{% if image %}
{% static image as final_image_path %}

View File

@ -504,7 +504,7 @@
</li>
{% else %}
<li class="nav-item">
<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 hx-boost="false" 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>
{% endif %}
{% if request.is_dealer %}

View File

@ -268,7 +268,7 @@
<th>{% trans "Marked Price"|capfirst %}</th>
<td>{{ car.finances.marked_price|floatformat:2 }}</td>
</tr>
<tr>
{% comment %} <tr>
<th>{% trans "Selling Price"|capfirst %}</th>
<td>{{ car.finances.selling_price|floatformat:2 }}</td>
</tr>
@ -295,7 +295,7 @@
<tr>
<th>{% trans "Total"|capfirst %}</th>
<td>{{ car.finances.total_vat|floatformat:2 }}</td>
</tr>
</tr> {% endcomment %}
{% if perms.inventory.change_carfinance %}
<tr>
<td colspan="2">

View File

@ -19,8 +19,8 @@
<script src="{% static 'vendors/zxing/index.min.js' %}"></script>
<script src="{% static 'vendors/tesseract/tesseract.min.js' %}"></script>
{% if not vendor_exists %}
{% url "vendor_create" request.dealer.slug as create_vendor_url %}
{% include "message-illustration.html" with value1="Please Add A Vendor, Before Adding A Car." value2="Create Vendor" message_image="images/empty/vendor2.png" url=create_vendor_url %}
{% url "user_create" request.dealer.slug as create_vendor_url %}
{% include "empty-illustration-page.html" with value="Vendor" url=create_vendor_url %}
{% endif %}
<!---->
<div class="row justify-content-center mt-5 mb-3 {% if not vendor_exists %}d-none{% endif %}" hx-boost="false">
@ -332,16 +332,17 @@
{% block customJS %}
<script>
// Global variables
let codeReader;
let currentStream = null;
const csrfToken = getCookie("csrftoken");
const ajaxUrl = "{% url 'ajax_handler' request.dealer.slug %}";
// Initialize when page loads and after HTMX swaps
document.addEventListener('DOMContentLoaded', initPage);
document.addEventListener('htmx:afterSwap', initPage);
function initPage() {
let codeReader;
let currentStream = null;
const csrfToken = getCookie("csrftoken");
const ajaxUrl = "{% url 'ajax_handler' request.dealer.slug %}";
// Get DOM elements
const elements = {
vinInput: document.getElementById("{{ form.vin.id_for_label }}"),

View File

@ -70,20 +70,20 @@
</style>
<div class="empty-state-container alert mb-2" role="alert">
<img src="{% static message_image %}" alt="message-image" class="empty-state-image mb-2">
<!-- Title -->
<h3 class="empty-state-title mb-2">
{% blocktrans %}{{ value1}}{% endblocktrans %}
</h3>
<div class="d-flex justify-content-between mt-4">
<a class="btn btn-primary mx-2" href="{{ url }}">
<i class="fa fa-plus me-2"></i>
{% blocktrans %}{{value2}}{% endblocktrans %}
</a>
</div>
</div>

View File

@ -125,16 +125,15 @@
<div class="row">
<div class="col">
{% if not items %}
{% url "car_add" request.dealer.slug as create_car_url %}
{% include "message-illustration.html" with value1="Please add at least one car before creating a quotation." value2="Add car" message_image="images/empty/no_car.png" url=create_car_url %}
{% url "car_add" request.dealer.slug as create_car_url %}
{% include "message-illustration.html" with value1="Please add at least one car before creating a quotation." value2="Add car" message_image="images/logos/no-content-new.jpg" url=create_car_url %}
{% endif %}
</div>
<div class="col">
{% if not customer_count %}
{% url "customer_create" request.dealer.slug as create_customer_url %}
{% include "message-illustration.html" with value1="Please add at least one customer before creating a quotation." value2="Add Customer" message_image="images/empty/no_estimate.png" url=create_customer_url %}
{% include "message-illustration.html" with value1="Please add at least one customer before creating a quotation." value2="Add Customer" message_image="images/logos/no-content-new.jpg" url=create_customer_url %}
{% endif %}
</div>
<div>
@ -162,41 +161,39 @@
{% endfor %}
</select>
<!-- Custom select UI -->
<div class="select-trigger">
<div class="selected-value">
<span>Select a car</span>
<!-- Custom select UI -->
<div class="select-trigger">
<div class="selected-value">
<span>Select a car</span>
</div>
<i class="fas fa-chevron-down dropdown-icon"></i>
</div>
<div class="options-container">
{% for item in items %}
<div class="option" data-value="{{ item.hash }}" data-image="{{item.logo}}">
<img src="{{item.logo}}" alt="{{item.model}}">
<span>{{item.make}} {{item.model}} {{item.serie}} {{item.trim}} {{item.color_name}}</span>
<div class="color-box" style="background-color: rgb({{ item.exterior_color }});"></div>
<div class="color-box" style="background-color: rgb({{ item.interior_color }});"></div>
<span style="color:gray;">({{item.hash_count}} in stock)</span>
</div>
{% endfor %}
</div>
</div>
</div>
<hr class="my-2">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-primary md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'estimate_list' request.dealer.slug%}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
</form>
</div>
</div>
<i class="fas fa-chevron-down dropdown-icon"></i>
</div>
<div class="options-container">
{% for item in items %}
<div class="option" data-value="{{ item.hash }}" data-image="{{item.logo}}">
<img src="{{item.logo}}" alt="{{item.model}}">
<span>{{item.make}} {{item.model}} {{item.serie}} {{item.trim}} {{item.color_name}}</span>
<div class="color-box" style="background-color: rgb({{ item.exterior_color }});"></div>
<div class="color-box" style="background-color: rgb({{ item.interior_color }});"></div>
<span style="color:gray;">({{item.hash_count}} in stock)</span>
</div>
{% endfor %}
</div>
</div>
</div>
<hr class="my-2">
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-3">
<button class="btn btn-lg btn-phoenix-primary md-me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{% url 'estimate_list' request.dealer.slug%}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block customJS %}
<script>
@ -431,5 +428,4 @@ function handleFormResponse(data) {
}
}
</script>
{% endblock %}
{% endblock %}

View File

@ -18,7 +18,6 @@
<div class="card shadow-sm border-0 rounded-3">
<div class="card-header bg-gray-200 py-3 border-0 rounded-top-3">
<h3 class="mb-0 fs-4 text-center">
{% if staff.created %}
{{ _("Edit Staff") }}
{% else %}
@ -31,6 +30,8 @@
<form class="row g-3 mb-3" method="post" class="form" novalidate>
{% csrf_token %}
{{ redirect_field }}
{{ form.first_name|as_crispy_field }}
{{ form.last_name|as_crispy_field }}
{{ form.name|as_crispy_field }}
{{ form.arabic_name|as_crispy_field }}
{{ form.email|as_crispy_field }}
@ -49,10 +50,10 @@
</div>
</form>
</div>
</div>
</div>
{% endblock %}

View File

@ -18,9 +18,9 @@
<a href="{% url 'group_list' request.dealer.slug %}"
class="btn btn-sm btn-phoenix-success"><i class="fa-solid fa-user-group me-1"></i> {% trans "Manage Groups & Permissions" %}</a>
{% else %}
{% url "pricing_page" request.dealer.slug as pricing_page_url %}
{% include "message-illustration.html" with value1="No Active Plan, please create your subscription plan." value2="Manage Subscription" message_image="images/messages/haikal_plan_message.jpg" url=pricing_page_url %}
{% include "message-illustration.html" with value1="No Active Plan, please create your subscription plan." value2="Manage Subscription" url=pricing_page_url %}
{% endif %}
</div>
@ -81,18 +81,14 @@
</div>
</section>
{% else %}
{% if request.user.userplan %}
{% url "user_create" request.dealer.slug as create_staff_url %}
{% include "empty-illustration-page.html" with value="staff" url=create_staff_url image="images/no_content/no_user.png"%}
{% else %}
{% if request.user.userplan %}
{% url "user_create" request.dealer.slug as create_staff_url %}
{% include "empty-illustration-page.html" with value="staff" url=create_staff_url %}
{% else %}
{% url "pricing_page" request.dealer.slug as pricing_page_url %}
{% include "message-illustration.html" with value1="No Active Plan, please create your subscription plan." value2="Buy Plan" message_image="images/no_content/no_plan.jpg" url=pricing_page_url %}
{% endif %}
{% else %}
{% url "pricing_page" request.dealer.slug as pricing_page_url %}
{% include "message-illustration.html" with value1="No Active Plan, please create your subscription plan." value2="Buy Plan" url=pricing_page_url %}
{% endif %}
{% endif %}
{% endblock %}

View File

@ -166,6 +166,6 @@
{% else %}
{% url "vendor_create" request.dealer.slug as create_vendor_url %}
{% include "empty-illustration-page.html" with value="vendor" url=create_vendor_url image="images/no_content/no_vendor.png" %}
{% include "empty-illustration-page.html" with value="vendor" url=create_vendor_url %}
{% endif %}
{% endblock %}