"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""

from __future__ import annotations
from ascend_sdk import utils
from ascend_sdk.types import (
    BaseModel,
    Nullable,
    OptionalNullable,
    UNSET,
    UNSET_SENTINEL,
)
from ascend_sdk.utils import validate_open_enum
from enum import Enum
from pydantic import model_serializer
from pydantic.functional_validators import PlainValidator
from typing import Optional
from typing_extensions import Annotated, NotRequired, TypedDict


class AchWithdrawalScheduleIraDistributionFederalTaxWithholdingAmountTypedDict(
    TypedDict
):
    r"""Fixed USD amount to withhold for taxes."""

    value: NotRequired[str]
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class AchWithdrawalScheduleIraDistributionFederalTaxWithholdingAmount(BaseModel):
    r"""Fixed USD amount to withhold for taxes."""

    value: Optional[str] = None
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class AchWithdrawalSchedulePercentageTypedDict(TypedDict):
    r"""Percentage of total disbursement amount to withhold for taxes."""

    value: NotRequired[str]
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class AchWithdrawalSchedulePercentage(BaseModel):
    r"""Percentage of total disbursement amount to withhold for taxes."""

    value: Optional[str] = None
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class AchWithdrawalScheduleFederalTaxWithholdingTypedDict(TypedDict):
    r"""The federal tax withholding."""

    amount: NotRequired[
        Nullable[
            AchWithdrawalScheduleIraDistributionFederalTaxWithholdingAmountTypedDict
        ]
    ]
    r"""Fixed USD amount to withhold for taxes."""
    percentage: NotRequired[Nullable[AchWithdrawalSchedulePercentageTypedDict]]
    r"""Percentage of total disbursement amount to withhold for taxes."""


class AchWithdrawalScheduleFederalTaxWithholding(BaseModel):
    r"""The federal tax withholding."""

    amount: OptionalNullable[
        AchWithdrawalScheduleIraDistributionFederalTaxWithholdingAmount
    ] = UNSET
    r"""Fixed USD amount to withhold for taxes."""

    percentage: OptionalNullable[AchWithdrawalSchedulePercentage] = UNSET
    r"""Percentage of total disbursement amount to withhold for taxes."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = ["amount", "percentage"]
        nullable_fields = ["amount", "percentage"]
        null_default_fields = []

        serialized = handler(self)

        m = {}

        for n, f in self.model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            serialized.pop(k, None)

            optional_nullable = k in optional_fields and k in nullable_fields
            is_set = (
                self.__pydantic_fields_set__.intersection({n})
                or k in null_default_fields
            )  # pylint: disable=no-member

            if val is not None and val != UNSET_SENTINEL:
                m[k] = val
            elif val != UNSET_SENTINEL and (
                not k in optional_fields or (optional_nullable and is_set)
            ):
                m[k] = val

        return m


class AchWithdrawalScheduleIraDistributionAmountTypedDict(TypedDict):
    r"""Fixed USD amount to withhold for taxes."""

    value: NotRequired[str]
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class AchWithdrawalScheduleIraDistributionAmount(BaseModel):
    r"""Fixed USD amount to withhold for taxes."""

    value: Optional[str] = None
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class AchWithdrawalScheduleIraDistributionPercentageTypedDict(TypedDict):
    r"""Percentage of total disbursement amount to withhold for taxes."""

    value: NotRequired[str]
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class AchWithdrawalScheduleIraDistributionPercentage(BaseModel):
    r"""Percentage of total disbursement amount to withhold for taxes."""

    value: Optional[str] = None
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class AchWithdrawalScheduleStateTaxWithholdingTypedDict(TypedDict):
    r"""The state tax withholding."""

    amount: NotRequired[Nullable[AchWithdrawalScheduleIraDistributionAmountTypedDict]]
    r"""Fixed USD amount to withhold for taxes."""
    percentage: NotRequired[
        Nullable[AchWithdrawalScheduleIraDistributionPercentageTypedDict]
    ]
    r"""Percentage of total disbursement amount to withhold for taxes."""


class AchWithdrawalScheduleStateTaxWithholding(BaseModel):
    r"""The state tax withholding."""

    amount: OptionalNullable[AchWithdrawalScheduleIraDistributionAmount] = UNSET
    r"""Fixed USD amount to withhold for taxes."""

    percentage: OptionalNullable[AchWithdrawalScheduleIraDistributionPercentage] = UNSET
    r"""Percentage of total disbursement amount to withhold for taxes."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = ["amount", "percentage"]
        nullable_fields = ["amount", "percentage"]
        null_default_fields = []

        serialized = handler(self)

        m = {}

        for n, f in self.model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            serialized.pop(k, None)

            optional_nullable = k in optional_fields and k in nullable_fields
            is_set = (
                self.__pydantic_fields_set__.intersection({n})
                or k in null_default_fields
            )  # pylint: disable=no-member

            if val is not None and val != UNSET_SENTINEL:
                m[k] = val
            elif val != UNSET_SENTINEL and (
                not k in optional_fields or (optional_nullable and is_set)
            ):
                m[k] = val

        return m


class AchWithdrawalScheduleType(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""The type of retirement distribution."""

    TYPE_UNSPECIFIED = "TYPE_UNSPECIFIED"
    NORMAL = "NORMAL"
    DISABILITY = "DISABILITY"
    SOSEPP = "SOSEPP"
    PREMATURE = "PREMATURE"
    DEATH = "DEATH"
    EXCESS_CONTRIBUTION_REMOVAL_BEFORE_TAX_DEADLINE = (
        "EXCESS_CONTRIBUTION_REMOVAL_BEFORE_TAX_DEADLINE"
    )
    EXCESS_CONTRIBUTION_REMOVAL_AFTER_TAX_DEADLINE = (
        "EXCESS_CONTRIBUTION_REMOVAL_AFTER_TAX_DEADLINE"
    )
    ROLLOVER_TO_QUALIFIED_PLAN = "ROLLOVER_TO_QUALIFIED_PLAN"
    ROLLOVER_TO_IRA = "ROLLOVER_TO_IRA"
    DISTRIBUTION_TRANSFER = "DISTRIBUTION_TRANSFER"
    RECHARACTERIZATION_PRIOR_YEAR = "RECHARACTERIZATION_PRIOR_YEAR"
    RECHARACTERIZATION_CURRENT_YEAR = "RECHARACTERIZATION_CURRENT_YEAR"
    DISTRIBUTION_CONVERSION = "DISTRIBUTION_CONVERSION"
    MANAGEMENT_FEE = "MANAGEMENT_FEE"
    PLAN_LOAN_401_K = "PLAN_LOAN_401K"
    PREMATURE_SIMPLE_IRA_LESS_THAN_2_YEARS = "PREMATURE_SIMPLE_IRA_LESS_THAN_2_YEARS"
    NORMAL_ROTH_IRA_GREATER_THAN_5_YEARS = "NORMAL_ROTH_IRA_GREATER_THAN_5_YEARS"


class IraDistributionTypedDict(TypedDict):
    r"""The ira distribution info for an IRA account"""

    federal_tax_withholding: NotRequired[
        Nullable[AchWithdrawalScheduleFederalTaxWithholdingTypedDict]
    ]
    r"""The federal tax withholding."""
    receiving_institution: NotRequired[str]
    r"""The institution receiving retirement funds when performing a transfer to an identical retirement account type at a different financial institution. This is required for check and wire withdrawals because we can't always identify the institution using the transfer instructions. For cash journals this value will default to \"Apex Clearing\", regardless of what is passed in here"""
    state_tax_withholding: NotRequired[
        Nullable[AchWithdrawalScheduleStateTaxWithholdingTypedDict]
    ]
    r"""The state tax withholding."""
    state_withholding_waiver: NotRequired[bool]
    r"""Whether or not this distribution has a state withholding waiver."""
    tax_year: NotRequired[int]
    r"""Tax year for which the distribution is applied."""
    type: NotRequired[AchWithdrawalScheduleType]
    r"""The type of retirement distribution."""


class IraDistribution(BaseModel):
    r"""The ira distribution info for an IRA account"""

    federal_tax_withholding: OptionalNullable[
        AchWithdrawalScheduleFederalTaxWithholding
    ] = UNSET
    r"""The federal tax withholding."""

    receiving_institution: Optional[str] = None
    r"""The institution receiving retirement funds when performing a transfer to an identical retirement account type at a different financial institution. This is required for check and wire withdrawals because we can't always identify the institution using the transfer instructions. For cash journals this value will default to \"Apex Clearing\", regardless of what is passed in here"""

    state_tax_withholding: OptionalNullable[
        AchWithdrawalScheduleStateTaxWithholding
    ] = UNSET
    r"""The state tax withholding."""

    state_withholding_waiver: Optional[bool] = None
    r"""Whether or not this distribution has a state withholding waiver."""

    tax_year: Optional[int] = None
    r"""Tax year for which the distribution is applied."""

    type: Annotated[
        Optional[AchWithdrawalScheduleType], PlainValidator(validate_open_enum(False))
    ] = None
    r"""The type of retirement distribution."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = [
            "federal_tax_withholding",
            "receiving_institution",
            "state_tax_withholding",
            "state_withholding_waiver",
            "tax_year",
            "type",
        ]
        nullable_fields = ["federal_tax_withholding", "state_tax_withholding"]
        null_default_fields = []

        serialized = handler(self)

        m = {}

        for n, f in self.model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            serialized.pop(k, None)

            optional_nullable = k in optional_fields and k in nullable_fields
            is_set = (
                self.__pydantic_fields_set__.intersection({n})
                or k in null_default_fields
            )  # pylint: disable=no-member

            if val is not None and val != UNSET_SENTINEL:
                m[k] = val
            elif val != UNSET_SENTINEL and (
                not k in optional_fields or (optional_nullable and is_set)
            ):
                m[k] = val

        return m


class AchWithdrawalScheduleAmountTypedDict(TypedDict):
    r"""A cash amount in the format of decimal value (mutually exclusive with 'full_disbursement')"""

    value: NotRequired[str]
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class AchWithdrawalScheduleAmount(BaseModel):
    r"""A cash amount in the format of decimal value (mutually exclusive with 'full_disbursement')"""

    value: Optional[str] = None
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class AchWithdrawalScheduleStartDateTypedDict(TypedDict):
    r"""The schedule start date"""

    day: NotRequired[int]
    r"""Day of a month. Must be from 1 to 31 and valid for the year and month, or 0 to specify a year by itself or a year and month where the day isn't significant."""
    month: NotRequired[int]
    r"""Month of a year. Must be from 1 to 12, or 0 to specify a year without a month and day."""
    year: NotRequired[int]
    r"""Year of the date. Must be from 1 to 9999, or 0 to specify a date without a year."""


class AchWithdrawalScheduleStartDate(BaseModel):
    r"""The schedule start date"""

    day: Optional[int] = None
    r"""Day of a month. Must be from 1 to 31 and valid for the year and month, or 0 to specify a year by itself or a year and month where the day isn't significant."""

    month: Optional[int] = None
    r"""Month of a year. Must be from 1 to 12, or 0 to specify a year without a month and day."""

    year: Optional[int] = None
    r"""Year of the date. Must be from 1 to 9999, or 0 to specify a date without a year."""


class AchWithdrawalScheduleState(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""The state of the represented schedule"""

    ACTIVE = "ACTIVE"
    CANCELED = "CANCELED"
    COMPLETED = "COMPLETED"


class AchWithdrawalScheduleTimeUnit(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""The time unit used to calculate the interval between transfers. The time period between transfers in a scheduled series is the unit of time times the multiplier"""

    DAY = "DAY"
    WEEK = "WEEK"
    MONTH = "MONTH"


class AchWithdrawalScheduleSchedulePropertiesTypedDict(TypedDict):
    r"""Common schedule properties"""

    occurrences: NotRequired[int]
    r"""The number of occurrences (empty or 0 indicates unlimited occurrences)"""
    start_date: NotRequired[Nullable[AchWithdrawalScheduleStartDateTypedDict]]
    r"""The schedule start date"""
    state: NotRequired[AchWithdrawalScheduleState]
    r"""The state of the represented schedule"""
    time_unit: NotRequired[AchWithdrawalScheduleTimeUnit]
    r"""The time unit used to calculate the interval between transfers. The time period between transfers in a scheduled series is the unit of time times the multiplier"""
    unit_multiplier: NotRequired[int]
    r"""The multiplier used to determine the length of the interval between transfers. The time period between transfers in a scheduled series is the unit of time times the multiplier"""


class AchWithdrawalScheduleScheduleProperties(BaseModel):
    r"""Common schedule properties"""

    occurrences: Optional[int] = None
    r"""The number of occurrences (empty or 0 indicates unlimited occurrences)"""

    start_date: OptionalNullable[AchWithdrawalScheduleStartDate] = UNSET
    r"""The schedule start date"""

    state: Annotated[
        Optional[AchWithdrawalScheduleState], PlainValidator(validate_open_enum(False))
    ] = None
    r"""The state of the represented schedule"""

    time_unit: Annotated[
        Optional[AchWithdrawalScheduleTimeUnit],
        PlainValidator(validate_open_enum(False)),
    ] = None
    r"""The time unit used to calculate the interval between transfers. The time period between transfers in a scheduled series is the unit of time times the multiplier"""

    unit_multiplier: Optional[int] = None
    r"""The multiplier used to determine the length of the interval between transfers. The time period between transfers in a scheduled series is the unit of time times the multiplier"""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = [
            "occurrences",
            "start_date",
            "state",
            "time_unit",
            "unit_multiplier",
        ]
        nullable_fields = ["start_date"]
        null_default_fields = []

        serialized = handler(self)

        m = {}

        for n, f in self.model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            serialized.pop(k, None)

            optional_nullable = k in optional_fields and k in nullable_fields
            is_set = (
                self.__pydantic_fields_set__.intersection({n})
                or k in null_default_fields
            )  # pylint: disable=no-member

            if val is not None and val != UNSET_SENTINEL:
                m[k] = val
            elif val != UNSET_SENTINEL and (
                not k in optional_fields or (optional_nullable and is_set)
            ):
                m[k] = val

        return m


class AchWithdrawalScheduleScheduleDetailsTypedDict(TypedDict):
    r"""The transfer schedule details"""

    amount: NotRequired[Nullable[AchWithdrawalScheduleAmountTypedDict]]
    r"""A cash amount in the format of decimal value (mutually exclusive with 'full_disbursement')"""
    client_schedule_id: NotRequired[str]
    r"""External identifier supplied by the API caller. Each request must have a unique pairing of client_schedule_id and account"""
    full_disbursement: NotRequired[bool]
    r"""Flag to indicate a full disbursement transfer (mutually exclusive with 'amount')"""
    schedule_properties: NotRequired[
        Nullable[AchWithdrawalScheduleSchedulePropertiesTypedDict]
    ]
    r"""Common schedule properties"""


class AchWithdrawalScheduleScheduleDetails(BaseModel):
    r"""The transfer schedule details"""

    amount: OptionalNullable[AchWithdrawalScheduleAmount] = UNSET
    r"""A cash amount in the format of decimal value (mutually exclusive with 'full_disbursement')"""

    client_schedule_id: Optional[str] = None
    r"""External identifier supplied by the API caller. Each request must have a unique pairing of client_schedule_id and account"""

    full_disbursement: Optional[bool] = None
    r"""Flag to indicate a full disbursement transfer (mutually exclusive with 'amount')"""

    schedule_properties: OptionalNullable[
        AchWithdrawalScheduleScheduleProperties
    ] = UNSET
    r"""Common schedule properties"""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = [
            "amount",
            "client_schedule_id",
            "full_disbursement",
            "schedule_properties",
        ]
        nullable_fields = ["amount", "schedule_properties"]
        null_default_fields = []

        serialized = handler(self)

        m = {}

        for n, f in self.model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            serialized.pop(k, None)

            optional_nullable = k in optional_fields and k in nullable_fields
            is_set = (
                self.__pydantic_fields_set__.intersection({n})
                or k in null_default_fields
            )  # pylint: disable=no-member

            if val is not None and val != UNSET_SENTINEL:
                m[k] = val
            elif val != UNSET_SENTINEL and (
                not k in optional_fields or (optional_nullable and is_set)
            ):
                m[k] = val

        return m


class AchWithdrawalScheduleTypedDict(TypedDict):
    r"""A withdrawal transfer schedule using the ACH mechanism"""

    bank_relationship: NotRequired[str]
    r"""The name of the bank relationship to be used in the ACH transaction"""
    ira_distribution: NotRequired[Nullable[IraDistributionTypedDict]]
    r"""The ira distribution info for an IRA account"""
    name: NotRequired[str]
    r"""The name of the ACH Withdrawal transfer schedule"""
    schedule_details: NotRequired[
        Nullable[AchWithdrawalScheduleScheduleDetailsTypedDict]
    ]
    r"""The transfer schedule details"""


class AchWithdrawalSchedule(BaseModel):
    r"""A withdrawal transfer schedule using the ACH mechanism"""

    bank_relationship: Optional[str] = None
    r"""The name of the bank relationship to be used in the ACH transaction"""

    ira_distribution: OptionalNullable[IraDistribution] = UNSET
    r"""The ira distribution info for an IRA account"""

    name: Optional[str] = None
    r"""The name of the ACH Withdrawal transfer schedule"""

    schedule_details: OptionalNullable[AchWithdrawalScheduleScheduleDetails] = UNSET
    r"""The transfer schedule details"""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = [
            "bank_relationship",
            "ira_distribution",
            "name",
            "schedule_details",
        ]
        nullable_fields = ["ira_distribution", "schedule_details"]
        null_default_fields = []

        serialized = handler(self)

        m = {}

        for n, f in self.model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            serialized.pop(k, None)

            optional_nullable = k in optional_fields and k in nullable_fields
            is_set = (
                self.__pydantic_fields_set__.intersection({n})
                or k in null_default_fields
            )  # pylint: disable=no-member

            if val is not None and val != UNSET_SENTINEL:
                m[k] = val
            elif val != UNSET_SENTINEL and (
                not k in optional_fields or (optional_nullable and is_set)
            ):
                m[k] = val

        return m
