# This file was auto-generated by Fern from our API Definition.

import typing
from ..core.client_wrapper import SyncClientWrapper
from ..requests.scheduled_shift import ScheduledShiftParams
from ..core.request_options import RequestOptions
from ..core.http_response import HttpResponse
from ..types.create_scheduled_shift_response import CreateScheduledShiftResponse
from ..core.serialization import convert_and_respect_annotation_metadata
from ..core.unchecked_base_model import construct_type
from json.decoder import JSONDecodeError
from ..core.api_error import ApiError
from ..requests.bulk_publish_scheduled_shifts_data import BulkPublishScheduledShiftsDataParams
from ..types.scheduled_shift_notification_audience import ScheduledShiftNotificationAudience
from ..types.bulk_publish_scheduled_shifts_response import BulkPublishScheduledShiftsResponse
from ..requests.scheduled_shift_query import ScheduledShiftQueryParams
from ..types.search_scheduled_shifts_response import SearchScheduledShiftsResponse
from ..types.retrieve_scheduled_shift_response import RetrieveScheduledShiftResponse
from ..core.jsonable_encoder import jsonable_encoder
from ..types.update_scheduled_shift_response import UpdateScheduledShiftResponse
from ..types.publish_scheduled_shift_response import PublishScheduledShiftResponse
from ..requests.timecard import TimecardParams
from ..types.create_timecard_response import CreateTimecardResponse
from ..requests.timecard_query import TimecardQueryParams
from ..types.search_timecards_response import SearchTimecardsResponse
from ..types.retrieve_timecard_response import RetrieveTimecardResponse
from ..types.update_timecard_response import UpdateTimecardResponse
from ..types.delete_timecard_response import DeleteTimecardResponse
from ..core.client_wrapper import AsyncClientWrapper
from ..core.http_response import AsyncHttpResponse

# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)


class RawLaborClient:
    def __init__(self, *, client_wrapper: SyncClientWrapper):
        self._client_wrapper = client_wrapper

    def create_scheduled_shift(
        self,
        *,
        scheduled_shift: ScheduledShiftParams,
        idempotency_key: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[CreateScheduledShiftResponse]:
        """
        Creates a scheduled shift by providing draft shift details such as job ID,
        team member assignment, and start and end times.

        The following `draft_shift_details` fields are required:
        - `location_id`
        - `job_id`
        - `start_at`
        - `end_at`

        Parameters
        ----------
        scheduled_shift : ScheduledShiftParams
            The scheduled shift with `draft_shift_details`.
            If needed, call [ListLocations](api-endpoint:Locations-ListLocations) to get location IDs,
            [ListJobs](api-endpoint:Team-ListJobs) to get job IDs, and [SearchTeamMembers](api-endpoint:Team-SearchTeamMembers)
            to get team member IDs and current job assignments.

            The `start_at` and `end_at` timestamps must be provided in the time zone + offset of the
            shift location specified in `location_id`. Example for Pacific Standard Time: 2024-10-31T12:30:00-08:00

        idempotency_key : typing.Optional[str]
            A unique identifier for the `CreateScheduledShift` request, used to ensure the
            [idempotency](https://developer.squareup.com/docs/build-basics/common-api-patterns/idempotency)
            of the operation.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[CreateScheduledShiftResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            "v2/labor/scheduled-shifts",
            method="POST",
            json={
                "idempotency_key": idempotency_key,
                "scheduled_shift": convert_and_respect_annotation_metadata(
                    object_=scheduled_shift, annotation=ScheduledShiftParams, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    CreateScheduledShiftResponse,
                    construct_type(
                        type_=CreateScheduledShiftResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def bulk_publish_scheduled_shifts(
        self,
        *,
        scheduled_shifts: typing.Dict[str, BulkPublishScheduledShiftsDataParams],
        scheduled_shift_notification_audience: typing.Optional[ScheduledShiftNotificationAudience] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[BulkPublishScheduledShiftsResponse]:
        """
        Publishes 1 - 100 scheduled shifts. This endpoint takes a map of individual publish
        requests and returns a map of responses. When a scheduled shift is published, Square keeps
        the `draft_shift_details` field as is and copies it to the `published_shift_details` field.

        The minimum `start_at` and maximum `end_at` timestamps of all shifts in a
        `BulkPublishScheduledShifts` request must fall within a two-week period.

        Parameters
        ----------
        scheduled_shifts : typing.Dict[str, BulkPublishScheduledShiftsDataParams]
            A map of 1 to 100 key-value pairs that represent individual publish requests.

            - Each key is the ID of a scheduled shift you want to publish.
            - Each value is a `BulkPublishScheduledShiftsData` object that contains the
            `version` field or is an empty object.

        scheduled_shift_notification_audience : typing.Optional[ScheduledShiftNotificationAudience]
            Indicates whether Square should send email notifications to team members and
            which team members should receive the notifications. This setting applies to all shifts
            specified in the bulk operation. The default value is `AFFECTED`.
            See [ScheduledShiftNotificationAudience](#type-scheduledshiftnotificationaudience) for possible values

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[BulkPublishScheduledShiftsResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            "v2/labor/scheduled-shifts/bulk-publish",
            method="POST",
            json={
                "scheduled_shifts": convert_and_respect_annotation_metadata(
                    object_=scheduled_shifts,
                    annotation=typing.Dict[str, BulkPublishScheduledShiftsDataParams],
                    direction="write",
                ),
                "scheduled_shift_notification_audience": scheduled_shift_notification_audience,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    BulkPublishScheduledShiftsResponse,
                    construct_type(
                        type_=BulkPublishScheduledShiftsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def search_scheduled_shifts(
        self,
        *,
        query: typing.Optional[ScheduledShiftQueryParams] = OMIT,
        limit: typing.Optional[int] = OMIT,
        cursor: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[SearchScheduledShiftsResponse]:
        """
        Returns a paginated list of scheduled shifts, with optional filter and sort settings.
        By default, results are sorted by `start_at` in ascending order.

        Parameters
        ----------
        query : typing.Optional[ScheduledShiftQueryParams]
            Query conditions used to filter and sort the results.

        limit : typing.Optional[int]
            The maximum number of results to return in a single response page. The default value is 50.

        cursor : typing.Optional[str]
            The pagination cursor returned by the previous call to this endpoint. Provide
            this cursor to retrieve the next page of results for your original request. For more
            information, see [Pagination](https://developer.squareup.com/docs/build-basics/common-api-patterns/pagination).

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[SearchScheduledShiftsResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            "v2/labor/scheduled-shifts/search",
            method="POST",
            json={
                "query": convert_and_respect_annotation_metadata(
                    object_=query, annotation=ScheduledShiftQueryParams, direction="write"
                ),
                "limit": limit,
                "cursor": cursor,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    SearchScheduledShiftsResponse,
                    construct_type(
                        type_=SearchScheduledShiftsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def retrieve_scheduled_shift(
        self, id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[RetrieveScheduledShiftResponse]:
        """
        Retrieves a scheduled shift by ID.

        Parameters
        ----------
        id : str
            The ID of the scheduled shift to retrieve.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[RetrieveScheduledShiftResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/labor/scheduled-shifts/{jsonable_encoder(id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    RetrieveScheduledShiftResponse,
                    construct_type(
                        type_=RetrieveScheduledShiftResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def update_scheduled_shift(
        self, id: str, *, scheduled_shift: ScheduledShiftParams, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[UpdateScheduledShiftResponse]:
        """
        Updates the draft shift details for a scheduled shift. This endpoint supports
        sparse updates, so only new, changed, or removed fields are required in the request.
        You must publish the shift to make updates public.

        You can make the following updates to `draft_shift_details`:
        - Change the `location_id`, `job_id`, `start_at`, and `end_at` fields.
        - Add, change, or clear the `team_member_id` and `notes` fields. To clear these fields,
        set the value to null.
        - Change the `is_deleted` field. To delete a scheduled shift, set `is_deleted` to true
        and then publish the shift.

        Parameters
        ----------
        id : str
            The ID of the scheduled shift to update.

        scheduled_shift : ScheduledShiftParams
            The scheduled shift with any updates in the `draft_shift_details` field.
            If needed, call [ListLocations](api-endpoint:Locations-ListLocations) to get location IDs,
            [ListJobs](api-endpoint:Team-ListJobs) to get job IDs, and [SearchTeamMembers](api-endpoint:Team-SearchTeamMembers)
            to get team member IDs and current job assignments. Updates made to `published_shift_details`
            are ignored.

            If provided, the `start_at` and `end_at` timestamps must be in the time zone + offset of the
            shift location specified in `location_id`. Example for Pacific Standard Time: 2024-10-31T12:30:00-08:00

            To enable [optimistic concurrency](https://developer.squareup.com/docs/build-basics/common-api-patterns/optimistic-concurrency)
            control for the request, provide the current version of the shift in the `version` field.
            If the provided version doesn't match the server version, the request fails. If `version` is
            omitted, Square executes a blind write, potentially overwriting data from another publish request.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[UpdateScheduledShiftResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/labor/scheduled-shifts/{jsonable_encoder(id)}",
            method="PUT",
            json={
                "scheduled_shift": convert_and_respect_annotation_metadata(
                    object_=scheduled_shift, annotation=ScheduledShiftParams, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    UpdateScheduledShiftResponse,
                    construct_type(
                        type_=UpdateScheduledShiftResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def publish_scheduled_shift(
        self,
        id: str,
        *,
        idempotency_key: str,
        version: typing.Optional[int] = OMIT,
        scheduled_shift_notification_audience: typing.Optional[ScheduledShiftNotificationAudience] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[PublishScheduledShiftResponse]:
        """
        Publishes a scheduled shift. When a scheduled shift is published, Square keeps the
        `draft_shift_details` field as is and copies it to the `published_shift_details` field.

        Parameters
        ----------
        id : str
            The ID of the scheduled shift to publish.

        idempotency_key : str
            A unique identifier for the `PublishScheduledShift` request, used to ensure the
            [idempotency](https://developer.squareup.com/docs/build-basics/common-api-patterns/idempotency)
            of the operation.

        version : typing.Optional[int]
            The current version of the scheduled shift, used to enable [optimistic concurrency](https://developer.squareup.com/docs/build-basics/common-api-patterns/optimistic-concurrency)
            control. If the provided version doesn't match the server version, the request fails.
            If omitted, Square executes a blind write, potentially overwriting data from another publish request.

        scheduled_shift_notification_audience : typing.Optional[ScheduledShiftNotificationAudience]
            Indicates whether Square should send an email notification to team members and
            which team members should receive the notification. The default value is `AFFECTED`.
            See [ScheduledShiftNotificationAudience](#type-scheduledshiftnotificationaudience) for possible values

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[PublishScheduledShiftResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/labor/scheduled-shifts/{jsonable_encoder(id)}/publish",
            method="POST",
            json={
                "idempotency_key": idempotency_key,
                "version": version,
                "scheduled_shift_notification_audience": scheduled_shift_notification_audience,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    PublishScheduledShiftResponse,
                    construct_type(
                        type_=PublishScheduledShiftResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def create_timecard(
        self,
        *,
        timecard: TimecardParams,
        idempotency_key: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[CreateTimecardResponse]:
        """
        Creates a new `Timecard`.

        A `Timecard` represents a complete workday for a single team member.
        You must provide the following values in your request to this
        endpoint:

        - `location_id`
        - `team_member_id`
        - `start_at`

        An attempt to create a new `Timecard` can result in a `BAD_REQUEST` error when:
        - The `status` of the new `Timecard` is `OPEN` and the team member has another
        timecard with an `OPEN` status.
        - The `start_at` date is in the future.
        - The `start_at` or `end_at` date overlaps another timecard for the same team member.
        - The `Break` instances are set in the request and a break `start_at`
        is before the `Timecard.start_at`, a break `end_at` is after
        the `Timecard.end_at`, or both.

        Parameters
        ----------
        timecard : TimecardParams
            The `Timecard` to be created.

        idempotency_key : typing.Optional[str]
            A unique string value to ensure the idempotency of the operation.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[CreateTimecardResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            "v2/labor/timecards",
            method="POST",
            json={
                "idempotency_key": idempotency_key,
                "timecard": convert_and_respect_annotation_metadata(
                    object_=timecard, annotation=TimecardParams, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    CreateTimecardResponse,
                    construct_type(
                        type_=CreateTimecardResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def search_timecards(
        self,
        *,
        query: typing.Optional[TimecardQueryParams] = OMIT,
        limit: typing.Optional[int] = OMIT,
        cursor: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[SearchTimecardsResponse]:
        """
        Returns a paginated list of `Timecard` records for a business.
        The list to be returned can be filtered by:
        - Location IDs
        - Team member IDs
        - Timecard status (`OPEN` or `CLOSED`)
        - Timecard start
        - Timecard end
        - Workday details

        The list can be sorted by:
        - `START_AT`
        - `END_AT`
        - `CREATED_AT`
        - `UPDATED_AT`

        Parameters
        ----------
        query : typing.Optional[TimecardQueryParams]
            Query filters.

        limit : typing.Optional[int]
            The number of resources in a page (200 by default).

        cursor : typing.Optional[str]
            An opaque cursor for fetching the next page.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[SearchTimecardsResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            "v2/labor/timecards/search",
            method="POST",
            json={
                "query": convert_and_respect_annotation_metadata(
                    object_=query, annotation=TimecardQueryParams, direction="write"
                ),
                "limit": limit,
                "cursor": cursor,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    SearchTimecardsResponse,
                    construct_type(
                        type_=SearchTimecardsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def retrieve_timecard(
        self, id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[RetrieveTimecardResponse]:
        """
        Returns a single `Timecard` specified by `id`.

        Parameters
        ----------
        id : str
            The UUID for the `Timecard` being retrieved.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[RetrieveTimecardResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/labor/timecards/{jsonable_encoder(id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    RetrieveTimecardResponse,
                    construct_type(
                        type_=RetrieveTimecardResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def update_timecard(
        self, id: str, *, timecard: TimecardParams, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[UpdateTimecardResponse]:
        """
        Updates an existing `Timecard`.

        When adding a `Break` to a `Timecard`, any earlier `Break` instances in the `Timecard` have
        the `end_at` property set to a valid RFC-3339 datetime string.

        When closing a `Timecard`, all `Break` instances in the `Timecard` must be complete with `end_at`
        set on each `Break`.

        Parameters
        ----------
        id : str
            The ID of the object being updated.

        timecard : TimecardParams
            The updated `Timecard` object.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[UpdateTimecardResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/labor/timecards/{jsonable_encoder(id)}",
            method="PUT",
            json={
                "timecard": convert_and_respect_annotation_metadata(
                    object_=timecard, annotation=TimecardParams, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    UpdateTimecardResponse,
                    construct_type(
                        type_=UpdateTimecardResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def delete_timecard(
        self, id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[DeleteTimecardResponse]:
        """
        Deletes a `Timecard`.

        Parameters
        ----------
        id : str
            The UUID for the `Timecard` being deleted.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[DeleteTimecardResponse]
            Success
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/labor/timecards/{jsonable_encoder(id)}",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    DeleteTimecardResponse,
                    construct_type(
                        type_=DeleteTimecardResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)


class AsyncRawLaborClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper

    async def create_scheduled_shift(
        self,
        *,
        scheduled_shift: ScheduledShiftParams,
        idempotency_key: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[CreateScheduledShiftResponse]:
        """
        Creates a scheduled shift by providing draft shift details such as job ID,
        team member assignment, and start and end times.

        The following `draft_shift_details` fields are required:
        - `location_id`
        - `job_id`
        - `start_at`
        - `end_at`

        Parameters
        ----------
        scheduled_shift : ScheduledShiftParams
            The scheduled shift with `draft_shift_details`.
            If needed, call [ListLocations](api-endpoint:Locations-ListLocations) to get location IDs,
            [ListJobs](api-endpoint:Team-ListJobs) to get job IDs, and [SearchTeamMembers](api-endpoint:Team-SearchTeamMembers)
            to get team member IDs and current job assignments.

            The `start_at` and `end_at` timestamps must be provided in the time zone + offset of the
            shift location specified in `location_id`. Example for Pacific Standard Time: 2024-10-31T12:30:00-08:00

        idempotency_key : typing.Optional[str]
            A unique identifier for the `CreateScheduledShift` request, used to ensure the
            [idempotency](https://developer.squareup.com/docs/build-basics/common-api-patterns/idempotency)
            of the operation.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[CreateScheduledShiftResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v2/labor/scheduled-shifts",
            method="POST",
            json={
                "idempotency_key": idempotency_key,
                "scheduled_shift": convert_and_respect_annotation_metadata(
                    object_=scheduled_shift, annotation=ScheduledShiftParams, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    CreateScheduledShiftResponse,
                    construct_type(
                        type_=CreateScheduledShiftResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def bulk_publish_scheduled_shifts(
        self,
        *,
        scheduled_shifts: typing.Dict[str, BulkPublishScheduledShiftsDataParams],
        scheduled_shift_notification_audience: typing.Optional[ScheduledShiftNotificationAudience] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[BulkPublishScheduledShiftsResponse]:
        """
        Publishes 1 - 100 scheduled shifts. This endpoint takes a map of individual publish
        requests and returns a map of responses. When a scheduled shift is published, Square keeps
        the `draft_shift_details` field as is and copies it to the `published_shift_details` field.

        The minimum `start_at` and maximum `end_at` timestamps of all shifts in a
        `BulkPublishScheduledShifts` request must fall within a two-week period.

        Parameters
        ----------
        scheduled_shifts : typing.Dict[str, BulkPublishScheduledShiftsDataParams]
            A map of 1 to 100 key-value pairs that represent individual publish requests.

            - Each key is the ID of a scheduled shift you want to publish.
            - Each value is a `BulkPublishScheduledShiftsData` object that contains the
            `version` field or is an empty object.

        scheduled_shift_notification_audience : typing.Optional[ScheduledShiftNotificationAudience]
            Indicates whether Square should send email notifications to team members and
            which team members should receive the notifications. This setting applies to all shifts
            specified in the bulk operation. The default value is `AFFECTED`.
            See [ScheduledShiftNotificationAudience](#type-scheduledshiftnotificationaudience) for possible values

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[BulkPublishScheduledShiftsResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v2/labor/scheduled-shifts/bulk-publish",
            method="POST",
            json={
                "scheduled_shifts": convert_and_respect_annotation_metadata(
                    object_=scheduled_shifts,
                    annotation=typing.Dict[str, BulkPublishScheduledShiftsDataParams],
                    direction="write",
                ),
                "scheduled_shift_notification_audience": scheduled_shift_notification_audience,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    BulkPublishScheduledShiftsResponse,
                    construct_type(
                        type_=BulkPublishScheduledShiftsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def search_scheduled_shifts(
        self,
        *,
        query: typing.Optional[ScheduledShiftQueryParams] = OMIT,
        limit: typing.Optional[int] = OMIT,
        cursor: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[SearchScheduledShiftsResponse]:
        """
        Returns a paginated list of scheduled shifts, with optional filter and sort settings.
        By default, results are sorted by `start_at` in ascending order.

        Parameters
        ----------
        query : typing.Optional[ScheduledShiftQueryParams]
            Query conditions used to filter and sort the results.

        limit : typing.Optional[int]
            The maximum number of results to return in a single response page. The default value is 50.

        cursor : typing.Optional[str]
            The pagination cursor returned by the previous call to this endpoint. Provide
            this cursor to retrieve the next page of results for your original request. For more
            information, see [Pagination](https://developer.squareup.com/docs/build-basics/common-api-patterns/pagination).

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[SearchScheduledShiftsResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v2/labor/scheduled-shifts/search",
            method="POST",
            json={
                "query": convert_and_respect_annotation_metadata(
                    object_=query, annotation=ScheduledShiftQueryParams, direction="write"
                ),
                "limit": limit,
                "cursor": cursor,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    SearchScheduledShiftsResponse,
                    construct_type(
                        type_=SearchScheduledShiftsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def retrieve_scheduled_shift(
        self, id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[RetrieveScheduledShiftResponse]:
        """
        Retrieves a scheduled shift by ID.

        Parameters
        ----------
        id : str
            The ID of the scheduled shift to retrieve.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[RetrieveScheduledShiftResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/labor/scheduled-shifts/{jsonable_encoder(id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    RetrieveScheduledShiftResponse,
                    construct_type(
                        type_=RetrieveScheduledShiftResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def update_scheduled_shift(
        self, id: str, *, scheduled_shift: ScheduledShiftParams, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[UpdateScheduledShiftResponse]:
        """
        Updates the draft shift details for a scheduled shift. This endpoint supports
        sparse updates, so only new, changed, or removed fields are required in the request.
        You must publish the shift to make updates public.

        You can make the following updates to `draft_shift_details`:
        - Change the `location_id`, `job_id`, `start_at`, and `end_at` fields.
        - Add, change, or clear the `team_member_id` and `notes` fields. To clear these fields,
        set the value to null.
        - Change the `is_deleted` field. To delete a scheduled shift, set `is_deleted` to true
        and then publish the shift.

        Parameters
        ----------
        id : str
            The ID of the scheduled shift to update.

        scheduled_shift : ScheduledShiftParams
            The scheduled shift with any updates in the `draft_shift_details` field.
            If needed, call [ListLocations](api-endpoint:Locations-ListLocations) to get location IDs,
            [ListJobs](api-endpoint:Team-ListJobs) to get job IDs, and [SearchTeamMembers](api-endpoint:Team-SearchTeamMembers)
            to get team member IDs and current job assignments. Updates made to `published_shift_details`
            are ignored.

            If provided, the `start_at` and `end_at` timestamps must be in the time zone + offset of the
            shift location specified in `location_id`. Example for Pacific Standard Time: 2024-10-31T12:30:00-08:00

            To enable [optimistic concurrency](https://developer.squareup.com/docs/build-basics/common-api-patterns/optimistic-concurrency)
            control for the request, provide the current version of the shift in the `version` field.
            If the provided version doesn't match the server version, the request fails. If `version` is
            omitted, Square executes a blind write, potentially overwriting data from another publish request.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[UpdateScheduledShiftResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/labor/scheduled-shifts/{jsonable_encoder(id)}",
            method="PUT",
            json={
                "scheduled_shift": convert_and_respect_annotation_metadata(
                    object_=scheduled_shift, annotation=ScheduledShiftParams, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    UpdateScheduledShiftResponse,
                    construct_type(
                        type_=UpdateScheduledShiftResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def publish_scheduled_shift(
        self,
        id: str,
        *,
        idempotency_key: str,
        version: typing.Optional[int] = OMIT,
        scheduled_shift_notification_audience: typing.Optional[ScheduledShiftNotificationAudience] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[PublishScheduledShiftResponse]:
        """
        Publishes a scheduled shift. When a scheduled shift is published, Square keeps the
        `draft_shift_details` field as is and copies it to the `published_shift_details` field.

        Parameters
        ----------
        id : str
            The ID of the scheduled shift to publish.

        idempotency_key : str
            A unique identifier for the `PublishScheduledShift` request, used to ensure the
            [idempotency](https://developer.squareup.com/docs/build-basics/common-api-patterns/idempotency)
            of the operation.

        version : typing.Optional[int]
            The current version of the scheduled shift, used to enable [optimistic concurrency](https://developer.squareup.com/docs/build-basics/common-api-patterns/optimistic-concurrency)
            control. If the provided version doesn't match the server version, the request fails.
            If omitted, Square executes a blind write, potentially overwriting data from another publish request.

        scheduled_shift_notification_audience : typing.Optional[ScheduledShiftNotificationAudience]
            Indicates whether Square should send an email notification to team members and
            which team members should receive the notification. The default value is `AFFECTED`.
            See [ScheduledShiftNotificationAudience](#type-scheduledshiftnotificationaudience) for possible values

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[PublishScheduledShiftResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/labor/scheduled-shifts/{jsonable_encoder(id)}/publish",
            method="POST",
            json={
                "idempotency_key": idempotency_key,
                "version": version,
                "scheduled_shift_notification_audience": scheduled_shift_notification_audience,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    PublishScheduledShiftResponse,
                    construct_type(
                        type_=PublishScheduledShiftResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def create_timecard(
        self,
        *,
        timecard: TimecardParams,
        idempotency_key: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[CreateTimecardResponse]:
        """
        Creates a new `Timecard`.

        A `Timecard` represents a complete workday for a single team member.
        You must provide the following values in your request to this
        endpoint:

        - `location_id`
        - `team_member_id`
        - `start_at`

        An attempt to create a new `Timecard` can result in a `BAD_REQUEST` error when:
        - The `status` of the new `Timecard` is `OPEN` and the team member has another
        timecard with an `OPEN` status.
        - The `start_at` date is in the future.
        - The `start_at` or `end_at` date overlaps another timecard for the same team member.
        - The `Break` instances are set in the request and a break `start_at`
        is before the `Timecard.start_at`, a break `end_at` is after
        the `Timecard.end_at`, or both.

        Parameters
        ----------
        timecard : TimecardParams
            The `Timecard` to be created.

        idempotency_key : typing.Optional[str]
            A unique string value to ensure the idempotency of the operation.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[CreateTimecardResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v2/labor/timecards",
            method="POST",
            json={
                "idempotency_key": idempotency_key,
                "timecard": convert_and_respect_annotation_metadata(
                    object_=timecard, annotation=TimecardParams, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    CreateTimecardResponse,
                    construct_type(
                        type_=CreateTimecardResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def search_timecards(
        self,
        *,
        query: typing.Optional[TimecardQueryParams] = OMIT,
        limit: typing.Optional[int] = OMIT,
        cursor: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[SearchTimecardsResponse]:
        """
        Returns a paginated list of `Timecard` records for a business.
        The list to be returned can be filtered by:
        - Location IDs
        - Team member IDs
        - Timecard status (`OPEN` or `CLOSED`)
        - Timecard start
        - Timecard end
        - Workday details

        The list can be sorted by:
        - `START_AT`
        - `END_AT`
        - `CREATED_AT`
        - `UPDATED_AT`

        Parameters
        ----------
        query : typing.Optional[TimecardQueryParams]
            Query filters.

        limit : typing.Optional[int]
            The number of resources in a page (200 by default).

        cursor : typing.Optional[str]
            An opaque cursor for fetching the next page.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[SearchTimecardsResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v2/labor/timecards/search",
            method="POST",
            json={
                "query": convert_and_respect_annotation_metadata(
                    object_=query, annotation=TimecardQueryParams, direction="write"
                ),
                "limit": limit,
                "cursor": cursor,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    SearchTimecardsResponse,
                    construct_type(
                        type_=SearchTimecardsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def retrieve_timecard(
        self, id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[RetrieveTimecardResponse]:
        """
        Returns a single `Timecard` specified by `id`.

        Parameters
        ----------
        id : str
            The UUID for the `Timecard` being retrieved.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[RetrieveTimecardResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/labor/timecards/{jsonable_encoder(id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    RetrieveTimecardResponse,
                    construct_type(
                        type_=RetrieveTimecardResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def update_timecard(
        self, id: str, *, timecard: TimecardParams, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[UpdateTimecardResponse]:
        """
        Updates an existing `Timecard`.

        When adding a `Break` to a `Timecard`, any earlier `Break` instances in the `Timecard` have
        the `end_at` property set to a valid RFC-3339 datetime string.

        When closing a `Timecard`, all `Break` instances in the `Timecard` must be complete with `end_at`
        set on each `Break`.

        Parameters
        ----------
        id : str
            The ID of the object being updated.

        timecard : TimecardParams
            The updated `Timecard` object.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[UpdateTimecardResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/labor/timecards/{jsonable_encoder(id)}",
            method="PUT",
            json={
                "timecard": convert_and_respect_annotation_metadata(
                    object_=timecard, annotation=TimecardParams, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    UpdateTimecardResponse,
                    construct_type(
                        type_=UpdateTimecardResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def delete_timecard(
        self, id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[DeleteTimecardResponse]:
        """
        Deletes a `Timecard`.

        Parameters
        ----------
        id : str
            The UUID for the `Timecard` being deleted.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[DeleteTimecardResponse]
            Success
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/labor/timecards/{jsonable_encoder(id)}",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    DeleteTimecardResponse,
                    construct_type(
                        type_=DeleteTimecardResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)
