You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

866 lines
31 KiB

{% extends "base.html" %}
{% block title %}Single Payment - Plutus{% endblock %}
{% block head %}
<style>
/* Background styling */
body {
background-color: #3a3a3a !important;
background-image: url("{{ url_for('static', filename='images/plutus3.JPG') }}") !important;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
background-attachment: fixed;
position: relative;
}
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(58, 58, 58, 0.85);
z-index: -1;
}
/* (No page-level z-index; Bootstrap modals handle their own layering) */
/* Page title and breadcrumb styling */
h1, h2, h3, h4, h5, h6 {
color: #faf8f0 !important;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
}
.breadcrumb-item a {
color: #d4af37 !important;
}
.breadcrumb-item.active {
color: #faf8f0 !important;
}
.card, .box {
background-color: rgba(250, 248, 240, 0.98) !important;
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
}
.alert {
background-color: rgba(250, 248, 240, 0.98);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
</style>
{% endblock %}
{% block content %}
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{{ url_for('main.index') }}">Dashboard</a></li>
<li class="breadcrumb-item active" aria-current="page">Single Payment</li>
</ol>
</nav>
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h1 class="h2">Single Payment Processing</h1>
<p class="text-muted">Process individual customer payments through Stripe</p>
</div>
</div>
<!-- Single Payment Form -->
<div class="card">
<div class="card-body">
<!-- Step 1: Enter Splynx ID -->
<div id="step1" class="payment-step">
<h2 class="h4">
<i class="fas fa-search me-2"></i>
Customer Lookup
</h2>
<div class="field">
<label class="label" for="lookup_splynx_id">Splynx Customer ID</label>
<div class="control">
<input class="input" type="number" id="lookup_splynx_id" placeholder="Enter customer ID" required>
</div>
<p class="help">Enter the Splynx customer ID to fetch customer details</p>
</div>
<!-- Loading State -->
<div id="loading" class="text-center py-5 d-none">
<div class="spinner"></div>
<p class="mt-3">Fetching customer details...</p>
</div>
<!-- Error State -->
<div id="customerError" class="alert alert-danger d-none">
<i class="fas fa-exclamation-triangle me-2"></i>
<span id="errorMessage">Customer not found or error occurred</span>
</div>
<div class="field is-grouped">
<div class="control">
<button class="button is-primary" id="nextBtn" onclick="fetchCustomerDetails()">
<span class="icon"><i class="fas fa-arrow-right"></i></span>
<span>Next</span>
</button>
</div>
</div>
</div>
<!-- Step 2: Select Invoices (NEW) -->
<div id="step2" class="payment-step d-none">
<h2 class="h4">
<i class="fas fa-file-invoice me-2"></i>
Select Invoices to Pay
</h2>
<!-- Loading State -->
<div id="invoiceLoading" class="text-center py-5 d-none">
<div class="spinner"></div>
<p class="mt-3">Fetching invoices...</p>
</div>
<!-- No Invoices State -->
<div id="noInvoices" class="alert alert-info d-none">
<i class="fas fa-info-circle me-2"></i>
No unpaid invoices found. You can still process a payment.
</div>
<!-- Invoices List -->
<div id="invoicesList" class="d-none">
<div class="alert alert-info mb-4">
<i class="fas fa-info-circle me-2"></i>
Select which invoices this payment should be applied to. You can select multiple invoices or skip to process a general payment.
</div>
<div class="card bg-light">
<div class="card-body">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="selectAllInvoices" onchange="toggleAllInvoices()">
<label class="form-check-label" for="selectAllInvoices">
<strong>Select All Invoices</strong>
</label>
</div>
<hr>
<div id="invoicesContainer">
<!-- Invoice checkboxes populated by JavaScript -->
</div>
<div class="mt-4">
<label class="form-label">Total Selected Amount</label>
<p class="h4" id="selectedInvoicesTotal">$0.00</p>
</div>
</div>
</div> <!-- /.card -->
</div>
<div class="field is-grouped">
<div class="control">
<button class="button is-light" onclick="goBackToStep1()">
<span class="icon"><i class="fas fa-arrow-left"></i></span>
<span>Back</span>
</button>
</div>
<div class="control">
<button class="button is-primary" onclick="goToStep3()">
<span class="icon"><i class="fas fa-arrow-right"></i></span>
<span>Continue to Payment</span>
</button>
</div>
</div>
</div>
<!-- Step 3: Confirm Customer & Enter Amount -->
<div id="step3" class="payment-step d-none">
<h2 class="h4">
<i class="fas fa-user-check me-2"></i>
Confirm Customer & Payment Details
</h2>
<div class="card bg-light mb-5">
<div class="card-body">
<h3 class="h5">Customer Information</h3>
<div id="customerDetails">
<!-- Customer details will be populated here -->
</div>
</div>
</div> <!-- /.card -->
<form id="paymentForm">
<input type="hidden" id="confirmed_splynx_id" name="splynx_id">
<div class="field">
<label class="label" for="payment_amount">Payment Amount (AUD)</label>
<div class="control has-icons-left">
<input class="input is-large" type="number" step="0.01" min="0.01" max="10000"
id="payment_amount" name="amount" placeholder="0.00" required>
<span class="icon is-small is-left">
<i class="fas fa-dollar-sign"></i>
</span>
</div>
<p class="help">Enter the amount to charge (maximum $10,000)</p>
</div>
<div class="field">
<label class="label" for="payment_method_select">Payment Method</label>
<div class="control has-icons-left" id="payment_method_container">
<div class="select is-fullwidth is-loading" id="payment_method_loading">
<select disabled>
<option>Loading payment methods...</option>
</select>
</div>
<span class="icon is-small is-left">
<i class="fas fa-credit-card"></i>
</span>
</div>
<div id="payment_method_error" class="alert alert-danger d-none mt-2">
<i class="fas fa-exclamation-triangle me-2"></i>
<span>Unable to load payment methods. Customer may not have any valid payment methods.</span>
</div>
<p class="form-text">Select which payment method to use for this payment</p>
</div>
<div class="alert alert-info">
<i class="fas fa-info-circle me-2"></i>
This payment will be processed immediately using the selected payment method.
</div>
</form>
<div class="field is-grouped">
<div class="control">
<button class="button is-light" id="backBtn" onclick="goBackToStep2()">
<span class="icon"><i class="fas fa-arrow-left"></i></span>
<span>Back</span>
</button>
</div>
<div class="control">
<button class="button is-warning" id="processBtn" onclick="showConfirmationModal()">
<span class="icon"><i class="fas fa-credit-card"></i></span>
<span>Process Payment</span>
</button>
</div>
</div>
</div>
</div>
</div> <!-- /.card -->
<!-- Payment Confirmation Modal -->
<div class="modal fade" id="confirmationModal" tabindex="-1" aria-labelledby="confirmationModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header bg-warning">
<h5 class="modal-title" id="confirmationModalLabel">Confirm Payment Processing</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p><strong>Customer:</strong> <span id="confirmCustomerName"></span></p>
<p><strong>Amount:</strong> <span id="confirmAmount"></span></p>
<p><strong>Payment Method:</strong> <span id="confirmPaymentMethod"></span></p>
<p class="mb-0">Are you sure you want to process this payment?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-warning" id="confirmPaymentBtn" onclick="processPayment()">
<i class="fas fa-credit-card me-2"></i>Confirm Payment
</button>
</div>
</div>
</div>
</div>
<!-- Success Modal -->
<div class="modal fade" id="successModal" tabindex="-1" aria-labelledby="successModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header bg-success text-white">
<h5 class="modal-title" id="successModalLabel">
<i class="fas fa-check-circle me-2"></i>Payment Successful
</h5>
</div>
<div class="modal-body">
<div class="text-center py-4">
<i class="fas fa-check-circle fa-3x text-success mb-4"></i>
<h3 class="h4">Payment Processed Successfully!</h3>
<div id="successMessage" class="mt-3">
<!-- Success details will be populated here -->
</div>
</div>
</div>
<div class="modal-footer justify-content-center">
<button type="button" class="btn btn-primary" onclick="closeSuccessModal()">
<i class="fas fa-check me-2"></i>Close
</button>
</div>
</div>
</div>
</div>
<!-- Fee Update Modal (Orange) -->
<div class="modal fade" id="feeUpdateModal" tabindex="-1" aria-labelledby="feeUpdateModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header bg-warning">
<h5 class="modal-title" id="feeUpdateModalLabel">
<i class="fas fa-clock me-2"></i>Direct Debit Processing
</h5>
</div>
<div class="modal-body">
<div class="text-center py-4">
<i class="fas fa-clock fa-3x text-warning mb-4"></i>
<h3 class="h4">Direct Debit is still being processed</h3>
<div class="mt-3">
<p>Your Direct Debit payment is currently being processed by the bank. This can take a few minutes to complete.</p>
<p><strong>Please check back later or click the button below to view payment details.</strong></p>
</div>
</div>
</div>
<div class="modal-footer justify-content-center">
<button type="button" class="btn btn-warning" id="viewPaymentDetailsBtn" onclick="viewPaymentDetails()">
<i class="fas fa-eye me-2"></i>View Payment Details
</button>
</div>
</div>
</div>
</div>
<!-- Error Modal -->
<div class="modal fade" id="errorModal" tabindex="-1" aria-labelledby="errorModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header bg-danger text-white">
<h5 class="modal-title" id="errorModalLabel">
<i class="fas fa-exclamation-circle me-2"></i>Payment Failed
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="text-center py-4">
<i class="fas fa-exclamation-circle fa-3x text-danger mb-4"></i>
<h3 class="h4">Payment Processing Failed</h3>
<div id="errorDetails" class="mt-3">
<!-- Error details will be populated here -->
</div>
</div>
</div>
<div class="modal-footer justify-content-center">
<button type="button" class="btn btn-danger" data-bs-dismiss="modal">
<i class="fas fa-times me-2"></i>Close
</button>
</div>
</div>
</div>
</div>
<style>
/* Loading spinner */
.spinner {
display: inline-block;
width: 40px;
height: 40px;
border: 4px solid rgba(212, 175, 55, 0.3);
border-radius: 50%;
border-top-color: var(--plutus-gold);
animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Step transitions */
.payment-step {
transition: opacity 0.3s ease, transform 0.3s ease;
}
.payment-step.d-none {
display: none;
}
/* Enhanced form styling */
.input.is-large {
font-size: 1.5rem;
font-weight: 600;
}
</style>
<script>
let currentCustomerData = null;
let currentPaymentId = null;
let allInvoices = [];
let selectedInvoices = [];
function fetchCustomerDetails() {
const splynxIdElement = document.getElementById('lookup_splynx_id');
const splynxId = splynxIdElement ? splynxIdElement.value : '';
// Clear previous errors
document.getElementById('customerError').classList.add('d-none');
if (!splynxId || splynxId.trim() === '' || splynxId.trim() === '0') {
showError('Please enter a valid Splynx Customer ID');
return;
}
// Show loading state
document.getElementById('loading').classList.remove('d-none');
document.getElementById('nextBtn').disabled = true;
const apiUrl = `/api/splynx/${splynxId.trim()}`;
// Make API call
fetch(apiUrl)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return response.json();
})
.then(data => {
// Hide loading
document.getElementById('loading').classList.add('d-none');
document.getElementById('nextBtn').disabled = false;
if (data && data.id) {
currentCustomerData = data;
displayCustomerDetails(data);
goToStep2();
} else {
showError('Customer not found or invalid data received');
}
})
.catch(error => {
console.error('Error fetching customer:', error);
document.getElementById('loading').classList.add('d-none');
document.getElementById('nextBtn').disabled = false;
showError(`Failed to fetch customer details: ${error.message}`);
});
}
function displayCustomerDetails(customer) {
const detailsHtml = `
<div class="row g-3">
<div class="col-md-6">
<strong>Name:</strong><br>
<span>${customer.name || 'N/A'}</span>
</div>
<div class="col-md-6">
<strong>Customer ID:</strong><br>
<span class="badge bg-info">${customer.id}</span>
</div>
<div class="col-md-6">
<strong>Status:</strong><br>
${customer.status === 'active'
? '<span class="badge bg-success">Active</span>'
: `<span class="badge bg-warning">${customer.status || 'Unknown'}</span>`
}
</div>
<div class="col-md-6">
<strong>Email:</strong><br>
<span>${customer.email || 'N/A'}</span>
</div>
<div class="col-12">
<strong>Address:</strong><br>
<span>${customer.street_1 || ''} ${customer.street_2 || ''}<br>
${customer.city || ''} ${customer.zip_code || ''}</span>
</div>
<div class="col-md-6">
<strong>Phone:</strong><br>
<span>${customer.phone || 'N/A'}</span>
</div>
</div>
`;
document.getElementById('customerDetails').innerHTML = detailsHtml;
document.getElementById('confirmed_splynx_id').value = customer.id;
// Fetch payment methods for this customer
fetchPaymentMethods(customer.id);
// Fetch invoices for this customer
fetchInvoices(customer.id);
}
function showError(message) {
document.getElementById('errorMessage').textContent = message;
document.getElementById('customerError').classList.remove('d-none');
}
function fetchPaymentMethods(splynxId) {
// Get the Stripe customer ID from MySQL first
fetch(`/api/stripe-customer-id/${splynxId}`)
.then(response => response.json())
.then(data => {
if (data.success && data.stripe_customer_id) {
// Now fetch payment methods for this Stripe customer
return fetch(`/api/stripe-payment-methods/${data.stripe_customer_id}`);
} else {
throw new Error('Customer does not have a Stripe customer ID');
}
})
.then(response => response.json())
.then(data => {
if (data.success && data.payment_methods) {
displayPaymentMethods(data.payment_methods);
} else {
showPaymentMethodError();
}
})
.catch(error => {
console.error('Error fetching payment methods:', error);
showPaymentMethodError();
});
}
function displayPaymentMethods(paymentMethods) {
const container = document.getElementById('payment_method_container');
if (!paymentMethods || paymentMethods.length === 0) {
showPaymentMethodError();
return;
}
// Create the select element
const selectHtml = `
<div class="select is-fullwidth">
<select id="payment_method_select" name="payment_method" required>
<option value="">Select a payment method</option>
${paymentMethods.map(pm => {
let displayText = '';
if (pm.type === 'card' && pm.card) {
const brand = pm.card.brand || 'Card';
const last4 = pm.card.last4 || '****';
displayText = `${brand.toUpperCase()} ending in ${last4}`;
} else if (pm.type === 'au_becs_debit' && pm.au_becs_debit) {
const last4 = pm.au_becs_debit.last4 || '****';
displayText = `AU Bank Account ending in ${last4}`;
} else {
displayText = pm.type.toUpperCase();
}
return `<option value="${pm.id}">${displayText}</option>`;
}).join('')}
</select>
</div>
`;
container.innerHTML = selectHtml + `
<span class="icon is-small is-left">
<i class="fas fa-credit-card"></i>
</span>
`;
// Hide any error messages
document.getElementById('payment_method_error').classList.add('d-none');
}
function showPaymentMethodError() {
const container = document.getElementById('payment_method_container');
// Show a disabled select with error message
container.innerHTML = `
<div class="select is-fullwidth">
<select disabled>
<option>No payment methods available</option>
</select>
</div>
<span class="icon is-small is-left">
<i class="fas fa-exclamation-triangle"></i>
</span>
`;
// Show error notification
document.getElementById('payment_method_error').classList.remove('d-none');
}
function goToStep2() {
// Hide step 1, show step 2 (invoice selection)
document.getElementById('step1').classList.add('d-none');
document.getElementById('step2').classList.remove('d-none');
}
function goBackToStep1() {
// Show step 1, hide step 2
document.getElementById('step1').classList.remove('d-none');
document.getElementById('step2').classList.add('d-none');
// Clear any errors
document.getElementById('customerError').classList.add('d-none');
document.getElementById('payment_method_error').classList.add('d-none');
// Reset payment method selector to loading state
const container = document.getElementById('payment_method_container');
container.innerHTML = `
<div class="select is-fullwidth is-loading" id="payment_method_loading">
<select disabled>
<option>Loading payment methods...</option>
</select>
</div>
<span class="icon is-small is-left">
<i class="fas fa-credit-card"></i>
</span>
`;
}
function goBackToStep2() {
// Show step 2, hide step 3
document.getElementById('step3').classList.add('d-none');
document.getElementById('step2').classList.remove('d-none');
}
function fetchInvoices(splynxId) {
document.getElementById('invoiceLoading').classList.remove('d-none');
fetch(`/api/splynx/invoices/${splynxId}`)
.then(response => response.json())
.then(data => {
document.getElementById('invoiceLoading').classList.add('d-none');
if (data.success && data.invoices && data.invoices.length > 0) {
allInvoices = data.invoices;
displayInvoices(data.invoices);
} else {
document.getElementById('noInvoices').classList.remove('d-none');
}
})
.catch(error => {
console.error('Error fetching invoices:', error);
document.getElementById('invoiceLoading').classList.add('d-none');
document.getElementById('noInvoices').classList.remove('d-none');
});
}
function displayInvoices(invoices) {
const container = document.getElementById('invoicesContainer');
let html = '';
invoices.forEach(invoice => {
html += `
<div class="form-check">
<input class="form-check-input invoice-checkbox" type="checkbox"
value="${invoice.id}"
data-amount="${invoice.total}"
onchange="updateSelectedTotal()"
id="invoice-${invoice.id}">
<label class="form-check-label" for="invoice-${invoice.id}">
<strong>${invoice.number}</strong> - ${invoice.date} -
<span class="fw-bold">$${invoice.total.toFixed(2)}</span>
<br>
<span class="text-muted small">${invoice.description}</span>
</label>
</div>
`;
});
container.innerHTML = html;
document.getElementById('invoicesList').classList.remove('d-none');
}
function toggleAllInvoices() {
const selectAll = document.getElementById('selectAllInvoices').checked;
document.querySelectorAll('.invoice-checkbox').forEach(cb => cb.checked = selectAll);
updateSelectedTotal();
}
function updateSelectedTotal() {
const checkboxes = document.querySelectorAll('.invoice-checkbox:checked');
selectedInvoices = [];
let total = 0;
checkboxes.forEach(cb => {
selectedInvoices.push(cb.value);
total += parseFloat(cb.dataset.amount);
});
document.getElementById('selectedInvoicesTotal').textContent = `$${total.toFixed(2)}`;
}
function goToStep3() {
// Hide step 2, show step 3
document.getElementById('step2').classList.add('d-none');
document.getElementById('step3').classList.remove('d-none');
// Pre-fill amount with selected invoice total if any selected
if (selectedInvoices.length > 0) {
const total = Array.from(document.querySelectorAll('.invoice-checkbox:checked'))
.reduce((sum, cb) => sum + parseFloat(cb.dataset.amount), 0);
document.getElementById('payment_amount').value = total.toFixed(2);
}
// Focus on amount input
document.getElementById('payment_amount').focus();
}
function showConfirmationModal() {
const amount = document.getElementById('payment_amount').value;
const paymentMethodSelect = document.getElementById('payment_method_select');
if (!amount || parseFloat(amount) <= 0) {
alert('Please enter a valid payment amount');
return;
}
if (!paymentMethodSelect || !paymentMethodSelect.value) {
alert('Please select a payment method');
return;
}
if (!currentCustomerData) {
alert('Customer data not found. Please restart the process.');
return;
}
// Update confirmation modal content
document.getElementById('confirmCustomerName').textContent = currentCustomerData.name || 'Unknown';
document.getElementById('confirmAmount').textContent = `$${parseFloat(amount).toFixed(2)}`;
document.getElementById('confirmPaymentMethod').textContent = paymentMethodSelect.options[paymentMethodSelect.selectedIndex].text;
// Show modal using Bootstrap Modal API
const modalEl = document.getElementById('confirmationModal');
const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
modal.show();
}
function processPayment() {
const form = document.getElementById('paymentForm');
const formData = new FormData(form);
// Add selected invoice IDs
formData.append('invoice_ids', selectedInvoices.join(','));
// Disable confirm button and show loading
const confirmBtn = document.getElementById('confirmPaymentBtn');
const originalText = confirmBtn.innerHTML;
confirmBtn.disabled = true;
confirmBtn.innerHTML = '<span class="icon"><i class="fas fa-spinner fa-spin"></i></span><span>Processing...</span>';
// Submit the payment
fetch('/single-payment/process', {
method: 'POST',
body: formData
})
.then(response => {
return response.json().then(data => {
return { status: response.status, data: data };
});
})
.then(result => {
// Hide confirmation modal
hideModal('confirmationModal');
const { status, data } = result;
// Check if payment was successful
if (status === 200 && data.success && data.payment_success) {
showSuccessModal(data);
} else if (status === 422 && data.fee_update) {
// Direct Debit needs fee update - show orange modal
showFeeUpdateModal(data);
} else {
// Payment failed or had an error - show the specific error
let errorMessage;
if (status === 422) {
// Payment processing failed (business logic error)
errorMessage = `Payment Failed: ${data.stripe_error || data.error || 'Unknown error'}`;
} else if (status >= 400) {
// Other HTTP errors
errorMessage = data.error || 'Payment processing failed';
} else {
// Unexpected status
errorMessage = 'Payment processing failed. Please try again.';
}
showErrorModal(errorMessage);
}
})
.catch(error => {
console.error('Error processing payment:', error);
hideModal('confirmationModal');
showErrorModal('Payment processing failed. Please try again.');
})
.finally(() => {
// Re-enable button
confirmBtn.disabled = false;
confirmBtn.innerHTML = originalText;
});
}
function showSuccessModal(data) {
const successHtml = `
<p><strong>Payment ID:</strong> ${data.payment_id}</p>
<p><strong>Payment Intent:</strong> ${data.payment_intent || 'N/A'}</p>
<p><strong>Amount:</strong> $${parseFloat(data.amount).toFixed(2)}</p>
<p><strong>Customer:</strong> ${data.customer_name}</p>
`;
document.getElementById('successMessage').innerHTML = successHtml;
// Show modal using Bootstrap Modal API
const modalEl = document.getElementById('successModal');
const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
modal.show();
}
function showErrorModal(errorMessage) {
document.getElementById('errorDetails').innerHTML = `<p>${errorMessage}</p>`;
// Show modal using Bootstrap Modal API
const modalEl = document.getElementById('errorModal');
const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
modal.show();
}
function hideModal(modalId) {
const el = document.getElementById(modalId);
if (!el) return;
const modal = bootstrap.Modal.getInstance(el) || bootstrap.Modal.getOrCreateInstance(el);
modal.hide();
}
function showFeeUpdateModal(data) {
currentPaymentId = data.payment_id;
// Show modal using Bootstrap Modal API
const modalEl = document.getElementById('feeUpdateModal');
const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
modal.show();
}
function viewPaymentDetails() {
if (currentPaymentId) {
// Redirect to the single payment detail page
window.location.href = `/single-payment/detail/${currentPaymentId}`;
}
}
function closeSuccessModal() {
hideModal('successModal');
// Reset form to step 1
goBackToStep1();
document.getElementById('lookup_splynx_id').value = '';
document.getElementById('payment_amount').value = '';
currentCustomerData = null;
allInvoices = [];
selectedInvoices = [];
}
// Bootstrap modals handle Escape key automatically, no need for custom handler
// Enter key navigation
document.getElementById('lookup_splynx_id').addEventListener('keypress', function(event) {
if (event.key === 'Enter') {
fetchCustomerDetails();
}
});
document.getElementById('payment_amount').addEventListener('keypress', function(event) {
if (event.key === 'Enter') {
showConfirmationModal();
}
});
</script>
{% endblock %}