fix(budget): fix invoice edit modal pre-population and add invoice popover#202
Merged
Conversation
…pover Issue 1: When editing an invoice linked to a budget line, the "Link to Work Item" dropdown always showed "None". Fixed by enriching the Invoice API response with a WorkItemBudgetSummary (workItemId, workItemTitle, description, plannedAmount, confidence) and using it to pre-populate the work item dropdown in the edit modal, along with an immediate fetch of the matching budget lines. Issue 2: The invoice count badge on WorkItemDetailPage navigated away to the vendor page. Replaced the <Link> with a button that toggles an absolutely-positioned popover listing all linked invoices with number, amount, vendor, date, and status. Each item links to the vendor detail page. Includes a click-outside handler and mobile bottom-sheet layout. Co-Authored-By: Claude <frontend-developer> (Sonnet 4.6) <noreply@anthropic.com> Co-Authored-By: Claude <backend-developer> (Sonnet 4.6) <noreply@anthropic.com>
Contributor
|
🎉 This PR is included in version 1.9.0-beta.44 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
steilerDev
pushed a commit
that referenced
this pull request
Feb 23, 2026
…e branch Add missing `workItemBudget` field to the manual Invoice object construction in `listAllInvoices()`. The `Invoice` type now requires `workItemBudget: WorkItemBudgetSummary | null` (added by PR #202), and `listAllInvoices()` was building Invoice objects inline rather than using `toInvoice()`, so the field was omitted. Co-Authored-By: Claude <backend-developer> (Sonnet 4.6) <noreply@anthropic.com>
steilerDev
added a commit
that referenced
this pull request
Feb 23, 2026
* feat(invoices): add standalone cross-vendor invoice API endpoints - Add vendorName field to Invoice type in shared/src/types/invoice.ts - Export InvoiceStatusSummary, InvoiceSummary, InvoiceListPaginatedResponse, and InvoiceDetailResponse from @cornerstone/shared - Update toInvoice() in invoiceService.ts to resolve and include vendorName - Add listAllInvoices() with pagination, filtering (status, vendorId, q), sorting (date, amount, status, vendor_name, due_date), and global status summary - Add getInvoiceById() for cross-vendor single invoice lookup - Create server/src/routes/standaloneInvoices.ts with GET /api/invoices and GET /api/invoices/:invoiceId endpoints - Register standaloneInvoiceRoutes at /api/invoices prefix in app.ts Co-Authored-By: Claude backend-developer (Sonnet 4.5) <noreply@anthropic.com> * feat(invoices): add standalone invoices list and detail pages - Add fetchAllInvoices and fetchInvoiceById to invoicesApi client - Add Invoices tab to BudgetSubNav between Vendors and Sources - Implement InvoicesPage with summary cards (Pending/Paid/Claimed), filterable/sortable paginated table, mobile card view, and create modal - Implement InvoiceDetailPage with edit and delete modals, budget line linking via work item selector, breadcrumb navigation - Register /budget/invoices and /budget/invoices/:id routes in App.tsx Fixes #200 Co-Authored-By: Claude frontend-developer (Sonnet 4.6) <noreply@anthropic.com> * style(invoices): fix Prettier formatting in new invoice pages Co-Authored-By: Claude orchestrator (Sonnet 4.6) <noreply@anthropic.com> * fix(invoices): add vendorName to Invoice mock fixtures in client tests The vendorName field added to the Invoice type requires updating all existing mock objects in test files. Co-Authored-By: Claude orchestrator (Sonnet 4.6) <noreply@anthropic.com> * fix(invoices): use InvoiceDetailResponse type in fetchInvoiceById Replace inline anonymous type `{ invoice: Invoice }` with the explicit `InvoiceDetailResponse` shared type in fetchInvoiceById, consistent with how other shared response types are used across the API client. Co-Authored-By: Claude <frontend-developer> (Sonnet 4.6) <noreply@anthropic.com> * fix(invoices): eliminate N+1 vendor query in vendor-scoped invoice service functions - `assertVendorExists()` now returns the vendor name (was void) - `toInvoice()` accepts an optional `knownVendorName` 3rd parameter; when provided it skips the per-call vendor DB lookup - `listInvoices`, `createInvoice`, and `updateInvoice` capture the vendor name returned by `assertVendorExists` and forward it to `toInvoice`, avoiding one extra SELECT per invoice row - `deleteInvoice` ignores the returned name (no `toInvoice` call needed) - `getInvoiceById` and `listAllInvoices` are unchanged — they either rely on the fallback lookup or already use a JOIN Co-Authored-By: Claude <backend-developer> (Sonnet 4.6) <noreply@anthropic.com> * docs(invoices): update API contract with standalone invoice endpoints Co-Authored-By: Claude product-architect (Opus 4.6) <noreply@anthropic.com> * test(invoices): add unit tests for listAllInvoices, getInvoiceById, fetchAllInvoices, fetchInvoiceById - Add 14 tests for listAllInvoices(): empty results, multi-vendor vendorName via JOIN, pagination (page/pageSize/metadata), status filter, vendorId filter, q search (case-insensitive), sort by amount (asc/desc), sort by vendor_name, global summary (unaffected by current page filter), zero values for unused statuses, combined filters - Add 4 tests for getInvoiceById(): all fields with vendorName, NotFoundError, cross-vendor lookup, null createdBy - Add 10 tests for fetchAllInvoices(): GET /api/invoices with no params, query strings (page/pageSize/q/status/vendorId/sortBy/sortOrder), full InvoiceListPaginatedResponse unwrapping, undefined param omission, clean path without query string, 401/500 errors - Add 6 tests for fetchInvoiceById(): GET /api/invoices/:id URL, correct invoiceId, Invoice unwrapped from { invoice } envelope, vendorName populated, 404/401 errors Co-Authored-By: Claude <qa-integration-tester> (Sonnet 4.6) <noreply@anthropic.com> * fix(invoices): rename InvoiceSummary to InvoiceStatusBreakdown to avoid collision The beta branch introduced a new InvoiceSummary type in workItemBudget.ts representing a per-invoice line summary. Our feature branch added a different InvoiceSummary type in invoice.ts representing a status breakdown (pending/ paid/claimed counts + totals). Rename ours to InvoiceStatusBreakdown to eliminate the duplicate identifier. Co-Authored-By: Claude <orchestrator> (Sonnet 4.6) <noreply@anthropic.com> * fix(invoices): fix type errors after merging beta changes into feature branch Add missing `workItemBudget` field to the manual Invoice object construction in `listAllInvoices()`. The `Invoice` type now requires `workItemBudget: WorkItemBudgetSummary | null` (added by PR #202), and `listAllInvoices()` was building Invoice objects inline rather than using `toInvoice()`, so the field was omitted. Co-Authored-By: Claude <backend-developer> (Sonnet 4.6) <noreply@anthropic.com> --------- Co-authored-by: Claude frontend-developer (Opus 4.6) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fix invoice edit modal work item dropdown (
VendorDetailPage): When editing an invoice linked to a budget line, the "Link to Work Item" dropdown always showed "None" because the API only returnedworkItemBudgetId. Now theInvoiceresponse includes aworkItemBudgetsummary withworkItemIdandworkItemTitle, which is used to pre-populate the work item dropdown and immediately load the matching budget lines.Replace invoice count link with popover (
WorkItemDetailPage): The invoice count badge was a<Link>that navigated away to the vendor page. Replaced with a<button>that toggles an absolutely-positioned dropdown listing each linked invoice (number, amount, vendor, date, status badge). Each entry links to the vendor detail page. Includes a click-outside handler and mobile bottom-sheet layout.Files Changed
shared/src/types/invoice.tsWorkItemBudgetSummaryinterface; addworkItemBudgettoInvoiceshared/src/types/workItemBudget.tsInvoiceSummaryinterface; addinvoices[]toWorkItemBudgetLineshared/src/index.tsserver/src/services/invoiceService.tstoWorkItemBudgetSummary()helper; enrichtoInvoice()with joined budget+workItem dataserver/src/services/workItemBudgetService.tsgetLinkedInvoices()via raw SQL LEFT JOIN; include intoWorkItemBudgetLine()client/src/pages/VendorDetailPage/VendorDetailPage.tsxopenEditInvoiceModal(); fetch budget lines immediately; update info noteclient/src/pages/WorkItemDetailPage/WorkItemDetailPage.tsx<Link>with button+popoverclient/src/pages/WorkItemDetailPage/WorkItemDetailPage.module.cssclient/src/lib/invoicesApi.test.tsworkItemBudget: nullto fixtureclient/src/pages/VendorDetailPage/VendorDetailPage.test.tsxworkItemBudget: nullandinvoices: []to fixturesTest Plan
shared,server,client)🤖 Generated with Claude Code