Skip to content

fix(invoices): include gig_invoice_items in GET response and POST return#351

Open
forgou37 wants to merge 1 commit into
profullstack:masterfrom
forgou37:fix/invoice-include-line-items
Open

fix(invoices): include gig_invoice_items in GET response and POST return#351
forgou37 wants to merge 1 commit into
profullstack:masterfrom
forgou37:fix/invoice-include-line-items

Conversation

@forgou37
Copy link
Copy Markdown
Contributor

Closes #350

Problem

The gig_invoice_items table was added in today's migration (20260530210000_gig_invoice_items.sql) but the invoice route doesn't join or return items.

Changes

GET /api/gigs/[id]/invoice — adds items:gig_invoice_items(id, description, amount_usd, position) to the Supabase select, so fetched invoices include their line-item breakdown.

POST /api/gigs/[id]/invoice — adds items to the 201 response body so callers immediately receive the created line items without a separate fetch.

Testing

Tested via gig abd6b2a0 (bug testing + PRs) — creating an itemized invoice and verifying the GET response now includes items.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 30, 2026

Greptile Summary

This PR wires up gig_invoice_items to the invoice API: the GET handler now joins the new table to return line items alongside each invoice, and the POST handler includes an items array in its 201 response so callers don't need a follow-up fetch.

  • GET change — appends items:gig_invoice_items(id, description, amount_usd, position) to the Supabase select; straightforward and correct.
  • POST 201 response — constructs items from the pre-insert lineItems input rather than from the database rows, so the returned objects lack the DB-generated id field present in GET responses; a shape mismatch that breaks callers expecting { id, description, amount_usd, position }.
  • Silent failure path — when gig_invoice_items insert fails, the error is only logged and the handler still returns 201 with an items array, implying successful persistence even when rows were never written.

Confidence Score: 3/5

The GET change is safe, but the POST response returns items built from input data rather than database rows, creating a shape mismatch with GET and masking a silent insert-failure path.

The GET-side join is straightforward and correct. The POST side has two concrete problems: the 201 response constructs items from the pre-insert input array so callers never receive the DB-generated id that the GET endpoint returns, and a pre-existing silent insert-failure path now actively misleads callers by returning an items array that may describe rows that were never written to the database.

src/app/api/gigs/[id]/invoice/route.ts — specifically the POST 201 response construction and the error handling around the gig_invoice_items insert

Important Files Changed

Filename Overview
src/app/api/gigs/[id]/invoice/route.ts Adds gig_invoice_items join to GET and an items field to the POST 201 response; items in POST are built from input data and lack DB-generated IDs, and a silent insert-failure path can return misleading 201 items.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Route as route.ts POST
    participant InvoiceDB as gig_invoices
    participant ItemsDB as gig_invoice_items

    Client->>Route: POST /api/gigs/[id]/invoice
    Route->>InvoiceDB: INSERT gig_invoices
    InvoiceDB-->>Route: invoice with id
    Route->>ItemsDB: INSERT gig_invoice_items
    alt Insert succeeds
        ItemsDB-->>Route: rows saved with DB ids
    else Insert fails
        ItemsDB-->>Route: error logged only
    end
    Note over Route: items built from input lineItems, no DB id
    Route-->>Client: 201 items missing id field

    Client->>Route: GET /api/gigs/[id]/invoice
    Route->>InvoiceDB: SELECT with items join
    InvoiceDB-->>Route: invoices with items including id
    Route-->>Client: 200 items include id field
Loading

Comments Outside Diff (1)

  1. src/app/api/gigs/[id]/invoice/route.ts, line 284-289 (link)

    P1 Silent item-insert failure makes 201 items misleading

    When the gig_invoice_items insert fails, the error is only logged and execution continues — the handler still returns 201 with an items array in the body. Callers now receive a response that looks like the items were persisted when they may not have been. If item persistence is required for a valid invoice, the failure should propagate (e.g., rolling back the parent invoice or returning a 500), not silently produce a response that implies success.

Reviews (1): Last reviewed commit: "fix(invoices): include gig_invoice_items..." | Re-trigger Greptile

Comment on lines +357 to +361
items: lineItems.map((it, idx) => ({
description: it.description ?? "",
amount_usd: it.amount,
position: idx,
})),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 POST items response missing database-assigned id

The GET endpoint returns items as { id, description, amount_usd, position }, but the 201 response constructs items from the pre-insert lineItems array and therefore omits the DB-generated id. Any caller that immediately uses the POST response to reference, update, or display individual line items won't have their IDs and will need a separate GET fetch — defeating the purpose of returning items in the 201 body at all.

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.

fix(invoices): GET and POST responses missing gig_invoice_items line items

1 participant