# coding: utf-8

"""
    Cloudbeds Accounting Service API

    The Cloudbeds Accounting Service API provides programmatic access to financial data and operations for hospitality properties. Use this API to manage transactions, folios, deposits, accounts receivable ledgers, trial balances, and related accounting configuration.  **Key concepts:** - **Transactions** represent individual financial entries (charges, payments,   taxes, fees) associated with a source such as a reservation, group profile,   or house account.  - **Folios** organize transactions into logical groups within a source. You   can create custom folios and move or route transactions between them.  - **Source Balances** provide a real-time financial summary (charges, payments,   balance due, tax/fee breakdowns) for a reservation, group profile, house   account, or accounts receivable ledger.  - **Accounts Receivable (AR) Ledgers** track outstanding balances that have   been transferred from reservations or group profiles for later collection.  - **Trial Balance** is a daily financial reconciliation report that summarizes   ledger activity across guest, deposit, and AR ledgers.  - **Custom Codes** let you map Cloudbeds internal transaction codes to your   own chart-of-accounts codes and general ledger codes.   **Authentication:** All endpoints require a valid OAuth2 bearer token. Endpoints are protected by scopes: `read:payment` for read operations and `write:payment` for mutating operations. A few search endpoints use POST with a request body to support complex filter criteria; these require the `read:payment` scope.  **Base URL:** Use `https://api.cloudbeds.com` for production and `https://api.cloudbeds-stage.com` for staging. All endpoint paths are prefixed with `/accounting/v1.0`.  **Property context:** Every request must include the `X-Property-ID` header to identify which property the request applies to.  **Monetary amounts:** Unless otherwise noted, monetary amounts are expressed in the smallest currency unit (e.g., cents for USD). Use the `currencyScale` field to determine the number of decimal places.  **Pagination:** Paginated endpoints return a `nextPageToken` value. Pass this token in subsequent requests to retrieve the next page of results. When `nextPageToken` is null or absent, you have reached the last page. 

    The version of the OpenAPI document: v0
    Generated by OpenAPI Generator (https://openapi-generator.tech)

    Do not edit the class manually.
"""  # noqa: E501


from __future__ import annotations
import pprint
import re  # noqa: F401
import json

from datetime import date, datetime
from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictFloat, StrictInt, StrictStr, field_validator
from typing import Any, ClassVar, Dict, List, Optional, Union
from cloudbeds_accounting.models.account import Account
from cloudbeds_accounting.models.action import Action
from cloudbeds_accounting.models.external_relation_kind import ExternalRelationKind
from cloudbeds_accounting.models.fiscal_document_summary import FiscalDocumentSummary
from cloudbeds_accounting.models.folio_payment_allocation import FolioPaymentAllocation
from cloudbeds_accounting.models.internal_transaction_code_group_enum import InternalTransactionCodeGroupEnum
from cloudbeds_accounting.models.payment_details import PaymentDetails
from cloudbeds_accounting.models.reservation_status import ReservationStatus
from cloudbeds_accounting.models.routing_context import RoutingContext
from cloudbeds_accounting.models.source_kind import SourceKind
from cloudbeds_accounting.models.user_model import UserModel
from typing import Optional, Set
from typing_extensions import Self

