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)
|
||||
|
||||
|
||||
@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)
|
||||
def update_entry_notes(
|
||||
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.text.count('entry-row editing') == 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