update the signup validation
This commit is contained in:
parent
aa71410493
commit
f64a94d7ad
@ -4629,17 +4629,19 @@ class SaleOrderDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailVie
|
||||
permission_required = ["inventory.view_saleorder"]
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
dealer = self.request.dealer
|
||||
context = super().get_context_data(**kwargs)
|
||||
sale_order = self.get_object()
|
||||
|
||||
data = get_finance_data(sale_order.estimate, dealer)
|
||||
print(data)
|
||||
# Add additional context data
|
||||
context["status_choices"] = dict(models.SaleOrder.STATUS_CHOICES)
|
||||
context["page_title"] = _("Sales Order Details")
|
||||
|
||||
# Calculate any additional properties you want to display
|
||||
context["is_delivered"] = sale_order.status == "DELIVERED"
|
||||
context["is_cancelled"] = sale_order.status == "CANCELLED"
|
||||
context["is_pending_approval"] = sale_order.status == "PENDING_APPROVAL"
|
||||
context["data"] = data
|
||||
|
||||
return context
|
||||
|
||||
@ -4955,6 +4957,7 @@ def create_estimate(request, dealer_slug, slug=None):
|
||||
if slug:
|
||||
opportunity = models.Opportunity.objects.get(slug=slug)
|
||||
customer = opportunity.customer
|
||||
print(customer)
|
||||
form.fields["customer"].queryset = models.Customer.objects.filter(
|
||||
pk=customer.pk
|
||||
)
|
||||
@ -5203,6 +5206,7 @@ class SaleOrderDetail(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
order_pk = self.kwargs.get("order_pk")
|
||||
print("hi")
|
||||
return models.SaleOrder.objects.get(
|
||||
pk=order_pk,
|
||||
)
|
||||
@ -5210,7 +5214,7 @@ class SaleOrderDetail(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
||||
def get_context_data(self, **kwargs):
|
||||
saleorder = kwargs.get("object")
|
||||
dealer = self.request.dealer
|
||||
estimate = saleorder.estimate
|
||||
estimate = saleorder.estimatep
|
||||
if estimate.get_itemtxs_data():
|
||||
# calculator = CarFinanceCalculator(estimate)
|
||||
# finance_data = calculator.get_finance_data()
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
17172
logs/django.po
Normal file
17172
logs/django.po
Normal file
File diff suppressed because it is too large
Load Diff
@ -269,11 +269,11 @@
|
||||
data-wizard-prev-btn="data-wizard-prev-btn">{% trans 'Previous' %}</button>
|
||||
<div class="flex-1 text-end">
|
||||
<button data-attr-disabled="!$form1_valid"
|
||||
data-attr-disabled="!$phone_number_valid"
|
||||
class="btn btn-phoenix-primary px-6 px-sm-6 next"
|
||||
type="button"
|
||||
id="next_btn"
|
||||
data-wizard-next-btn="data-wizard-next-btn">{% trans 'Next' %}</button>
|
||||
data-attr-disabled="!$phone_number_valid"
|
||||
class="btn btn-phoenix-primary px-6 px-sm-6 next"
|
||||
type="button"
|
||||
id="next_btn"
|
||||
data-wizard-next-btn="data-wizard-next-btn">{% trans 'Next' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -372,7 +372,7 @@
|
||||
hideLoading();
|
||||
const data = await response.json();
|
||||
if (response.ok) {
|
||||
notify("success","Account created successfully");
|
||||
notify("success","{% trans'Account created successfully'%}");
|
||||
setTimeout(() => {
|
||||
window.location.href = "{% url 'account_login' %}";
|
||||
}, 1000);
|
||||
|
||||
@ -86,6 +86,7 @@
|
||||
alt="" />
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{% if opportunity.customer %}
|
||||
<h5>{{ opportunity.customer|capfirst }}</h5>
|
||||
@ -129,6 +130,13 @@
|
||||
</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">
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
hx-swap="outerHTML"
|
||||
hx-select-oob="#toast-container"
|
||||
hx-indicator="#spinner">
|
||||
|
||||
|
||||
<li class="nav-item">
|
||||
{% comment %} <p class="navbar-vertical-label text-primary fs-8 text-truncate">{{request.dealer|default:"Apps"}}</p>
|
||||
<hr class="navbar-vertical-line"> {% endcomment %}
|
||||
@ -223,7 +223,7 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'sales_list' request.dealer.slug %}">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="nav-link-icon"><span class="fas fa-money-check"></span></span><span class="nav-link-text">{% trans "Sale Orders"|capfirst %}</span>
|
||||
<span class="nav-link-icon"><span class="fas fa-money-check"></span></span><span class="nav-link-text">{% trans "Sale Order"|capfirst %}</span>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@ -440,7 +440,7 @@
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
</div> {% endcomment %}
|
||||
{% endif %}
|
||||
@ -450,10 +450,12 @@
|
||||
<a class="nav-link ps-2" href="{% if request.is_dealer%}{% url 'ticket_list' request.dealer.slug %} {% else %}#{%endif%}">
|
||||
<div class="d-flex align-items-center">
|
||||
{% if user.is_authenticated%}
|
||||
|
||||
|
||||
<span class="nav-link-icon"><span class="fa-solid fa-gear me-1 fs-5"></span></span>
|
||||
|
||||
<span class="nav-link-icon"><span class="fa-solid fa-gear me-1 fs-7"></span></span>
|
||||
<span class="nav-link-text">{{ request.dealer.user.username }}</span>
|
||||
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</a>
|
||||
|
||||
@ -53,6 +53,28 @@
|
||||
max-width:60rem;
|
||||
|
||||
}
|
||||
|
||||
/* Validation styles */
|
||||
.is-invalid {
|
||||
border-color: #dc3545 !important;
|
||||
padding-right: calc(1.5em + 0.75rem) !important;
|
||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e") !important;
|
||||
background-repeat: no-repeat !important;
|
||||
background-position: right calc(0.375em + 0.1875rem) center !important;
|
||||
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem) !important;
|
||||
}
|
||||
|
||||
.invalid-feedback {
|
||||
display: none;
|
||||
width: 100%;
|
||||
margin-top: 0.25rem;
|
||||
font-size: 0.875em;
|
||||
color: #dc3545;
|
||||
}
|
||||
|
||||
.is-invalid ~ .invalid-feedback {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
{% endblock customCSS %}
|
||||
{% block content %}
|
||||
@ -192,6 +214,9 @@
|
||||
class="form-control form-control-sm"
|
||||
placeholder="{{ _("Cardholder Name") }}"
|
||||
required>
|
||||
<div class="invalid-feedback" id="card_name_feedback">
|
||||
{{ _("Please enter the cardholder name") }}
|
||||
</div>
|
||||
</div>
|
||||
<label class="form-label" for="card_number">{{ _("Card Number") }}</label>
|
||||
<div class="input-group">
|
||||
@ -206,6 +231,9 @@
|
||||
inputmode="numeric"
|
||||
required
|
||||
title="Enter a 16-digit card number">
|
||||
<div class="invalid-feedback" id="card_number_feedback">
|
||||
{{ _("Please enter a valid 16-digit card number") }}
|
||||
</div>
|
||||
</div>
|
||||
<label class="form-label" for="card_expiry">{{ _("Expiry Date") }} (MM/YY)</label>
|
||||
<div class="input-group">
|
||||
@ -220,6 +248,9 @@
|
||||
inputmode="numeric"
|
||||
required
|
||||
title="Enter expiry in MM/YY format">
|
||||
<div class="invalid-feedback" id="card_expiry_feedback">
|
||||
{{ _("Please enter a valid expiry date (MM/YY)") }}
|
||||
</div>
|
||||
</div>
|
||||
<label class="form-label" for="card_cvv">{{ _("CVV") }}</label>
|
||||
<div class="input-group">
|
||||
@ -234,6 +265,9 @@
|
||||
inputmode="numeric"
|
||||
required
|
||||
title="Enter 3-digit CVV">
|
||||
<div class="invalid-feedback" id="card_cvv_feedback">
|
||||
{{ _("Please enter a valid 3-digit CVV") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -336,11 +370,19 @@
|
||||
|
||||
// Initialize summary updates
|
||||
initSummaryUpdates();
|
||||
|
||||
// Initialize validation
|
||||
initValidation();
|
||||
}
|
||||
|
||||
function handleFormSubmit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Validate all steps before submission
|
||||
if (!validateAllSteps()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof Swal !== 'undefined') {
|
||||
Swal.fire({
|
||||
title: 'Processing...',
|
||||
@ -426,6 +468,11 @@
|
||||
}
|
||||
|
||||
function handleNext() {
|
||||
// Validate current step before proceeding
|
||||
if (!validateCurrentStep(currentStep)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentStep < steps.length - 1) {
|
||||
currentStep++;
|
||||
showStep(currentStep);
|
||||
@ -487,6 +534,9 @@
|
||||
function formatCardNumber(e) {
|
||||
let val = this.value.replace(/\D/g, "").substring(0, 16);
|
||||
this.value = val.replace(/(.{4})/g, "$1 ").trim();
|
||||
|
||||
// Validate as user types
|
||||
validateCardNumber(this);
|
||||
}
|
||||
|
||||
function formatExpiryDate(e) {
|
||||
@ -495,6 +545,9 @@
|
||||
val = val.substring(0, 2) + "/" + val.substring(2);
|
||||
}
|
||||
this.value = val;
|
||||
|
||||
// Validate as user types
|
||||
validateExpiryDate(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -509,21 +562,211 @@
|
||||
updatePricingSummary(); // Initial call
|
||||
}
|
||||
|
||||
function updatePricingSummary() {
|
||||
function initValidation() {
|
||||
// Add input event listeners for validation
|
||||
const cardNameInput = document.getElementById("card_name");
|
||||
const cardNumberInput = document.getElementById("card_number");
|
||||
const cardExpiryInput = document.getElementById("card_expiry");
|
||||
const cardCvvInput = document.getElementById("card_cvv");
|
||||
|
||||
if (cardNameInput) {
|
||||
cardNameInput.addEventListener("blur", function() {
|
||||
validateCardName(this);
|
||||
});
|
||||
}
|
||||
|
||||
if (cardNumberInput) {
|
||||
cardNumberInput.addEventListener("blur", function() {
|
||||
validateCardNumber(this);
|
||||
});
|
||||
}
|
||||
|
||||
if (cardExpiryInput) {
|
||||
cardExpiryInput.addEventListener("blur", function() {
|
||||
validateExpiryDate(this);
|
||||
});
|
||||
}
|
||||
|
||||
if (cardCvvInput) {
|
||||
cardCvvInput.addEventListener("blur", function() {
|
||||
validateCvv(this);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function validateCurrentStep(stepIndex) {
|
||||
switch(stepIndex) {
|
||||
case 0: // Plan selection
|
||||
return validatePlanSelection();
|
||||
case 1: // User information
|
||||
return validateUserInfo();
|
||||
case 2: // Payment information
|
||||
return validatePaymentInfo();
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function validateAllSteps() {
|
||||
return validatePlanSelection() &&
|
||||
validateUserInfo() &&
|
||||
validatePaymentInfo();
|
||||
}
|
||||
|
||||
function validatePlanSelection() {
|
||||
const selectedPlan = document.querySelector('input[name="selected_plan"]:checked');
|
||||
if (!selectedPlan) return;
|
||||
if (!selectedPlan) {
|
||||
if (typeof Swal !== 'undefined') {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: 'Please select a plan to continue'
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const price = parseFloat(selectedPlan.dataset.price) || 0;
|
||||
const tax = price * 0.15;
|
||||
const total = price + tax;
|
||||
function validateUserInfo() {
|
||||
const firstName = document.getElementById("first_name");
|
||||
const lastName = document.getElementById("last_name");
|
||||
const email = document.getElementById("email");
|
||||
const phone = document.getElementById("phone");
|
||||
|
||||
const summaryPrice = document.getElementById("summary_price");
|
||||
const summaryTax = document.getElementById("summary-tax");
|
||||
const summaryTotal = document.getElementById("summary-total");
|
||||
let isValid = true;
|
||||
|
||||
if (summaryPrice) summaryPrice.textContent = price.toFixed(2);
|
||||
if (summaryTax) summaryTax.textContent = tax.toFixed(2);
|
||||
if (summaryTotal) summaryTotal.textContent = total.toFixed(2);
|
||||
if (!firstName.value.trim()) {
|
||||
markAsInvalid(firstName, "Please enter your first name");
|
||||
isValid = false;
|
||||
} else {
|
||||
markAsValid(firstName);
|
||||
}
|
||||
|
||||
if (!lastName.value.trim()) {
|
||||
markAsInvalid(lastName, "Please enter your last name");
|
||||
isValid = false;
|
||||
} else {
|
||||
markAsValid(lastName);
|
||||
}
|
||||
|
||||
if (!email.value.trim() || !isValidEmail(email.value)) {
|
||||
markAsInvalid(email, "Please enter a valid email address");
|
||||
isValid = false;
|
||||
} else {
|
||||
markAsValid(email);
|
||||
}
|
||||
|
||||
if (!phone.value.trim()) {
|
||||
markAsInvalid(phone, "Please enter your phone number");
|
||||
isValid = false;
|
||||
} else {
|
||||
markAsValid(phone);
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
function validatePaymentInfo() {
|
||||
const cardName = document.getElementById("card_name");
|
||||
const cardNumber = document.getElementById("card_number");
|
||||
const cardExpiry = document.getElementById("card_expiry");
|
||||
const cardCvv = document.getElementById("card_cvv");
|
||||
|
||||
let isValid = true;
|
||||
|
||||
if (!validateCardName(cardName)) {
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (!validateCardNumber(cardNumber)) {
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (!validateExpiryDate(cardExpiry)) {
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (!validateCvv(cardCvv)) {
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
function validateCardName(input) {
|
||||
if (!input.value.trim()) {
|
||||
markAsInvalid(input, "Please enter the cardholder name");
|
||||
return false;
|
||||
} else {
|
||||
markAsValid(input);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function validateCardNumber(input) {
|
||||
// Remove spaces for validation
|
||||
const cardNumber = input.value.replace(/\s/g, '');
|
||||
|
||||
if (cardNumber.length !== 16 || !/^\d+$/.test(cardNumber)) {
|
||||
markAsInvalid(input, "Please enter a valid 16-digit card number");
|
||||
return false;
|
||||
} else {
|
||||
markAsValid(input);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function validateExpiryDate(input) {
|
||||
const value = input.value;
|
||||
const pattern = /^(0[1-9]|1[0-2])\/\d{2}$/;
|
||||
|
||||
if (!pattern.test(value)) {
|
||||
markAsInvalid(input, "Please enter a valid expiry date (MM/YY)");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the card is expired
|
||||
const [month, year] = value.split('/');
|
||||
const expiryDate = new Date(2000 + parseInt(year), parseInt(month) - 1);
|
||||
const currentDate = new Date();
|
||||
|
||||
if (expiryDate < currentDate) {
|
||||
markAsInvalid(input, "This card has expired");
|
||||
return false;
|
||||
}
|
||||
|
||||
markAsValid(input);
|
||||
return true;
|
||||
}
|
||||
|
||||
function validateCvv(input) {
|
||||
if (!input.value.trim() || input.value.length !== 3 || !/^\d+$/.test(input.value)) {
|
||||
markAsInvalid(input, "Please enter a valid 3-digit CVV");
|
||||
return false;
|
||||
} else {
|
||||
markAsValid(input);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function isValidEmail(email) {
|
||||
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
return re.test(email);
|
||||
}
|
||||
|
||||
function markAsInvalid(input, message) {
|
||||
input.classList.add("is-invalid");
|
||||
|
||||
// Update feedback message if available
|
||||
const feedback = document.getElementById(input.id + "_feedback");
|
||||
if (feedback) {
|
||||
feedback.textContent = message;
|
||||
}
|
||||
}
|
||||
|
||||
function markAsValid(input) {
|
||||
input.classList.remove("is-invalid");
|
||||
}
|
||||
</script>
|
||||
{% endblock customJS %}
|
||||
{% endblock customJS %}
|
||||
@ -210,17 +210,15 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for car in data.cars %}
|
||||
<tr>
|
||||
<td>{{ car.vin }}</td>
|
||||
<td>{{ car.make }}</td>
|
||||
<td>{{ car.model }}</td>
|
||||
<td>{{ car.year }}</td>
|
||||
<td class="text-center">{{ car.quantity }}</td>
|
||||
<td class="text-center">{{ car.unit_price }}</td>
|
||||
<td class="highlight fw-semibold text-center">{{ car.total }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td>{{ data.car.vin }}</td>
|
||||
<td>{{ data.car.make }}</td>
|
||||
<td>{{ data.car.model }}</td>
|
||||
<td>{{ data.car.year }}</td>
|
||||
<td class="text-center">{{ data.car.quantity }}</td>
|
||||
<td class="text-center">{{ data.car.unit_price }}</td>
|
||||
<td class="highlight fw-semibold text-center">{{ data.car.total }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@ -98,15 +98,15 @@
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<p>
|
||||
<strong>{% trans "Make" %}:</strong> {{ sale_order.cars.0.id_car_make }}
|
||||
<strong>{% trans "Make" %}:</strong> {{ data.car.id_car_make }}
|
||||
<br>
|
||||
<strong>{% trans "Model" %}:</strong> {{ sale_order.cars.0.id_car_model }}
|
||||
<strong>{% trans "Model" %}:</strong> {{ data.car.id_car_model }}
|
||||
<br>
|
||||
<strong>{% trans "Year" %}:</strong> {{ sale_order.cars.0.year }}
|
||||
<strong>{% trans "Year" %}:</strong> {{ data.car.year }}
|
||||
<br>
|
||||
<strong>{% trans "Vin" %}:</strong> {{ sale_order.cars.0.vin }}
|
||||
<strong>{% trans "Vin" %}:</strong> {{ data.car.vin }}
|
||||
<br>
|
||||
<strong>{% trans "Status" %}:</strong><span class="badge bg-success">{{ sale_order.cars.0.status|capfirst }}</span>
|
||||
<strong>{% trans "Status" %}:</strong><span class="badge bg-success">{{ data.car.status|capfirst }}</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-6"></div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user