Files
Moon-Household-Budget/templates/transactions.html

177 lines
8.2 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% 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 %}
{% if skipped_count %}
<div style="background:#fffbe6;border:1px solid #f5c542;border-radius:var(--radius);padding:0.65rem 1rem;margin-bottom:1rem;display:flex;align-items:center;gap:0.75rem;">
<span>⏭️ <strong>{{ skipped_count }} transaction{{ 's' if skipped_count != 1 else '' }}</strong> still need{{ '' if skipped_count != 1 else 's' }} a category (skipped for now).</span>
<a href="{{ url_for('transactions_view', category='__skipped__') }}" class="btn btn-ghost" style="font-size:0.82rem;padding:0.2rem 0.65rem;">Show them</a>
</div>
{% 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>
<option value="__skipped__" {% if filter_cat == '__skipped__' %}selected{% endif %}>⏭️ Needs category</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 %}