Project quotations — expose delete affordance matching invoice delete
Why¶
Owner reported that a quotation could be created but not deleted like an invoice, and asked whether this was an RBAC issue or whether the web app did not currently allow quotation removal.
Diagnosis¶
- The backend route already supports deletion:
DELETE /api/projects/by-id/[projectId]/quotations. - The server-side helper already supports both paths:
- pending quotations are hard-deleted;
- converted quotations are soft-deleted when the quotation record carries
quotationStatus: "Invoiced"andlinkedInvoiceNumber. - This was not primarily an RBAC failure. The quotation route gates POST/PATCH/DELETE behind
projects:detail:write@epl, while invoices use the dedicatedprojects:invoice:delete@epldelete permission. - The actual missing piece was UI exposure.
ProjectShowApphad an invoice delete button in manage mode, but no equivalent quotation-row delete button or client handler.
What Changed¶
- Added
handleDeleteQuotation()tocomponents/projects/ProjectShowApp.tsx. - Added a quotation-row delete button in manage mode, mirroring the invoice row behavior.
- Pending unsaved quotation rows use the close icon to cancel creation.
- Saved quotations call the existing quotation DELETE API and refresh the quotation list from the response.
Verification¶
NODE_OPTIONS=--max-old-space-size=8192 ./node_modules/.bin/tsc --noEmitpasses.
Attestation¶
- Read
AGENTS.md. - Checked task board by scope (
quotation,project quotation, delete/remove); no existing task covered this missing UI affordance. - Source: Codex local session ·
/Users/gutchumi/dev/ArtifactoftheEstablisher-codex-invoice-hotfix.