Automated Action 0b5aa51985 Add web frontend for invoice generation service
- Add Jinja2 templates and static files for web UI
- Create frontend routes for invoice management
- Implement home page with recent invoices list
- Add invoice creation form with dynamic items
- Create invoice search functionality
- Implement invoice details view with status update
- Add JavaScript for form validation and dynamic UI
- Update main.py to serve static files
- Update documentation
2025-05-18 21:43:44 +00:00

191 lines
5.4 KiB
HTML

{% extends "base.html" %}
{% block title %}Invoice {{ invoice.invoice_number }} - Invoice Generation Service{% endblock %}
{% block content %}
<div class="card">
<div class="invoice-header">
<h2>Invoice #{{ invoice.invoice_number }}</h2>
<span class="invoice-status status-{{ invoice.status.lower() }}">
{{ invoice.status }}
</span>
</div>
<div class="invoice-actions">
<button id="print-invoice" class="btn">Print Invoice</button>
<form method="POST" action="{{ url_for('update_status', invoice_id=invoice.id) }}" class="status-form">
<select name="status" id="invoice-status">
<option value="PENDING" {% if invoice.status == 'PENDING' %}selected{% endif %}>PENDING</option>
<option value="PAID" {% if invoice.status == 'PAID' %}selected{% endif %}>PAID</option>
<option value="CANCELLED" {% if invoice.status == 'CANCELLED' %}selected{% endif %}>CANCELLED</option>
</select>
<button type="submit" class="btn">Update Status</button>
</form>
</div>
<div class="invoice-content">
<div class="invoice-section">
<h3>Invoice Details</h3>
<dl>
<dt>Invoice Number</dt>
<dd>{{ invoice.invoice_number }}</dd>
<dt>Date Created</dt>
<dd>{{ invoice.date_created.strftime('%Y-%m-%d') }}</dd>
<dt>Due Date</dt>
<dd>{{ invoice.due_date.strftime('%Y-%m-%d') }}</dd>
<dt>Status</dt>
<dd>
<span class="invoice-status status-{{ invoice.status.lower() }}">
{{ invoice.status }}
</span>
</dd>
</dl>
</div>
<div class="invoice-section">
<h3>Customer Information</h3>
<dl>
<dt>Name</dt>
<dd>{{ invoice.customer_name }}</dd>
{% if invoice.customer_email %}
<dt>Email</dt>
<dd>{{ invoice.customer_email }}</dd>
{% endif %}
{% if invoice.customer_address %}
<dt>Address</dt>
<dd>{{ invoice.customer_address }}</dd>
{% endif %}
</dl>
</div>
{% if invoice.notes %}
<div class="invoice-section">
<h3>Notes</h3>
<p>{{ invoice.notes }}</p>
</div>
{% endif %}
<div class="invoice-section">
<h3>Invoice Items</h3>
<table class="items-table">
<thead>
<tr>
<th>Description</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
{% for item in invoice.items %}
<tr>
<td>{{ item.description }}</td>
<td>{{ item.quantity }}</td>
<td>${{ "%.2f"|format(item.unit_price) }}</td>
<td>${{ "%.2f"|format(item.amount) }}</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="3" class="total-label">Total Amount</td>
<td class="total-amount">${{ "%.2f"|format(invoice.total_amount) }}</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
{% endblock %}
{% block extra_css %}
<style>
.invoice-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.invoice-actions {
display: flex;
justify-content: space-between;
margin-bottom: 2rem;
padding-bottom: 1rem;
border-bottom: 1px solid #eee;
}
.status-form {
display: flex;
align-items: center;
gap: 0.5rem;
}
.status-form select {
padding: 0.5rem;
border-radius: 4px;
border: 1px solid #ddd;
}
.invoice-section {
margin-bottom: 2rem;
}
.invoice-section h3 {
color: #3498db;
margin-bottom: 1rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid #eee;
}
.invoice-section dl {
display: grid;
grid-template-columns: 1fr 3fr;
gap: 0.75rem;
}
.invoice-section dt {
font-weight: 600;
color: #7f8c8d;
}
.items-table {
width: 100%;
border-collapse: collapse;
}
.items-table th,
.items-table td {
padding: 0.75rem;
border-bottom: 1px solid #ddd;
}
.items-table th {
background-color: #f5f7fa;
}
.total-label {
text-align: right;
font-weight: 600;
}
.total-amount {
font-weight: 700;
font-size: 1.1rem;
}
</style>
{% endblock %}
{% block extra_js %}
<script>
document.getElementById('print-invoice').addEventListener('click', function() {
window.print();
});
</script>
{% endblock %}