Skip to content

Use Currency And UserRole Enums In Responses - #67

Merged
dinoconstantinou87 merged 2 commits into
mainfrom
feat/response-enums
Oct 4, 2026
Merged

dinoconstantinou87 merged 2 commits into
mainfrom
feat/response-enums

Conversation

@dinoconstantinou87

@dinoconstantinou87 dinoconstantinou87 commented Oct 4, 2026 •

Copy link
Copy Markdown
Owner

Summary

Currency and UserRole were request-only: responses kept plain strings. Every other enum in the spec is used on
both sides, so these now are too, and every output field takes an enum directly instead of unwrapping its raw value.

$ freeagent project create --contact 215832 --name "E2E HRK Project" --currency HRK
✔ Success
  Created project https://api.sandbox.freeagent.com/v2/projects/51654

$ freeagent task show 43347
...
Billing
  Billable:        Yes
  Currency:        HRK
  Billing Rate:    HRK 10.00

$ freeagent invoice create --contact 215832 --dated-on 2026-10-04 --payment-terms-in-days 30 --currency HRK
✖ Error
  FreeAgent rejected the request (HTTP 422): Exchange rates for this transaction are not known
  • Currency is widened from 113 to 124 codes and used on every response currency: bank account, bill, company,
    credit note, estimate, expense, invoice, project, recurring invoice and task.
  • User.role is a UserRole.
  • Every --currency now takes all 124 codes. A code a resource refuses reaches FreeAgent, whose refusal passes
    straight through.

Why 124 Codes

A response enum has to decode every value FreeAgent stores, or a record and its whole list page fail. The 113 were
the codes every resource accepts. A full probe of all 308 ISO 4217 codes (in the earlier currency work) found more:

  • Projects, and so tasks, accept the 115 active codes plus nine retired ones: ANG, BGN, HRK, LTL, LVL, MRO, STD, VEF
    and ZMK. That makes 124.
  • Estimates and expenses accept the 115 active codes, SSP and VES included.
  • Invoices and credit notes refuse the retired nine, and answer SSP and VES with a 500 that creates nothing.

One enum of 124 is used for requests and responses. The invoice, credit note, estimate and expense payloads say which
codes they refuse.

Fields Take Enums Directly

FieldValue gains generic overloads beside its cases, so a field passes the enum itself:

Field("Currency") { .text($0.currency) }
Field("Status") { .status($0.status) }
Field("Total") { .currency($0.totalValue, code: $0.currency) }
Field("Permission") { .text($0.permissionLevel) }
  • text and status take any RawRepresentable<String> and show its raw value.
  • text also takes a RawRepresentable & CustomStringConvertible, so PermissionLevel shows its name.
  • currency(_:code:) takes a RawRepresentable<String> code.

Every ?.rawValue and ?.description in a field closure is gone, across all commands. The invoice, credit note,
estimate and bill item tables carry a Currency?.

Other Changes

  • project create reads the company's currency as a Currency, so its "company currency is not one a project
    can use" error can no longer happen. The error and its test are deleted.

  • The expense rebill integration test skips integration-test projects. It picked projects.last, and projects
    list alphabetically, so the project lifecycle test's temporary ZZ Integration Test project sorted last while it
    existed. Running in parallel on this PR's first CI run, the rebill test picked it just before it was deleted and got a
    422 Project not found for this company. The race predates this PR; it shows when both suites are selected.

Known Trade-Off

A record in a code FreeAgent no longer accepts anywhere would fail to decode, and so would its list page. An old
production account's history could hold one. The sandbox cannot show whether any exist.

Tests

  • FieldValue tests cover an enum's raw value, nil, a described enum and a currency enum code.

  • The 11 integration suites changed-suites selects (bank_accounts, bills, company, credit_notes, estimates, expenses,
    invoices, projects, recurring_invoices, tasks, users) pass against the sandbox, 63 tests.

  • 148 CLI, 90 API and 11 tools unit tests pass, and format and lint are clean.

  • The debug CLI was run against the sandbox. That covered:

    • a project and a task in HRK, created, shown and listed;
    • an estimate in SSP, created, shown and listed;
    • an invoice in HRK, refused by FreeAgent (422, exit 4);
    • user show and list with role and permission, bank accounts and company.

    Every record was deleted afterwards.

🤖 Generated with Claude Code

dinoconstantinou87 and others added 2 commits October 4, 2026 09:52
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dinoconstantinou87
dinoconstantinou87 merged commit 10b013f into main Oct 4, 2026
4 checks passed
@dinoconstantinou87
dinoconstantinou87 deleted the feat/response-enums branch October 4, 2026 09:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant