update the signup validation

This commit is contained in:
ismail 2025-08-31 16:09:04 +03:00
parent aa71410493
commit f64a94d7ad
10 changed files with 30111 additions and 9322 deletions

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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">

View File

@ -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>

View File

@ -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 %}

View File

@ -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>

View File

@ -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>