Edit name/amount on budget template entries (#21) #22
4 changed files with 248 additions and 207 deletions
|
|
@ -39,11 +39,16 @@ def _section_view(db: Session, section: Section) -> service.SectionView:
|
||||||
|
|
||||||
|
|
||||||
def _render_section(
|
def _render_section(
|
||||||
request: Request, db: Session, section: Section
|
request: Request,
|
||||||
|
db: Session,
|
||||||
|
section: Section,
|
||||||
|
editing_id: int | None = None,
|
||||||
) -> HTMLResponse:
|
) -> HTMLResponse:
|
||||||
view = _section_view(db, section)
|
view = _section_view(db, section)
|
||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
request, "partials/section.html", {"section": view}
|
request,
|
||||||
|
"partials/section.html",
|
||||||
|
{"section": view, "editing_id": editing_id},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -361,64 +361,160 @@ details.group[open] > summary .chevron::after { opacity: 0; }
|
||||||
.total .applied { color: var(--ink-soft); }
|
.total .applied { color: var(--ink-soft); }
|
||||||
.total.empty { color: var(--muted); }
|
.total.empty { color: var(--muted); }
|
||||||
|
|
||||||
/* =============== ENTRY TABLE =============== */
|
/* =============== ENTRY LIST (BUDGET TEMPLATE) =============== */
|
||||||
|
|
||||||
table.entries {
|
.budget-entries { display: flex; flex-direction: column; }
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
font-family: var(--sans);
|
|
||||||
}
|
|
||||||
table.entries thead { display: none; }
|
|
||||||
|
|
||||||
table.entries tbody tr.entry {
|
.entry-row.reading {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 1fr) 5.5rem 5.5rem 1.2rem;
|
grid-template-columns: minmax(0, 1fr) 5.5rem auto;
|
||||||
gap: 0.6rem;
|
gap: 0.6rem;
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
padding: 0.26rem 0.25rem 0.28rem;
|
padding: 0.26rem 0.25rem 0.28rem;
|
||||||
position: relative;
|
|
||||||
border-bottom: 1px dotted var(--rule);
|
border-bottom: 1px dotted var(--rule);
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
table.entries tbody tr.entry:hover { background: var(--paper-stripe); }
|
.entry-row.reading:hover { background: var(--paper-stripe); }
|
||||||
table.entries tbody tr.entry td {
|
|
||||||
padding: 0;
|
.entry-row.reading .entry-name {
|
||||||
border: none;
|
font-family: var(--sans);
|
||||||
vertical-align: baseline;
|
font-weight: 500;
|
||||||
|
font-size: 1.02rem;
|
||||||
|
color: var(--ink);
|
||||||
|
letter-spacing: 0.01em;
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.entry-row.reading .note-badge {
|
||||||
|
font-family: var(--sans);
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
color: var(--muted);
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
.entry-row.reading .note-badge::before {
|
||||||
|
content: "· ";
|
||||||
|
color: var(--rule);
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
.entry-row.reading .entry-amount {
|
||||||
|
font-family: var(--sans);
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 1rem;
|
||||||
|
color: var(--ink);
|
||||||
|
font-feature-settings: "lnum" 1, "tnum" 1;
|
||||||
|
text-align: right;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.entries tbody tr.entry::after {
|
.entry-row.reading .entry-actions {
|
||||||
content: "";
|
display: flex;
|
||||||
position: absolute;
|
gap: 0.3rem;
|
||||||
left: 0; right: 0; bottom: -1px;
|
align-items: center;
|
||||||
height: 2px;
|
|
||||||
background: var(--sage-soft);
|
|
||||||
width: min(100%, calc(var(--ratio, 1) * 100%));
|
|
||||||
transition: width 0.25s ease;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
}
|
||||||
table.entries tbody tr.entry.state-edited::after,
|
.entry-row.reading .entry-actions button {
|
||||||
table.entries tbody tr.entry[data-deviation="over"]::after {
|
background: none;
|
||||||
background: var(--accent);
|
border: none;
|
||||||
opacity: 0.85;
|
cursor: pointer;
|
||||||
|
padding: 0;
|
||||||
|
line-height: 1;
|
||||||
|
color: var(--rule);
|
||||||
|
opacity: 0;
|
||||||
|
transition: color 0.12s ease, opacity 0.12s ease;
|
||||||
}
|
}
|
||||||
table.entries tbody tr.entry.state-new_in_month::after {
|
.entry-row.reading:hover .entry-actions button { opacity: 1; }
|
||||||
background: var(--indigo);
|
.entry-row.reading .entry-actions button.edit {
|
||||||
opacity: 0.55;
|
font-size: 0.95rem;
|
||||||
|
color: var(--rule);
|
||||||
|
}
|
||||||
|
.entry-row.reading .entry-actions button.edit:hover { color: var(--ink); }
|
||||||
|
.entry-row.reading .entry-actions button.delete {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
.entry-row.reading .entry-actions button.delete:hover { color: var(--accent); }
|
||||||
|
|
||||||
|
.entry-row.editing {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) 5.5rem minmax(0, 1.4fr) auto;
|
||||||
|
gap: 0.5rem;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.26rem 0.25rem 0.28rem;
|
||||||
|
border-bottom: 1px dotted var(--rule);
|
||||||
|
background: var(--paper-soft);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.entry-row.editing input {
|
||||||
|
font-family: var(--sans);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
padding: 0.2rem 0.4rem;
|
||||||
|
border: 1px solid var(--rule);
|
||||||
|
background: var(--paper);
|
||||||
|
color: var(--ink);
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.12s;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.entry-row.editing input:focus { border-color: var(--ink); }
|
||||||
|
.entry-row.editing input[type="number"] {
|
||||||
|
text-align: right;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
.entry-row.editing .notes-input {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 0.88rem;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
.entry-row.editing .entry-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.4rem;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.entry-row.editing .save-btn,
|
||||||
|
.entry-row.editing .cancel-btn {
|
||||||
|
font-family: var(--sans);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
letter-spacing: 0.12em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding: 0.22rem 0.6rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
|
||||||
|
}
|
||||||
|
.entry-row.editing .save-btn {
|
||||||
|
border: 1px solid var(--ink);
|
||||||
|
background: var(--paper-soft);
|
||||||
|
color: var(--ink);
|
||||||
|
}
|
||||||
|
.entry-row.editing .save-btn:hover {
|
||||||
|
background: var(--sage);
|
||||||
|
color: var(--paper);
|
||||||
|
border-color: var(--sage);
|
||||||
|
}
|
||||||
|
.entry-row.editing .cancel-btn {
|
||||||
|
border: 1px solid var(--rule);
|
||||||
|
background: transparent;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
.entry-row.editing .cancel-btn:hover {
|
||||||
|
color: var(--accent);
|
||||||
|
border-color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.empty td {
|
.empty-row {
|
||||||
padding: 0.4rem 0.5rem !important;
|
padding: 0.4rem 0.5rem;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.add-row td {
|
.add-row {
|
||||||
padding: 0.4rem 0.25rem 0.2rem !important;
|
padding: 0.4rem 0.25rem 0.2rem;
|
||||||
border-bottom: none !important;
|
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
display: block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add-entry disclosure: collapsed trigger, expanded form */
|
/* Add-entry disclosure: collapsed trigger, expanded form */
|
||||||
|
|
@ -455,112 +551,18 @@ details.add-entry > .month-add-form {
|
||||||
margin-top: 0.45rem;
|
margin-top: 0.45rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.entry-name {
|
@media (max-width: 520px) {
|
||||||
font-family: var(--sans);
|
.entry-row.reading {
|
||||||
font-weight: 500;
|
grid-template-columns: minmax(0, 1fr) 4.6rem auto;
|
||||||
font-size: 1.02rem;
|
gap: 0.4rem;
|
||||||
color: var(--ink);
|
}
|
||||||
letter-spacing: 0.01em;
|
.entry-row.editing {
|
||||||
min-width: 0;
|
grid-template-columns: minmax(0, 1fr) 4.6rem;
|
||||||
overflow: hidden;
|
gap: 0.4rem;
|
||||||
text-overflow: ellipsis;
|
}
|
||||||
white-space: nowrap;
|
.entry-row.editing .notes-input,
|
||||||
|
.entry-row.editing .entry-actions { grid-column: 1 / -1; }
|
||||||
}
|
}
|
||||||
.entry-name input {
|
|
||||||
font: inherit;
|
|
||||||
color: inherit;
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
border-bottom: 1px solid transparent;
|
|
||||||
padding: 0;
|
|
||||||
width: 100%;
|
|
||||||
outline: none;
|
|
||||||
transition: border-color 0.12s;
|
|
||||||
}
|
|
||||||
.entry-name input:hover { border-bottom-color: var(--rule); }
|
|
||||||
.entry-name input:focus { border-bottom-color: var(--ink); }
|
|
||||||
|
|
||||||
.entry-amount {
|
|
||||||
font-family: var(--sans);
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 1rem;
|
|
||||||
color: var(--ink);
|
|
||||||
font-feature-settings: "lnum" 1, "tnum" 1;
|
|
||||||
text-align: right;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
.entry-amount input {
|
|
||||||
font: inherit;
|
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
color: inherit;
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
border-bottom: 1px solid transparent;
|
|
||||||
padding: 0;
|
|
||||||
width: 100%;
|
|
||||||
outline: none;
|
|
||||||
text-align: right;
|
|
||||||
transition: border-color 0.12s;
|
|
||||||
}
|
|
||||||
.entry-amount input:hover { border-bottom-color: var(--rule); }
|
|
||||||
.entry-amount input:focus { border-bottom-color: var(--ink); }
|
|
||||||
|
|
||||||
/* On the budget page the planned-amount cell is the only numeric cell;
|
|
||||||
still render it like a ledger number. */
|
|
||||||
tr.entry td.entry-amount:first-of-type { color: var(--ink); }
|
|
||||||
|
|
||||||
.entry-actions button.delete {
|
|
||||||
font-family: var(--sans);
|
|
||||||
font-size: 1.2rem;
|
|
||||||
line-height: 1;
|
|
||||||
color: var(--rule);
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0;
|
|
||||||
opacity: 0;
|
|
||||||
transition: color 0.12s ease, opacity 0.12s ease;
|
|
||||||
align-self: center;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
tr.entry:hover .entry-actions button.delete { opacity: 1; }
|
|
||||||
.entry-actions button.delete:hover { color: var(--accent); }
|
|
||||||
|
|
||||||
/* Notes row — hidden when empty, shown on hover or when value is set */
|
|
||||||
tr.entry-notes-row {
|
|
||||||
display: block;
|
|
||||||
grid-column: 1 / -1;
|
|
||||||
font-family: var(--sans);
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
color: var(--muted);
|
|
||||||
line-height: 1.3;
|
|
||||||
padding: 0;
|
|
||||||
margin-top: -0.25rem;
|
|
||||||
}
|
|
||||||
tr.entry-notes-row td {
|
|
||||||
padding: 0 0.25rem 0.25rem !important;
|
|
||||||
border-bottom: 1px dotted var(--rule) !important;
|
|
||||||
}
|
|
||||||
tr.entry-notes-row input.notes-input {
|
|
||||||
font: inherit;
|
|
||||||
font-style: italic;
|
|
||||||
color: inherit;
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
width: 100%;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
tr.entry-notes-row input.notes-input::placeholder {
|
|
||||||
color: var(--rule);
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
/* Empty notes render subtly (placeholder only) so they stay clickable. */
|
|
||||||
tr.entry-notes-row:has(input:placeholder-shown) { opacity: 0.55; }
|
|
||||||
tr.entry-notes-row:hover,
|
|
||||||
tr.entry-notes-row:has(input:focus) { opacity: 1; }
|
|
||||||
|
|
||||||
.tag {
|
.tag {
|
||||||
font-family: var(--sans);
|
font-family: var(--sans);
|
||||||
|
|
@ -980,13 +982,6 @@ form.add-posting-form button[type="submit"] {
|
||||||
}
|
}
|
||||||
form.add-posting-form button[type="submit"]:hover { background: var(--ink); color: var(--paper); }
|
form.add-posting-form button[type="submit"]:hover { background: var(--ink); color: var(--paper); }
|
||||||
|
|
||||||
.empty-row {
|
|
||||||
padding: 0.5rem 0.5rem;
|
|
||||||
color: var(--muted);
|
|
||||||
font-style: italic;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
.entry-block > summary {
|
.entry-block > summary {
|
||||||
grid-template-columns: 0.9rem minmax(0, 1fr) 4.2rem 7rem 1rem;
|
grid-template-columns: 0.9rem minmax(0, 1fr) 4.2rem 7rem 1rem;
|
||||||
|
|
@ -1118,8 +1113,4 @@ button[disabled] {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
justify-self: center;
|
justify-self: center;
|
||||||
}
|
}
|
||||||
table.entries tbody tr.entry {
|
|
||||||
grid-template-columns: minmax(0, 1fr) 4.6rem 4.6rem 1rem;
|
|
||||||
gap: 0.4rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,67 @@
|
||||||
${{ '{:,.2f}'.format(section.total) }}
|
${{ '{:,.2f}'.format(section.total) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<table class="entries">
|
<div class="entries budget-entries">
|
||||||
<tbody>
|
|
||||||
{% for entry in section.entries %}
|
{% for entry in section.entries %}
|
||||||
<tr class="entry state-unchanged" style="--ratio: 1">
|
{% if editing_id is not none and entry.id == editing_id %}
|
||||||
<td class="entry-name">{{ entry.name }}</td>
|
<form
|
||||||
<td class="entry-amount">${{ '{:,.2f}'.format(entry.amount) }}</td>
|
class="entry-row editing"
|
||||||
<td class="entry-amount"></td>
|
hx-post="/entries/{{ entry.id }}"
|
||||||
<td class="entry-actions">
|
hx-target="#section-{{ section.section.value }}"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
class="name-input"
|
||||||
|
type="text"
|
||||||
|
name="name"
|
||||||
|
value="{{ entry.name }}"
|
||||||
|
required
|
||||||
|
aria-label="Name"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
class="amount-input"
|
||||||
|
type="number"
|
||||||
|
step="0.01"
|
||||||
|
min="0"
|
||||||
|
name="amount"
|
||||||
|
value="{{ '%.2f' | format(entry.amount) }}"
|
||||||
|
required
|
||||||
|
aria-label="Amount"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
class="notes-input"
|
||||||
|
type="text"
|
||||||
|
name="notes"
|
||||||
|
value="{{ entry.notes or '' }}"
|
||||||
|
placeholder="notes (optional)"
|
||||||
|
aria-label="Notes"
|
||||||
|
>
|
||||||
|
<div class="entry-actions">
|
||||||
|
<button type="submit" class="save-btn">Save</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="cancel-btn"
|
||||||
|
hx-get="/sections/{{ section.section.value }}"
|
||||||
|
hx-target="#section-{{ section.section.value }}"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
>Cancel</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<div class="entry-row reading">
|
||||||
|
<span class="entry-name">
|
||||||
|
{{ entry.name }}{% if entry.notes %}<span class="note-badge">{{ entry.notes }}</span>{% endif %}
|
||||||
|
</span>
|
||||||
|
<span class="entry-amount">${{ '{:,.2f}'.format(entry.amount) }}</span>
|
||||||
|
<div class="entry-actions">
|
||||||
|
<button
|
||||||
|
class="edit"
|
||||||
|
type="button"
|
||||||
|
hx-get="/entries/{{ entry.id }}/edit"
|
||||||
|
hx-target="#section-{{ section.section.value }}"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
aria-label="Edit {{ entry.name }}"
|
||||||
|
>✎</button>
|
||||||
<button
|
<button
|
||||||
class="delete"
|
class="delete"
|
||||||
type="button"
|
type="button"
|
||||||
|
|
@ -21,29 +74,13 @@
|
||||||
hx-swap="outerHTML"
|
hx-swap="outerHTML"
|
||||||
aria-label="Delete {{ entry.name }}"
|
aria-label="Delete {{ entry.name }}"
|
||||||
>×</button>
|
>×</button>
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
</div>
|
||||||
<tr class="entry-notes-row">
|
{% endif %}
|
||||||
<td colspan="4">
|
|
||||||
<input
|
|
||||||
class="notes-input"
|
|
||||||
type="text"
|
|
||||||
name="notes"
|
|
||||||
value="{{ entry.notes or '' }}"
|
|
||||||
placeholder="notes..."
|
|
||||||
hx-post="/entries/{{ entry.id }}/notes"
|
|
||||||
hx-trigger="change"
|
|
||||||
hx-target="#section-{{ section.section.value }}"
|
|
||||||
hx-swap="outerHTML"
|
|
||||||
aria-label="Notes for {{ entry.name }}"
|
|
||||||
>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<tr class="empty"><td colspan="4">No entries yet.</td></tr>
|
<div class="empty-row">No entries yet.</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<tr class="add-row">
|
<div class="add-row">
|
||||||
<td colspan="4">
|
|
||||||
<details class="add-entry">
|
<details class="add-entry">
|
||||||
<summary><span class="add-trigger">+ add {{ section.label|lower }}</span></summary>
|
<summary><span class="add-trigger">+ add {{ section.label|lower }}</span></summary>
|
||||||
<form
|
<form
|
||||||
|
|
@ -59,8 +96,6 @@
|
||||||
<input class="notes-input add-notes" type="text" name="notes" placeholder="notes (optional)">
|
<input class="notes-input add-notes" type="text" name="notes" placeholder="notes (optional)">
|
||||||
</form>
|
</form>
|
||||||
</details>
|
</details>
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
</div>
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
|
|
@ -136,17 +136,27 @@ def test_update_month_entry_route_accepts_notes(client):
|
||||||
assert "auto-pay" in response.text
|
assert "auto-pay" in response.text
|
||||||
|
|
||||||
|
|
||||||
def test_budget_page_renders_notes_inputs(client):
|
def test_budget_page_renders_note_badge_when_notes_set(client):
|
||||||
client.post(
|
client.post(
|
||||||
"/sections/fixed_bill/entries",
|
"/sections/fixed_bill/entries",
|
||||||
data={"name": "Rent", "amount": "1200.00", "notes": "due 1st"},
|
data={"name": "Rent", "amount": "1200.00", "notes": "due 1st"},
|
||||||
)
|
)
|
||||||
response = client.get("/")
|
response = client.get("/")
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert "entry-notes-row" in response.text
|
assert "note-badge" in response.text
|
||||||
assert "due 1st" in response.text
|
assert "due 1st" in response.text
|
||||||
|
|
||||||
|
|
||||||
|
def test_budget_page_omits_note_badge_when_notes_empty(client):
|
||||||
|
client.post(
|
||||||
|
"/sections/food/entries",
|
||||||
|
data={"name": "Groceries", "amount": "400.00"},
|
||||||
|
)
|
||||||
|
response = client.get("/")
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert "note-badge" not in response.text
|
||||||
|
|
||||||
|
|
||||||
def test_month_page_renders_notes_inputs(client):
|
def test_month_page_renders_notes_inputs(client):
|
||||||
client.post(
|
client.post(
|
||||||
"/sections/fixed_bill/entries",
|
"/sections/fixed_bill/entries",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue