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

from __future__ import annotations
from .lineitemtype import LineItemType
from .linkedcustomer import LinkedCustomer, LinkedCustomerTypedDict
from .linkedinvoiceitem import LinkedInvoiceItem, LinkedInvoiceItemTypedDict
from .linkedledgeraccount import LinkedLedgerAccount, LinkedLedgerAccountTypedDict
from .linkedpurchaseorder import LinkedPurchaseOrder, LinkedPurchaseOrderTypedDict
from .linkedtaxrate import LinkedTaxRate, LinkedTaxRateTypedDict
from .linkedtrackingcategory import (
    LinkedTrackingCategory,
    LinkedTrackingCategoryTypedDict,
)
from .linkedworktag import LinkedWorktag, LinkedWorktagTypedDict
from .rebilling import Rebilling, RebillingTypedDict
from apideck_unify import models
from apideck_unify.types import (
    BaseModel,
    Nullable,
    OptionalNullable,
    UNSET,
    UNSET_SENTINEL,
)
from apideck_unify.utils import validate_open_enum
from datetime import datetime
from pydantic import field_serializer, model_serializer
from pydantic.functional_validators import PlainValidator
from typing import List, Optional
from typing_extensions import Annotated, NotRequired, TypedDict


class BillLineItemTypedDict(TypedDict):
    id: NotRequired[str]
    r"""A unique identifier for an object."""
    row_id: NotRequired[str]
    r"""Row ID"""
    code: NotRequired[Nullable[str]]
    r"""User defined item code"""
    line_number: NotRequired[Nullable[int]]
    r"""Line number of the resource"""
    description: NotRequired[Nullable[str]]
    r"""User defined description"""
    type: NotRequired[Nullable[LineItemType]]
    r"""Line Item type"""
    tax_amount: NotRequired[Nullable[float]]
    r"""Tax amount"""
    total_amount: NotRequired[Nullable[float]]
    r"""Total amount of the line item"""
    quantity: NotRequired[Nullable[float]]
    unit_price: NotRequired[Nullable[float]]
    unit_of_measure: NotRequired[Nullable[str]]
    r"""Description of the unit type the item is sold as, ie: kg, hour."""
    discount_percentage: NotRequired[Nullable[float]]
    r"""Discount percentage applied to the line item when supported downstream."""
    discount_amount: NotRequired[Nullable[float]]
    r"""Discount amount applied to the line item when supported downstream."""
    location_id: NotRequired[Nullable[str]]
    r"""The ID of the location"""
    department_id: NotRequired[Nullable[str]]
    r"""The ID of the department"""
    subsidiary_id: NotRequired[Nullable[str]]
    r"""The ID of the subsidiary"""
    category_id: NotRequired[Nullable[str]]
    r"""ID of the category of the line item"""
    shipping_id: NotRequired[Nullable[str]]
    r"""ID of the shipping of the line item"""
    memo: NotRequired[Nullable[str]]
    r"""Memo"""
    prepaid: NotRequired[Nullable[bool]]
    r"""Whether the line item is prepaid"""
    tax_applicable_on: NotRequired[Nullable[str]]
    r"""Tax applicable on"""
    tax_recoverability: NotRequired[Nullable[str]]
    r"""Tax recoverability"""
    tax_method: NotRequired[Nullable[str]]
    r"""Method of tax calculation"""
    retention_amount: NotRequired[Nullable[float]]
    r"""Retention amount"""
    payment_amount: NotRequired[Nullable[float]]
    r"""Payment amount"""
    item: NotRequired[LinkedInvoiceItemTypedDict]
    tax_rate: NotRequired[LinkedTaxRateTypedDict]
    ledger_account: NotRequired[Nullable[LinkedLedgerAccountTypedDict]]
    purchase_order: NotRequired[Nullable[LinkedPurchaseOrderTypedDict]]
    tracking_categories: NotRequired[
        Nullable[List[Nullable[LinkedTrackingCategoryTypedDict]]]
    ]
    r"""A list of linked tracking categories."""
    customer: NotRequired[Nullable[LinkedCustomerTypedDict]]
    r"""The customer this entity is linked to."""
    rebilling: NotRequired[Nullable[RebillingTypedDict]]
    r"""Rebilling metadata for this line item."""
    row_version: NotRequired[Nullable[str]]
    r"""A binary value used to detect updates to a object and prevent data conflicts. It is incremented each time an update is made to the object."""
    updated_by: NotRequired[Nullable[str]]
    r"""The user who last updated the object."""
    created_by: NotRequired[Nullable[str]]
    r"""The user who created the object."""
    created_at: NotRequired[Nullable[datetime]]
    r"""The date and time when the object was created."""
    updated_at: NotRequired[Nullable[datetime]]
    r"""The date and time when the object was last updated."""
    worktags: NotRequired[List[Nullable[LinkedWorktagTypedDict]]]
    r"""A list of linked worktags. This is only supported for Workday."""