class FolioTransactionResponse(BaseModel):
    """
    FolioTransactionResponse
    """ # noqa: E501
    id: Optional[StrictStr] = None
    property_id: Optional[StrictStr] = Field(default=None, alias="propertyId")
    amount: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="Transaction amount in decimal form (e.g. 150.00, not 15000). Sign depends on account type.")
    currency: Optional[StrictStr] = Field(default=None, description="Currency ISO code")
    currency_scale: Optional[StrictInt] = Field(default=None, description="Number of decimal places for the currency", alias="currencyScale")
    description: Optional[StrictStr] = None
    notes: Optional[StrictStr] = None
    quantity: Optional[StrictInt] = None
    transaction_type: Optional[StrictStr] = Field(default=None, description="UI-facing transaction type. Derived from internalTransactionCode: if code suffix is \"A\" → \"adjustment\", otherwise mapped from internalCodeGroup. Maps 1:1 to MFD ReservationTransactionType except roomRevenue is split into 3. ", alias="transactionType")
    internal_transaction_code: Optional[StrictStr] = Field(default=None, description="Internal code managed by Cloudbeds (e.g. \"1000\", \"9000\")", alias="internalTransactionCode")
    internal_code_group: Optional[InternalTransactionCodeGroupEnum] = Field(default=None, alias="internalCodeGroup")
    custom_transaction_code: Optional[StrictStr] = Field(default=None, description="Custom code managed by Property", alias="customTransactionCode")
    general_ledger_custom_code: Optional[StrictStr] = Field(default=None, alias="generalLedgerCustomCode")
    transaction_datetime: Optional[datetime] = Field(default=None, description="Transaction datetime (UTC)", alias="transactionDatetime")
    transaction_datetime_property_time: Optional[datetime] = Field(default=None, description="Transaction datetime in property timezone", alias="transactionDatetimePropertyTime")
    service_date: Optional[date] = Field(default=None, alias="serviceDate")
    created_at: Optional[datetime] = Field(default=None, alias="createdAt")
    source_id: Optional[StrictStr] = Field(default=None, alias="sourceId")
    source_kind: Optional[SourceKind] = Field(default=None, alias="sourceKind")
    sub_source_id: Optional[StrictStr] = Field(default=None, description="Booking room ID for reservations", alias="subSourceId")
    sub_source_identifier: Optional[StrictStr] = Field(default=None, description="Booking room identifier", alias="subSourceIdentifier")
    source_identifier: Optional[StrictStr] = Field(default=None, description="Reservation identifier or group code", alias="sourceIdentifier")
    parent_id: Optional[StrictStr] = Field(default=None, alias="parentId")
    root_id: Optional[StrictStr] = Field(default=None, alias="rootId")
    origin_id: Optional[StrictStr] = Field(default=None, alias="originId")
    routed_from: Optional[StrictStr] = Field(default=None, alias="routedFrom")
    customer_id: Optional[StrictStr] = Field(default=None, alias="customerId")
    user_id: Optional[StrictStr] = Field(default=None, alias="userId")
    external_relation_id: Optional[StrictStr] = Field(default=None, alias="externalRelationId")
    external_relation_kind: Optional[ExternalRelationKind] = Field(default=None, alias="externalRelationKind")
    account: Optional[Account] = None
    folio_id: Optional[StrictStr] = Field(default=None, alias="folioId")
    posted: Optional[StrictBool] = Field(default=None, description="Whether the transaction is posted")
    state: Optional[StrictStr] = None
    read_only: Optional[StrictBool] = Field(default=None, description="Whether the transaction is read-only (no void/refund/allocation actions allowed). Computed from reservation status, property config, and transaction state. ", alias="readOnly")
    reservation_name: Optional[StrictStr] = Field(default=None, alias="reservationName")
    room_name: Optional[StrictStr] = Field(default=None, description="Room name/identifier for the booking room associated with this transaction", alias="roomName")
    checkin_date: Optional[date] = Field(default=None, alias="checkinDate")
    checkout_date: Optional[date] = Field(default=None, alias="checkoutDate")
    reservation_status: Optional[ReservationStatus] = Field(default=None, alias="reservationStatus")
    user: Optional[UserModel] = None
    actions: Optional[List[Action]] = Field(default=None, description="Returns the list of actions available for the transaction")
    payment_details: Optional[PaymentDetails] = Field(default=None, alias="paymentDetails")
    routing_context: Optional[RoutingContext] = Field(default=None, alias="routingContext")
    locked: Optional[StrictBool] = Field(default=None, description="Whether transaction is locked by fiscal documents")
    locked_by_fiscal_documents: Optional[List[FiscalDocumentSummary]] = Field(default=None, alias="lockedByFiscalDocuments")
    allocated_payments: Optional[List[FolioPaymentAllocation]] = Field(default=None, description="Payment allocations for payment-type transactions. Only present for PAYMENT transactions.", alias="allocatedPayments")
    foreign_currency: Optional[StrictStr] = Field(default=None, description="Original payment currency code when different from property currency", alias="foreignCurrency")
    foreign_currency_amount: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="Amount in foreign currency", alias="foreignCurrencyAmount")
    __properties: ClassVar[List[str]] = ["id", "propertyId", "amount", "currency", "currencyScale", "description", "notes", "quantity", "transactionType", "internalTransactionCode", "internalCodeGroup", "customTransactionCode", "generalLedgerCustomCode", "transactionDatetime", "transactionDatetimePropertyTime", "serviceDate", "createdAt", "sourceId", "sourceKind", "subSourceId", "subSourceIdentifier", "sourceIdentifier", "parentId", "rootId", "originId", "routedFrom", "customerId", "userId", "externalRelationId", "externalRelationKind", "account", "folioId", "posted", "state", "readOnly", "reservationName", "roomName", "checkinDate", "checkoutDate", "reservationStatus", "user", "actions", "paymentDetails", "routingContext", "locked", "lockedByFiscalDocuments", "allocatedPayments", "foreignCurrency", "foreignCurrencyAmount"]

    @field_validator('transaction_type')
    def transaction_type_validate_enum(cls, value):
        """Validates the enum, returning unknown_default_open_api for unrecognized values"""
        if value is None:
            return value

        _allowed_values = set(['payment', 'product', 'addon', 'rate', 'roomRevenue_manual', 'roomRevenue_cancellation', 'roomRevenue_no_show', 'tax', 'fee', 'custom_item', 'accountsReceivable', 'adjustment', 'space', 'unknown_default_open_api'])
        if value not in _allowed_values:
            return 'unknown_default_open_api'
        return value

    @field_validator('state')
    def state_validate_enum(cls, value):
        """Validates the enum, returning unknown_default_open_api for unrecognized values"""
        if value is None:
            return value

        _allowed_values = set(['VOIDED', 'TRANSFERRED', 'CANCELLED', 'REFUNDED', 'DELETED', 'unknown_default_open_api'])
        if value not in _allowed_values:
            return 'unknown_default_open_api'
        return value

    model_config = ConfigDict(
        populate_by_name=True,
        validate_assignment=True,
        protected_namespaces=(),
    )


    def to_str(self) -> str:
        """Returns the string representation of the model using alias"""
        return pprint.pformat(self.model_dump(by_alias=True))

    def to_json(self) -> str:
        """Returns the JSON representation of the model using alias"""
        # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
        return json.dumps(self.to_dict())

    @classmethod
    def from_json(cls, json_str: str) -> Optional[Self]:
        """Create an instance of FolioTransactionResponse from a JSON string"""
        return cls.from_dict(json.loads(json_str))

    def to_dict(self) -> Dict[str, Any]:
        """Return the dictionary representation of the model using alias.

        This has the following differences from calling pydantic's
        `self.model_dump(by_alias=True)`:

        * `None` is only added to the output dict for nullable fields that
          were set at model initialization. Other fields with value `None`
          are ignored.
        """
        excluded_fields: Set[str] = set([
        ])

        _dict = self.model_dump(
            by_alias=True,
            exclude=excluded_fields,
            exclude_none=True,
        )
        # override the default output from pydantic by calling `to_dict()` of account
        if self.account:
            _dict['account'] = self.account.to_dict()
        # override the default output from pydantic by calling `to_dict()` of user
        if self.user:
            _dict['user'] = self.user.to_dict()
        # override the default output from pydantic by calling `to_dict()` of each item in actions (list)
        _items = []
        if self.actions:
            for _item_actions in self.actions:
                if _item_actions:
                    _items.append(_item_actions.to_dict())
            _dict['actions'] = _items
        # override the default output from pydantic by calling `to_dict()` of payment_details
        if self.payment_details:
            _dict['paymentDetails'] = self.payment_details.to_dict()
        # override the default output from pydantic by calling `to_dict()` of routing_context
        if self.routing_context:
            _dict['routingContext'] = self.routing_context.to_dict()
        # override the default output from pydantic by calling `to_dict()` of each item in locked_by_fiscal_documents (list)
        _items = []
        if self.locked_by_fiscal_documents:
            for _item_locked_by_fiscal_documents in self.locked_by_fiscal_documents:
                if _item_locked_by_fiscal_documents:
                    _items.append(_item_locked_by_fiscal_documents.to_dict())
            _dict['lockedByFiscalDocuments'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in allocated_payments (list)
        _items = []
        if self.allocated_payments:
            for _item_allocated_payments in self.allocated_payments:
                if _item_allocated_payments:
                    _items.append(_item_allocated_payments.to_dict())
            _dict['allocatedPayments'] = _items
        # set to None if actions (nullable) is None
        # and model_fields_set contains the field
        if self.actions is None and "actions" in self.model_fields_set:
            _dict['actions'] = None

        # set to None if allocated_payments (nullable) is None
        # and model_fields_set contains the field
        if self.allocated_payments is None and "allocated_payments" in self.model_fields_set:
            _dict['allocatedPayments'] = None

        return _dict

    @classmethod
    def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
        """Create an instance of FolioTransactionResponse from a dict"""
        if obj is None:
            return None

        if not isinstance(obj, dict):
            return cls.model_validate(obj)

        _obj = cls.model_validate({
            "id": obj.get("id"),
            "propertyId": obj.get("propertyId"),
            "amount": obj.get("amount"),
            "currency": obj.get("currency"),
            "currencyScale": obj.get("currencyScale"),
            "description": obj.get("description"),
            "notes": obj.get("notes"),
            "quantity": obj.get("quantity"),
            "transactionType": obj.get("transactionType"),
            "internalTransactionCode": obj.get("internalTransactionCode"),
            "internalCodeGroup": obj.get("internalCodeGroup"),
            "customTransactionCode": obj.get("customTransactionCode"),
            "generalLedgerCustomCode": obj.get("generalLedgerCustomCode"),
            "transactionDatetime": obj.get("transactionDatetime"),
            "transactionDatetimePropertyTime": obj.get("transactionDatetimePropertyTime"),
            "serviceDate": obj.get("serviceDate"),
            "createdAt": obj.get("createdAt"),
            "sourceId": obj.get("sourceId"),
            "sourceKind": obj.get("sourceKind"),
            "subSourceId": obj.get("subSourceId"),
            "subSourceIdentifier": obj.get("subSourceIdentifier"),
            "sourceIdentifier": obj.get("sourceIdentifier"),
            "parentId": obj.get("parentId"),
            "rootId": obj.get("rootId"),
            "originId": obj.get("originId"),
            "routedFrom": obj.get("routedFrom"),
            "customerId": obj.get("customerId"),
            "userId": obj.get("userId"),
            "externalRelationId": obj.get("externalRelationId"),
            "externalRelationKind": obj.get("externalRelationKind"),
            "account": Account.from_dict(obj["account"]) if obj.get("account") is not None else None,
            "folioId": obj.get("folioId"),
            "posted": obj.get("posted"),
            "state": obj.get("state"),
            "readOnly": obj.get("readOnly"),
            "reservationName": obj.get("reservationName"),
            "roomName": obj.get("roomName"),
            "checkinDate": obj.get("checkinDate"),
            "checkoutDate": obj.get("checkoutDate"),
            "reservationStatus": obj.get("reservationStatus"),
            "user": UserModel.from_dict(obj["user"]) if obj.get("user") is not None else None,
            "actions": [Action.from_dict(_item) for _item in obj["actions"]] if obj.get("actions") is not None else None,
            "paymentDetails": PaymentDetails.from_dict(obj["paymentDetails"]) if obj.get("paymentDetails") is not None else None,
            "routingContext": RoutingContext.from_dict(obj["routingContext"]) if obj.get("routingContext") is not None else None,
            "locked": obj.get("locked"),
            "lockedByFiscalDocuments": [FiscalDocumentSummary.from_dict(_item) for _item in obj["lockedByFiscalDocuments"]] if obj.get("lockedByFiscalDocuments") is not None else None,
            "allocatedPayments": [FolioPaymentAllocation.from_dict(_item) for _item in obj["allocatedPayments"]] if obj.get("allocatedPayments") is not None else None,
            "foreignCurrency": obj.get("foreignCurrency"),
            "foreignCurrencyAmount": obj.get("foreignCurrencyAmount")
        })
        return _obj


