diff --git a/README.md b/README.md index db0a18e..32a358d 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ func main() { client := finchgo.NewClient( option.WithAccessToken("my access token"), ) - page, err := client.HRIS.Directory.ListIndividuals(context.TODO(), finchgo.HRISDirectoryListIndividualsParams{}) + page, err := client.HRIS.Directory.List(context.TODO(), finchgo.HRISDirectoryListParams{}) if err != nil { panic(err.Error()) } @@ -142,7 +142,7 @@ client := finchgo.NewClient( option.WithHeader("X-Some-Header", "custom_header_info"), ) -client.HRIS.Directory.ListIndividuals(context.TODO(), ..., +client.HRIS.Directory.List(context.TODO(), ..., // Override the header option.WithHeader("X-Some-Header", "some_other_custom_header_info"), // Add an undocumented field to the request body, using sjson syntax @@ -159,7 +159,7 @@ This library provides some conveniences for working with paginated list endpoint You can use `.ListAutoPaging()` methods to iterate through items across all pages: ```go -iter := client.HRIS.Directory.ListIndividualsAutoPaging(context.TODO(), finchgo.HRISDirectoryListIndividualsParams{}) +iter := client.HRIS.Directory.ListAutoPaging(context.TODO(), finchgo.HRISDirectoryListParams{}) // Automatically fetches more pages as needed. for iter.Next() { individualInDirectory := iter.Current() @@ -174,7 +174,7 @@ Or you can use simple `.List()` methods to fetch a single page and receive a sta with additional helper methods like `.GetNextPage()`, e.g.: ```go -page, err := client.HRIS.Directory.ListIndividuals(context.TODO(), finchgo.HRISDirectoryListIndividualsParams{}) +page, err := client.HRIS.Directory.List(context.TODO(), finchgo.HRISDirectoryListParams{}) for page != nil { for _, directory := range page.Individuals { fmt.Printf("%+v\n", directory) @@ -196,7 +196,7 @@ When the API returns a non-success status code, we return an error with type To handle errors, we recommend that you use the `errors.As` pattern: ```go -_, err := client.HRIS.Directory.ListIndividuals(context.TODO(), finchgo.HRISDirectoryListIndividualsParams{}) +_, err := client.HRIS.Directory.List(context.TODO(), finchgo.HRISDirectoryListParams{}) if err != nil { var apierr *finchgo.Error if errors.As(err, &apierr) { @@ -221,9 +221,9 @@ To set a per-retry timeout, use `option.WithRequestTimeout()`. // This sets the timeout for the request, including all the retries. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() -client.HRIS.Directory.ListIndividuals( +client.HRIS.Directory.List( ctx, - finchgo.HRISDirectoryListIndividualsParams{}, + finchgo.HRISDirectoryListParams{}, // This sets the per-retry timeout option.WithRequestTimeout(20*time.Second), ) @@ -244,9 +244,9 @@ client := finchgo.NewClient( ) // Override per-request: -client.HRIS.Directory.ListIndividuals( +client.HRIS.Directory.List( context.TODO(), - finchgo.HRISDirectoryListIndividualsParams{}, + finchgo.HRISDirectoryListParams{}, option.WithMaxRetries(5), ) ``` @@ -290,7 +290,7 @@ middleware has been applied. ## Semantic Versioning -This package generally attempts to follow [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: +This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: 1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals)_. 2. Changes that we do not expect to impact the vast majority of users in practice. diff --git a/api.md b/api.md index e6d59c4..4c844d3 100644 --- a/api.md +++ b/api.md @@ -27,7 +27,7 @@ Response Types: Methods: -- client.HRIS.Directory.ListIndividuals(ctx context.Context, query finchgo.HRISDirectoryListIndividualsParams) (finchgo.IndividualsPage, error) +- client.HRIS.Directory.List(ctx context.Context, query finchgo.HRISDirectoryListParams) (finchgo.IndividualsPage, error) ## Individuals @@ -82,9 +82,9 @@ Params Types: Response Types: +- finchgo.BenefitContribution - finchgo.BenefitFrequency - finchgo.BenefitType -- finchgo.BenfitContribution - finchgo.CompanyBenefit - finchgo.CreateCompanyBenefitsResponse - finchgo.SupportedBenefit diff --git a/client_test.go b/client_test.go index 495b688..56cf786 100644 --- a/client_test.go +++ b/client_test.go @@ -29,7 +29,7 @@ func TestContextCancel(t *testing.T) { ) cancelCtx, cancel := context.WithCancel(context.Background()) cancel() - res, err := client.HRIS.Directory.ListIndividuals(cancelCtx, finchgo.HRISDirectoryListIndividualsParams{}) + res, err := client.HRIS.Directory.List(cancelCtx, finchgo.HRISDirectoryListParams{}) if err == nil || res != nil { t.Error("Expected there to be a cancel error and for the response to be nil") } @@ -61,7 +61,7 @@ func TestContextCancelDelay(t *testing.T) { time.Sleep(time.Millisecond * time.Duration(2)) cancel() }() - res, err := client.HRIS.Directory.ListIndividuals(cancelCtx, finchgo.HRISDirectoryListIndividualsParams{}) + res, err := client.HRIS.Directory.List(cancelCtx, finchgo.HRISDirectoryListParams{}) if err == nil || res != nil { t.Error("expected there to be a cancel error and for the response to be nil") } @@ -89,7 +89,7 @@ func TestContextDeadline(t *testing.T) { option.WithAccessToken("AccessToken"), option.WithHTTPClient(&http.Client{Transport: &neverTransport{}}), ) - res, err := client.HRIS.Directory.ListIndividuals(deadlineCtx, finchgo.HRISDirectoryListIndividualsParams{}) + res, err := client.HRIS.Directory.List(deadlineCtx, finchgo.HRISDirectoryListParams{}) if err == nil || res != nil { t.Error("expected there to be a deadline error and for the response to be nil") } diff --git a/hrisbenefit.go b/hrisbenefit.go index 4e295d1..0806d5f 100644 --- a/hrisbenefit.go +++ b/hrisbenefit.go @@ -120,6 +120,35 @@ func (r *HRISBenefitService) ListSupportedBenefitsAutoPaging(ctx context.Context return shared.NewSinglePageAutoPager(r.ListSupportedBenefits(ctx, opts...)) } +type BenefitContribution struct { + // Contribution amount in cents (if `fixed`) or basis points (if `percent`). + Amount int64 `json:"amount,nullable"` + // Contribution type. + Type BenefitContributionType `json:"type,nullable"` + JSON benefitContributionJSON +} + +// benefitContributionJSON contains the JSON metadata for the struct +// [BenefitContribution] +type benefitContributionJSON struct { + Amount apijson.Field + Type apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *BenefitContribution) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +// Contribution type. +type BenefitContributionType string + +const ( + BenefitContributionTypeFixed BenefitContributionType = "fixed" + BenefitContributionTypePercent BenefitContributionType = "percent" +) + type BenefitFrequency string const ( @@ -152,41 +181,12 @@ const ( BenefitTypeCustomPreTax BenefitType = "custom_pre_tax" ) -type BenfitContribution struct { - // Contribution amount in cents (if `fixed`) or basis points (if `percent`). - Amount int64 `json:"amount,nullable"` - // Contribution type. - Type BenfitContributionType `json:"type,nullable"` - JSON benfitContributionJSON -} - -// benfitContributionJSON contains the JSON metadata for the struct -// [BenfitContribution] -type benfitContributionJSON struct { - Amount apijson.Field - Type apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *BenfitContribution) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -// Contribution type. -type BenfitContributionType string - -const ( - BenfitContributionTypeFixed BenfitContributionType = "fixed" - BenfitContributionTypePercent BenfitContributionType = "percent" -) - type CompanyBenefit struct { - BenefitID string `json:"benefit_id,required"` - CompanyContribution BenfitContribution `json:"company_contribution,required,nullable"` - Description string `json:"description,required,nullable"` - EmployeeDeduction BenfitContribution `json:"employee_deduction,required,nullable"` - Frequency BenefitFrequency `json:"frequency,required,nullable"` + BenefitID string `json:"benefit_id,required"` + CompanyContribution BenefitContribution `json:"company_contribution,required,nullable"` + Description string `json:"description,required,nullable"` + EmployeeDeduction BenefitContribution `json:"employee_deduction,required,nullable"` + Frequency BenefitFrequency `json:"frequency,required,nullable"` // Type of benefit. Type BenefitType `json:"type,required,nullable"` JSON companyBenefitJSON diff --git a/hrisbenefitindividual.go b/hrisbenefitindividual.go index a6406b6..0a9dfc3 100644 --- a/hrisbenefitindividual.go +++ b/hrisbenefitindividual.go @@ -124,9 +124,9 @@ type IndividualBenefitBody struct { AnnualMaximum int64 `json:"annual_maximum,nullable"` // If the benefit supports catch up (401k, 403b, etc.), whether catch up is enabled // for this individual. - CatchUp bool `json:"catch_up,nullable"` - CompanyContribution BenfitContribution `json:"company_contribution,nullable"` - EmployeeDeduction BenfitContribution `json:"employee_deduction,nullable"` + CatchUp bool `json:"catch_up,nullable"` + CompanyContribution BenefitContribution `json:"company_contribution,nullable"` + EmployeeDeduction BenefitContribution `json:"employee_deduction,nullable"` // Type for HSA contribution limit if the benefit is a HSA. HsaContributionLimit IndividualBenefitBodyHsaContributionLimit `json:"hsa_contribution_limit,nullable"` JSON individualBenefitBodyJSON diff --git a/hrisdirectory.go b/hrisdirectory.go index 4c4199b..2c9a33d 100644 --- a/hrisdirectory.go +++ b/hrisdirectory.go @@ -32,6 +32,31 @@ func NewHRISDirectoryService(opts ...option.RequestOption) (r *HRISDirectoryServ } // Read company directory and organization structure +func (r *HRISDirectoryService) List(ctx context.Context, query HRISDirectoryListParams, opts ...option.RequestOption) (res *IndividualsPage, err error) { + var raw *http.Response + opts = append(r.Options, opts...) + opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...) + path := "employer/directory" + cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, query, &res, opts...) + if err != nil { + return nil, err + } + err = cfg.Execute() + if err != nil { + return nil, err + } + res.SetPageConfig(cfg, raw) + return res, nil +} + +// Read company directory and organization structure +func (r *HRISDirectoryService) ListAutoPaging(ctx context.Context, query HRISDirectoryListParams, opts ...option.RequestOption) *IndividualsPageAutoPager { + return NewIndividualsPageAutoPager(r.List(ctx, query, opts...)) +} + +// Read company directory and organization structure +// +// Deprecated: use `List` instead func (r *HRISDirectoryService) ListIndividuals(ctx context.Context, query HRISDirectoryListIndividualsParams, opts ...option.RequestOption) (res *IndividualsPage, err error) { var raw *http.Response opts = append(r.Options, opts...) @@ -50,6 +75,8 @@ func (r *HRISDirectoryService) ListIndividuals(ctx context.Context, query HRISDi } // Read company directory and organization structure +// +// Deprecated: use `List` instead func (r *HRISDirectoryService) ListIndividualsAutoPaging(ctx context.Context, query HRISDirectoryListIndividualsParams, opts ...option.RequestOption) *IndividualsPageAutoPager { return NewIndividualsPageAutoPager(r.ListIndividuals(ctx, query, opts...)) } @@ -219,6 +246,22 @@ func (r *IndividualInDirectoryManager) UnmarshalJSON(data []byte) (err error) { return apijson.UnmarshalRoot(data, r) } +type HRISDirectoryListParams struct { + // Number of employees to return (defaults to all) + Limit param.Field[int64] `query:"limit"` + // Index to start from (defaults to 0) + Offset param.Field[int64] `query:"offset"` +} + +// URLQuery serializes [HRISDirectoryListParams]'s query parameters as +// `url.Values`. +func (r HRISDirectoryListParams) URLQuery() (v url.Values) { + return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ + ArrayFormat: apiquery.ArrayQueryFormatComma, + NestedFormat: apiquery.NestedQueryFormatBrackets, + }) +} + type HRISDirectoryListIndividualsParams struct { // Number of employees to return (defaults to all) Limit param.Field[int64] `query:"limit"` diff --git a/hrisdirectory_test.go b/hrisdirectory_test.go index eaebd2f..7f7c73a 100644 --- a/hrisdirectory_test.go +++ b/hrisdirectory_test.go @@ -13,6 +13,31 @@ import ( "github.com/Finch-API/finch-api-go/option" ) +func TestHRISDirectoryListWithOptionalParams(t *testing.T) { + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := finchgo.NewClient( + option.WithBaseURL(baseURL), + option.WithAccessToken("AccessToken"), + ) + _, err := client.HRIS.Directory.List(context.TODO(), finchgo.HRISDirectoryListParams{ + Limit: finchgo.F(int64(0)), + Offset: finchgo.F(int64(0)), + }) + if err != nil { + var apierr *finchgo.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + func TestHRISDirectoryListIndividualsWithOptionalParams(t *testing.T) { baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { diff --git a/paginationauto_test.go b/paginationauto_test.go index 1c1af0d..334a413 100644 --- a/paginationauto_test.go +++ b/paginationauto_test.go @@ -24,7 +24,7 @@ func TestAutoPagination(t *testing.T) { option.WithBaseURL(baseURL), option.WithAccessToken("AccessToken"), ) - iter := client.HRIS.Directory.ListIndividualsAutoPaging(context.TODO(), finchgo.HRISDirectoryListIndividualsParams{}) + iter := client.HRIS.Directory.ListAutoPaging(context.TODO(), finchgo.HRISDirectoryListParams{}) // Prism mock isn't going to give us real pagination for i := 0; i < 3 && iter.Next(); i++ { directory := iter.Current() diff --git a/paginationmanual_test.go b/paginationmanual_test.go index b29f012..4c5e41c 100644 --- a/paginationmanual_test.go +++ b/paginationmanual_test.go @@ -24,7 +24,7 @@ func TestManualPagination(t *testing.T) { option.WithBaseURL(baseURL), option.WithAccessToken("AccessToken"), ) - page, err := client.HRIS.Directory.ListIndividuals(context.TODO(), finchgo.HRISDirectoryListIndividualsParams{}) + page, err := client.HRIS.Directory.List(context.TODO(), finchgo.HRISDirectoryListParams{}) if err != nil { t.Fatalf("err should be nil: %s", err.Error()) } diff --git a/usage_test.go b/usage_test.go index 1cfda3d..a957e94 100644 --- a/usage_test.go +++ b/usage_test.go @@ -24,7 +24,7 @@ func TestUsage(t *testing.T) { option.WithBaseURL(baseURL), option.WithAccessToken("AccessToken"), ) - page, err := client.HRIS.Directory.ListIndividuals(context.TODO(), finchgo.HRISDirectoryListIndividualsParams{}) + page, err := client.HRIS.Directory.List(context.TODO(), finchgo.HRISDirectoryListParams{}) if err != nil { t.Error(err) }