feat(invoices): add deposit refund entries with negative claim adjustments - #1880
Conversation
…ments Adds an entryType (deposit/refund) to invoice deposits so refunds can be recorded alongside deposit installments. Refunds are entered as positive amounts and treated as negative contributions when computing the final payment amount; only paid/claimed refunds reduce it. Fixes #1876 Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com> Co-Authored-By: Claude backend-developer (Haiku 4.5) <noreply@anthropic.com> Co-Authored-By: Claude frontend-developer (Haiku 4.5) <noreply@anthropic.com> Co-Authored-By: Claude translator (Sonnet 4.5) <noreply@anthropic.com> Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <noreply@anthropic.com> Co-Authored-By: Claude e2e-test-engineer (Sonnet 4.5) <noreply@anthropic.com>
…ssertions
toContainText assertions expected bare digit strings ('2000', '1500',
'1000') but formatCurrency renders thousands-grouping ('€2,000.00') for
values >= 1000, so the Scenario 9/10 refund tests never matched.
Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>
Co-Authored-By: Claude e2e-test-engineer (Sonnet 4.5) <noreply@anthropic.com>
|
[ux-designer] Design review of PR #1880 against the visual spec posted on issue #1876. Verified against specToken adherence — clean. Every new declaration in Entry-type radio group — matches spec verbatim: plain Refund badge + negative amount (table row & mobile card) — both Accessibility — the Dark mode — Responsive/touch targets — no new breakpoint logic; Effective Amount displays — Adjudicated deviations — validated on their merits
FindingsNone — no hardcoded values, no dark-mode gaps, no accessibility regressions, no component-reuse violations. Implementation matches the spec closely enough that this was a fast review. Verdict: APPROVED |
|
[security-engineer] Security review of PR #1880 (story #1876, deposit refunds). Scope reviewed: 1. 2. Immutability via 3. Sum-invariant / money handling 4. Negative-fraction aggregation (refund abuse potential) This is a data-integrity/business-logic nuance rather than a classic OWASP vulnerability — no auth bypass, no cross-user data exposure, and all users in this single-tenant household app already hold equivalent trust to invoice/budget financial data. I'm flagging it Informational, not blocking: consider (in a follow-up, not this PR) validating 5. Error responses 6. Misc
No critical or high findings. One informational note above (item 4) for future consideration — does not block merge. Verdict: APPROVED |
|
[product-architect] Architecture review of PR #1880 (story #1876 — deposit refunds with negative claim adjustments). Scope reviewed: migration 0040, Drizzle schema + shared types, the refund-aware aggregation design in VerifiedMigration 0040 — correct. I ran the DDL against better-sqlite3 (3.53.1) directly to confirm rather than trust the pattern: Consumer SQL projection coverage — complete. I grepped exhaustively for every site that joins Type consistency. Error-code conventions. No added query cost. Test coverage is proportionate and well-targeted. What I specifically wanted to see is present: a zero-refund regression/identity test at every consumer boundary ( Wiki updated in the same PR. Both Findings (medium/low — none blocking)1. (Medium) Two different "a refund is realized" thresholds coexist, and only one is documented. Both behaviours are individually defensible ( 2. (Medium) The documented 3. (Medium/Low) Refund headroom is independent of what has actually been paid. 4. (Low) Findings 1, 2 and 4 are all the same fix: one consolidated paragraph in the No API contract violations, no schema/type inconsistencies, no missed consumer projections, no naming or error-shape deviations, and no business logic that belongs elsewhere. VERDICT: APPROVED |
|
[product-owner] Product Owner review of PR #1880 against story #1876 — Deposit refunds with negative claim adjustments. Acceptance Criteria Coverage
9 of 9 acceptance criteria met. Adjudicated Deviations — validated, not re-litigated1. Effective amount on the invoice list via a new hidden-by-default "Effective Amount" column. Accepted, and I think it was the right call. The existing "Remaining Amount" column answers a different question (invoice amount − Σ itemized budget lines); silently rebinding it to 2. Wiki accuracy: checked. The submodule bump ( Glossary Decision — APPROVED
Approved. "Refund" qualifies as a domain term rather than generic UI copy: it is a first-class entry type on the deposit entity and surfaces as a badge label, a radio option, and an error string. It sits directly alongside the existing ScopeClean. No undocumented functionality. The Non-blocking follow-ups (do not fix in this PR)
VERDICT: APPROVED |
|
🎉 This PR is included in version 2.13.0-beta.26 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
getColumnCellText() compared innerText() against a mixed-case label, but .tableHeader applies text-transform: uppercase, so the rendered text is always upper-case and the comparison never matched. Deterministic, not a race — the test has failed on every run since the helper was introduced in #1880. Confirmed from a CI trace: all five header scans across the full 3s retry window returned "REMAINING AMOUNT". Co-Authored-By: Claude e2e-test-engineer <noreply@anthropic.com>
Fixes the E2E failures that block `E2E Gates` on the `beta` -> `main` promotion. All 16 shards green. - `invoices.spec.ts:841` had never passed since it was written in #1880: the header lookup compared `innerText()` (which reflects `.tableHeader`'s `text-transform: uppercase`) against a mixed-case label. Fixing that exposed a second bug — the test read its invoice off page 1 of a 37-item list where it wasn't — now fixed by searching first. - `i18n.spec.ts:305` deleted the locale preference while `localStorage` still held `de`, so `LocaleContext.syncWithServer`'s migration branch re-created the row 13ms later. Now sets German server-side only and asserts `localStorage` is empty before deleting. - `i18n.spec.ts:131` and `dashboard.spec.ts` failed on genuine cross-test contamination of the shared admin user's preference rows: serial mode and per-test users respectively. Follow-ups filed: #1957 (shared-admin preference isolation across specs), #1955 (the underlying production debounce race). Co-Authored-By: Claude dev-team-lead <noreply@anthropic.com> Co-Authored-By: Claude e2e-test-engineer <noreply@anthropic.com> Co-Authored-By: Claude product-owner <noreply@anthropic.com>
|
🎉 This PR is included in version 2.13.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Summary
entryType(deposit|refund) to invoice deposits so refunds can be recorded alongside deposit installments; immutable after creation.paid/claimedrefunds reduce it, pending refunds do not.Badge, and refund-aware totals on the invoice list and detail pages.Fixes #1876
Test plan
Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) noreply@anthropic.com
Co-Authored-By: Claude backend-developer (Haiku 4.5) noreply@anthropic.com
Co-Authored-By: Claude frontend-developer (Haiku 4.5) noreply@anthropic.com
Co-Authored-By: Claude translator (Sonnet 4.5) noreply@anthropic.com
Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) noreply@anthropic.com
Co-Authored-By: Claude e2e-test-engineer (Sonnet 4.5) noreply@anthropic.com