# coding: utf-8

"""
    Zuora API Reference

    REST API reference for the Zuora Billing, Payments, and Central Platform! Check out the [REST API Overview](https://www.zuora.com/developer/api-references/api/overview/).

    The version of the OpenAPI document: 2024-05-20
    Contact: docs@zuora.com
    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
from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictFloat, StrictInt, StrictStr
from typing import Any, ClassVar, Dict, List, Optional, Union
from zuora_sdk.models.expanded_contact import ExpandedContact
from typing import Optional, Set
from typing_extensions import Self

class ExpandedSubscription(BaseModel):
    """
    ExpandedSubscription
    """ # noqa: E501
    # avoid validation
    def __init__(self, **kwargs):
        # Directly assign values without validation using `construct()`
        model = self.construct(**kwargs)
        self.__dict__.update(model.__dict__)

        _dict_all = convert_snake_dict_to_camel(kwargs, self.model_fields, self.__properties)

        _dict = self.to_alias_dict(_dict_all)
        for field_name, field_info in self.model_fields.items():
            alias = field_info.alias or field_name
            if alias in _dict:
                self.__dict__[field_name] = _dict.get(alias)
        self.update_additional_properties(self, _dict_all)
        pass

    def __setattr__(self, name, value):
        # Override setattr to bypass validation when setting attributes
        object.__setattr__(self, name, value)

    id: Optional[StrictStr] = None
    account_id: Optional[StrictStr] = Field(default=None, alias="accountId")
    auto_renew: Optional[StrictBool] = Field(default=None, alias="autoRenew")
    cancelled_date: Optional[date] = Field(default=None, alias="cancelledDate")
    contract_acceptance_date: Optional[date] = Field(default=None, alias="contractAcceptanceDate")
    contract_effective_date: Optional[date] = Field(default=None, alias="contractEffectiveDate")
    creator_account_id: Optional[StrictStr] = Field(default=None, alias="creatorAccountId")
    creator_invoice_owner_id: Optional[StrictStr] = Field(default=None, alias="creatorInvoiceOwnerId")
    current_term: Optional[StrictInt] = Field(default=None, alias="currentTerm")
    current_term_period_type: Optional[StrictStr] = Field(default=None, alias="currentTermPeriodType")
    initial_term: Optional[StrictInt] = Field(default=None, alias="initialTerm")
    initial_term_period_type: Optional[StrictStr] = Field(default=None, alias="initialTermPeriodType")
    invoice_group_number: Optional[StrictStr] = Field(default=None, alias="invoiceGroupNumber")
    invoice_owner_id: Optional[StrictStr] = Field(default=None, alias="invoiceOwnerId")
    is_invoice_separate: Optional[StrictBool] = Field(default=None, alias="isInvoiceSeparate")
    name: Optional[StrictStr] = None
    notes: Optional[StrictStr] = None
    original_created_date: Optional[StrictStr] = Field(default=None, alias="originalCreatedDate")
    original_id: Optional[StrictStr] = Field(default=None, alias="originalId")
    previous_subscription_id: Optional[StrictStr] = Field(default=None, alias="previousSubscriptionId")
    renewal_setting: Optional[StrictStr] = Field(default=None, alias="renewalSetting")
    renewal_term: Optional[StrictInt] = Field(default=None, alias="renewalTerm")
    renewal_term_period_type: Optional[StrictStr] = Field(default=None, alias="renewalTermPeriodType")
    revision: Optional[StrictStr] = None
    service_activation_date: Optional[date] = Field(default=None, alias="serviceActivationDate")
    status: Optional[StrictStr] = None
    is_latest_version: Optional[StrictBool] = Field(default=None, alias="isLatestVersion")
    subscription_end_date: Optional[date] = Field(default=None, alias="subscriptionEndDate")
    subscription_start_date: Optional[date] = Field(default=None, alias="subscriptionStartDate")
    subscription_version_amendment_id: Optional[StrictStr] = Field(default=None, alias="subscriptionVersionAmendmentId")
    term_end_date: Optional[date] = Field(default=None, alias="termEndDate")
    term_start_date: Optional[date] = Field(default=None, alias="termStartDate")
    term_type: Optional[StrictStr] = Field(default=None, alias="termType")
    version: Optional[StrictInt] = None
    created_by_id: Optional[StrictStr] = Field(default=None, alias="createdById")
    created_date: Optional[StrictStr] = Field(default=None, alias="createdDate")
    updated_by_id: Optional[StrictStr] = Field(default=None, alias="updatedById")
    updated_date: Optional[StrictStr] = Field(default=None, alias="updatedDate")
    c_mrr: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="cMRR")
    bill_to_contact_snapshot_id: Optional[StrictStr] = Field(default=None, alias="billToContactSnapshotId")
    bill_to_contact_id: Optional[StrictStr] = Field(default=None, alias="billToContactId")
    invoice_template_id: Optional[StrictStr] = Field(default=None, alias="invoiceTemplateId")
    sequence_set_id: Optional[StrictStr] = Field(default=None, alias="sequenceSetId")
    sold_to_contact_id: Optional[StrictStr] = Field(default=None, alias="soldToContactId")
    sold_to_contact_snapshot_id: Optional[StrictStr] = Field(default=None, alias="soldToContactSnapshotId")
    ship_to_contact_id: Optional[StrictStr] = Field(default=None, alias="shipToContactId")
    ship_to_contact_snapshot_id: Optional[StrictStr] = Field(default=None, alias="shipToContactSnapshotId")
    externally_managed_by: Optional[StrictStr] = Field(default=None, alias="externallyManagedBy")
    last_booking_date: Optional[date] = Field(default=None, alias="lastBookingDate")
    invoice_schedule_id: Optional[StrictStr] = Field(default=None, alias="invoiceScheduleId")
    cancel_reason: Optional[StrictStr] = Field(default=None, alias="cancelReason")
    prepayment: Optional[StrictBool] = None
    currency: Optional[StrictStr] = None
    is_single_versioned: Optional[StrictBool] = Field(default=None, alias="isSingleVersioned")
    order_id: Optional[StrictStr] = Field(default=None, alias="orderId")
    ramp_id: Optional[StrictStr] = Field(default=None, alias="rampId")
    payment_term: Optional[StrictStr] = Field(default=None, alias="paymentTerm")
    payment_method_id: Optional[StrictStr] = Field(default=None, alias="paymentMethodId")
    payment_gateway_id: Optional[StrictStr] = Field(default=None, alias="paymentGatewayId")
    quote_number__qt: Optional[StrictStr] = Field(default=None, alias="quoteNumber__QT")
    quote_type__qt: Optional[StrictStr] = Field(default=None, alias="quoteType__QT")
    quote_business_type__qt: Optional[StrictStr] = Field(default=None, alias="quoteBusinessType__QT")
    opportunity_name__qt: Optional[StrictStr] = Field(default=None, alias="opportunityName__QT")
    opportunity_close_date__qt: Optional[date] = Field(default=None, alias="opportunityCloseDate__QT")
    cpq_bundle_json_id__qt: Optional[StrictStr] = Field(default=None, alias="cpqBundleJsonId__QT")
    account: Optional[ExpandedAccount] = None
    invoice_owner: Optional[ExpandedAccount] = Field(default=None, alias="invoiceOwner")
    bill_to_contact: Optional[ExpandedContact] = Field(default=None, alias="billToContact")
    invoice_items: Optional[List[ExpandedInvoiceItem]] = Field(default=None, alias="invoiceItems")
    rate_plans: Optional[List[ExpandedRatePlan]] = Field(default=None, alias="ratePlans")
    order: Optional[ExpandedOrders] = None
    additional_properties: Dict[str, Any] = {}
    __properties: ClassVar[List[str]] = ["id", "accountId", "autoRenew", "cancelledDate", "contractAcceptanceDate", "contractEffectiveDate", "creatorAccountId", "creatorInvoiceOwnerId", "currentTerm", "currentTermPeriodType", "initialTerm", "initialTermPeriodType", "invoiceGroupNumber", "invoiceOwnerId", "isInvoiceSeparate", "name", "notes", "originalCreatedDate", "originalId", "previousSubscriptionId", "renewalSetting", "renewalTerm", "renewalTermPeriodType", "revision", "serviceActivationDate", "status", "isLatestVersion", "subscriptionEndDate", "subscriptionStartDate", "subscriptionVersionAmendmentId", "termEndDate", "termStartDate", "termType", "version", "createdById", "createdDate", "updatedById", "updatedDate", "cMRR", "billToContactSnapshotId", "billToContactId", "invoiceTemplateId", "sequenceSetId", "soldToContactId", "soldToContactSnapshotId", "shipToContactId", "shipToContactSnapshotId", "externallyManagedBy", "lastBookingDate", "invoiceScheduleId", "cancelReason", "prepayment", "currency", "isSingleVersioned", "orderId", "rampId", "paymentTerm", "paymentMethodId", "paymentGatewayId", "quoteNumber__QT", "quoteType__QT", "quoteBusinessType__QT", "opportunityName__QT", "opportunityCloseDate__QT", "cpqBundleJsonId__QT", "account", "invoiceOwner", "billToContact", "invoiceItems", "ratePlans", "order"]

    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 ExpandedSubscription 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.
        * Fields in `self.additional_properties` are added to the output dict.
        """
        excluded_fields: Set[str] = set([
            "additional_properties",
        ])

        _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 invoice_owner
        if self.invoice_owner:
            _dict['invoiceOwner'] = self.invoice_owner.to_dict()
        # override the default output from pydantic by calling `to_dict()` of bill_to_contact
        if self.bill_to_contact:
            _dict['billToContact'] = self.bill_to_contact.to_dict()
        # override the default output from pydantic by calling `to_dict()` of each item in invoice_items (list)
        _items = []
        if self.invoice_items:
            for _item_invoice_items in self.invoice_items:
                if _item_invoice_items:
                    _items.append(_item_invoice_items.to_dict())
            _dict['invoiceItems'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in rate_plans (list)
        _items = []
        if self.rate_plans:
            for _item_rate_plans in self.rate_plans:
                if _item_rate_plans:
                    _items.append(_item_rate_plans.to_dict())
            _dict['ratePlans'] = _items
        # override the default output from pydantic by calling `to_dict()` of order
        if self.order:
            _dict['order'] = self.order.to_dict()
        # puts key-value pairs in additional_properties in the top level
        if self.additional_properties is not None:
            for _key, _value in self.additional_properties.items():
                _dict[_key] = _value

        return _dict

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

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

        obj = convert_snake_dict_to_camel(obj, cls.model_fields, cls.__properties)

        _obj = cls.model_validate(cls.to_alias_dict(obj))
        return cls.update_additional_properties(_obj, obj)

    @classmethod
    def update_additional_properties(cls, obj, _dict: Optional[Dict[str, Any]]):
        # store additional fields in additional_properties

        # store additional fields in additional_properties
        for _key in _dict.keys():
            if _key not in cls.__properties:
                obj.additional_properties[_key] = _dict.get(_key)


        return obj
        pass

    @classmethod
    def to_alias_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]:

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

        return {
            "id": obj.get("id"),
            "accountId": obj.get("accountId"),
            "autoRenew": obj.get("autoRenew"),
            "cancelledDate": obj.get("cancelledDate"),
            "contractAcceptanceDate": obj.get("contractAcceptanceDate"),
            "contractEffectiveDate": obj.get("contractEffectiveDate"),
            "creatorAccountId": obj.get("creatorAccountId"),
            "creatorInvoiceOwnerId": obj.get("creatorInvoiceOwnerId"),
            "currentTerm": obj.get("currentTerm"),
            "currentTermPeriodType": obj.get("currentTermPeriodType"),
            "initialTerm": obj.get("initialTerm"),
            "initialTermPeriodType": obj.get("initialTermPeriodType"),
            "invoiceGroupNumber": obj.get("invoiceGroupNumber"),
            "invoiceOwnerId": obj.get("invoiceOwnerId"),
            "isInvoiceSeparate": obj.get("isInvoiceSeparate"),
            "name": obj.get("name"),
            "notes": obj.get("notes"),
            "originalCreatedDate": obj.get("originalCreatedDate"),
            "originalId": obj.get("originalId"),
            "previousSubscriptionId": obj.get("previousSubscriptionId"),
            "renewalSetting": obj.get("renewalSetting"),
            "renewalTerm": obj.get("renewalTerm"),
            "renewalTermPeriodType": obj.get("renewalTermPeriodType"),
            "revision": obj.get("revision"),
            "serviceActivationDate": obj.get("serviceActivationDate"),
            "status": obj.get("status"),
            "isLatestVersion": obj.get("isLatestVersion"),
            "subscriptionEndDate": obj.get("subscriptionEndDate"),
            "subscriptionStartDate": obj.get("subscriptionStartDate"),
            "subscriptionVersionAmendmentId": obj.get("subscriptionVersionAmendmentId"),
            "termEndDate": obj.get("termEndDate"),
            "termStartDate": obj.get("termStartDate"),
            "termType": obj.get("termType"),
            "version": obj.get("version"),
            "createdById": obj.get("createdById"),
            "createdDate": obj.get("createdDate"),
            "updatedById": obj.get("updatedById"),
            "updatedDate": obj.get("updatedDate"),
            "cMRR": obj.get("cMRR"),
            "billToContactSnapshotId": obj.get("billToContactSnapshotId"),
            "billToContactId": obj.get("billToContactId"),
            "invoiceTemplateId": obj.get("invoiceTemplateId"),
            "sequenceSetId": obj.get("sequenceSetId"),
            "soldToContactId": obj.get("soldToContactId"),
            "soldToContactSnapshotId": obj.get("soldToContactSnapshotId"),
            "shipToContactId": obj.get("shipToContactId"),
            "shipToContactSnapshotId": obj.get("shipToContactSnapshotId"),
            "externallyManagedBy": obj.get("externallyManagedBy"),
            "lastBookingDate": obj.get("lastBookingDate"),
            "invoiceScheduleId": obj.get("invoiceScheduleId"),
            "cancelReason": obj.get("cancelReason"),
            "prepayment": obj.get("prepayment"),
            "currency": obj.get("currency"),
            "isSingleVersioned": obj.get("isSingleVersioned"),
            "orderId": obj.get("orderId"),
            "rampId": obj.get("rampId"),
            "paymentTerm": obj.get("paymentTerm"),
            "paymentMethodId": obj.get("paymentMethodId"),
            "paymentGatewayId": obj.get("paymentGatewayId"),
            "quoteNumber__QT": obj.get("quoteNumber__QT"),
            "quoteType__QT": obj.get("quoteType__QT"),
            "quoteBusinessType__QT": obj.get("quoteBusinessType__QT"),
            "opportunityName__QT": obj.get("opportunityName__QT"),
            "opportunityCloseDate__QT": obj.get("opportunityCloseDate__QT"),
            "cpqBundleJsonId__QT": obj.get("cpqBundleJsonId__QT"),
            "account": ExpandedAccount.from_dict(obj["account"]) if obj.get("account") is not None else None,
            "invoiceOwner": ExpandedAccount.from_dict(obj["invoiceOwner"]) if obj.get("invoiceOwner") is not None else None,
            "billToContact": ExpandedContact.from_dict(obj["billToContact"]) if obj.get("billToContact") is not None else None,
            "invoiceItems": [ExpandedInvoiceItem.from_dict(_item) for _item in obj["invoiceItems"]] if obj.get("invoiceItems") is not None else None,
            "ratePlans": [ExpandedRatePlan.from_dict(_item) for _item in obj["ratePlans"]] if obj.get("ratePlans") is not None else None,
            "order": ExpandedOrders.from_dict(obj["order"]) if obj.get("order") is not None else None
        }
        return _obj
from zuora_sdk.models.expanded_account import ExpandedAccount
from zuora_sdk.models.expanded_invoice_item import ExpandedInvoiceItem
from zuora_sdk.models.expanded_orders import ExpandedOrders
from zuora_sdk.models.expanded_rate_plan import ExpandedRatePlan
# TODO: Rewrite to not use raise_errors
ExpandedSubscription.model_rebuild(raise_errors=False)


def convert_snake_dict_to_camel(_dict: dict, model_fields, properties):
    if not isinstance(_dict, dict):
        return _dict
    new_dict = {}
    for k, v in _dict.items():
        if k in model_fields:
            # model_fields: key is attribute name like bill_to_contact,
            alias = model_fields.get(k).alias or k
            new_dict[alias] = v
            pass
        else:
            new_key = snake_to_camel(k)
            if properties is not None and isinstance(properties, list) and new_key in properties:
                new_dict[new_key] = v
            else:
                new_dict[k] = v
    return new_dict
    pass


def snake_to_camel(name):
    if name is None or '_' not in name:
        return name
    components = name.split('_')
    return components[0] + ''.join(x.title() for x in components[1:])
