# 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, field_validator
from typing import Any, ClassVar, Dict, List, Optional, Union
from zuora_sdk.models.apply_discount_to import ApplyDiscountTo
from zuora_sdk.models.billing_period_alignment import BillingPeriodAlignment
from zuora_sdk.models.charge_function import ChargeFunction
from zuora_sdk.models.charge_model_configuration_for_subscription import ChargeModelConfigurationForSubscription
from zuora_sdk.models.commitment_type import CommitmentType
from zuora_sdk.models.delivery_schedule import DeliverySchedule
from zuora_sdk.models.discount_apply_detail import DiscountApplyDetail
from zuora_sdk.models.discount_level import DiscountLevel
from zuora_sdk.models.end_date_condition import EndDateCondition
from zuora_sdk.models.interval_pricing import IntervalPricing
from zuora_sdk.models.price_change_option import PriceChangeOption
from zuora_sdk.models.rate_plan_charge_tier import RatePlanChargeTier
from zuora_sdk.models.trigger_event import TriggerEvent
from zuora_sdk.models.up_to_periods_type import UpToPeriodsType
from zuora_sdk.models.validity_period_type import ValidityPeriodType
from typing import Optional, Set
from typing_extensions import Self

class RatePlanChargeSegmentInfo(BaseModel):
    """
    RatePlanChargeSegmentInfo
    """ # 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
    amended_by_order_on: Optional[date] = Field(default=None, description="The date when the rate plan charge is amended through an order or amendment. This field is to standardize the booking date information to increase audit ability and traceability of data between Zuora Billing and Zuora Revenue. It is mapped as the booking date for a sale order line in Zuora Revenue. ", alias="amendedByOrderOn")
    apply_discount_to: Optional[ApplyDiscountTo] = Field(default=None, alias="applyDiscountTo")
    charge_function: Optional[ChargeFunction] = Field(default=None, alias="chargeFunction")
    charge_model_configuration: Optional[ChargeModelConfigurationForSubscription] = Field(default=None, alias="chargeModelConfiguration")
    charged_through_date: Optional[date] = Field(default=None, description="The date through which a customer has been billed for the charge. ", alias="chargedThroughDate")
    commitment_type: Optional[CommitmentType] = Field(default=None, alias="commitmentType")
    prepaid_committed_amount: Optional[StrictStr] = Field(default=None, alias="prepaidCommittedAmount")
    credit_option: Optional[StrictStr] = Field(default=None, description="**Note**: This field is only available if you have the [Prepaid with Drawdown](https://knowledgecenter.zuora.com/Billing/Billing_and_Payments/J_Billing_Operations/Prepaid_with_Drawdown) feature enabled.  To use this field, you must set the `X-Zuora-WSDL-Version` request header to 114 or higher. Otherwise, an error occurs.  The way to calculate credit. See [Credit Option](https://knowledgecenter.zuora.com/Billing/Billing_and_Payments/J_Billing_Operations/Prepaid_with_Drawdown/Create_prepayment_charge#Credit_Option) for more information. ", alias="creditOption")
    currency: Optional[StrictStr] = Field(default=None, description="Currency used by the account. For example, `USD` or `EUR`.")
    delivery_schedule: Optional[DeliverySchedule] = Field(default=None, alias="deliverySchedule")
    number_of_deliveries: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="numberOfDeliveries")
    description: Optional[StrictStr] = Field(default=None, description="Description of the rate plan charge.")
    discount_amount: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="The amount of the discount.", alias="discountAmount")
    discount_apply_details: Optional[List[DiscountApplyDetail]] = Field(default=None, description="Container for the application details about a discount rate plan charge.   Only discount rate plan charges have values in this field. ", alias="discountApplyDetails")
    discount_class: Optional[StrictStr] = Field(default=None, description="The class that the discount belongs to. The discount class defines the order in which discount rate plan charges are applied.  For more information, see [Manage Discount Classes](https://knowledgecenter.zuora.com/BC_Subscription_Management/Product_Catalog/B_Charge_Models/Manage_Discount_Classes). ", alias="discountClass")
    discount_level: Optional[DiscountLevel] = Field(default=None, alias="discountLevel")
    discount_percentage: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="The amount of the discount as a percentage. ", alias="discountPercentage")
    apply_to_billing_period_partially: Optional[StrictBool] = Field(default=None, alias="applyToBillingPeriodPartially")
    dmrc: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="The change (delta) of monthly recurring charge exists when the change in monthly recurring revenue caused by an amendment or a new subscription. ")
    done: Optional[StrictBool] = Field(default=None, description="A value of `true` indicates that an invoice for a charge segment has been completed. A value of `false` indicates that an invoice has not been completed for the charge segment. ")
    drawdown_rate: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="drawdownRate")
    drawdown_uom: Optional[StrictStr] = Field(default=None, description="Specifies the units to measure usage.", alias="drawdownUom")
    dtcv: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="After an amendment or an AutomatedPriceChange event, `dtcv` displays the change (delta) for the total contract value (TCV) amount for this charge, compared with its previous value with recurring charge types. ")
    effective_end_date: Optional[date] = Field(default=None, alias="effectiveEndDate")
    effective_start_date: Optional[date] = Field(default=None, alias="effectiveStartDate")
    end_date_condition: Optional[EndDateCondition] = Field(default=None, alias="endDateCondition")
    included_units: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="includedUnits")
    input_argument_id: Optional[StrictStr] = Field(default=None, alias="inputArgumentId")
    is_committed: Optional[StrictBool] = Field(default=None, alias="isCommitted")
    is_prepaid: Optional[StrictBool] = Field(default=None, alias="isPrepaid")
    is_rollover: Optional[StrictBool] = Field(default=None, alias="isRollover")
    mrr: Optional[Union[StrictFloat, StrictInt]] = None
    original_order_date: Optional[date] = Field(default=None, alias="originalOrderDate")
    overage_price: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="overagePrice")
    prepaid_operation_type: Optional[StrictStr] = Field(default=None, alias="prepaidOperationType")
    prepaid_quantity: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="prepaidQuantity")
    prepaid_total_quantity: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="prepaidTotalQuantity")
    prepaid_uom: Optional[StrictStr] = Field(default=None, description="Specifies the units to measure usage.", alias="prepaidUOM")
    quantity: Optional[Union[StrictFloat, StrictInt]] = None
    price: Optional[Union[StrictFloat, StrictInt]] = None
    price_change_option: Optional[PriceChangeOption] = Field(default=PriceChangeOption.NOCHANGE, alias="priceChangeOption")
    price_increase_percentage: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="priceIncreasePercentage")
    pricing_summary: Optional[StrictStr] = Field(default=None, alias="pricingSummary")
    original_list_price: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="originalListPrice")
    processed_through_date: Optional[date] = Field(default=None, alias="processedThroughDate")
    rollover_apply: Optional[StrictStr] = Field(default=None, alias="rolloverApply")
    rollover_period_length: Optional[StrictInt] = Field(default=None, alias="rolloverPeriodLength")
    rollover_periods: Optional[StrictInt] = Field(default=None, alias="rolloverPeriods")
    proration_option: Optional[StrictStr] = Field(default=None, alias="prorationOption")
    segment: Optional[StrictInt] = None
    specific_end_date: Optional[date] = Field(default=None, alias="specificEndDate")
    subscription_charge_interval_pricing: Optional[List[IntervalPricing]] = Field(default=None, alias="subscriptionChargeIntervalPricing")
    tcv: Optional[Union[StrictFloat, StrictInt]] = None
    tiers: Optional[List[RatePlanChargeTier]] = None
    trigger_date: Optional[date] = Field(default=None, alias="triggerDate")
    billing_period_alignment: Optional[BillingPeriodAlignment] = Field(default=None, alias="billingPeriodAlignment")
    trigger_event: Optional[TriggerEvent] = Field(default=None, alias="triggerEvent")
    up_to_periods: Optional[StrictInt] = Field(default=None, alias="upToPeriods")
    up_to_periods_type: Optional[UpToPeriodsType] = Field(default=None, alias="upToPeriodsType")
    validity_period_type: Optional[ValidityPeriodType] = Field(default=None, alias="validityPeriodType")
    sales_price: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="salesPrice")
    accounting_code: Optional[StrictStr] = Field(default=None, alias="accountingCode")
    revenue_recognition_code: Optional[StrictStr] = Field(default=None, alias="revenueRecognitionCode")
    rev_rec_trigger_condition: Optional[StrictStr] = Field(default=None, alias="revRecTriggerCondition")
    estimated_end_date: Optional[date] = Field(default=None, alias="estimatedEndDate")
    estimated_start_date: Optional[date] = Field(default=None, alias="estimatedStartDate")
    taxable: Optional[StrictBool] = None
    tax_code: Optional[StrictStr] = Field(default=None, alias="taxCode")
    tax_mode: Optional[StrictStr] = Field(default=None, alias="taxMode")
    additional_properties: Dict[str, Any] = {}
    __properties: ClassVar[List[str]] = ["id", "amendedByOrderOn", "applyDiscountTo", "chargeFunction", "chargeModelConfiguration", "chargedThroughDate", "commitmentType", "prepaidCommittedAmount", "creditOption", "currency", "deliverySchedule", "numberOfDeliveries", "description", "discountAmount", "discountApplyDetails", "discountClass", "discountLevel", "discountPercentage", "applyToBillingPeriodPartially", "dmrc", "done", "drawdownRate", "drawdownUom", "dtcv", "effectiveEndDate", "effectiveStartDate", "endDateCondition", "includedUnits", "inputArgumentId", "isCommitted", "isPrepaid", "isRollover", "mrr", "originalOrderDate", "overagePrice", "prepaidOperationType", "prepaidQuantity", "prepaidTotalQuantity", "prepaidUOM", "quantity", "price", "priceChangeOption", "priceIncreasePercentage", "pricingSummary", "originalListPrice", "processedThroughDate", "rolloverApply", "rolloverPeriodLength", "rolloverPeriods", "prorationOption", "segment", "specificEndDate", "subscriptionChargeIntervalPricing", "tcv", "tiers", "triggerDate", "billingPeriodAlignment", "triggerEvent", "upToPeriods", "upToPeriodsType", "validityPeriodType", "salesPrice", "accountingCode", "revenueRecognitionCode", "revRecTriggerCondition", "estimatedEndDate", "estimatedStartDate", "taxable", "taxCode", "taxMode"]

    @field_validator('credit_option')
    def credit_option_validate_enum(cls, value):
        """Validates the enum"""
        if value is None:
            return value

        if value not in set(['TimeBased', 'ConsumptionBased', 'FullCreditBack']):
            raise ValueError("must be one of enum values ('TimeBased', 'ConsumptionBased', 'FullCreditBack')")
        return value

    @field_validator('prepaid_operation_type')
    def prepaid_operation_type_validate_enum(cls, value):
        """Validates the enum"""
        if value is None:
            return value

        if value not in set(['topup', 'drawdown']):
            raise ValueError("must be one of enum values ('topup', 'drawdown')")
        return value

    @field_validator('rollover_apply')
    def rollover_apply_validate_enum(cls, value):
        """Validates the enum"""
        if value is None:
            return value

        if value not in set(['ApplyFirst', 'ApplyLast']):
            raise ValueError("must be one of enum values ('ApplyFirst', 'ApplyLast')")
        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 RatePlanChargeSegmentInfo 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 charge_model_configuration
        if self.charge_model_configuration:
            _dict['chargeModelConfiguration'] = self.charge_model_configuration.to_dict()
        # override the default output from pydantic by calling `to_dict()` of delivery_schedule
        if self.delivery_schedule:
            _dict['deliverySchedule'] = self.delivery_schedule.to_dict()
        # override the default output from pydantic by calling `to_dict()` of each item in discount_apply_details (list)
        _items = []
        if self.discount_apply_details:
            for _item_discount_apply_details in self.discount_apply_details:
                if _item_discount_apply_details:
                    _items.append(_item_discount_apply_details.to_dict())
            _dict['discountApplyDetails'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in subscription_charge_interval_pricing (list)
        _items = []
        if self.subscription_charge_interval_pricing:
            for _item_subscription_charge_interval_pricing in self.subscription_charge_interval_pricing:
                if _item_subscription_charge_interval_pricing:
                    _items.append(_item_subscription_charge_interval_pricing.to_dict())
            _dict['subscriptionChargeIntervalPricing'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in tiers (list)
        _items = []
        if self.tiers:
            for _item_tiers in self.tiers:
                if _item_tiers:
                    _items.append(_item_tiers.to_dict())
            _dict['tiers'] = _items
        # 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 RatePlanChargeSegmentInfo 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"),
            "amendedByOrderOn": obj.get("amendedByOrderOn"),
            "applyDiscountTo": obj.get("applyDiscountTo"),
            "chargeFunction": obj.get("chargeFunction"),
            "chargeModelConfiguration": ChargeModelConfigurationForSubscription.from_dict(obj["chargeModelConfiguration"]) if obj.get("chargeModelConfiguration") is not None else None,
            "chargedThroughDate": obj.get("chargedThroughDate"),
            "commitmentType": obj.get("commitmentType"),
            "prepaidCommittedAmount": obj.get("prepaidCommittedAmount"),
            "creditOption": obj.get("creditOption"),
            "currency": obj.get("currency"),
            "deliverySchedule": DeliverySchedule.from_dict(obj["deliverySchedule"]) if obj.get("deliverySchedule") is not None else None,
            "numberOfDeliveries": obj.get("numberOfDeliveries"),
            "description": obj.get("description"),
            "discountAmount": obj.get("discountAmount"),
            "discountApplyDetails": [DiscountApplyDetail.from_dict(_item) for _item in obj["discountApplyDetails"]] if obj.get("discountApplyDetails") is not None else None,
            "discountClass": obj.get("discountClass"),
            "discountLevel": obj.get("discountLevel"),
            "discountPercentage": obj.get("discountPercentage"),
            "applyToBillingPeriodPartially": obj.get("applyToBillingPeriodPartially"),
            "dmrc": obj.get("dmrc"),
            "done": obj.get("done"),
            "drawdownRate": obj.get("drawdownRate"),
            "drawdownUom": obj.get("drawdownUom"),
            "dtcv": obj.get("dtcv"),
            "effectiveEndDate": obj.get("effectiveEndDate"),
            "effectiveStartDate": obj.get("effectiveStartDate"),
            "endDateCondition": obj.get("endDateCondition"),
            "includedUnits": obj.get("includedUnits"),
            "inputArgumentId": obj.get("inputArgumentId"),
            "isCommitted": obj.get("isCommitted"),
            "isPrepaid": obj.get("isPrepaid"),
            "isRollover": obj.get("isRollover"),
            "mrr": obj.get("mrr"),
            "originalOrderDate": obj.get("originalOrderDate"),
            "overagePrice": obj.get("overagePrice"),
            "prepaidOperationType": obj.get("prepaidOperationType"),
            "prepaidQuantity": obj.get("prepaidQuantity"),
            "prepaidTotalQuantity": obj.get("prepaidTotalQuantity"),
            "prepaidUOM": obj.get("prepaidUOM"),
            "quantity": obj.get("quantity"),
            "price": obj.get("price"),
            "priceChangeOption": obj.get("priceChangeOption") if obj.get("priceChangeOption") is not None else PriceChangeOption.NOCHANGE,
            "priceIncreasePercentage": obj.get("priceIncreasePercentage"),
            "pricingSummary": obj.get("pricingSummary"),
            "originalListPrice": obj.get("originalListPrice"),
            "processedThroughDate": obj.get("processedThroughDate"),
            "rolloverApply": obj.get("rolloverApply"),
            "rolloverPeriodLength": obj.get("rolloverPeriodLength"),
            "rolloverPeriods": obj.get("rolloverPeriods"),
            "prorationOption": obj.get("prorationOption"),
            "segment": obj.get("segment"),
            "specificEndDate": obj.get("specificEndDate"),
            "subscriptionChargeIntervalPricing": [IntervalPricing.from_dict(_item) for _item in obj["subscriptionChargeIntervalPricing"]] if obj.get("subscriptionChargeIntervalPricing") is not None else None,
            "tcv": obj.get("tcv"),
            "tiers": [RatePlanChargeTier.from_dict(_item) for _item in obj["tiers"]] if obj.get("tiers") is not None else None,
            "triggerDate": obj.get("triggerDate"),
            "billingPeriodAlignment": obj.get("billingPeriodAlignment"),
            "triggerEvent": obj.get("triggerEvent"),
            "upToPeriods": obj.get("upToPeriods"),
            "upToPeriodsType": obj.get("upToPeriodsType"),
            "validityPeriodType": obj.get("validityPeriodType"),
            "salesPrice": obj.get("salesPrice"),
            "accountingCode": obj.get("accountingCode"),
            "revenueRecognitionCode": obj.get("revenueRecognitionCode"),
            "revRecTriggerCondition": obj.get("revRecTriggerCondition"),
            "estimatedEndDate": obj.get("estimatedEndDate"),
            "estimatedStartDate": obj.get("estimatedStartDate"),
            "taxable": obj.get("taxable"),
            "taxCode": obj.get("taxCode"),
            "taxMode": obj.get("taxMode")
        }
        return _obj


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:])