class BillLineItem(BaseModel):
    id: Optional[str] = None
    r"""A unique identifier for an object."""

    row_id: Optional[str] = None
    r"""Row ID"""

    code: OptionalNullable[str] = UNSET
    r"""User defined item code"""

    line_number: OptionalNullable[int] = UNSET
    r"""Line number of the resource"""

    description: OptionalNullable[str] = UNSET
    r"""User defined description"""

    type: Annotated[
        OptionalNullable[LineItemType], PlainValidator(validate_open_enum(False))
    ] = UNSET
    r"""Line Item type"""

    tax_amount: OptionalNullable[float] = UNSET
    r"""Tax amount"""

    total_amount: OptionalNullable[float] = UNSET
    r"""Total amount of the line item"""

    quantity: OptionalNullable[float] = UNSET

    unit_price: OptionalNullable[float] = UNSET

    unit_of_measure: OptionalNullable[str] = UNSET
    r"""Description of the unit type the item is sold as, ie: kg, hour."""

    discount_percentage: OptionalNullable[float] = UNSET
    r"""Discount percentage applied to the line item when supported downstream."""

    discount_amount: OptionalNullable[float] = UNSET
    r"""Discount amount applied to the line item when supported downstream."""

    location_id: OptionalNullable[str] = UNSET
    r"""The ID of the location"""

    department_id: OptionalNullable[str] = UNSET
    r"""The ID of the department"""

    subsidiary_id: OptionalNullable[str] = UNSET
    r"""The ID of the subsidiary"""

    category_id: OptionalNullable[str] = UNSET
    r"""ID of the category of the line item"""

    shipping_id: OptionalNullable[str] = UNSET
    r"""ID of the shipping of the line item"""

    memo: OptionalNullable[str] = UNSET
    r"""Memo"""

    prepaid: OptionalNullable[bool] = UNSET
    r"""Whether the line item is prepaid"""

    tax_applicable_on: OptionalNullable[str] = UNSET
    r"""Tax applicable on"""

    tax_recoverability: OptionalNullable[str] = UNSET
    r"""Tax recoverability"""

    tax_method: OptionalNullable[str] = UNSET
    r"""Method of tax calculation"""

    retention_amount: OptionalNullable[float] = UNSET
    r"""Retention amount"""

    payment_amount: OptionalNullable[float] = UNSET
    r"""Payment amount"""

    item: Optional[LinkedInvoiceItem] = None

    tax_rate: Optional[LinkedTaxRate] = None

    ledger_account: OptionalNullable[LinkedLedgerAccount] = UNSET

    purchase_order: OptionalNullable[LinkedPurchaseOrder] = UNSET

    tracking_categories: OptionalNullable[List[Nullable[LinkedTrackingCategory]]] = (
        UNSET
    )
    r"""A list of linked tracking categories."""

    customer: OptionalNullable[LinkedCustomer] = UNSET
    r"""The customer this entity is linked to."""

    rebilling: OptionalNullable[Rebilling] = UNSET
    r"""Rebilling metadata for this line item."""

    row_version: OptionalNullable[str] = UNSET
    r"""A binary value used to detect updates to a object and prevent data conflicts. It is incremented each time an update is made to the object."""

    updated_by: OptionalNullable[str] = UNSET
    r"""The user who last updated the object."""

    created_by: OptionalNullable[str] = UNSET
    r"""The user who created the object."""

    created_at: OptionalNullable[datetime] = UNSET
    r"""The date and time when the object was created."""

    updated_at: OptionalNullable[datetime] = UNSET
    r"""The date and time when the object was last updated."""

    worktags: Optional[List[Nullable[LinkedWorktag]]] = None
    r"""A list of linked worktags. This is only supported for Workday."""

    @field_serializer("type")
    def serialize_type(self, value):
        if isinstance(value, str):
            try:
                return models.LineItemType(value)
            except ValueError:
                return value
        return value

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = [
            "id",
            "row_id",
            "code",
            "line_number",
            "description",
            "type",
            "tax_amount",
            "total_amount",
            "quantity",
            "unit_price",
            "unit_of_measure",
            "discount_percentage",
            "discount_amount",
            "location_id",
            "department_id",
            "subsidiary_id",
            "category_id",
            "shipping_id",
            "memo",
            "prepaid",
            "tax_applicable_on",
            "tax_recoverability",
            "tax_method",
            "retention_amount",
            "payment_amount",
            "item",
            "tax_rate",
            "ledger_account",
            "purchase_order",
            "tracking_categories",
            "customer",
            "rebilling",
            "row_version",
            "updated_by",
            "created_by",
            "created_at",
            "updated_at",
            "worktags",
        ]
        nullable_fields = [
            "code",
            "line_number",
            "description",
            "type",
            "tax_amount",
            "total_amount",
            "quantity",
            "unit_price",
            "unit_of_measure",
            "discount_percentage",
            "discount_amount",
            "location_id",
            "department_id",
            "subsidiary_id",
            "category_id",
            "shipping_id",
            "memo",
            "prepaid",
            "tax_applicable_on",
            "tax_recoverability",
            "tax_method",
            "retention_amount",
            "payment_amount",
            "ledger_account",
            "purchase_order",
            "tracking_categories",
            "customer",
            "rebilling",
            "row_version",
            "updated_by",
            "created_by",
            "created_at",
            "updated_at",
        ]
        null_default_fields = []

        serialized = handler(self)

        m = {}

        for n, f in type(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
