Skip to content

Comments

feat: add work order dropdown and receipt linking to expense detail edit (#235)#242

Merged
daveharmswebdev merged 5 commits intomainfrom
feature/235-expense-workorder-receipt-linking
Feb 21, 2026
Merged

feat: add work order dropdown and receipt linking to expense detail edit (#235)#242
daveharmswebdev merged 5 commits intomainfrom
feature/235-expense-workorder-receipt-linking

Conversation

@daveharmswebdev
Copy link
Owner

Summary

Implements Story 16.4 — Expense-WorkOrder & Expense-Receipt Linking (Issue #235).

Allows property owners editing an expense at /expenses/:id to:

  • Link a work order via a dropdown filtered by the expense's property (AC1), which clears and reloads when the property changes (AC2)
  • Link an unprocessed receipt via an inline thumbnail picker (AC3)
  • Unlink a receipt from edit mode, returning it to the unprocessed queue (AC4)

Changes

Backend (new)

  • LinkReceiptToExpense.cs — MediatR command + handler that sets both FK sides of the 1:1 receipt-expense relationship (expense.ReceiptId, receipt.ExpenseId) and marks receipt.ProcessedAt = UtcNow. Follows the Story 15.4 UnlinkReceipt pattern in reverse. Includes property sync when receipt has no property.
  • LinkReceiptToExpenseValidator.cs — FluentValidation: ExpenseId and ReceiptId must be non-empty GUIDs.
  • ExpensesController.cs — New POST /api/v1/expenses/{id}/link-receipt endpoint returning 204/404/409. Includes LinkReceiptRequest record.

Frontend (modified)

  • expense-detail.component.ts — Added work order dropdown (workOrderId form control, loadWorkOrders(), propertyId valueChanges listener for AC2 reset), receipt picker UI (thumbnail grid, loadUnprocessedReceipts() via ApiClient, linkReceipt() method, unlink button in edit mode). Added SlicePipe for description truncation.
  • expense.service.ts — Added linkReceipt(expenseId, receiptId) method (manual, pending NSwag regen).
  • expense-detail.component.spec.ts — Fixed TEA red-phase test by providing mock unprocessed receipts to component signal.

Tests & E2E (pre-created by TEA agent)

  • LinkReceiptToExpenseHandlerTests.cs — 9 unit tests: happy path (both FKs, ProcessedAt, property sync, SaveChanges) + error cases (404 expense/receipt, 409 conflict already linked/processed)
  • LinkReceiptToExpenseValidatorTests.cs — 3 validation tests
  • expense-detail.component.spec.ts — 10 new component tests (5 work order dropdown AC1/AC2, 5 receipt linking AC3/AC4)
  • expense-linking.spec.ts — 7 E2E acceptance tests (require full stack for green)
  • expense-detail.page.ts — Page object with receipt linking locators and methods

Sprint artifacts

  • Story status → dev-complete
  • Sprint status YAML updated

Test Results

Suite Result
Backend (dotnet test) 1,484 / 1,484 pass (941 Application + 85 Infrastructure + 458 API)
Frontend (npm test) 2,420 / 2,420 pass
TypeScript compilation 0 errors
E2E (acceptance) 7 tests written, require running backend for validation

API Design

POST /api/v1/expenses/{id}/link-receipt
Body: { "receiptId": "guid" }
204 — Receipt linked successfully
404 — Expense or receipt not found
409 — Expense already has receipt / receipt already processed

Test plan

  • Backend unit tests pass (dotnet test --filter "LinkReceiptToExpense")
  • Frontend component tests pass (npm test from /frontend)
  • TypeScript compiles with zero errors
  • E2E: Navigate to expense detail → Edit → see work order dropdown with property's work orders
  • E2E: Change property in edit form → work order dropdown clears and reloads
  • E2E: Edit expense with no receipt → see receipt picker with unprocessed thumbnails
  • E2E: Select receipt thumbnail → click "Link Selected Receipt" → success snackbar
  • E2E: Edit expense with linked receipt → see "Unlink Receipt" button (not picker)
  • Verify NSwag client regeneration after merge (npm run generate-api)

🤖 Generated with Claude Code

daveharmswebdev and others added 5 commits February 21, 2026 06:45
…dit view

Implements Story 16.4 (Issue #235) — allows property owners to link
expenses to work orders and receipts from the detail edit page.

Backend: new LinkReceiptToExpense command/handler sets both FK sides of
the 1:1 relationship (expense.ReceiptId + receipt.ExpenseId) and marks
the receipt as processed, following the Story 15.4 pattern. Includes
FluentValidation validator and POST /api/v1/expenses/{id}/link-receipt
endpoint with 204/404/409 responses.

Frontend: expense detail edit form now includes a work order dropdown
(filtered by property, clears on property change) and an inline receipt
picker with thumbnail selection for unprocessed receipts.

12 new backend unit tests, 10 new frontend component tests, 7 E2E
acceptance tests (red-phase, ready for full-stack validation).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…behind toggle

Work order section now displays description and status badge instead of just
a link. Receipt picker in edit mode no longer auto-loads thumbnails — users
click "Browse Receipts to Link" to reveal available receipts, preventing
confusion with the "No receipt linked" state.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ly view

Info, Receipt, and Work Order now each have their own mat-card in edit mode,
providing visual symmetry with the readonly detail view.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Mock PUT response directly in AC1 save test (fake workOrderId FK fails on real server)
- Add browse receipts toggle step in AC3 tests (picker is behind button, not auto-shown)
- Fix AC4 unlink mock from POST /unlink-receipt to DELETE /receipt (matching actual API)
- Update page object with browseReceiptsButton locator and correct receipt section testid

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…se detail

Inject LinkReceiptToExpenseValidator via IValidator<T> instead of manual
instantiation, matching the established pattern across all controllers.
Track propertyId valueChanges subscription to prevent stacking on
repeated Edit/Cancel cycles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@daveharmswebdev daveharmswebdev merged commit dac1b22 into main Feb 21, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant