# 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_product_rate_plan_charge import ExpandedProductRatePlanCharge
from typing import Optional, Set
from typing_extensions import Self

class ExpandedRatePlanCharge(BaseModel):
    """
    ExpandedRatePlanCharge
    """ # 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)

    rate_plan_id: Optional[StrictStr] = Field(default=None, alias="ratePlanId")
    product_rate_plan_charge_id: Optional[StrictStr] = Field(default=None, alias="productRatePlanChargeId")
    accounting_code: Optional[StrictStr] = Field(default=None, alias="accountingCode")
    accounting_code_entity_id: Optional[StrictInt] = Field(default=None, alias="accountingCodeEntityId")
    apply_discount_to: Optional[StrictStr] = Field(default=None, alias="applyDiscountTo")
    bill_cycle_day: Optional[StrictInt] = Field(default=None, alias="billCycleDay")
    bill_cycle_type: Optional[StrictStr] = Field(default=None, alias="billCycleType")
    billing_period: Optional[StrictStr] = Field(default=None, alias="billingPeriod")
    billing_period_alignment: Optional[StrictStr] = Field(default=None, alias="billingPeriodAlignment")
    billing_timing: Optional[StrictStr] = Field(default=None, alias="billingTiming")
    charged_through_date: Optional[date] = Field(default=None, alias="chargedThroughDate")
    charge_function: Optional[StrictStr] = Field(default=None, alias="chargeFunction")
    charge_model: Optional[StrictStr] = Field(default=None, alias="chargeModel")
    charge_number: Optional[StrictStr] = Field(default=None, alias="chargeNumber")
    charge_type: Optional[StrictStr] = Field(default=None, alias="chargeType")
    description: Optional[StrictStr] = None
    discount_level: Optional[StrictStr] = Field(default=None, alias="discountLevel")
    d_mrc: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="dMRC")
    drawdown_rate: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="drawdownRate")
    d_tcv: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="dTCV")
    effective_end_date: Optional[date] = Field(default=None, alias="effectiveEndDate")
    effective_start_date: Optional[date] = Field(default=None, alias="effectiveStartDate")
    end_date_condition: Optional[StrictStr] = Field(default=None, alias="endDateCondition")
    exclude_item_booking_from_revenue_accounting: Optional[StrictBool] = Field(default=None, alias="excludeItemBookingFromRevenueAccounting")
    reflect_discount_in_net_amount: Optional[StrictBool] = Field(default=None, alias="reflectDiscountInNetAmount")
    revenue_recognition_timing: Optional[StrictStr] = Field(default=None, alias="revenueRecognitionTiming")
    revenue_amortization_method: Optional[StrictStr] = Field(default=None, alias="revenueAmortizationMethod")
    exclude_item_billing_from_revenue_accounting: Optional[StrictBool] = Field(default=None, alias="excludeItemBillingFromRevenueAccounting")
    invoice_schedule_id: Optional[StrictStr] = Field(default=None, alias="invoiceScheduleId")
    is_last_segment: Optional[StrictBool] = Field(default=None, alias="isLastSegment")
    is_prepaid: Optional[StrictBool] = Field(default=None, alias="isPrepaid")
    is_rollover: Optional[StrictBool] = Field(default=None, alias="isRollover")
    rollover_periods: Optional[StrictInt] = Field(default=None, alias="rolloverPeriods")
    rollover_period_length: Optional[StrictInt] = Field(default=None, alias="rolloverPeriodLength")
    rollover_apply: Optional[StrictStr] = Field(default=None, alias="rolloverApply")
    is_processed: Optional[StrictBool] = Field(default=None, alias="isProcessed")
    list_price_base: Optional[StrictStr] = Field(default=None, alias="listPriceBase")
    specific_list_price_base: Optional[StrictInt] = Field(default=None, alias="specificListPriceBase")
    price_upsell_quantity_stacked: Optional[StrictBool] = Field(default=None, alias="priceUpsellQuantityStacked")
    commitment_type: Optional[StrictStr] = Field(default=None, alias="commitmentType")
    is_committed: Optional[StrictBool] = Field(default=None, alias="isCommitted")
    m_rr: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="mRR")
    name: Optional[StrictStr] = None
    number_of_periods: Optional[StrictInt] = Field(default=None, alias="numberOfPeriods")
    original_id: Optional[StrictStr] = Field(default=None, alias="originalId")
    overage_calculation_option: Optional[StrictStr] = Field(default=None, alias="overageCalculationOption")
    overage_unused_units_credit_option: Optional[StrictStr] = Field(default=None, alias="overageUnusedUnitsCreditOption")
    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")
    sales_price: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="salesPrice")
    estimated_start_date: Optional[date] = Field(default=None, alias="estimatedStartDate")
    estimated_end_date: Optional[date] = Field(default=None, alias="estimatedEndDate")
    price_change_option: Optional[StrictStr] = Field(default=None, alias="priceChangeOption")
    price_increase_percentage: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="priceIncreasePercentage")
    processed_through_date: Optional[date] = Field(default=None, alias="processedThroughDate")
    proration_option: Optional[StrictStr] = Field(default=None, alias="prorationOption")
    quantity: Optional[Union[StrictFloat, StrictInt]] = None
    number_of_deliveries: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="numberOfDeliveries")
    rating_group: Optional[StrictStr] = Field(default=None, alias="ratingGroup")
    revenue_recognition_rule_name: Optional[StrictStr] = Field(default=None, alias="revenueRecognitionRuleName")
    rev_rec_code: Optional[StrictStr] = Field(default=None, alias="revRecCode")
    rev_rec_trigger_condition: Optional[StrictStr] = Field(default=None, alias="revRecTriggerCondition")
    segment: Optional[StrictInt] = None
    specific_billing_period: Optional[StrictInt] = Field(default=None, alias="specificBillingPeriod")
    specific_end_date: Optional[date] = Field(default=None, alias="specificEndDate")
    taxable: Optional[StrictBool] = None
    tax_code_name: Optional[StrictStr] = Field(default=None, alias="taxCodeName")
    tax_mode_option: Optional[StrictStr] = Field(default=None, alias="taxModeOption")
    t_cv: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, alias="tCV")
    trigger_date: Optional[date] = Field(default=None, alias="triggerDate")
    trigger_event: Optional[StrictStr] = Field(default=None, alias="triggerEvent")
    u_om: Optional[StrictStr] = Field(default=None, alias="uOM")
    up_to_periods: Optional[StrictInt] = Field(default=None, alias="upToPeriods")
    up_to_periods_type: Optional[StrictStr] = Field(default=None, alias="upToPeriodsType")
    version: Optional[StrictInt] = None
    weekly_bill_cycle_day: Optional[StrictStr] = Field(default=None, alias="weeklyBillCycleDay")
    id: Optional[StrictStr] = 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")
    subscription_id: Optional[StrictStr] = Field(default=None, alias="subscriptionId")
    subscription_owner_id: Optional[StrictStr] = Field(default=None, alias="subscriptionOwnerId")
    invoice_owner_id: Optional[StrictStr] = Field(default=None, alias="invoiceOwnerId")
    original_order_date: Optional[date] = Field(default=None, alias="originalOrderDate")
    amended_by_order_on: Optional[date] = Field(default=None, alias="amendedByOrderOn")
    validity_period_type: Optional[StrictStr] = Field(default=None, alias="validityPeriodType")
    credit_option: Optional[StrictStr] = Field(default=None, alias="creditOption")
    apply_to_billing_period_partially: Optional[StrictBool] = Field(default=None, alias="applyToBillingPeriodPartially")
    product_charge_definition_id: Optional[StrictStr] = Field(default=None, alias="productChargeDefinitionId")
    reverted: Optional[StrictBool] = None
    account_receivable_accounting_code_id: Optional[StrictStr] = Field(default=None, alias="accountReceivableAccountingCodeId")
    deferred_revenue_accounting_code_id: Optional[StrictStr] = Field(default=None, alias="deferredRevenueAccountingCodeId")
    recognized_revenue_accounting_code_id: Optional[StrictStr] = Field(default=None, alias="recognizedRevenueAccountingCodeId")
    prepaid_uom: Optional[StrictStr] = Field(default=None, alias="prepaidUOM")
    drawdown_uom: Optional[StrictStr] = Field(default=None, alias="drawdownUom")
    is_prorate_partial_month: Optional[StrictBool] = Field(default=None, alias="isProratePartialMonth")
    proration_unit: Optional[StrictStr] = Field(default=None, alias="prorationUnit")
    days_in_month: Optional[StrictStr] = Field(default=None, alias="daysInMonth")
    rate_plan: Optional[ExpandedRatePlan] = Field(default=None, alias="ratePlan")
    product_rate_plan_charge: Optional[ExpandedProductRatePlanCharge] = Field(default=None, alias="productRatePlanCharge")
    rate_plan_charge_tiers: Optional[List[ExpandedRatePlanChargeTier]] = Field(default=None, alias="ratePlanChargeTiers")
    additional_properties: Dict[str, Any] = {}
    __properties: ClassVar[List[str]] = ["ratePlanId", "productRatePlanChargeId", "accountingCode", "accountingCodeEntityId", "applyDiscountTo", "billCycleDay", "billCycleType", "billingPeriod", "billingPeriodAlignment", "billingTiming", "chargedThroughDate", "chargeFunction", "chargeModel", "chargeNumber", "chargeType", "description", "discountLevel", "dMRC", "drawdownRate", "dTCV", "effectiveEndDate", "effectiveStartDate", "endDateCondition", "excludeItemBookingFromRevenueAccounting", "reflectDiscountInNetAmount", "revenueRecognitionTiming", "revenueAmortizationMethod", "excludeItemBillingFromRevenueAccounting", "invoiceScheduleId", "isLastSegment", "isPrepaid", "isRollover", "rolloverPeriods", "rolloverPeriodLength", "rolloverApply", "isProcessed", "listPriceBase", "specificListPriceBase", "priceUpsellQuantityStacked", "commitmentType", "isCommitted", "mRR", "name", "numberOfPeriods", "originalId", "overageCalculationOption", "overageUnusedUnitsCreditOption", "prepaidOperationType", "prepaidQuantity", "prepaidTotalQuantity", "salesPrice", "estimatedStartDate", "estimatedEndDate", "priceChangeOption", "priceIncreasePercentage", "processedThroughDate", "prorationOption", "quantity", "numberOfDeliveries", "ratingGroup", "revenueRecognitionRuleName", "revRecCode", "revRecTriggerCondition", "segment", "specificBillingPeriod", "specificEndDate", "taxable", "taxCodeName", "taxModeOption", "tCV", "triggerDate", "triggerEvent", "uOM", "upToPeriods", "upToPeriodsType", "version", "weeklyBillCycleDay", "id", "createdById", "createdDate", "updatedById", "updatedDate", "subscriptionId", "subscriptionOwnerId", "invoiceOwnerId", "originalOrderDate", "amendedByOrderOn", "validityPeriodType", "creditOption", "applyToBillingPeriodPartially", "productChargeDefinitionId", "reverted", "accountReceivableAccountingCodeId", "deferredRevenueAccountingCodeId", "recognizedRevenueAccountingCodeId", "prepaidUOM", "drawdownUom", "isProratePartialMonth", "prorationUnit", "daysInMonth", "ratePlan", "productRatePlanCharge", "ratePlanChargeTiers"]

    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 ExpandedRatePlanCharge 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 rate_plan
        if self.rate_plan:
            _dict['ratePlan'] = self.rate_plan.to_dict()
        # override the default output from pydantic by calling `to_dict()` of product_rate_plan_charge
        if self.product_rate_plan_charge:
            _dict['productRatePlanCharge'] = self.product_rate_plan_charge.to_dict()
        # override the default output from pydantic by calling `to_dict()` of each item in rate_plan_charge_tiers (list)
        _items = []
        if self.rate_plan_charge_tiers:
            for _item_rate_plan_charge_tiers in self.rate_plan_charge_tiers:
                if _item_rate_plan_charge_tiers:
                    _items.append(_item_rate_plan_charge_tiers.to_dict())
            _dict['ratePlanChargeTiers'] = _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 ExpandedRatePlanCharge 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 {
            "ratePlanId": obj.get("ratePlanId"),
            "productRatePlanChargeId": obj.get("productRatePlanChargeId"),
            "accountingCode": obj.get("accountingCode"),
            "accountingCodeEntityId": obj.get("accountingCodeEntityId"),
            "applyDiscountTo": obj.get("applyDiscountTo"),
            "billCycleDay": obj.get("billCycleDay"),
            "billCycleType": obj.get("billCycleType"),
            "billingPeriod": obj.get("billingPeriod"),
            "billingPeriodAlignment": obj.get("billingPeriodAlignment"),
            "billingTiming": obj.get("billingTiming"),
            "chargedThroughDate": obj.get("chargedThroughDate"),
            "chargeFunction": obj.get("chargeFunction"),
            "chargeModel": obj.get("chargeModel"),
            "chargeNumber": obj.get("chargeNumber"),
            "chargeType": obj.get("chargeType"),
            "description": obj.get("description"),
            "discountLevel": obj.get("discountLevel"),
            "dMRC": obj.get("dMRC"),
            "drawdownRate": obj.get("drawdownRate"),
            "dTCV": obj.get("dTCV"),
            "effectiveEndDate": obj.get("effectiveEndDate"),
            "effectiveStartDate": obj.get("effectiveStartDate"),
            "endDateCondition": obj.get("endDateCondition"),
            "excludeItemBookingFromRevenueAccounting": obj.get("excludeItemBookingFromRevenueAccounting"),
            "reflectDiscountInNetAmount": obj.get("reflectDiscountInNetAmount"),
            "revenueRecognitionTiming": obj.get("revenueRecognitionTiming"),
            "revenueAmortizationMethod": obj.get("revenueAmortizationMethod"),
            "excludeItemBillingFromRevenueAccounting": obj.get("excludeItemBillingFromRevenueAccounting"),
            "invoiceScheduleId": obj.get("invoiceScheduleId"),
            "isLastSegment": obj.get("isLastSegment"),
            "isPrepaid": obj.get("isPrepaid"),
            "isRollover": obj.get("isRollover"),
            "rolloverPeriods": obj.get("rolloverPeriods"),
            "rolloverPeriodLength": obj.get("rolloverPeriodLength"),
            "rolloverApply": obj.get("rolloverApply"),
            "isProcessed": obj.get("isProcessed"),
            "listPriceBase": obj.get("listPriceBase"),
            "specificListPriceBase": obj.get("specificListPriceBase"),
            "priceUpsellQuantityStacked": obj.get("priceUpsellQuantityStacked"),
            "commitmentType": obj.get("commitmentType"),
            "isCommitted": obj.get("isCommitted"),
            "mRR": obj.get("mRR"),
            "name": obj.get("name"),
            "numberOfPeriods": obj.get("numberOfPeriods"),
            "originalId": obj.get("originalId"),
            "overageCalculationOption": obj.get("overageCalculationOption"),
            "overageUnusedUnitsCreditOption": obj.get("overageUnusedUnitsCreditOption"),
            "prepaidOperationType": obj.get("prepaidOperationType"),
            "prepaidQuantity": obj.get("prepaidQuantity"),
            "prepaidTotalQuantity": obj.get("prepaidTotalQuantity"),
            "salesPrice": obj.get("salesPrice"),
            "estimatedStartDate": obj.get("estimatedStartDate"),
            "estimatedEndDate": obj.get("estimatedEndDate"),
            "priceChangeOption": obj.get("priceChangeOption"),
            "priceIncreasePercentage": obj.get("priceIncreasePercentage"),
            "processedThroughDate": obj.get("processedThroughDate"),
            "prorationOption": obj.get("prorationOption"),
            "quantity": obj.get("quantity"),
            "numberOfDeliveries": obj.get("numberOfDeliveries"),
            "ratingGroup": obj.get("ratingGroup"),
            "revenueRecognitionRuleName": obj.get("revenueRecognitionRuleName"),
            "revRecCode": obj.get("revRecCode"),
            "revRecTriggerCondition": obj.get("revRecTriggerCondition"),
            "segment": obj.get("segment"),
            "specificBillingPeriod": obj.get("specificBillingPeriod"),
            "specificEndDate": obj.get("specificEndDate"),
            "taxable": obj.get("taxable"),
            "taxCodeName": obj.get("taxCodeName"),
            "taxModeOption": obj.get("taxModeOption"),
            "tCV": obj.get("tCV"),
            "triggerDate": obj.get("triggerDate"),
            "triggerEvent": obj.get("triggerEvent"),
            "uOM": obj.get("uOM"),
            "upToPeriods": obj.get("upToPeriods"),
            "upToPeriodsType": obj.get("upToPeriodsType"),
            "version": obj.get("version"),
            "weeklyBillCycleDay": obj.get("weeklyBillCycleDay"),
            "id": obj.get("id"),
            "createdById": obj.get("createdById"),
            "createdDate": obj.get("createdDate"),
            "updatedById": obj.get("updatedById"),
            "updatedDate": obj.get("updatedDate"),
            "subscriptionId": obj.get("subscriptionId"),
            "subscriptionOwnerId": obj.get("subscriptionOwnerId"),
            "invoiceOwnerId": obj.get("invoiceOwnerId"),
            "originalOrderDate": obj.get("originalOrderDate"),
            "amendedByOrderOn": obj.get("amendedByOrderOn"),
            "validityPeriodType": obj.get("validityPeriodType"),
            "creditOption": obj.get("creditOption"),
            "applyToBillingPeriodPartially": obj.get("applyToBillingPeriodPartially"),
            "productChargeDefinitionId": obj.get("productChargeDefinitionId"),
            "reverted": obj.get("reverted"),
            "accountReceivableAccountingCodeId": obj.get("accountReceivableAccountingCodeId"),
            "deferredRevenueAccountingCodeId": obj.get("deferredRevenueAccountingCodeId"),
            "recognizedRevenueAccountingCodeId": obj.get("recognizedRevenueAccountingCodeId"),
            "prepaidUOM": obj.get("prepaidUOM"),
            "drawdownUom": obj.get("drawdownUom"),
            "isProratePartialMonth": obj.get("isProratePartialMonth"),
            "prorationUnit": obj.get("prorationUnit"),
            "daysInMonth": obj.get("daysInMonth"),
            "ratePlan": ExpandedRatePlan.from_dict(obj["ratePlan"]) if obj.get("ratePlan") is not None else None,
            "productRatePlanCharge": ExpandedProductRatePlanCharge.from_dict(obj["productRatePlanCharge"]) if obj.get("productRatePlanCharge") is not None else None,
            "ratePlanChargeTiers": [ExpandedRatePlanChargeTier.from_dict(_item) for _item in obj["ratePlanChargeTiers"]] if obj.get("ratePlanChargeTiers") is not None else None
        }
        return _obj
from zuora_sdk.models.expanded_rate_plan import ExpandedRatePlan
from zuora_sdk.models.expanded_rate_plan_charge_tier import ExpandedRatePlanChargeTier
# TODO: Rewrite to not use raise_errors
ExpandedRatePlanCharge.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:])
