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

from __future__ import annotations
from codat_bankfeeds.types import (
    BaseModel,
    Nullable,
    OptionalNullable,
    UNSET,
    UNSET_SENTINEL,
)
from codat_bankfeeds.utils import serialize_decimal, validate_decimal
from decimal import Decimal
from enum import Enum
import pydantic
from pydantic import model_serializer
from pydantic.functional_serializers import PlainSerializer
from pydantic.functional_validators import BeforeValidator
from typing import Optional
from typing_extensions import Annotated, NotRequired, TypedDict


class BankTransactionType(str, Enum):
    r"""Type of transaction for the bank statement line."""

    UNKNOWN = "Unknown"
    CREDIT = "Credit"
    DEBIT = "Debit"
    INT = "Int"
    DIV = "Div"
    FEE = "Fee"
    SER_CHG = "SerChg"
    DEP = "Dep"
    ATM = "Atm"
    POS = "Pos"
    XFER = "Xfer"
    CHECK = "Check"
    PAYMENT = "Payment"
    CASH = "Cash"
    DIRECT_DEP = "DirectDep"
    DIRECT_DEBIT = "DirectDebit"
    REPEAT_PMT = "RepeatPmt"
    OTHER = "Other"


class BankTransactionsTypedDict(TypedDict):
    amount: NotRequired[Decimal]
    r"""The amount transacted in the bank transaction."""
    balance: NotRequired[Decimal]
    r"""The remaining balance in the account with ID `accountId`. This field is optional for QuickBooks Online but is required for Xero, Sage, NetSuite, Exact, and FreeAgent."""
    counterparty: NotRequired[Nullable[str]]
    r"""The giving or receiving party such as a person or organization."""
    date_: NotRequired[str]
    r"""In Codat's data model, dates and times are represented using the <a class=\"external\" href=\"https://en.wikipedia.org/wiki/ISO_8601\" target=\"_blank\">ISO 8601 standard</a>. Date and time fields are formatted as strings; for example:

    ```
    2023-08-22T10:21:00
    2023-08-22
    ```

    When pushing bank transaction data to Codat, the date is treated as a local date. This means:

    - The date/time is used exactly as provided, without any timezone conversion.
    - If a timezone offset is included (e.g., `2023-08-22T10:21:00-05:00`), the offset will be ignored and only the local date/time portion will be used.
    - We recommend providing dates without a timezone suffix for clarity (e.g., `2023-08-22T10:21:00` rather than `2023-08-22T10:21:00Z`).
    """
    description: NotRequired[Nullable[str]]
    r"""Description of the bank transaction."""
    id: NotRequired[str]
    r"""Identifier for the bank account transaction, unique for the company in the accounting software."""
    reconciled: NotRequired[Nullable[bool]]
    r"""`True` if the bank transaction has been [reconciled](https://www.xero.com/uk/guides/what-is-bank-reconciliation/) in the accounting software."""
    reference: NotRequired[Nullable[str]]
    r"""An optional reference to the bank transaction."""
    transaction_type: NotRequired[Nullable[BankTransactionType]]
    r"""Type of transaction for the bank statement line."""


class BankTransactions(BaseModel):
    amount: Annotated[
        Optional[Decimal],
        BeforeValidator(validate_decimal),
        PlainSerializer(serialize_decimal(False)),
    ] = None
    r"""The amount transacted in the bank transaction."""

    balance: Annotated[
        Optional[Decimal],
        BeforeValidator(validate_decimal),
        PlainSerializer(serialize_decimal(False)),
    ] = None
    r"""The remaining balance in the account with ID `accountId`. This field is optional for QuickBooks Online but is required for Xero, Sage, NetSuite, Exact, and FreeAgent."""

    counterparty: OptionalNullable[str] = UNSET
    r"""The giving or receiving party such as a person or organization."""

    date_: Annotated[Optional[str], pydantic.Field(alias="date")] = None
    r"""In Codat's data model, dates and times are represented using the <a class=\"external\" href=\"https://en.wikipedia.org/wiki/ISO_8601\" target=\"_blank\">ISO 8601 standard</a>. Date and time fields are formatted as strings; for example:

    ```
    2023-08-22T10:21:00
    2023-08-22
    ```

    When pushing bank transaction data to Codat, the date is treated as a local date. This means:

    - The date/time is used exactly as provided, without any timezone conversion.
    - If a timezone offset is included (e.g., `2023-08-22T10:21:00-05:00`), the offset will be ignored and only the local date/time portion will be used.
    - We recommend providing dates without a timezone suffix for clarity (e.g., `2023-08-22T10:21:00` rather than `2023-08-22T10:21:00Z`).
    """

    description: OptionalNullable[str] = UNSET
    r"""Description of the bank transaction."""

    id: Optional[str] = None
    r"""Identifier for the bank account transaction, unique for the company in the accounting software."""

    reconciled: OptionalNullable[bool] = UNSET
    r"""`True` if the bank transaction has been [reconciled](https://www.xero.com/uk/guides/what-is-bank-reconciliation/) in the accounting software."""

    reference: OptionalNullable[str] = UNSET
    r"""An optional reference to the bank transaction."""

    transaction_type: Annotated[
        OptionalNullable[BankTransactionType], pydantic.Field(alias="transactionType")
    ] = UNSET
    r"""Type of transaction for the bank statement line."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(
            [
                "amount",
                "balance",
                "counterparty",
                "date",
                "description",
                "id",
                "reconciled",
                "reference",
                "transactionType",
            ]
        )
        nullable_fields = set(
            [
                "counterparty",
                "description",
                "reconciled",
                "reference",
                "transactionType",
            ]
        )
        serialized = handler(self)
        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            is_nullable_and_explicitly_set = (
                k in nullable_fields
                and (self.__pydantic_fields_set__.intersection({n}))  # pylint: disable=no-member
            )

            if val != UNSET_SENTINEL:
                if (
                    val is not None
                    or k not in optional_fields
                    or is_nullable_and_explicitly_set
                ):
                    m[k] = val

        return m
