Initial commit — Moon Household Budget
This commit is contained in:
168
templates/transactions.html
Normal file
168
templates/transactions.html
Normal file
@@ -0,0 +1,168 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<h1>All Transactions</h1>
|
||||
</div>
|
||||
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% for category, message in messages %}
|
||||
<div class="alert-banner {{ 'alert-success' if category == 'success' else 'alert-error' }}" style="margin-bottom:1rem;">
|
||||
{{ message }}
|
||||
{% if category == 'success' %}
|
||||
<a href="{{ url_for('review') }}" class="btn btn-primary">Review Now</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
|
||||
<!-- Import -->
|
||||
<details class="add-debt-details" style="margin-bottom:1.25rem;">
|
||||
<summary class="btn" style="display:inline-block;cursor:pointer;background:#7A9E7E;color:#fff;border:none;">⬆️ Import Statement</summary>
|
||||
<div class="card-wide" style="margin-top:0.75rem;">
|
||||
<p class="helper-text" style="margin-bottom:0.75rem;">Supports CSV exports from your bank or credit union. PDF import only works if the PDF has selectable text — scanned statements won't work.</p>
|
||||
<form method="POST" action="{{ url_for('import_transactions') }}" enctype="multipart/form-data" class="import-form">
|
||||
<div class="form-group">
|
||||
<label>Account Name</label>
|
||||
<input type="text" name="account" placeholder="e.g. WestConsin Checking, Discover" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Statement File</label>
|
||||
<div class="file-drop-area">
|
||||
<input type="file" name="statement" accept=".pdf,.csv" required>
|
||||
<p>Click to choose a file, or drag and drop here</p>
|
||||
<p class="file-types">PDF or CSV</p>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Import</button>
|
||||
</form>
|
||||
<details style="margin-top:1rem;">
|
||||
<summary class="muted" style="cursor:pointer;font-size:0.85rem;">How to export your statements ▾</summary>
|
||||
<ul style="margin-top:0.5rem;font-size:0.83rem;line-height:1.7;padding-left:1.25rem;">
|
||||
<li><strong>WestConsin Credit Union:</strong> Log in → select your account → Download/Export → choose CSV → pick date range</li>
|
||||
<li><strong>Most other banks:</strong> Log in → Account Details or Transaction History → Export / Download → choose CSV</li>
|
||||
<li><strong>Affirm:</strong> affirm.com → Account → Payment History → Export</li>
|
||||
<li><strong>Klarna:</strong> klarna.com → Purchases → Export CSV</li>
|
||||
<li><strong>Afterpay:</strong> afterpay.com → Orders → Export</li>
|
||||
</ul>
|
||||
<p class="helper-text" style="margin-top:0.5rem;">If a CSV imports 0 transactions, let Claude know — the column format varies by bank and may need a quick fix.</p>
|
||||
</details>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
{% if spending_by_cat %}
|
||||
<details class="add-debt-details" style="margin-bottom:1.25rem;">
|
||||
<summary class="btn btn-ghost" style="display:inline-block;cursor:pointer;">📊 {{ week_label }} Spending</summary>
|
||||
<div style="margin-top:0.75rem;background:#fff;border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;">
|
||||
<table class="budget-table">
|
||||
<thead>
|
||||
<tr><th>Category</th><th>Spent</th><th>Budgeted</th><th>Remaining</th><th style="width:25%;"></th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for cat, amt in spending_by_cat.items() %}
|
||||
{% set budgeted = budgeted_by_cat.get(cat, 0) %}
|
||||
{% set remaining = budgeted - amt %}
|
||||
{% set over = budgeted > 0 and amt > budgeted %}
|
||||
{% set pct = [(amt / budgeted * 100)|int, 100]|min if budgeted > 0 else 100 %}
|
||||
<tr{% if over %} style="background:#fdf0f0;"{% endif %}>
|
||||
<td><span class="tag" style="background:{{ colors.get(cat,'#ddd') }};">{{ cat }}</span></td>
|
||||
<td class="amount">${{ amt | money }}</td>
|
||||
<td class="amount muted">{% if budgeted %}${{ budgeted | money }}{% else %}<span style="color:#ccc;">—</span>{% endif %}</td>
|
||||
<td class="amount {% if over %}{% else %}{% endif %}">
|
||||
{% if budgeted %}
|
||||
{% if over %}
|
||||
<span style="color:#c07070;">-${{ (amt - budgeted) | money }} over</span>
|
||||
{% else %}
|
||||
<span style="color:#5A9E68;">${{ remaining | money }}</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="muted">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<div style="background:#EDE8E2;border-radius:4px;height:7px;">
|
||||
<div style="background:{{ '#c07070' if over else colors.get(cat,'#bbb') }};border-radius:4px;height:7px;width:{{ pct }}%;"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr class="total-row">
|
||||
<td>Total</td>
|
||||
<td class="amount">${{ spending_by_cat.values() | sum | money }}</td>
|
||||
<td class="amount muted">{% if budgeted_by_cat %}${{ budgeted_by_cat.values() | sum | money }}{% endif %}</td>
|
||||
<td colspan="2"></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</details>
|
||||
{% endif %}
|
||||
|
||||
<form method="GET" style="display:flex;gap:0.75rem;align-items:flex-end;flex-wrap:wrap;margin-bottom:1.25rem;background:var(--warm-white);padding:0.85rem 1rem;border-radius:var(--radius);border:1px solid var(--border);">
|
||||
<div style="flex:1;min-width:180px;">
|
||||
<label style="display:block;font-size:0.8rem;margin-bottom:0.2rem;">Search</label>
|
||||
<input type="text" name="search" value="{{ filter_search }}" class="budget-input" style="width:100%;" placeholder="merchant, notes…">
|
||||
</div>
|
||||
<div>
|
||||
<label style="display:block;font-size:0.8rem;margin-bottom:0.2rem;">From</label>
|
||||
<input type="date" name="from_date" value="{{ filter_from }}" class="budget-input">
|
||||
</div>
|
||||
<div>
|
||||
<label style="display:block;font-size:0.8rem;margin-bottom:0.2rem;">To</label>
|
||||
<input type="date" name="to_date" value="{{ filter_to }}" class="budget-input">
|
||||
</div>
|
||||
<div>
|
||||
<label style="display:block;font-size:0.8rem;margin-bottom:0.2rem;">Category</label>
|
||||
<select name="category" class="budget-input">
|
||||
<option value="">— all —</option>
|
||||
{% for cat in categories %}
|
||||
<option value="{{ cat }}" {% if filter_cat == cat %}selected{% endif %}>{{ cat }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary" style="height:36px;">Search</button>
|
||||
{% if filter_from or filter_to or filter_cat or filter_search %}
|
||||
<a href="{{ url_for('transactions_view') }}" class="btn btn-ghost" style="height:36px;line-height:36px;padding-top:0;padding-bottom:0;">Clear</a>
|
||||
{% endif %}
|
||||
</form>
|
||||
|
||||
{% if transactions %}
|
||||
<table class="txn-table txn-table-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Description</th>
|
||||
<th>Account</th>
|
||||
<th>Amount</th>
|
||||
<th>Category</th>
|
||||
<th>Notes</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for t in transactions %}
|
||||
<tr>
|
||||
<td>{{ t.date }}</td>
|
||||
<td>{{ t.description }}</td>
|
||||
<td class="muted">{{ t.account }}</td>
|
||||
<td class="amount">${{ t.amount | money }}</td>
|
||||
<td>
|
||||
{% if t.category %}
|
||||
<span class="tag" style="background: {{ colors.get(t.category, '#ddd') }};">
|
||||
{{ t.category }}{% if t.subcategory %} › {{ t.subcategory }}{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="muted">{{ t.notes }}</td>
|
||||
<td><a href="{{ url_for('edit_transaction', txn_id=t.id) }}" class="edit-link">Edit</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<p>No transactions yet. <a href="{{ url_for('import_transactions') }}">Import a statement</a> to get started.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user