feat(api): ROT/RUT, articles, and project lifecycle on the v1 API (#904)

* feat(api): ROT/RUT + articles + dimensions on the v1 invoice surface (#895)

- v1 invoice POST now routes through buildInvoiceWriteData, the same
  builder as the dashboard: ROT/RUT deduction lines (server-side compute,
  personnummer encryption), article_id + revenue_account linkage,
  accruals, and line_type no longer get silently dropped on the wire.
- v1 invoice PATCH accepts default_dimensions so integrations can tag a
  draft with a project/cost centre after creation.
- New PATCH/DELETE /dimensions/:id/values/:valueId: rename, archive,
  set end_date on project codes; delete unreferenced values (409 with an
  archive hint when the BFL retention trigger blocks).
- New GET /articles: read-only artikelregister list (incl. housework_type)
  so callers can resolve article_id before composing invoice lines.
- Invoice GET/POST projections now expose deduction fields and full item
  columns; dry-run previews never echo the encrypted personnummer.

Closes #895

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(api): address review on #904

- Extract shared v1 invoice projections to lib/api/v1/invoice-columns.ts
  so create/detail/patch responses can't drift; PATCH now returns
  deduction_total + deduction_personnummer_last4 like GET/POST.
- Narrow the v1 create customer fetch back to the three fields the
  builder reads instead of select('*').

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-07-06 15:21:53 +02:00
committed by GitHub
co-authored by Claude Opus 4.7
parent 31b244acf5
commit cdac1808c9
12 changed files with 1311 additions and 148 deletions
@@ -1,16 +1,18 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`v1 spec snapshot > matches the recorded endpoint count > endpoint-count 1`] = `104`;
exports[`v1 spec snapshot > matches the recorded endpoint count > endpoint-count 1`] = `107`;
exports[`v1 spec snapshot > matches the recorded endpoint key set > endpoint-keys 1`] = `
[
"DELETE /api/v1/companies/:companyId/customers/:id",
"DELETE /api/v1/companies/:companyId/dimensions/:id/values/:valueId",
"DELETE /api/v1/companies/:companyId/employees/:id",
"DELETE /api/v1/companies/:companyId/salary-runs/:id",
"DELETE /api/v1/companies/:companyId/suppliers/:id",
"DELETE /api/v1/companies/:companyId/webhooks/:id",
"GET /api/v1/companies",
"GET /api/v1/companies/:companyId/accounts",
"GET /api/v1/companies/:companyId/articles",
"GET /api/v1/companies/:companyId/compliance/check",
"GET /api/v1/companies/:companyId/customers",
"GET /api/v1/companies/:companyId/customers/:id",
@@ -53,6 +55,7 @@ exports[`v1 spec snapshot > matches the recorded endpoint key set > endpoint-key
"GET /api/v1/health",
"GET /api/v1/operations/:id",
"PATCH /api/v1/companies/:companyId/customers/:id",
"PATCH /api/v1/companies/:companyId/dimensions/:id/values/:valueId",
"PATCH /api/v1/companies/:companyId/employees/:id",
"PATCH /api/v1/companies/:companyId/invoices/:id",
"PATCH /api/v1/companies/:companyId/salary-runs/:id",