Edit name/amount on budget template entries (#21) #22
2 changed files with 118 additions and 0 deletions
|
|
@ -162,6 +162,34 @@ def edit_entry(
|
||||||
return _render_section(request, db, entry.section, editing_id=entry.id)
|
return _render_section(request, db, entry.section, editing_id=entry.id)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/entries/{entry_id}", response_class=HTMLResponse)
|
||||||
|
def save_entry(
|
||||||
|
entry_id: int,
|
||||||
|
request: Request,
|
||||||
|
name: str = Form(...),
|
||||||
|
amount: str = Form(...),
|
||||||
|
notes: str | None = Form(None),
|
||||||
|
db: Session = Depends(get_session),
|
||||||
|
) -> HTMLResponse:
|
||||||
|
clean_name = name.strip()
|
||||||
|
if not clean_name:
|
||||||
|
raise HTTPException(status_code=400, detail="name is required")
|
||||||
|
parsed = _parse_amount(amount)
|
||||||
|
updated = service.update_entry(
|
||||||
|
db, entry_id, name=clean_name, amount=parsed, notes=notes
|
||||||
|
)
|
||||||
|
if updated is None:
|
||||||
|
raise HTTPException(status_code=404, detail="entry not found")
|
||||||
|
response = _render_section(request, db, updated.section)
|
||||||
|
extras: list[HTMLResponse] = [
|
||||||
|
_render_zero(request, db),
|
||||||
|
_render_group_totals(request, db),
|
||||||
|
]
|
||||||
|
if updated.section == Section.debt_minimum:
|
||||||
|
extras.append(_render_target(request, db))
|
||||||
|
return _append_oob(response, *extras)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/entries/{entry_id}/notes", response_class=HTMLResponse)
|
@router.post("/entries/{entry_id}/notes", response_class=HTMLResponse)
|
||||||
def update_entry_notes(
|
def update_entry_notes(
|
||||||
entry_id: int,
|
entry_id: int,
|
||||||
|
|
|
||||||
|
|
@ -114,3 +114,93 @@ def test_get_entry_edit_other_rows_stay_in_read_mode(client):
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.text.count('entry-row editing') == 1
|
assert response.text.count('entry-row editing') == 1
|
||||||
assert response.text.count('entry-row reading') == 1
|
assert response.text.count('entry-row reading') == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_entry_updates_name_and_amount(client):
|
||||||
|
client.post(
|
||||||
|
"/sections/subscription/entries",
|
||||||
|
data={"name": "Twitch", "amount": "10.99"},
|
||||||
|
)
|
||||||
|
response = client.post(
|
||||||
|
"/entries/1",
|
||||||
|
data={"name": "Twitch Prime", "amount": "11.99", "notes": ""},
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert "Twitch Prime" in response.text
|
||||||
|
assert "$11.99" in response.text
|
||||||
|
# returns to read mode
|
||||||
|
assert 'class="entry-row reading"' in response.text
|
||||||
|
# OOB swaps for zero widget and group total
|
||||||
|
assert 'id="zero-widget"' in response.text
|
||||||
|
assert 'id="group-total-flexible"' in response.text
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_entry_updates_notes_as_badge(client):
|
||||||
|
client.post(
|
||||||
|
"/sections/subscription/entries",
|
||||||
|
data={"name": "Spotify", "amount": "17.48"},
|
||||||
|
)
|
||||||
|
response = client.post(
|
||||||
|
"/entries/1",
|
||||||
|
data={"name": "Spotify", "amount": "17.48", "notes": "family plan"},
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert "note-badge" in response.text
|
||||||
|
assert "family plan" in response.text
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_entry_debt_minimum_includes_target_oob(client):
|
||||||
|
client.post(
|
||||||
|
"/sections/debt_minimum/entries",
|
||||||
|
data={"name": "Card A", "amount": "50.00"},
|
||||||
|
)
|
||||||
|
response = client.post(
|
||||||
|
"/entries/1",
|
||||||
|
data={"name": "Card A", "amount": "60.00", "notes": ""},
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert 'id="section-debt_target"' in response.text
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_entry_empty_name_returns_400(client):
|
||||||
|
client.post(
|
||||||
|
"/sections/subscription/entries",
|
||||||
|
data={"name": "Twitch", "amount": "10.99"},
|
||||||
|
)
|
||||||
|
response = client.post(
|
||||||
|
"/entries/1",
|
||||||
|
data={"name": " ", "amount": "11.99", "notes": ""},
|
||||||
|
)
|
||||||
|
assert response.status_code == 400
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_entry_negative_amount_returns_400(client):
|
||||||
|
client.post(
|
||||||
|
"/sections/subscription/entries",
|
||||||
|
data={"name": "Twitch", "amount": "10.99"},
|
||||||
|
)
|
||||||
|
response = client.post(
|
||||||
|
"/entries/1",
|
||||||
|
data={"name": "Twitch", "amount": "-1.00", "notes": ""},
|
||||||
|
)
|
||||||
|
assert response.status_code == 400
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_entry_non_numeric_amount_returns_400(client):
|
||||||
|
client.post(
|
||||||
|
"/sections/subscription/entries",
|
||||||
|
data={"name": "Twitch", "amount": "10.99"},
|
||||||
|
)
|
||||||
|
response = client.post(
|
||||||
|
"/entries/1",
|
||||||
|
data={"name": "Twitch", "amount": "eleven", "notes": ""},
|
||||||
|
)
|
||||||
|
assert response.status_code == 400
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_entry_missing_returns_404(client):
|
||||||
|
response = client.post(
|
||||||
|
"/entries/9999",
|
||||||
|
data={"name": "Whatever", "amount": "1.00", "notes": ""},
|
||||||
|
)
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue