From 3a2cdfa1acd3082c96b6ccfefea742dfaab7361e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 15 May 2026 17:53:53 +0000 Subject: [PATCH 1/2] feat(api): add enroll many --- .stats.yml | 6 +- api.md | 2 + hrisbenefitindividual.go | 170 ++++++++++++++++++++++++++++++++++ hrisbenefitindividual_test.go | 52 +++++++++++ 4 files changed, 227 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index b9153e4..2bdeb15 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 47 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/finch/finch-5092370ef89959c46138a85f9d6d3c919682a5492a0f9f85ac4421de702f35a8.yml +configured_endpoints: 48 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/finch/finch-8a983c70d7cbbc4023463a85ebdabcee1645603ab46337aa9cfa18f1872f0ae1.yml openapi_spec_hash: a4ca94b3405fc83934c949068943e16c -config_hash: a1c4b7d897cbf8ed42c5f474b3161d79 +config_hash: 812b56df3e506bc2af056b2898327b8a diff --git a/api.md b/api.md index 4e3b557..7f3b6c2 100644 --- a/api.md +++ b/api.md @@ -179,12 +179,14 @@ Methods: Response Types: +- finchgo.EnrolledIndividualBenefitResponse - finchgo.IndividualBenefit - finchgo.UnenrolledIndividualBenefitResponse - finchgo.HRISBenefitIndividualEnrolledIDsResponse Methods: +- client.HRIS.Benefits.Individuals.EnrollMany(ctx context.Context, benefitID string, params finchgo.HRISBenefitIndividualEnrollManyParams) (\*finchgo.EnrolledIndividualBenefitResponse, error) - client.HRIS.Benefits.Individuals.EnrolledIDs(ctx context.Context, benefitID string, query finchgo.HRISBenefitIndividualEnrolledIDsParams) (\*finchgo.HRISBenefitIndividualEnrolledIDsResponse, error) - client.HRIS.Benefits.Individuals.GetManyBenefits(ctx context.Context, benefitID string, query finchgo.HRISBenefitIndividualGetManyBenefitsParams) (\*pagination.SinglePage[finchgo.IndividualBenefit], error) - client.HRIS.Benefits.Individuals.UnenrollMany(ctx context.Context, benefitID string, params finchgo.HRISBenefitIndividualUnenrollManyParams) (\*finchgo.UnenrolledIndividualBenefitResponse, error) diff --git a/hrisbenefitindividual.go b/hrisbenefitindividual.go index 9d13938..35417a4 100644 --- a/hrisbenefitindividual.go +++ b/hrisbenefitindividual.go @@ -10,6 +10,7 @@ import ( "net/url" "reflect" "slices" + "time" "github.com/Finch-API/finch-api-go/internal/apijson" "github.com/Finch-API/finch-api-go/internal/apiquery" @@ -39,6 +40,22 @@ func NewHRISBenefitIndividualService(opts ...option.RequestOption) (r *HRISBenef return } +// Enroll an individual into a deduction or contribution. This is an overwrite +// operation. If the employee is already enrolled, the enrollment amounts will be +// adjusted. Making the same request multiple times will not create new +// enrollments, but will continue to set the state of the existing enrollment. +func (r *HRISBenefitIndividualService) EnrollMany(ctx context.Context, benefitID string, params HRISBenefitIndividualEnrollManyParams, opts ...option.RequestOption) (res *EnrolledIndividualBenefitResponse, err error) { + var preClientOpts = []option.RequestOption{requestconfig.WithBearerAuthSecurity()} + opts = slices.Concat(preClientOpts, r.Options, opts) + if benefitID == "" { + err = errors.New("missing required benefit_id parameter") + return nil, err + } + path := fmt.Sprintf("employer/benefits/%s/individuals", benefitID) + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...) + return res, err +} + // Lists individuals currently enrolled in a given deduction. func (r *HRISBenefitIndividualService) EnrolledIDs(ctx context.Context, benefitID string, query HRISBenefitIndividualEnrolledIDsParams, opts ...option.RequestOption) (res *HRISBenefitIndividualEnrolledIDsResponse, err error) { var preClientOpts = []option.RequestOption{requestconfig.WithBearerAuthSecurity()} @@ -93,6 +110,27 @@ func (r *HRISBenefitIndividualService) UnenrollMany(ctx context.Context, benefit return res, err } +type EnrolledIndividualBenefitResponse struct { + JobID string `json:"job_id" api:"required" format:"uuid"` + JSON enrolledIndividualBenefitResponseJSON `json:"-"` +} + +// enrolledIndividualBenefitResponseJSON contains the JSON metadata for the struct +// [EnrolledIndividualBenefitResponse] +type enrolledIndividualBenefitResponseJSON struct { + JobID apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *EnrolledIndividualBenefitResponse) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r enrolledIndividualBenefitResponseJSON) RawJSON() string { + return r.raw +} + type IndividualBenefit struct { Body IndividualBenefitBody `json:"body" api:"required"` Code int64 `json:"code" api:"required"` @@ -796,6 +834,138 @@ func (r hrisBenefitIndividualEnrolledIDsResponseJSON) RawJSON() string { return r.raw } +type HRISBenefitIndividualEnrollManyParams struct { + // The entity IDs to specify which entities' data to access. + EntityIDs param.Field[[]string] `query:"entity_ids" format:"uuid"` + // Array of the individual_id to enroll and a configuration object. + Individuals []HRISBenefitIndividualEnrollManyParamsIndividual `json:"individuals"` +} + +func (r HRISBenefitIndividualEnrollManyParams) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r.Individuals) +} + +// URLQuery serializes [HRISBenefitIndividualEnrollManyParams]'s query parameters +// as `url.Values`. +func (r HRISBenefitIndividualEnrollManyParams) URLQuery() (v url.Values) { + return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ + ArrayFormat: apiquery.ArrayQueryFormatBrackets, + NestedFormat: apiquery.NestedQueryFormatBrackets, + }) +} + +type HRISBenefitIndividualEnrollManyParamsIndividual struct { + Configuration param.Field[HRISBenefitIndividualEnrollManyParamsIndividualsConfiguration] `json:"configuration"` + // Finch id (uuidv4) for the individual to enroll + IndividualID param.Field[string] `json:"individual_id"` +} + +func (r HRISBenefitIndividualEnrollManyParamsIndividual) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type HRISBenefitIndividualEnrollManyParamsIndividualsConfiguration struct { + // For HSA benefits only - whether the contribution limit is for an individual or + // family + AnnualContributionLimit param.Field[HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationAnnualContributionLimit] `json:"annual_contribution_limit"` + // Maximum annual amount in cents + AnnualMaximum param.Field[int64] `json:"annual_maximum"` + // For retirement benefits only - whether catch up contributions are enabled + CatchUp param.Field[bool] `json:"catch_up"` + CompanyContribution param.Field[HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContribution] `json:"company_contribution"` + // The date the enrollment will take effect + EffectiveDate param.Field[time.Time] `json:"effective_date" format:"date"` + EmployeeDeduction param.Field[HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationEmployeeDeduction] `json:"employee_deduction"` +} + +func (r HRISBenefitIndividualEnrollManyParamsIndividualsConfiguration) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +// For HSA benefits only - whether the contribution limit is for an individual or +// family +type HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationAnnualContributionLimit string + +const ( + HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationAnnualContributionLimitIndividual HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationAnnualContributionLimit = "individual" + HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationAnnualContributionLimitFamily HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationAnnualContributionLimit = "family" +) + +func (r HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationAnnualContributionLimit) IsKnown() bool { + switch r { + case HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationAnnualContributionLimitIndividual, HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationAnnualContributionLimitFamily: + return true + } + return false +} + +type HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContribution struct { + // Amount in cents for fixed type or basis points (1/100th of a percent) for + // percent type + Amount param.Field[int64] `json:"amount"` + // Array of tier objects for tiered contribution matching (required when type is + // tiered) + Tiers param.Field[[]HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContributionTier] `json:"tiers"` + Type param.Field[HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContributionType] `json:"type"` +} + +func (r HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContribution) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContributionTier struct { + // The employer match percentage in basis points (0-10000 = 0-100%) + Match param.Field[int64] `json:"match" api:"required"` + // The employee contribution threshold in basis points (0-10000 = 0-100%) + Threshold param.Field[int64] `json:"threshold" api:"required"` +} + +func (r HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContributionTier) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContributionType string + +const ( + HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContributionTypeFixed HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContributionType = "fixed" + HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContributionTypePercent HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContributionType = "percent" + HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContributionTypeTiered HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContributionType = "tiered" +) + +func (r HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContributionType) IsKnown() bool { + switch r { + case HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContributionTypeFixed, HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContributionTypePercent, HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContributionTypeTiered: + return true + } + return false +} + +type HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationEmployeeDeduction struct { + // Amount in cents for fixed type or basis points (1/100th of a percent) for + // percent type + Amount param.Field[int64] `json:"amount"` + Type param.Field[HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationEmployeeDeductionType] `json:"type"` +} + +func (r HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationEmployeeDeduction) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + +type HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationEmployeeDeductionType string + +const ( + HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationEmployeeDeductionTypeFixed HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationEmployeeDeductionType = "fixed" + HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationEmployeeDeductionTypePercent HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationEmployeeDeductionType = "percent" +) + +func (r HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationEmployeeDeductionType) IsKnown() bool { + switch r { + case HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationEmployeeDeductionTypeFixed, HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationEmployeeDeductionTypePercent: + return true + } + return false +} + type HRISBenefitIndividualEnrolledIDsParams struct { // The entity IDs to specify which entities' data to access. EntityIDs param.Field[[]string] `query:"entity_ids" format:"uuid"` diff --git a/hrisbenefitindividual_test.go b/hrisbenefitindividual_test.go index a0aaff0..df4e4b2 100644 --- a/hrisbenefitindividual_test.go +++ b/hrisbenefitindividual_test.go @@ -7,12 +7,64 @@ import ( "errors" "os" "testing" + "time" "github.com/Finch-API/finch-api-go" "github.com/Finch-API/finch-api-go/internal/testutil" "github.com/Finch-API/finch-api-go/option" ) +func TestHRISBenefitIndividualEnrollManyWithOptionalParams(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("My Access Token"), + option.WithClientID("4ab15e51-11ad-49f4-acae-f343b7794375"), + option.WithClientSecret("My Client Secret"), + ) + _, err := client.HRIS.Benefits.Individuals.EnrollMany( + context.TODO(), + "benefit_id", + finchgo.HRISBenefitIndividualEnrollManyParams{ + EntityIDs: finchgo.F([]string{"550e8400-e29b-41d4-a716-446655440000"}), + Individuals: []finchgo.HRISBenefitIndividualEnrollManyParamsIndividual{{ + Configuration: finchgo.F(finchgo.HRISBenefitIndividualEnrollManyParamsIndividualsConfiguration{ + AnnualContributionLimit: finchgo.F(finchgo.HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationAnnualContributionLimitIndividual), + AnnualMaximum: finchgo.Null[int64](), + CatchUp: finchgo.F(true), + CompanyContribution: finchgo.F(finchgo.HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContribution{ + Amount: finchgo.F(int64(0)), + Tiers: finchgo.F([]finchgo.HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContributionTier{{ + Match: finchgo.F(int64(0)), + Threshold: finchgo.F(int64(0)), + }}), + Type: finchgo.F(finchgo.HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationCompanyContributionTypeFixed), + }), + EffectiveDate: finchgo.F(time.Now()), + EmployeeDeduction: finchgo.F(finchgo.HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationEmployeeDeduction{ + Amount: finchgo.F(int64(10000)), + Type: finchgo.F(finchgo.HRISBenefitIndividualEnrollManyParamsIndividualsConfigurationEmployeeDeductionTypeFixed), + }), + }), + IndividualID: finchgo.F("d02a6346-1f08-4312-a064-49ff3cafaa7a"), + }}, + }, + ) + 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 TestHRISBenefitIndividualEnrolledIDsWithOptionalParams(t *testing.T) { baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { From f431b39c5bf92f517e1814d51d6e74cc4f7089da Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 15 May 2026 17:54:18 +0000 Subject: [PATCH 2/2] release: 1.36.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ README.md | 2 +- internal/version.go | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 44959ac..f29e96b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.35.0" + ".": "1.36.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index cd6d398..8d19304 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.36.0 (2026-05-15) + +Full Changelog: [v1.35.0...v1.36.0](https://github.com/Finch-API/finch-api-go/compare/v1.35.0...v1.36.0) + +### Features + +* **api:** add enroll many ([3a2cdfa](https://github.com/Finch-API/finch-api-go/commit/3a2cdfa1acd3082c96b6ccfefea742dfaab7361e)) + ## 1.35.0 (2026-05-13) Full Changelog: [v1.34.1...v1.35.0](https://github.com/Finch-API/finch-api-go/compare/v1.34.1...v1.35.0) diff --git a/README.md b/README.md index 58c4055..77ce6c5 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Or to pin the version: ```sh -go get -u 'github.com/Finch-API/finch-api-go@v1.35.0' +go get -u 'github.com/Finch-API/finch-api-go@v1.36.0' ``` diff --git a/internal/version.go b/internal/version.go index 33b1bc6..d6caaff 100644 --- a/internal/version.go +++ b/internal/version.go @@ -2,4 +2,4 @@ package internal -const PackageVersion = "1.35.0" // x-release-please-version +const PackageVersion = "1.36.0" // x-release-please-version