diff --git a/company_assisted.go b/company_assisted.go new file mode 100644 index 00000000..bdd3cab8 --- /dev/null +++ b/company_assisted.go @@ -0,0 +1,178 @@ +// Non-generated wrapper for /employer/company endpoint to handle 202 responses from assisted connections. +// This file will not be overwritten by codegen. + +package finchgo + +import ( + "context" + "net/http" + "reflect" + "slices" + + "github.com/Finch-API/finch-api-go/internal/apijson" + "github.com/Finch-API/finch-api-go/internal/requestconfig" + "github.com/Finch-API/finch-api-go/option" + "github.com/tidwall/gjson" +) + +// GetWithAssistedSupport reads basic company data with support for 202 responses +// from assisted connections. Returns a union type that can be either: +// - Company (200 OK with Company data) +// - CompanyDataSyncInProgress (202 Accepted with sync status) +func (r *HRISCompanyService) GetWithAssistedSupport(ctx context.Context, opts ...option.RequestOption) (res *CompanyResponse, err error) { + opts = slices.Concat(r.Options, opts) + path := "employer/company" + err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) + return +} + +// CompanyResponse is the union wrapper for response variants +type CompanyResponse struct { + Code float64 `json:"code"` + FinchCode string `json:"finch_code"` + Message string `json:"message"` + Name string `json:"name"` + JSON companyResponseJSON `json:"-"` + union CompanyResponseUnion +} + +// companyResponseJSON contains the JSON metadata for the struct [CompanyResponse] +type companyResponseJSON struct { + Code apijson.Field + FinchCode apijson.Field + Message apijson.Field + Name apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r companyResponseJSON) RawJSON() string { + return r.raw +} + +func (r *CompanyResponse) UnmarshalJSON(data []byte) (err error) { + *r = CompanyResponse{} + err = apijson.UnmarshalRoot(data, &r.union) + if err != nil { + return err + } + return apijson.Port(r.union, &r) +} + +// AsUnion returns a [CompanyResponseUnion] interface which you can cast +// to the specific types for more type safety. +// +// Possible runtime types of the union are [Company], +// [CompanyDataSyncInProgress]. +func (r CompanyResponse) AsUnion() CompanyResponseUnion { + return r.union +} + +// Union satisfied by [Company] or [CompanyDataSyncInProgress]. +type CompanyResponseUnion interface { + implementsCompanyResponse() +} + +func init() { + apijson.RegisterUnion( + reflect.TypeOf((*CompanyResponseUnion)(nil)).Elem(), + "code", + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(Company{}), + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(CompanyDataSyncInProgress{}), + }, + ) +} + +// Make Company satisfy the union interface +func (r Company) implementsCompanyResponse() {} + +// CompanyDataSyncInProgress represents a 202 response when data sync is in progress +type CompanyDataSyncInProgress struct { + Code CompanyDataSyncInProgressCode `json:"code,required"` + FinchCode CompanyDataSyncInProgressFinchCode `json:"finch_code,required"` + Message CompanyDataSyncInProgressMessage `json:"message,required"` + Name CompanyDataSyncInProgressName `json:"name,required"` + JSON companyDataSyncInProgressJSON `json:"-"` +} + +// companyDataSyncInProgressJSON contains the JSON metadata for the struct +// [CompanyDataSyncInProgress] +type companyDataSyncInProgressJSON struct { + Code apijson.Field + FinchCode apijson.Field + Message apijson.Field + Name apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *CompanyDataSyncInProgress) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r companyDataSyncInProgressJSON) RawJSON() string { + return r.raw +} + +func (r CompanyDataSyncInProgress) implementsCompanyResponse() {} + +type CompanyDataSyncInProgressCode float64 + +const ( + CompanyDataSyncInProgressCode202 CompanyDataSyncInProgressCode = 202 +) + +func (r CompanyDataSyncInProgressCode) IsKnown() bool { + switch r { + case CompanyDataSyncInProgressCode202: + return true + } + return false +} + +type CompanyDataSyncInProgressFinchCode string + +const ( + CompanyDataSyncInProgressFinchCodeDataSyncInProgress CompanyDataSyncInProgressFinchCode = "data_sync_in_progress" +) + +func (r CompanyDataSyncInProgressFinchCode) IsKnown() bool { + switch r { + case CompanyDataSyncInProgressFinchCodeDataSyncInProgress: + return true + } + return false +} + +type CompanyDataSyncInProgressMessage string + +const ( + CompanyDataSyncInProgressMessageTheCompanyDataIsBeingFetchedPleaseCheckBackLater CompanyDataSyncInProgressMessage = "The company data is being fetched. Please check back later." +) + +func (r CompanyDataSyncInProgressMessage) IsKnown() bool { + switch r { + case CompanyDataSyncInProgressMessageTheCompanyDataIsBeingFetchedPleaseCheckBackLater: + return true + } + return false +} + +type CompanyDataSyncInProgressName string + +const ( + CompanyDataSyncInProgressNameAccepted CompanyDataSyncInProgressName = "accepted" +) + +func (r CompanyDataSyncInProgressName) IsKnown() bool { + switch r { + case CompanyDataSyncInProgressNameAccepted: + return true + } + return false +} diff --git a/company_assisted_test.go b/company_assisted_test.go new file mode 100644 index 00000000..b1a868b8 --- /dev/null +++ b/company_assisted_test.go @@ -0,0 +1,113 @@ +package finchgo_test + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + finchgo "github.com/Finch-API/finch-api-go" + "github.com/Finch-API/finch-api-go/option" +) + +func TestCompanyGetWithAssistedSupport_200Response(t *testing.T) { + // Mock server that returns 200 with Company data + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/employer/company" { + t.Errorf("Expected path /employer/company, got %s", r.URL.Path) + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + resp := map[string]interface{}{ + "id": "12345678-1234-1234-1234-123456789012", + "legal_name": "Test Company LLC", + "ein": "12-3456789", + "primary_email": "test@example.com", + "primary_phone_number": "+11234567890", + "entity": map[string]interface{}{ + "type": "llc", + "subtype": nil, + }, + "locations": []interface{}{}, + "accounts": []interface{}{}, + "departments": []interface{}{}, + } + json.NewEncoder(w).Encode(resp) + })) + defer server.Close() + + client := finchgo.NewClient( + option.WithAccessToken("test-token"), + option.WithBaseURL(server.URL), + ) + + resp, err := client.HRIS.Company.GetWithAssistedSupport(context.Background()) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + // Check that we got a Company response + switch u := resp.AsUnion().(type) { + case finchgo.Company: + if u.ID != "12345678-1234-1234-1234-123456789012" { + t.Errorf("Expected ID 12345678-1234-1234-1234-123456789012, got %s", u.ID) + } + if u.LegalName != "Test Company LLC" { + t.Errorf("Expected LegalName 'Test Company LLC', got %s", u.LegalName) + } + case finchgo.CompanyDataSyncInProgress: + t.Fatalf("Expected Company, got CompanyDataSyncInProgress") + default: + t.Fatalf("Unexpected union type: %T", u) + } +} + +func TestCompanyGetWithAssistedSupport_202Response(t *testing.T) { + // Mock server that returns 202 with sync status + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/employer/company" { + t.Errorf("Expected path /employer/company, got %s", r.URL.Path) + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) // SDK doesn't check HTTP status, relies on body + resp := map[string]interface{}{ + "code": 202, + "finch_code": "data_sync_in_progress", + "message": "The company data is being fetched. Please check back later.", + "name": "accepted", + } + json.NewEncoder(w).Encode(resp) + })) + defer server.Close() + + client := finchgo.NewClient( + option.WithAccessToken("test-token"), + option.WithBaseURL(server.URL), + ) + + resp, err := client.HRIS.Company.GetWithAssistedSupport(context.Background()) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + // Check that we got a CompanyDataSyncInProgress response + switch u := resp.AsUnion().(type) { + case finchgo.Company: + t.Fatalf("Expected CompanyDataSyncInProgress, got Company") + case finchgo.CompanyDataSyncInProgress: + if u.Code != finchgo.CompanyDataSyncInProgressCode202 { + t.Errorf("Expected Code 202, got %v", u.Code) + } + if u.FinchCode != finchgo.CompanyDataSyncInProgressFinchCodeDataSyncInProgress { + t.Errorf("Expected FinchCode 'data_sync_in_progress', got %s", u.FinchCode) + } + if u.Name != finchgo.CompanyDataSyncInProgressNameAccepted { + t.Errorf("Expected Name 'accepted', got %s", u.Name) + } + default: + t.Fatalf("Unexpected union type: %T", u) + } +} diff --git a/examples/company_assisted/main.go b/examples/company_assisted/main.go new file mode 100644 index 00000000..e1795010 --- /dev/null +++ b/examples/company_assisted/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "context" + "fmt" + "os" + + finchgo "github.com/Finch-API/finch-api-go" + "github.com/Finch-API/finch-api-go/option" +) + +func main() { + client := finchgo.NewClient( + option.WithAccessToken(os.Getenv("FINCH_ACCESS_TOKEN")), + ) + + resp, err := client.HRIS.Company.GetWithAssistedSupport(context.Background()) + if err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } + + // Handle the union response + switch u := resp.AsUnion().(type) { + case finchgo.Company: + // 200 OK - Company data is ready + fmt.Printf("Company ID: %s\n", u.ID) + fmt.Printf("Legal Name: %s\n", u.LegalName) + fmt.Printf("EIN: %s\n", u.Ein) + fmt.Printf("Primary Email: %s\n", u.PrimaryEmail) + + case finchgo.CompanyDataSyncInProgress: + // 202 Accepted - Data sync in progress + fmt.Printf("Status: %s (code %v)\n", u.Name, u.Code) + fmt.Printf("Message: %s\n", u.Message) + fmt.Printf("Finch Code: %s\n", u.FinchCode) + fmt.Println("\nPlease retry this request later. Data is still syncing from the provider.") + + default: + fmt.Fprintf(os.Stderr, "Unexpected response type: %T\n", u) + os.Exit(1) + } +}