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.
319 lines
12 KiB
319 lines
12 KiB
{% extends "base.html" %}
|
|
|
|
{% block title %}Payment Plans - 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;
|
|
}
|
|
|
|
.container-fluid, .container {
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
/* Ensure navbar and footer are above background */
|
|
.navbar, .footer, main {
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
/* 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 {
|
|
background-color: rgba(250, 248, 240, 0.98) !important;
|
|
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
.table-responsive {
|
|
background-color: rgba(250, 248, 240, 0.98);
|
|
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">Payment Plans</li>
|
|
</ol>
|
|
</nav>
|
|
|
|
<div class="d-flex justify-content-between align-items-start mb-4">
|
|
<div>
|
|
<h1 class="h2 mb-1">Payment Plans</h1>
|
|
<p class="text-muted">Recurring payment management</p>
|
|
</div>
|
|
<a class="btn btn-primary" href="{{ url_for('main.payment_plans_create') }}">
|
|
<i class="fas fa-plus"></i> New Payment Plan
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Summary Statistics -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="card shadow text-center">
|
|
<div class="card-body">
|
|
<p class="h4 text-success mb-1">{{ summary.active_plans }}</p>
|
|
<p class="text-muted mb-0">Active Plans</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card shadow text-center">
|
|
<div class="card-body">
|
|
<p class="h4 text-warning mb-1">{{ summary.inactive_plans }}</p>
|
|
<p class="text-muted mb-0">Inactive Plans</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card shadow text-center">
|
|
<div class="card-body">
|
|
<p class="h4 text-info mb-1">{{ summary.total_plans }}</p>
|
|
<p class="text-muted mb-0">Total Plans</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card shadow text-center">
|
|
<div class="card-body">
|
|
<p class="h4 text-primary mb-1">{{ summary.total_recurring_amount | currency }}</p>
|
|
<p class="text-muted mb-0">Monthly Recurring</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Payment Plans Table -->
|
|
<div class="card shadow">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<h2 class="h4 mb-0">Payment Plans</h2>
|
|
<div class="input-group" style="max-width: 350px;">
|
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
|
<input class="form-control" type="text" id="searchInput" placeholder="Search Customer ID, Amount...">
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filter Controls -->
|
|
<div class="row g-3 mb-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label form-label-sm">Filter by Status:</label>
|
|
<select class="form-select form-select-sm" id="statusFilter">
|
|
<option value="">All</option>
|
|
<option value="active">Active</option>
|
|
<option value="inactive">Inactive</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label form-label-sm">Filter by Frequency:</label>
|
|
<select class="form-select form-select-sm" id="frequencyFilter">
|
|
<option value="">All</option>
|
|
<option value="Weekly">Weekly</option>
|
|
<option value="Fortnightly">Fortnightly</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
{% if plans %}
|
|
<div class="table-responsive">
|
|
<table class="table table-striped table-hover" id="plansTable">
|
|
<thead>
|
|
<tr>
|
|
<th>Plan ID</th>
|
|
<th>Customer</th>
|
|
<th>Splynx ID</th>
|
|
<th>Amount</th>
|
|
<th>Frequency</th>
|
|
<th>Start Date</th>
|
|
<th>Status</th>
|
|
<th>Created</th>
|
|
<th>Created By</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for plan in plans %}
|
|
<tr data-status="{{ 'active' if plan.Enabled else 'inactive' }}"
|
|
data-frequency="{{ plan.Frequency }}"
|
|
data-splynx-id="{{ plan.Splynx_ID }}"
|
|
data-amount="{{ plan.Amount }}"
|
|
data-customer-name="">
|
|
<td>
|
|
<a href="{{ url_for('main.payment_plans_detail', plan_id=plan.id) }}" class="fw-semibold">
|
|
#{{ plan.id }}
|
|
</a>
|
|
</td>
|
|
<td>
|
|
<span class="customer-name" data-splynx-id="{{ plan.Splynx_ID }}">
|
|
<i class="fas fa-spinner fa-spin"></i>
|
|
Loading...
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<a href="https://billing.interphone.com.au/admin/customers/view?id={{ plan.Splynx_ID }}"
|
|
target="_blank" class="badge bg-info">{{ plan.Splynx_ID }}</a>
|
|
</td>
|
|
<td>
|
|
<strong>{{ plan.Amount | currency }}</strong>
|
|
</td>
|
|
<td>
|
|
<span class="badge {% if plan.Frequency == 'Weekly' %}bg-warning{% elif plan.Frequency == 'Fortnightly' %}bg-info{% else %}bg-secondary{% endif %}">
|
|
{{ plan.Frequency }}
|
|
</span>
|
|
</td>
|
|
<td>{{ plan.Start_Date.strftime('%Y-%m-%d') if plan.Start_Date else '-' }}</td>
|
|
<td>
|
|
{% if plan.Enabled %}
|
|
<span class="badge bg-success">Active</span>
|
|
{% else %}
|
|
<span class="badge bg-danger">Inactive</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>{{ plan.Created.strftime('%Y-%m-%d %H:%M') if plan.Created else '-' }}</td>
|
|
<td>{{ plan.created_by or 'Unknown' }}</td>
|
|
<td>
|
|
<div class="btn-group btn-group-sm" role="group">
|
|
<a class="btn btn-info btn-sm"
|
|
href="{{ url_for('main.payment_plans_detail', plan_id=plan.id) }}">
|
|
<i class="fas fa-eye"></i>
|
|
</a>
|
|
<a class="btn btn-warning btn-sm"
|
|
href="{{ url_for('main.payment_plans_edit', plan_id=plan.id) }}">
|
|
<i class="fas fa-edit"></i>
|
|
</a>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% else %}
|
|
<div class="text-center py-5">
|
|
<i class="fas fa-calendar-alt fa-3x text-muted mb-3"></i>
|
|
<p class="h5 text-muted">No Payment Plans Found</p>
|
|
<p class="text-muted">Get started by creating your first payment plan.</p>
|
|
<a class="btn btn-primary" href="{{ url_for('main.payment_plans_create') }}">
|
|
<i class="fas fa-plus"></i> Create Payment Plan
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Load customer names asynchronously
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const customerElements = document.querySelectorAll('.customer-name');
|
|
|
|
customerElements.forEach(function(element) {
|
|
const splynxId = element.dataset.splynxId;
|
|
|
|
fetch(`/api/splynx/${splynxId}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data && data.name) {
|
|
element.innerHTML = data.name;
|
|
// Update the row data attribute for search
|
|
const row = element.closest('tr');
|
|
row.dataset.customerName = data.name.toLowerCase();
|
|
} else {
|
|
element.innerHTML = '<span class="text-danger">Unknown Customer</span>';
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error fetching customer:', error);
|
|
element.innerHTML = '<span class="text-danger">Error Loading</span>';
|
|
});
|
|
});
|
|
});
|
|
|
|
// Search and filter functionality
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const searchInput = document.getElementById('searchInput');
|
|
const statusFilter = document.getElementById('statusFilter');
|
|
const frequencyFilter = document.getElementById('frequencyFilter');
|
|
const table = document.getElementById('plansTable');
|
|
|
|
if (!table) return; // No table to filter
|
|
|
|
function filterTable() {
|
|
const searchTerm = searchInput.value.toLowerCase();
|
|
const statusValue = statusFilter.value;
|
|
const frequencyValue = frequencyFilter.value;
|
|
const rows = table.querySelectorAll('tbody tr');
|
|
|
|
rows.forEach(function(row) {
|
|
const splynxId = row.dataset.splynxId;
|
|
const amount = row.dataset.amount;
|
|
const customerName = row.dataset.customerName || '';
|
|
const status = row.dataset.status;
|
|
const frequency = row.dataset.frequency;
|
|
|
|
// Search filter
|
|
const searchMatch = !searchTerm ||
|
|
splynxId.includes(searchTerm) ||
|
|
amount.includes(searchTerm) ||
|
|
customerName.includes(searchTerm);
|
|
|
|
// Status filter
|
|
const statusMatch = !statusValue || status === statusValue;
|
|
|
|
// Frequency filter
|
|
const frequencyMatch = !frequencyValue || frequency === frequencyValue;
|
|
|
|
// Show/hide row
|
|
if (searchMatch && statusMatch && frequencyMatch) {
|
|
row.style.display = '';
|
|
} else {
|
|
row.style.display = 'none';
|
|
}
|
|
});
|
|
}
|
|
|
|
// Add event listeners
|
|
searchInput.addEventListener('input', filterTable);
|
|
statusFilter.addEventListener('change', filterTable);
|
|
frequencyFilter.addEventListener('change', filterTable);
|
|
});
|
|
</script>
|
|
{% endblock %}
|
|
|