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.
166 lines
5.8 KiB
166 lines
5.8 KiB
<!doctype html> |
|
<html> |
|
<head> |
|
<title>Invoices</title> |
|
<style> |
|
.status-badge { |
|
display: inline-block; |
|
padding: 3px 8px; |
|
border-radius: 999px; |
|
font-size: 12px; |
|
font-weight: bold; |
|
text-transform: uppercase; |
|
letter-spacing: 0.03em; |
|
} |
|
.status-draft { background: #e5e7eb; color: #111827; } |
|
.status-pending { background: #dbeafe; color: #1d4ed8; } |
|
.status-partial { background: #fef3c7; color: #92400e; } |
|
.status-paid { background: #dcfce7; color: #166534; } |
|
.status-overdue { background: #fee2e2; color: #991b1b; } |
|
.status-cancelled { background: #e5e7eb; color: #4b5563; } |
|
|
|
.locked-note { |
|
color: #92400e; |
|
font-weight: bold; |
|
} |
|
|
|
.filter-box { |
|
border: 1px solid #ccc; |
|
padding: 12px; |
|
margin: 14px 0; |
|
max-width: 1100px; |
|
} |
|
.filter-row { |
|
display: flex; |
|
gap: 14px; |
|
align-items: end; |
|
flex-wrap: wrap; |
|
} |
|
.filter-row div { |
|
display: flex; |
|
flex-direction: column; |
|
} |
|
input[type="date"], |
|
input[type="number"], |
|
select { |
|
padding: 6px; |
|
min-width: 150px; |
|
} |
|
.action-links { |
|
margin-top: 12px; |
|
display: flex; |
|
gap: 18px; |
|
flex-wrap: wrap; |
|
} |
|
</style> |
|
</head> |
|
|
|
<body> |
|
|
|
<h1>Invoices</h1> |
|
|
|
<p><a href="/">Home</a></p> |
|
<p><a href="/invoices/new">Create Invoice</a></p> |
|
|
|
<div class="filter-box"> |
|
<form method="get" action="/invoices"> |
|
<div class="filter-row"> |
|
<div> |
|
<label for="start_date">Issued From</label> |
|
<input type="date" id="start_date" name="start_date" value="{{ filters.start_date if filters is defined else '' }}"> |
|
</div> |
|
|
|
<div> |
|
<label for="end_date">Issued To</label> |
|
<input type="date" id="end_date" name="end_date" value="{{ filters.end_date if filters is defined else '' }}"> |
|
</div> |
|
|
|
<div> |
|
<label for="status">Status</label> |
|
<select id="status" name="status"> |
|
<option value="" {% if not filters.status %}selected{% endif %}>All</option> |
|
<option value="draft" {% if filters.status == 'draft' %}selected{% endif %}>draft</option> |
|
<option value="pending" {% if filters.status == 'pending' %}selected{% endif %}>pending</option> |
|
<option value="partial" {% if filters.status == 'partial' %}selected{% endif %}>partial</option> |
|
<option value="paid" {% if filters.status == 'paid' %}selected{% endif %}>paid</option> |
|
<option value="overdue" {% if filters.status == 'overdue' %}selected{% endif %}>overdue</option> |
|
<option value="cancelled" {% if filters.status == 'cancelled' %}selected{% endif %}>cancelled</option> |
|
</select> |
|
</div> |
|
|
|
<div> |
|
<label for="client_id">Client</label> |
|
<select id="client_id" name="client_id"> |
|
<option value="" {% if not filters.client_id %}selected{% endif %}>All Clients</option> |
|
{% for c in clients %} |
|
<option value="{{ c.id }}" {% if filters.client_id == (c.id|string) %}selected{% endif %}> |
|
{{ c.client_code }} - {{ c.company_name }} |
|
</option> |
|
{% endfor %} |
|
</select> |
|
</div> |
|
|
|
<div> |
|
<label for="limit">Limit</label> |
|
<input type="number" id="limit" name="limit" min="1" step="1" value="{{ filters.limit if filters is defined else '' }}"> |
|
</div> |
|
|
|
<div> |
|
<button type="submit">Apply Filters</button> |
|
</div> |
|
</div> |
|
|
|
<div class="action-links"> |
|
<a href="/invoices">Clear Filters</a> |
|
<a href="/invoices/export.csv?start_date={{ filters.start_date if filters is defined else '' }}&end_date={{ filters.end_date if filters is defined else '' }}&status={{ filters.status if filters is defined else '' }}&client_id={{ filters.client_id if filters is defined else '' }}&limit={{ filters.limit if filters is defined else '' }}">Export Filtered CSV</a> |
|
<a href="/invoices/export-pdf.zip?start_date={{ filters.start_date if filters is defined else '' }}&end_date={{ filters.end_date if filters is defined else '' }}&status={{ filters.status if filters is defined else '' }}&client_id={{ filters.client_id if filters is defined else '' }}&limit={{ filters.limit if filters is defined else '' }}">Export Filtered PDF ZIP</a> |
|
<a href="/invoices/print?start_date={{ filters.start_date if filters is defined else '' }}&end_date={{ filters.end_date if filters is defined else '' }}&status={{ filters.status if filters is defined else '' }}&client_id={{ filters.client_id if filters is defined else '' }}&limit={{ filters.limit if filters is defined else '' }}">Batch Print</a> |
|
</div> |
|
</form> |
|
</div> |
|
|
|
<table border="1" cellpadding="6"> |
|
<tr> |
|
<th>ID</th> |
|
<th>Invoice</th> |
|
<th>Client</th> |
|
<th>Currency</th> |
|
<th>Total</th> |
|
<th>Paid</th> |
|
<th>Remaining</th> |
|
<th>Status</th> |
|
<th>Issued</th> |
|
<th>Due</th> |
|
<th>Actions</th> |
|
</tr> |
|
|
|
{% for i in invoices %} |
|
<tr> |
|
<td>{{ i.id }}</td> |
|
<td>{{ i.invoice_number }}</td> |
|
<td>{{ i.client_code }} - {{ i.company_name }}</td> |
|
<td>{{ i.currency_code }}</td> |
|
<td>{{ i.total_amount|money(i.currency_code) }}</td> |
|
<td>{{ i.amount_paid|money(i.currency_code) }}</td> |
|
<td>{{ (i.total_amount - i.amount_paid)|money(i.currency_code) }}</td> |
|
<td> |
|
<span class="status-badge status-{{ i.status }}">{{ i.status }}</span> |
|
</td> |
|
<td>{{ i.issued_at|localtime }}</td> |
|
<td>{{ i.due_at|localtime }}</td> |
|
<td> |
|
<a href="/invoices/view/{{ i.id }}">View</a> | |
|
<a href="/invoices/pdf/{{ i.id }}">PDF</a> | |
|
<a href="/invoices/edit/{{ i.id }}">Edit</a> |
|
{% if i.payment_count > 0 %} |
|
<span class="locked-note">(Locked)</span> |
|
{% endif %} |
|
</td> |
|
</tr> |
|
{% endfor %} |
|
|
|
</table> |
|
|
|
{% include "footer.html" %} |
|
</body> |
|
</html>
|
|
|