219 lines
9.3 KiB
HTML
219 lines
9.3 KiB
HTML
{% extends "base.html" %}
|
|
{% load crispy_forms_filters %}
|
|
{% load i18n static %}
|
|
{% 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">
|
|
{% 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.") }}<a class="ms-3 text-body-primary fs-9"
|
|
href="{% url 'car_add' request.dealer.slug %}">{{ _("Add Car") }}</a>
|
|
</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.") }}<a class="ms-3 text-body-primary fs-9"
|
|
href="{% url 'customer_create' request.dealer.slug %}">{{ _("Add Customer") }}</a>
|
|
</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>
|
|
{% csrf_token %}
|
|
<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 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>
|
|
{% empty %}
|
|
<option disabled>{% trans "No Cars Found" %}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<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-3 col-md-3">
|
|
<button class="btn btn-sm btn-phoenix-danger removeBtn">
|
|
<i class="fa-solid fa-trash me-1"></i> {{ _("Remove") }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-12">
|
|
<button id="addMoreBtn" class="btn btn-sm btn-phoenix-primary">
|
|
<i class="fa-solid fa-plus me-2"></i> {{ _("Add More") }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="d-flex justify-content-center">
|
|
<button class="btn btn-sm btn-phoenix-success me-2" type="submit">
|
|
<i class="fa-solid fa-floppy-disk me-1"></i>
|
|
<!--<i class="bi bi-save"></i> -->
|
|
{{ _("Save") }}
|
|
</button>
|
|
<a href="{{ request.META.HTTP_REFERER }}"
|
|
class="btn btn-sm btn-phoenix-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
{% endblock content %}
|
|
{% block customJS %}
|
|
<script>
|
|
const Toast = Swal.mixin({
|
|
toast: true,
|
|
position: "top-end",
|
|
showConfirmButton: false,
|
|
timer: 2000,
|
|
timerProgressBar: false,
|
|
didOpen: (toast) => {
|
|
toast.onmouseenter = Swal.stopTimer;
|
|
toast.onmouseleave = Swal.resumeTimer;
|
|
}
|
|
});
|
|
// Add new form fields
|
|
document.getElementById('addMoreBtn').addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
const formrow = document.getElementById('formrow');
|
|
const newForm = document.createElement('div');
|
|
newForm.className = 'form-row row g-3 mb-3 mt-5';
|
|
newForm.innerHTML = `
|
|
<div class="mb-2 col-sm-4">
|
|
<select class="form-control item" name="item[]" required>
|
|
{% for item in items %}
|
|
<option value="{{ item.hash }}">{{ item.make }} {{item.model}} {{item.serie}} {{item.trim}} {{item.color}}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="mb-2 col-sm-2">
|
|
<input class="form-control quantity" type="number" placeholder="Quantity" name="quantity[]" required>
|
|
</div>
|
|
<div class="mb-2 col-sm-1">
|
|
<button class="btn btn-phoenix-danger removeBtn"><i class="fa-solid fa-trash"></i> {{ _("Remove") }}</button>
|
|
</div>
|
|
`;
|
|
formrow.appendChild(newForm);
|
|
|
|
// Add remove button functionality
|
|
newForm.querySelector('.removeBtn').addEventListener('click', function() {
|
|
newForm.remove();
|
|
});
|
|
});
|
|
|
|
// Add remove button functionality to the initial form
|
|
document.querySelectorAll('.form-row').forEach(row => {
|
|
row.querySelector('.removeBtn').addEventListener('click', function() {
|
|
row.remove();
|
|
});
|
|
});
|
|
|
|
// Handle form submission
|
|
document.getElementById('mainForm').addEventListener('submit', async function(e) {
|
|
e.preventDefault();
|
|
|
|
const titleInput = document.querySelector('[name="title"]');
|
|
if (titleInput.value.length < 5) {
|
|
notify("error", "Customer Estimate Title must be at least 5 characters long.");
|
|
return; // Stop form submission
|
|
}
|
|
|
|
// Collect all form data
|
|
const formData = {
|
|
csrfmiddlewaretoken: document.querySelector('[name=csrfmiddlewaretoken]').value,
|
|
title: document.querySelector('[name=title]').value,
|
|
customer: document.querySelector('[name=customer]').value,
|
|
item: [],
|
|
quantity: [],
|
|
opportunity_id: "{{opportunity_id}}"
|
|
};
|
|
|
|
|
|
// Collect multi-value fields (e.g., item[], quantity[])
|
|
document.querySelectorAll('[name="item[]"]').forEach(input => {
|
|
formData.item.push(input.value);
|
|
});
|
|
document.querySelectorAll('[name="quantity[]"]').forEach(input => {
|
|
formData.quantity.push(input.value);
|
|
});
|
|
console.log(formData);
|
|
|
|
try {
|
|
// Send data to the server using fetch
|
|
const response = await fetch("{% url 'estimate_create' request.dealer.slug %}", {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRFToken': formData.csrfmiddlewaretoken,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(formData)
|
|
});
|
|
|
|
// Parse the JSON response
|
|
const data = await response.json();
|
|
|
|
// Handle the response
|
|
if (data.status === "error") {
|
|
notify("error", data.message); // Display an error message
|
|
} else if (data.status === "success") {
|
|
notify("success","Estimate created successfully");
|
|
setTimeout(() => {
|
|
window.location.assign(data.url); // Redirect to the provided URL
|
|
}, 1000);
|
|
} else {
|
|
notify("error","Unexpected response from the server");
|
|
}
|
|
} catch (error) {
|
|
|
|
notify("error", error);
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock customJS %}
|