Add company forms, signatories, and federal-tax read commands - #150
Add company forms, signatories, and federal-tax read commands#150ashieh wants to merge 2 commits into
Conversation
Beta users could only reach these via the raw `gusto api` escape hatch. Surface them as first-class read commands under `company`, add the matching read scopes to required-scopes, and cover them with unit, scope, and smoke tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Austin Shieh <austin.shieh@gusto.com>
cd021c0 to
9ce9286
Compare
| tokenStdin?: boolean; | ||
| } | ||
|
|
||
| export function companyFormsListHandler(opts: CompanyResourceReadOpts): CommandHandler { |
There was a problem hiding this comment.
forms list and signatories hit fetchCompanyResource with no --cursor/--limit/--all — every other company-scoped collection endpoint here (contractor list, employee list) goes through parsePaginationFlags + ctx.client.paginate. If a company's got more forms or signatories than fit in one page, this silently returns page one with no next and no signal anything's missing. company locations skips pagination too, but that's a naturally small list — forms can pile up over years. Worth wiring the same pagination flags in, or confirming with the API that these two never paginate.
There was a problem hiding this comment.
Fixed in 96ac7c4. forms list now goes through parsePaginationFlags + ctx.client.paginate with --cursor/--limit/--all (matching employee/contractor list) and surfaces next. I confirmed with the API: the company forms index paginates server-side (its controller calls paginate(...)), so a single un-paged GET was a real silent-truncation risk. Signatories I left un-paginated on purpose: that endpoint does not paginate and the API caps a company at one signatory, so there is no page to drop.
| }); | ||
| }); | ||
|
|
||
| describe("companyFormsListHandler", () => { |
There was a problem hiding this comment.
None of the five new handlers gets a non-2xx test — this file only covers the happy path plus the malformed-body case for the two array endpoints. company.network.test.ts and employee.network.test.ts both test the 404/500 → ApiError → exit code mapping per handler; this is the first batch of new handlers in a while that skips it.
There was a problem hiding this comment.
Added in 96ac7c4. Each of the five new handlers now has a non-2xx spec asserting the ApiError maps to a failed result with the api-client exit code (ExitCode.ApiClient). I used 404 rather than 500 because a persistent 500 trips the client's real retry backoff and hangs the test; 404 exercises the same ApiError to exit-code path. The forms-list case also gained a --limit cap test and a --cursor + --all conflict test.
| }; | ||
| } | ||
|
|
||
| export function companyFormShowHandler(formUuid: string, opts: FormReadOpts): CommandHandler { |
There was a problem hiding this comment.
companyFormShowHandler/companyFormPdfHandler call fetchResource(...) untyped, so result.data stays unknown. fetchResource<T> already supports a type param and companyShowHandler above uses it (ctx.client.get<CompanyRecord>) — worth typing these two the same way.
There was a problem hiding this comment.
Done in 96ac7c4. Both now pass the type param: fetchResource<FormRecord> for show and fetchResource<FormPdfUrl> for pdf, so result.data is typed instead of unknown. The field shapes come from the forms presenter (title/type/year/quarter/requires_signing/document_url, etc.).
forms list now uses parsePaginationFlags + client.paginate (--cursor/--limit/--all) like employee and contractor list; the forms index paginates server-side, so the prior single un-paged GET silently dropped later pages. signatories stays un-paginated because the API caps a company at one signatory. Type companyFormShowHandler and companyFormPdfHandler fetchResource calls (FormRecord, FormPdfUrl) so result.data is no longer unknown, and add non-2xx specs for all five new company read handlers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Austin Shieh <austin.shieh@gusto.com>
What
Adds first-class read commands under
companyfor data that was previously only reachable through the rawgusto apiescape hatch:company forms listGET /v1/companies/{uuid}/formscompany forms show <form_uuid>(aliasget)GET /v1/forms/{uuid}company forms pdf <form_uuid>GET /v1/forms/{uuid}/pdfcompany signatoriesGET /v1/companies/{uuid}/signatoriescompany federal-taxesGET /v1/companies/{uuid}/federal_tax_detailsformsis a nested sub-group (list/show/pdf) since it has multiple operations;signatoriesandfederal-taxesare single-op and stay flat, mirroringcompany locations.Scopes
Adds the matching read scopes to
required-scopes.ts:company_forms:read,signatories:read,company_federal_taxes:read. These are read-only and do not overlap with the dropped write/manage scopes.Notes
forms list,signatories) guard against a non-array 2xx body withmalformed_response, matching the existing collection-read convention.federal-taxesreturns a single object, so it has no array guard.Testing
required-scopestest asserts the three new scopes are present and not dropped.