Add employee update command for work-state changes - #152
Open
tmfahey wants to merge 5 commits into
Open
Conversation
Signed-off-by: tmfahey <taylor.fahey@gusto.com>
Signed-off-by: tmfahey <taylor.fahey@gusto.com>
Signed-off-by: tmfahey <taylor.fahey@gusto.com>
Signed-off-by: tmfahey <taylor.fahey@gusto.com>
Signed-off-by: tmfahey <taylor.fahey@gusto.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the employee work-state write path to the CLI:
gusto employee update <employee_uuid> --work-state <ST>resolves<ST>to an existing company location in that state, then PUTs the employee's active work address to point at it (PUT /v1/work_addresses/{uuid}). Create the location first withgusto company locationsif none exists yet.complianceblock naming the new state's outstanding (unanswered) tax requirements fromGET /v1/companies/{uuid}/tax_requirements/{state}, and whether any of them block payroll - so a silent state move doesn't turn into months of missed filings.--work-stateis a no-op (changed: false): no location lookup, no write, no nudge fetch.Follows existing conventions: agent-mode writes are gated behind
--confirm,--dry-runpreviews the resolved request without sending it,--exampleprints a canned payload.Why a location lookup instead of a bare state string
The work-address PUT only accepts a
location_uuid, not a raw state - Gusto ties work-state to a company location record. Rather than silently creating one,employee updatefails with a clearno_company_location_for_stateerror pointing atgusto company locationswhen there's no active location in the target state yet. Creating locations felt like a separate concern to bolt on here.Scope change
Updating a work address needs the
employees:manageOAuth scope, and the nudge GET needscompany_tax_requirements:read.employees:managewas previously dropped from the partner app grant as unused - this PR moves it back intoREQUIRED_SCOPES(with an audit-guard test) and addscompany_tax_requirements:read. The partner OAuth app registration itself will need updating to match; flagging that here so it doesn't get missed.Implementation
findLocationForState(src/lib/locations.ts) andbuildComplianceNudge(src/commands/employee.ts) are small pure functions, unit-tested independently of the network layer.isValidStateCode(src/lib/parse.ts) is a format-only check (two letters) - like the otherparse.tsvalidators, it doesn't hardcode an enumerable state list; the API is the source of truth for whether it's real.withCompanyContext, since the single-request write helpers (writeResource/putCompanyResource) don't fit a multi-call flow. The confirmation gate runs up front against the write's general shape, before any network call - the specific work-address UUID isn't known yet at that point.compliancecarries{ fetched: false, error }instead, plus a top-levelwarningstring with a copy-pasteablegusto api requestretry command. Thewarningexists so a caller that only checks the top-levelokdoesn't mistake "the nudge never loaded" for "no compliance concerns" - the entire point of this feature is catching that exact silent-move failure mode.Testing
isValidStateCode,findLocationForState, andbuildComplianceNudge.--example, missing/invalid--work-state, invalid--effective-date, the agent-mode confirm gate, no-active-work-address, a malformed (non-array) work-addresses body, already-in-target-state as a no-op (both exact-case and a lowercase--work-statematching the stored uppercase state, with and without--dry-run), a lowercase--work-stateresolving to the right location on a real change, no-matching-location, picking the right location out of several, a location whose own stored state is lowercase,--dry-run,--confirmsuccess with the compliance nudge, a rejected PUT (stale version) failing the command rather than reporting a phantom success, a failed nudge fetch surfacing thewarning, and UUID encoding.required-scopes.test.tsaudit-guard tests for both new scopes.