fix(contacts): 400 not 500 deleting a company with related records (PMS-170) #145
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/pms-170-company-delete-fk-400"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Fixes PMS-170:
DELETE /api/v1/contacts/companies/{id}returned HTTP 500 when the company was still referenced by a child row, instead of a 400.Cause
delete_company(src/modules/contacts/service.rs) explicitly guards onlytickets. Every other table that foreign-keyscompanies(contracts, invoices, payments, projects, assets, time entries, appointments, sub-companies viaparent_company_id, ...) isON DELETE RESTRICT, so theDELETEraises Postgres23503, which the genericFrom<sqlx::Error>maps toAppError::Database-> 500. Surfaced by the PMS-155 E2E teardown (DELETE …/companies/819d811c… -> 500).Fix
Catch
23503on the DELETE and returnAppError::BadRequestwith an actionable message naming the likely blockers - the same shape as the PMS-149 ticket-delete fix. Other database errors propagate unchanged;CASCADEchildren (contacts, company_sites) still delete cleanly.Tests
tests/company_delete.rs: seeds a parent company and a child referencing it viaparent_company_id(the minimal RESTRICT blocker, no other FKs to satisfy), then assertsDELETEof the parent returns 400.cargo check --all-targets,clippy --all-targets,fmt --checkall clean.Note
Independent of PMS-178 (audit-list 500, PR #144). With both merged + deployed, the PMS-155 E2E run is fully green (PMS-178 was the test failure; PMS-170 was the best-effort teardown 500 warning).
🤖 Generated with Claude Code
DELETE /api/v1/contacts/companies/{id} returned HTTP 500 when the company was still referenced by a child row. delete_company explicitly guards only `tickets` (400 "existing tickets"); every other table that foreign-keys `companies` (contracts, invoices, payments, projects, assets, time entries, appointments, sub-companies, ...) is ON DELETE RESTRICT, so the DELETE raised Postgres 23503, which the generic From<sqlx::Error> mapped to AppError::Database -> 500. Catch 23503 on the DELETE and return AppError::BadRequest with an actionable message naming the likely blockers, mirroring the PMS-149 ticket-delete fix. Other database errors still propagate as before. CASCADE children (contacts, company_sites) are unaffected and still delete cleanly. Add an integration regression test (tests/company_delete.rs) using the self-referential parent/child company FK as the minimal RESTRICT blocker: deleting a company that a child references returns 400. #PMS-170 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>