update pricing
This commit is contained in:
parent
62dd1188c9
commit
255c08b74b
@ -2133,7 +2133,8 @@ class VatRateForm(forms.ModelForm):
|
||||
label="VAT Rate",
|
||||
max_digits=5,
|
||||
decimal_places=2,
|
||||
validators=[vat_rate_validator]
|
||||
validators=[vat_rate_validator],
|
||||
help_text=_("VAT rate as decimal between 0 and 1 (e.g., 0.2 for 20%)"),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
|
||||
@ -1332,6 +1332,7 @@ urlpatterns = [
|
||||
path('<slug:dealer_slug>/help_center/tickets/<int:ticket_id>/', views.ticket_detail, name='ticket_detail'),
|
||||
path('help_center/tickets/<int:ticket_id>/update/', views.ticket_update, name='ticket_update'),
|
||||
# path('help_center/tickets/<int:ticket_id>/ticket_mark_resolved/', views.ticket_mark_resolved, name='ticket_mark_resolved'),
|
||||
path('payment_results/', views.payment_result, name='payment_result'),
|
||||
|
||||
]
|
||||
|
||||
|
||||
@ -2336,28 +2336,28 @@ class DealerDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
||||
return context
|
||||
|
||||
|
||||
from .forms import VatRateForm
|
||||
from .forms import VatRateForm
|
||||
@login_required
|
||||
def dealer_vat_rate_update(request, slug):
|
||||
dealer = get_object_or_404(models.Dealer, slug=slug)
|
||||
|
||||
|
||||
vat_rate_instance, created = models.VatRate.objects.get_or_create(dealer=dealer)
|
||||
|
||||
if request.method == "POST":
|
||||
|
||||
|
||||
form = VatRateForm(request.POST, instance=vat_rate_instance)
|
||||
|
||||
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(request, _("VAT rate updated successfully"))
|
||||
return redirect("dealer_detail", slug=slug)
|
||||
else:
|
||||
|
||||
|
||||
messages.error(request, _("Please enter valid vat rate between 0 and 1."))
|
||||
redirect("dealer_detail", slug=slug)
|
||||
|
||||
return redirect("dealer_detail", slug=slug)
|
||||
|
||||
|
||||
|
||||
class DealerUpdateView(
|
||||
LoginRequiredMixin, PermissionRequiredMixin, SuccessMessageMixin, UpdateView
|
||||
@ -9867,7 +9867,8 @@ def payment_callback(request, dealer_slug):
|
||||
payment_status = request.GET.get("status")
|
||||
logger.info(f"Received payment callback for dealer_slug: {dealer_slug}, payment_id: {payment_id}, status: {payment_status}")
|
||||
order = Order.objects.filter(user=dealer.user, status=1).first() # Status 1 = NEW
|
||||
|
||||
if history.status == "paid":
|
||||
return redirect('home')
|
||||
if payment_status == "paid":
|
||||
logger.info(f"Payment successful for transaction ID {payment_id}. Processing order completion.")
|
||||
|
||||
@ -10764,7 +10765,7 @@ class PurchaseOrderListView(LoginRequiredMixin, PermissionRequiredMixin, ListVie
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["entity_slug"] = dealer.entity.slug
|
||||
context["vendors"] = vendors
|
||||
context["empty_state_value"] = _("purchase order")
|
||||
context["empty_state_value"] = _("purchase order")
|
||||
|
||||
return context
|
||||
|
||||
@ -11762,4 +11763,10 @@ class CarDealershipSignUpView(CreateView):
|
||||
def form_valid(self, form):
|
||||
response = super().form_valid(form)
|
||||
messages.success(self.request, _('Your request has been submitted. We will contact you soon.'))
|
||||
return response
|
||||
return response
|
||||
|
||||
def payment_result(request):
|
||||
s = request.GET.get("status")
|
||||
if s == "success":
|
||||
return render(request, 'plans/payment_success.html')
|
||||
return render(request, 'plans/payment_failed.html')
|
||||
|
||||
50
templates/plans/payment_failed.html
Normal file
50
templates/plans/payment_failed.html
Normal file
@ -0,0 +1,50 @@
|
||||
{% extends "base.html" %}
|
||||
{% load i18n static %}
|
||||
{% block content %}
|
||||
<main class="main">
|
||||
<section class="py-4">
|
||||
<div class="container d-flex justify-content-between align-items-center">
|
||||
<h1 class="h3 mb-0 text-body-emphasis">{% trans "Payment Failed" %}</h1>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb mb-0">
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'home' %}">{% trans "Home" %}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">{% trans "Payment Failed" %}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="d-flex align-items-center justify-content-center py-5">
|
||||
<div class="container text-center" style="max-width: 32rem;">
|
||||
<div class="card p-5 shadow-sm border-0 rounded-4" data-aos="fade-up">
|
||||
<div class="card-body p-0">
|
||||
<div class="mb-4">
|
||||
<i class="bi bi-x-circle-fill text-danger" style="font-size: 5rem;"></i>
|
||||
</div>
|
||||
|
||||
<h2 class="mt-4 mb-3 text-body-emphasis fw-bold">{% trans "Payment Failed" %}</h2>
|
||||
|
||||
{% if message %}
|
||||
<p class="lead text-body-secondary">{{ message }}.</p>
|
||||
{% else %}
|
||||
<p class="lead text-body-secondary">
|
||||
{% trans "We couldn't process your payment. Please review your information and try again." %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<div class="d-grid gap-3 col-md-8 mx-auto mt-4">
|
||||
<a href="{% url 'pricing_page' request.dealer.slug %}" class="btn btn-danger btn-lg rounded-pill">
|
||||
{% trans "Go Back and Try Again" %}
|
||||
</a>
|
||||
<a href="{% url 'home' %}" class="btn btn-link text-body-secondary text-decoration-none">
|
||||
{% trans "Back to Home" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
{% endblock content %}
|
||||
50
templates/plans/payment_success.html
Normal file
50
templates/plans/payment_success.html
Normal file
@ -0,0 +1,50 @@
|
||||
{% extends "base.html" %}
|
||||
{% load i18n static %}
|
||||
|
||||
{% block content %}
|
||||
<main class="main">
|
||||
<section class="py-4">
|
||||
<div class="container d-flex justify-content-between align-items-center">
|
||||
<h1 class="h3 mb-0 text-body-emphasis">{% trans "Payment Successful" %}</h1>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb mb-0">
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'home' %}">{% trans "Home" %}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">{% trans "Success" %}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="d-flex align-items-center justify-content-center py-5">
|
||||
<div class="container text-center" style="max-width: 32rem;">
|
||||
<div class="card p-5 shadow-sm border-0 rounded-4" data-aos="fade-up">
|
||||
<div class="card-body p-0">
|
||||
<div class="mb-4">
|
||||
<i class="bi bi-check-circle-fill text-success" style="font-size: 5rem;"></i>
|
||||
</div>
|
||||
|
||||
<h2 class="mt-4 mb-3 text-body-emphasis fw-bold">{{ _("Thank You") }}!</h2>
|
||||
|
||||
<p class="lead text-body-secondary">
|
||||
{{ _("Your payment was successful") }}. {{ _("Your order is being processed") }}.
|
||||
</p>
|
||||
|
||||
<div class="d-grid gap-3 col-md-8 mx-auto mt-4">
|
||||
{% if invoice %}
|
||||
<a href="{% url 'invoice_preview_html' invoice.pk %}"
|
||||
class="btn btn-primary btn-lg rounded-pill">
|
||||
<i class="fas fa-eye me-2"></i> {{ _("View Invoice") }}
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="{% url 'home' %}" class="btn btn-link text-body-secondary text-decoration-none">
|
||||
<i class="fas fa-home me-2"></i> {{ _("Back to Home") }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
{% endblock content %}
|
||||
@ -8,7 +8,7 @@
|
||||
{% block customCSS %}
|
||||
<link rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
|
||||
integrity="sha512-X... (Your actual integrity hash)"
|
||||
integrity="sha512-X..."
|
||||
crossorigin="anonymous"
|
||||
referrerpolicy="no-referrer" />
|
||||
<style>
|
||||
@ -21,7 +21,7 @@
|
||||
--card-selected-shadow: rgba(13, 110, 253, 0.4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.pricing-card-label {
|
||||
transition: all 0.2s ease-in-out;
|
||||
cursor: pointer;
|
||||
@ -177,9 +177,9 @@
|
||||
.fa-ul .fa-li {
|
||||
left: -1em;
|
||||
}
|
||||
|
||||
</style>
|
||||
{% endblock customCSS %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container py-5" id="pricing_container">
|
||||
<h1 class="text-center mb-5 text-primary fw-bold">{{ _("Choose Your Plan") }}</h1>
|
||||
@ -256,6 +256,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step d-none row justify-content-center" id="step2">
|
||||
<div class="col-lg-8 col-md-10">
|
||||
<h4 class="text-center mb-4 text-secondary">{{ _("2. Enter Your Information") }}</h4>
|
||||
@ -335,6 +336,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step d-none row justify-content-center" id="step3">
|
||||
<div class="col-lg-8 col-md-10">
|
||||
<h4 class="text-center mb-4 text-secondary">{{ _("3. Payment Information") }}</h4>
|
||||
@ -414,6 +416,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step d-none row justify-content-center" id="step4">
|
||||
<div class="col-lg-8 col-md-10">
|
||||
<h4 class="text-center mb-4 text-secondary">{{ _("4. Confirm Your Information") }}</h4>
|
||||
@ -423,10 +426,10 @@
|
||||
<p class="mb-1"><i class="fas fa-box me-2"></i><strong>{{ _("Plan") }}:</strong> <span id="summary_plan"></span></p>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<p class="mb-1"><i class="fas fa-tag me-2"></i><strong>{{ _("Price") }}:</strong> <span id="summary_price"></span></p>
|
||||
<p class="mb-1"><i class="fas fa-tag me-2"></i><strong>{{ _("Price (excl. VAT)") }}:</strong> <span id="summary_price"></span> <span class="icon-saudi_riyal"></span></p>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<p class="mb-1"><i class="fas fa-receipt me-2"></i><strong>{{ _("VAT") }} (15%):</strong> <span id="summary-tax">0.00</span> <span class="icon-saudi_riyal"></span></p>
|
||||
<p class="mb-1"><i class="fas fa-receipt me-2"></i><strong>{{ _("VAT") }} (15%):</strong> <span id="summary-tax"></span> <span class="icon-saudi_riyal"></span></p>
|
||||
</div>
|
||||
<hr class="my-3">
|
||||
<div class="summary-item">
|
||||
@ -458,6 +461,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between mt-5">
|
||||
<button type="button"
|
||||
class="btn btn-lg btn-phoenix-secondary px-5"
|
||||
@ -472,11 +476,10 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
{% endblock content %}
|
||||
|
||||
{% block customJS %}
|
||||
<script>
|
||||
// wizard-form.js
|
||||
document.addEventListener('DOMContentLoaded', initWizardForm);
|
||||
document.addEventListener('htmx:afterSwap', initWizardForm);
|
||||
|
||||
@ -484,22 +487,22 @@
|
||||
const form = document.getElementById('wizardForm');
|
||||
if (!form) return;
|
||||
|
||||
// Remove old event listeners to prevent duplicates
|
||||
// Remove old event listeners to prevent duplicates
|
||||
form.removeEventListener('submit', handleFormSubmit);
|
||||
|
||||
// Add new submit handler
|
||||
// Add new submit handler
|
||||
form.addEventListener('submit', handleFormSubmit);
|
||||
|
||||
// Initialize radio button selections
|
||||
// Initialize radio button selections
|
||||
initPlanSelection();
|
||||
|
||||
// Initialize wizard steps
|
||||
// Initialize wizard steps
|
||||
initWizardSteps();
|
||||
|
||||
// Initialize card input formatting
|
||||
// Initialize card input formatting
|
||||
initCardInputs();
|
||||
|
||||
// Initialize summary updates
|
||||
// Initialize summary updates
|
||||
initSummaryUpdates();
|
||||
|
||||
// Initialize validation
|
||||
@ -523,7 +526,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
// Submit the form after a slight delay
|
||||
// Submit the form after a slight delay
|
||||
setTimeout(() => {
|
||||
const form = e.target;
|
||||
if (form.reportValidity()) {
|
||||
@ -537,13 +540,13 @@
|
||||
function initPlanSelection() {
|
||||
const radios = document.querySelectorAll('.btn-check');
|
||||
radios.forEach(radio => {
|
||||
// Remove old listeners
|
||||
// Remove old listeners
|
||||
radio.removeEventListener('change', handlePlanChange);
|
||||
|
||||
// Add new listeners
|
||||
// Add new listeners
|
||||
radio.addEventListener('change', handlePlanChange);
|
||||
|
||||
// Initialize selected state
|
||||
// Initialize selected state
|
||||
if (radio.checked) {
|
||||
updatePlanSelection(radio.id);
|
||||
}
|
||||
@ -580,8 +583,9 @@
|
||||
nextBtn.removeEventListener("click", handleNext);
|
||||
prevBtn.removeEventListener("click", handlePrev);
|
||||
|
||||
nextBtn.addEventListener("click", handleNext);
|
||||
prevBtn.addEventListener("click", handlePrev);
|
||||
// Add new listeners
|
||||
nextBtn.addEventListener("click", handleNext);
|
||||
prevBtn.addEventListener("click", handlePrev);
|
||||
|
||||
function showStep(index) {
|
||||
steps.forEach((step, i) => {
|
||||
@ -622,11 +626,7 @@
|
||||
}
|
||||
|
||||
function populateSummary() {
|
||||
const selectedPlan = document.querySelector('input[name="selected_plan"]:checked');
|
||||
if (selectedPlan) {
|
||||
document.getElementById("summary_plan").textContent = selectedPlan.dataset.name;
|
||||
document.getElementById("summary_price").textContent = selectedPlan.dataset.price;
|
||||
}
|
||||
updatePricingSummary(); // Reuse logic for pricing
|
||||
|
||||
const firstName = document.getElementById("first_name")?.value || '';
|
||||
const lastName = document.getElementById("last_name")?.value || '';
|
||||
@ -648,7 +648,7 @@
|
||||
return "**** **** **** " + last4;
|
||||
}
|
||||
|
||||
// Initialize
|
||||
// Initialize
|
||||
showStep(currentStep);
|
||||
}
|
||||
|
||||
@ -669,7 +669,7 @@
|
||||
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);
|
||||
}
|
||||
@ -697,6 +697,20 @@
|
||||
updatePricingSummary(); // Initial call
|
||||
}
|
||||
|
||||
function updatePricingSummary() {
|
||||
const selectedPlan = document.querySelector('input[name="selected_plan"]:checked');
|
||||
if (!selectedPlan) return;
|
||||
|
||||
const priceWithTax = parseFloat(selectedPlan.dataset.price);
|
||||
const basePrice = priceWithTax / 1.15;
|
||||
const vat = priceWithTax - basePrice;
|
||||
|
||||
document.getElementById("summary_plan").textContent = selectedPlan.dataset.name;
|
||||
document.getElementById("summary_price").textContent = basePrice.toFixed(2);
|
||||
document.getElementById("summary-tax").textContent = vat.toFixed(2);
|
||||
document.getElementById("summary-total").textContent = priceWithTax.toFixed(2);
|
||||
}
|
||||
|
||||
function initValidation() {
|
||||
// Add input event listeners for validation
|
||||
const cardNameInput = document.getElementById("card_name");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user