From d0dfad021d7fc84525e196c72ae343e8cb9f9622 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 7 Jan 2025 19:44:16 +0000
Subject: [PATCH] feat(api): manual updates
---
.stats.yml | 2 +-
api.md | 19 ++
src/finch/resources/hris/__init__.py | 14 +
src/finch/resources/hris/documents.py | 310 ++++++++++++++++++
src/finch/resources/hris/hris.py | 32 ++
src/finch/types/hris/__init__.py | 6 +
src/finch/types/hris/document_list_params.py | 28 ++
.../types/hris/document_list_response.py | 15 +
src/finch/types/hris/document_response.py | 31 ++
.../types/hris/document_retreive_response.py | 12 +
src/finch/types/hris/w42005.py | 36 ++
src/finch/types/hris/w42020.py | 54 +++
tests/api_resources/hris/test_documents.py | 168 ++++++++++
13 files changed, 726 insertions(+), 1 deletion(-)
create mode 100644 src/finch/resources/hris/documents.py
create mode 100644 src/finch/types/hris/document_list_params.py
create mode 100644 src/finch/types/hris/document_list_response.py
create mode 100644 src/finch/types/hris/document_response.py
create mode 100644 src/finch/types/hris/document_retreive_response.py
create mode 100644 src/finch/types/hris/w42005.py
create mode 100644 src/finch/types/hris/w42020.py
create mode 100644 tests/api_resources/hris/test_documents.py
diff --git a/.stats.yml b/.stats.yml
index 429b6e48..d70f0f4c 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,2 +1,2 @@
-configured_endpoints: 39
+configured_endpoints: 41
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/finch%2Ffinch-cf610d4dbb7e3d84161b5783a0861b2e551422eb5cf727dde86a839325d7ef76.yml
diff --git a/api.md b/api.md
index f611006b..b113706c 100644
--- a/api.md
+++ b/api.md
@@ -96,6 +96,25 @@ Methods:
- client.hris.pay_statements.retrieve_many(\*\*params) -> SyncResponsesPage[PayStatementResponse]
+## Documents
+
+Types:
+
+```python
+from finch.types.hris import (
+ DocumentResponse,
+ W42005,
+ W42020,
+ DocumentListResponse,
+ DocumentRetreiveResponse,
+)
+```
+
+Methods:
+
+- client.hris.documents.list(\*\*params) -> DocumentListResponse
+- client.hris.documents.retreive(document_id) -> DocumentRetreiveResponse
+
## Benefits
Types:
diff --git a/src/finch/resources/hris/__init__.py b/src/finch/resources/hris/__init__.py
index 969b31f5..5a795829 100644
--- a/src/finch/resources/hris/__init__.py
+++ b/src/finch/resources/hris/__init__.py
@@ -40,6 +40,14 @@
DirectoryWithStreamingResponse,
AsyncDirectoryWithStreamingResponse,
)
+from .documents import (
+ Documents,
+ AsyncDocuments,
+ DocumentsWithRawResponse,
+ AsyncDocumentsWithRawResponse,
+ DocumentsWithStreamingResponse,
+ AsyncDocumentsWithStreamingResponse,
+)
from .employments import (
Employments,
AsyncEmployments,
@@ -102,6 +110,12 @@
"AsyncPayStatementsWithRawResponse",
"PayStatementsWithStreamingResponse",
"AsyncPayStatementsWithStreamingResponse",
+ "Documents",
+ "AsyncDocuments",
+ "DocumentsWithRawResponse",
+ "AsyncDocumentsWithRawResponse",
+ "DocumentsWithStreamingResponse",
+ "AsyncDocumentsWithStreamingResponse",
"Benefits",
"AsyncBenefits",
"BenefitsWithRawResponse",
diff --git a/src/finch/resources/hris/documents.py b/src/finch/resources/hris/documents.py
new file mode 100644
index 00000000..8ce6892c
--- /dev/null
+++ b/src/finch/resources/hris/documents.py
@@ -0,0 +1,310 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Any, List, cast
+from typing_extensions import Literal
+
+import httpx
+
+from ... import _legacy_response
+from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ..._utils import (
+ maybe_transform,
+ async_maybe_transform,
+)
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
+from ...types.hris import document_list_params
+from ..._base_client import make_request_options
+from ...types.hris.document_list_response import DocumentListResponse
+from ...types.hris.document_retreive_response import DocumentRetreiveResponse
+
+__all__ = ["Documents", "AsyncDocuments"]
+
+
+class Documents(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> DocumentsWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return the
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/Finch-API/finch-api-python#accessing-raw-response-data-eg-headers
+ """
+ return DocumentsWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> DocumentsWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/Finch-API/finch-api-python#with_streaming_response
+ """
+ return DocumentsWithStreamingResponse(self)
+
+ def list(
+ self,
+ *,
+ individual_ids: List[str] | NotGiven = NOT_GIVEN,
+ limit: int | NotGiven = NOT_GIVEN,
+ offset: int | NotGiven = NOT_GIVEN,
+ types: List[Literal["w4_2020", "w4_2005"]] | NotGiven = NOT_GIVEN,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> DocumentListResponse:
+ """**Beta:** This endpoint is in beta and may change.
+
+
+ Retrieve a list of company-wide documents.
+
+ Args:
+ individual_ids: Comma-delimited list of stable Finch uuids for each individual. If empty,
+ defaults to all individuals
+
+ limit: Number of documents to return (defaults to all)
+
+ offset: Index to start from (defaults to 0)
+
+ types: Comma-delimited list of document types to filter on. If empty, defaults to all
+ types
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get(
+ "/employer/documents",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "individual_ids": individual_ids,
+ "limit": limit,
+ "offset": offset,
+ "types": types,
+ },
+ document_list_params.DocumentListParams,
+ ),
+ ),
+ cast_to=DocumentListResponse,
+ )
+
+ def retreive(
+ self,
+ document_id: str,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> DocumentRetreiveResponse:
+ """**Beta:** This endpoint is in beta and may change.
+
+
+ Retrieve details of a specific document by its ID.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not document_id:
+ raise ValueError(f"Expected a non-empty value for `document_id` but received {document_id!r}")
+ return cast(
+ DocumentRetreiveResponse,
+ self._get(
+ f"/employer/documents/{document_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, DocumentRetreiveResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+
+class AsyncDocuments(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncDocumentsWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return the
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/Finch-API/finch-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncDocumentsWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncDocumentsWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/Finch-API/finch-api-python#with_streaming_response
+ """
+ return AsyncDocumentsWithStreamingResponse(self)
+
+ async def list(
+ self,
+ *,
+ individual_ids: List[str] | NotGiven = NOT_GIVEN,
+ limit: int | NotGiven = NOT_GIVEN,
+ offset: int | NotGiven = NOT_GIVEN,
+ types: List[Literal["w4_2020", "w4_2005"]] | NotGiven = NOT_GIVEN,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> DocumentListResponse:
+ """**Beta:** This endpoint is in beta and may change.
+
+
+ Retrieve a list of company-wide documents.
+
+ Args:
+ individual_ids: Comma-delimited list of stable Finch uuids for each individual. If empty,
+ defaults to all individuals
+
+ limit: Number of documents to return (defaults to all)
+
+ offset: Index to start from (defaults to 0)
+
+ types: Comma-delimited list of document types to filter on. If empty, defaults to all
+ types
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._get(
+ "/employer/documents",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "individual_ids": individual_ids,
+ "limit": limit,
+ "offset": offset,
+ "types": types,
+ },
+ document_list_params.DocumentListParams,
+ ),
+ ),
+ cast_to=DocumentListResponse,
+ )
+
+ async def retreive(
+ self,
+ document_id: str,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> DocumentRetreiveResponse:
+ """**Beta:** This endpoint is in beta and may change.
+
+
+ Retrieve details of a specific document by its ID.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not document_id:
+ raise ValueError(f"Expected a non-empty value for `document_id` but received {document_id!r}")
+ return cast(
+ DocumentRetreiveResponse,
+ await self._get(
+ f"/employer/documents/{document_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, DocumentRetreiveResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+
+class DocumentsWithRawResponse:
+ def __init__(self, documents: Documents) -> None:
+ self._documents = documents
+
+ self.list = _legacy_response.to_raw_response_wrapper(
+ documents.list,
+ )
+ self.retreive = _legacy_response.to_raw_response_wrapper(
+ documents.retreive,
+ )
+
+
+class AsyncDocumentsWithRawResponse:
+ def __init__(self, documents: AsyncDocuments) -> None:
+ self._documents = documents
+
+ self.list = _legacy_response.async_to_raw_response_wrapper(
+ documents.list,
+ )
+ self.retreive = _legacy_response.async_to_raw_response_wrapper(
+ documents.retreive,
+ )
+
+
+class DocumentsWithStreamingResponse:
+ def __init__(self, documents: Documents) -> None:
+ self._documents = documents
+
+ self.list = to_streamed_response_wrapper(
+ documents.list,
+ )
+ self.retreive = to_streamed_response_wrapper(
+ documents.retreive,
+ )
+
+
+class AsyncDocumentsWithStreamingResponse:
+ def __init__(self, documents: AsyncDocuments) -> None:
+ self._documents = documents
+
+ self.list = async_to_streamed_response_wrapper(
+ documents.list,
+ )
+ self.retreive = async_to_streamed_response_wrapper(
+ documents.retreive,
+ )
diff --git a/src/finch/resources/hris/hris.py b/src/finch/resources/hris/hris.py
index abbd52fd..32b91c31 100644
--- a/src/finch/resources/hris/hris.py
+++ b/src/finch/resources/hris/hris.py
@@ -27,6 +27,14 @@
DirectoryWithStreamingResponse,
AsyncDirectoryWithStreamingResponse,
)
+from .documents import (
+ Documents,
+ AsyncDocuments,
+ DocumentsWithRawResponse,
+ AsyncDocumentsWithRawResponse,
+ DocumentsWithStreamingResponse,
+ AsyncDocumentsWithStreamingResponse,
+)
from ..._resource import SyncAPIResource, AsyncAPIResource
from .employments import (
Employments,
@@ -89,6 +97,10 @@ def payments(self) -> Payments:
def pay_statements(self) -> PayStatements:
return PayStatements(self._client)
+ @cached_property
+ def documents(self) -> Documents:
+ return Documents(self._client)
+
@cached_property
def benefits(self) -> Benefits:
return Benefits(self._client)
@@ -138,6 +150,10 @@ def payments(self) -> AsyncPayments:
def pay_statements(self) -> AsyncPayStatements:
return AsyncPayStatements(self._client)
+ @cached_property
+ def documents(self) -> AsyncDocuments:
+ return AsyncDocuments(self._client)
+
@cached_property
def benefits(self) -> AsyncBenefits:
return AsyncBenefits(self._client)
@@ -190,6 +206,10 @@ def payments(self) -> PaymentsWithRawResponse:
def pay_statements(self) -> PayStatementsWithRawResponse:
return PayStatementsWithRawResponse(self._hris.pay_statements)
+ @cached_property
+ def documents(self) -> DocumentsWithRawResponse:
+ return DocumentsWithRawResponse(self._hris.documents)
+
@cached_property
def benefits(self) -> BenefitsWithRawResponse:
return BenefitsWithRawResponse(self._hris.benefits)
@@ -223,6 +243,10 @@ def payments(self) -> AsyncPaymentsWithRawResponse:
def pay_statements(self) -> AsyncPayStatementsWithRawResponse:
return AsyncPayStatementsWithRawResponse(self._hris.pay_statements)
+ @cached_property
+ def documents(self) -> AsyncDocumentsWithRawResponse:
+ return AsyncDocumentsWithRawResponse(self._hris.documents)
+
@cached_property
def benefits(self) -> AsyncBenefitsWithRawResponse:
return AsyncBenefitsWithRawResponse(self._hris.benefits)
@@ -256,6 +280,10 @@ def payments(self) -> PaymentsWithStreamingResponse:
def pay_statements(self) -> PayStatementsWithStreamingResponse:
return PayStatementsWithStreamingResponse(self._hris.pay_statements)
+ @cached_property
+ def documents(self) -> DocumentsWithStreamingResponse:
+ return DocumentsWithStreamingResponse(self._hris.documents)
+
@cached_property
def benefits(self) -> BenefitsWithStreamingResponse:
return BenefitsWithStreamingResponse(self._hris.benefits)
@@ -289,6 +317,10 @@ def payments(self) -> AsyncPaymentsWithStreamingResponse:
def pay_statements(self) -> AsyncPayStatementsWithStreamingResponse:
return AsyncPayStatementsWithStreamingResponse(self._hris.pay_statements)
+ @cached_property
+ def documents(self) -> AsyncDocumentsWithStreamingResponse:
+ return AsyncDocumentsWithStreamingResponse(self._hris.documents)
+
@cached_property
def benefits(self) -> AsyncBenefitsWithStreamingResponse:
return AsyncBenefitsWithStreamingResponse(self._hris.benefits)
diff --git a/src/finch/types/hris/__init__.py b/src/finch/types/hris/__init__.py
index 75802659..40744f3e 100644
--- a/src/finch/types/hris/__init__.py
+++ b/src/finch/types/hris/__init__.py
@@ -2,6 +2,8 @@
from __future__ import annotations
+from .w42005 import W42005 as W42005
+from .w42020 import W42020 as W42020
from .company import Company as Company
from .payment import Payment as Payment
from .individual import Individual as Individual
@@ -11,18 +13,22 @@
from .employment_data import EmploymentData as EmploymentData
from .benefits_support import BenefitsSupport as BenefitsSupport
from .benefit_frequency import BenefitFrequency as BenefitFrequency
+from .document_response import DocumentResponse as DocumentResponse
from .supported_benefit import SupportedBenefit as SupportedBenefit
from .benfit_contribution import BenfitContribution as BenfitContribution
from .individual_response import IndividualResponse as IndividualResponse
from .payment_list_params import PaymentListParams as PaymentListParams
from .benefit_contribution import BenefitContribution as BenefitContribution
+from .document_list_params import DocumentListParams as DocumentListParams
from .benefit_create_params import BenefitCreateParams as BenefitCreateParams
from .benefit_update_params import BenefitUpdateParams as BenefitUpdateParams
from .directory_list_params import DirectoryListParams as DirectoryListParams
+from .document_list_response import DocumentListResponse as DocumentListResponse
from .pay_statement_response import PayStatementResponse as PayStatementResponse
from .individual_in_directory import IndividualInDirectory as IndividualInDirectory
from .employment_data_response import EmploymentDataResponse as EmploymentDataResponse
from .support_per_benefit_type import SupportPerBenefitType as SupportPerBenefitType
+from .document_retreive_response import DocumentRetreiveResponse as DocumentRetreiveResponse
from .pay_statement_response_body import PayStatementResponseBody as PayStatementResponseBody
from .benefit_features_and_operations import BenefitFeaturesAndOperations as BenefitFeaturesAndOperations
from .employment_retrieve_many_params import EmploymentRetrieveManyParams as EmploymentRetrieveManyParams
diff --git a/src/finch/types/hris/document_list_params.py b/src/finch/types/hris/document_list_params.py
new file mode 100644
index 00000000..15fff861
--- /dev/null
+++ b/src/finch/types/hris/document_list_params.py
@@ -0,0 +1,28 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import List
+from typing_extensions import Literal, TypedDict
+
+__all__ = ["DocumentListParams"]
+
+
+class DocumentListParams(TypedDict, total=False):
+ individual_ids: List[str]
+ """Comma-delimited list of stable Finch uuids for each individual.
+
+ If empty, defaults to all individuals
+ """
+
+ limit: int
+ """Number of documents to return (defaults to all)"""
+
+ offset: int
+ """Index to start from (defaults to 0)"""
+
+ types: List[Literal["w4_2020", "w4_2005"]]
+ """Comma-delimited list of document types to filter on.
+
+ If empty, defaults to all types
+ """
diff --git a/src/finch/types/hris/document_list_response.py b/src/finch/types/hris/document_list_response.py
new file mode 100644
index 00000000..6218db89
--- /dev/null
+++ b/src/finch/types/hris/document_list_response.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List
+
+from ..._models import BaseModel
+from ..shared.paging import Paging
+from .document_response import DocumentResponse
+
+__all__ = ["DocumentListResponse"]
+
+
+class DocumentListResponse(BaseModel):
+ documents: List[DocumentResponse]
+
+ paging: Paging
diff --git a/src/finch/types/hris/document_response.py b/src/finch/types/hris/document_response.py
new file mode 100644
index 00000000..eb68db53
--- /dev/null
+++ b/src/finch/types/hris/document_response.py
@@ -0,0 +1,31 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["DocumentResponse"]
+
+
+class DocumentResponse(BaseModel):
+ id: Optional[str] = None
+ """A stable Finch id for the document."""
+
+ individual_id: Optional[str] = None
+ """The ID of the individual associated with the document.
+
+ This will be null for employer-level documents.
+ """
+
+ type: Optional[Literal["w4_2020", "w4_2005"]] = None
+ """The type of document."""
+
+ url: Optional[str] = None
+ """A URL to access the document.
+
+ Format: `https://api.tryfinch.com/employer/documents/:document_id`.
+ """
+
+ year: Optional[float] = None
+ """The year the document applies to, if available."""
diff --git a/src/finch/types/hris/document_retreive_response.py b/src/finch/types/hris/document_retreive_response.py
new file mode 100644
index 00000000..91530524
--- /dev/null
+++ b/src/finch/types/hris/document_retreive_response.py
@@ -0,0 +1,12 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Annotated, TypeAlias
+
+from .w42005 import W42005
+from .w42020 import W42020
+from ..._utils import PropertyInfo
+
+__all__ = ["DocumentRetreiveResponse"]
+
+DocumentRetreiveResponse: TypeAlias = Annotated[Union[W42020, W42005], PropertyInfo(discriminator="type")]
diff --git a/src/finch/types/hris/w42005.py b/src/finch/types/hris/w42005.py
new file mode 100644
index 00000000..77d3a130
--- /dev/null
+++ b/src/finch/types/hris/w42005.py
@@ -0,0 +1,36 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["W42005", "Data"]
+
+
+class Data(BaseModel):
+ additional_withholding: Optional[int] = None
+ """Additional withholding amount (in cents)."""
+
+ exemption: Optional[Literal["exempt", "non_exempt"]] = None
+ """Indicates exemption status from federal tax withholding."""
+
+ filing_status: Optional[Literal["married", "married_but_withhold_at_higher_single_rate", "single"]] = None
+ """The individual's filing status for tax purposes."""
+
+ individual_id: Optional[str] = None
+ """The unique identifier for the individual associated with this 2005 W4 form."""
+
+ total_number_of_allowances: Optional[int] = None
+ """Total number of allowances claimed (in cents)."""
+
+
+class W42005(BaseModel):
+ data: Optional[Data] = None
+ """Detailed information specific to the 2005 W4 form."""
+
+ type: Optional[Literal["w4_2005"]] = None
+ """Specifies the form type, indicating that this document is a 2005 W4 form."""
+
+ year: Optional[float] = None
+ """The tax year this W4 document applies to."""
diff --git a/src/finch/types/hris/w42020.py b/src/finch/types/hris/w42020.py
new file mode 100644
index 00000000..840463ec
--- /dev/null
+++ b/src/finch/types/hris/w42020.py
@@ -0,0 +1,54 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["W42020", "Data"]
+
+
+class Data(BaseModel):
+ amount_for_other_dependents: Optional[int] = None
+ """
+ Amount claimed for dependents other than qualifying children under 17 (in
+ cents).
+ """
+
+ amount_for_qualifying_children_under_17: Optional[int] = None
+ """Amount claimed for dependents under 17 years old (in cents)."""
+
+ deductions: Optional[int] = None
+ """Deductible expenses (in cents)."""
+
+ extra_withholding: Optional[int] = None
+ """Additional withholding amount (in cents)."""
+
+ filing_status: Optional[
+ Literal[
+ "head_of_household",
+ "married_filing_jointly_or_qualifying_surviving_spouse",
+ "single_or_married_filing_separately",
+ ]
+ ] = None
+ """The individual's filing status for tax purposes."""
+
+ individual_id: Optional[str] = None
+ """The unique identifier for the individual associated with this document."""
+
+ other_income: Optional[int] = None
+ """Additional income from sources outside of primary employment (in cents)."""
+
+ total_claim_dependent_and_other_credits: Optional[int] = None
+ """Total amount claimed for dependents and other credits (in cents)."""
+
+
+class W42020(BaseModel):
+ data: Optional[Data] = None
+ """Detailed information specific to the 2020 W4 form."""
+
+ type: Optional[Literal["w4_2020"]] = None
+ """Specifies the form type, indicating that this document is a 2020 W4 form."""
+
+ year: Optional[float] = None
+ """The tax year this W4 document applies to."""
diff --git a/tests/api_resources/hris/test_documents.py b/tests/api_resources/hris/test_documents.py
new file mode 100644
index 00000000..7833d4f3
--- /dev/null
+++ b/tests/api_resources/hris/test_documents.py
@@ -0,0 +1,168 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from finch import Finch, AsyncFinch
+from tests.utils import assert_matches_type
+from finch.types.hris import DocumentListResponse, DocumentRetreiveResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestDocuments:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_list(self, client: Finch) -> None:
+ document = client.hris.documents.list()
+ assert_matches_type(DocumentListResponse, document, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: Finch) -> None:
+ document = client.hris.documents.list(
+ individual_ids=["string"],
+ limit=0,
+ offset=0,
+ types=["w4_2020"],
+ )
+ assert_matches_type(DocumentListResponse, document, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Finch) -> None:
+ response = client.hris.documents.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ document = response.parse()
+ assert_matches_type(DocumentListResponse, document, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Finch) -> None:
+ with client.hris.documents.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ document = response.parse()
+ assert_matches_type(DocumentListResponse, document, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_retreive(self, client: Finch) -> None:
+ document = client.hris.documents.retreive(
+ "document_id",
+ )
+ assert_matches_type(DocumentRetreiveResponse, document, path=["response"])
+
+ @parametrize
+ def test_raw_response_retreive(self, client: Finch) -> None:
+ response = client.hris.documents.with_raw_response.retreive(
+ "document_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ document = response.parse()
+ assert_matches_type(DocumentRetreiveResponse, document, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retreive(self, client: Finch) -> None:
+ with client.hris.documents.with_streaming_response.retreive(
+ "document_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ document = response.parse()
+ assert_matches_type(DocumentRetreiveResponse, document, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retreive(self, client: Finch) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `document_id` but received ''"):
+ client.hris.documents.with_raw_response.retreive(
+ "",
+ )
+
+
+class TestAsyncDocuments:
+ parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncFinch) -> None:
+ document = await async_client.hris.documents.list()
+ assert_matches_type(DocumentListResponse, document, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncFinch) -> None:
+ document = await async_client.hris.documents.list(
+ individual_ids=["string"],
+ limit=0,
+ offset=0,
+ types=["w4_2020"],
+ )
+ assert_matches_type(DocumentListResponse, document, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncFinch) -> None:
+ response = await async_client.hris.documents.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ document = response.parse()
+ assert_matches_type(DocumentListResponse, document, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncFinch) -> None:
+ async with async_client.hris.documents.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ document = await response.parse()
+ assert_matches_type(DocumentListResponse, document, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_retreive(self, async_client: AsyncFinch) -> None:
+ document = await async_client.hris.documents.retreive(
+ "document_id",
+ )
+ assert_matches_type(DocumentRetreiveResponse, document, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retreive(self, async_client: AsyncFinch) -> None:
+ response = await async_client.hris.documents.with_raw_response.retreive(
+ "document_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ document = response.parse()
+ assert_matches_type(DocumentRetreiveResponse, document, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retreive(self, async_client: AsyncFinch) -> None:
+ async with async_client.hris.documents.with_streaming_response.retreive(
+ "document_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ document = await response.parse()
+ assert_matches_type(DocumentRetreiveResponse, document, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retreive(self, async_client: AsyncFinch) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `document_id` but received ''"):
+ await async_client.hris.documents.with_raw_response.retreive(
+ "",
+ )