# coding: utf-8

"""
    Voucherify API

    Voucherify promotion engine REST API. Please see https://docs.voucherify.io/docs for more details.

    The version of the OpenAPI document: v2018-08-01
    Contact: support@voucherify.io
    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 pydantic import BaseModel, ConfigDict, Field, StrictFloat, StrictInt, StrictStr, field_validator
from typing import Any, ClassVar, Dict, List, Optional, Union
from voucherify.models.applicable_to_effect import ApplicableToEffect
from voucherify.models.inapplicable_to_order_item_units_item import InapplicableToOrderItemUnitsItem
from typing import Optional, Set
from typing_extensions import Self

class InapplicableTo(BaseModel):
    """
    InapplicableTo
    """ # noqa: E501
    object: Optional[StrictStr] = Field(default=None, description="This object stores information about the resource to which the discount is applicable.")
    id: Optional[StrictStr] = Field(default=None, description="Unique product collection, product, or SKU identifier assigned by Voucherify.")
    source_id: Optional[StrictStr] = Field(default=None, description="The source identifier from your inventory system.")
    product_id: Optional[StrictStr] = Field(default=None, description="Parent product's unique ID assigned by Voucherify.")
    product_source_id: Optional[StrictStr] = Field(default=None, description="Parent product's source ID from your inventory system.")
    price: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="New fixed price of an item. Value is multiplied by 100 to precisely represent 2 decimal places. For example, a $10 price is written as 1000. In case of the fixed price being calculated by the formula, i.e. the price_formula parameter is present in the fixed price definition, this value becomes the fallback value. Such that in a case where the formula cannot be calculated due to missing metadata, for example, this value will be used as the fixed price.")
    price_formula: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="Formula used to calculate the discounted price of an item.")
    effect: ApplicableToEffect
    quantity_limit: Optional[StrictInt] = Field(default=None, description="The maximum number of units allowed to be discounted per order line item.")
    aggregated_quantity_limit: Optional[StrictInt] = Field(default=None, description="The maximum number of units allowed to be discounted combined across all matched order line items.")
    amount_limit: Optional[StrictInt] = Field(default=None, description="Upper limit allowed to be applied as a discount per order line item. Value is multiplied by 100 to precisely represent 2 decimal places. For example, a $6 maximum discount is written as 600.")
    aggregated_amount_limit: Optional[StrictInt] = Field(default=None, description="Maximum discount amount per order. Value is multiplied by 100 to precisely represent 2 decimal places. For example, a $6 maximum discount on the entire order is written as 600. This value is definable for the following discount effects: - `APPLY_TO_ITEMS` (each item subtotal is discounted equally) - `APPLY_TO_ITEMS_BY_QUANTITY` (each unit of matched products has the same discount value)")
    order_item_indices: Optional[List[StrictInt]] = Field(default=None, description="Lists which order lines are (not) covered by the discount. The order in the array is determined by the sequence of applied discounts, while the numbers correspond to the order lines sent in the `order` object in the request. The first order line is assigned `0`, the second order line is assigned `1`, and so on.")
    order_item_units: Optional[List[InapplicableToOrderItemUnitsItem]] = Field(default=None, description="Lists which units within order lines are covered by the discount. The order line items are listed according to sequence of applied discounts while the `index` corresponds to the order line sent in the `order` object in the request.")
    repeat: Optional[StrictInt] = Field(default=None, description="Determines the recurrence of the discount, e.g. `\"repeat\": 3` means that the discount is applied to every third item.")
    skip_initially: Optional[StrictInt] = Field(default=None, description="Determines how many items are skipped before the discount is applied.")
    target: Optional[StrictStr] = Field(default=None, description="Determines to which kinds of objects the discount is applicable. `ITEM` includes products and SKUs. `UNIT` means particular units within an order line.")
    __properties: ClassVar[List[str]] = ["object", "id", "source_id", "product_id", "product_source_id", "price", "price_formula", "effect", "quantity_limit", "aggregated_quantity_limit", "amount_limit", "aggregated_amount_limit", "order_item_indices", "order_item_units", "repeat", "skip_initially", "target"]

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

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

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

        if value not in set(['ITEM', 'UNIT']):
            raise ValueError("must be one of enum values ('ITEM', 'UNIT')")
        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 InapplicableTo 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 each item in order_item_units (list)
        _items = []
        if self.order_item_units:
            for _item_order_item_units in self.order_item_units:
                if _item_order_item_units:
                    _items.append(_item_order_item_units.to_dict())
            _dict['order_item_units'] = _items
        # set to None if object (nullable) is None
        # and model_fields_set contains the field
        if self.object is None and "object" in self.model_fields_set:
            _dict['object'] = None

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        return _dict

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

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

        _obj = cls.model_validate({
            "object": obj.get("object"),
            "id": obj.get("id"),
            "source_id": obj.get("source_id"),
            "product_id": obj.get("product_id"),
            "product_source_id": obj.get("product_source_id"),
            "price": obj.get("price"),
            "price_formula": obj.get("price_formula"),
            "effect": obj.get("effect"),
            "quantity_limit": obj.get("quantity_limit"),
            "aggregated_quantity_limit": obj.get("aggregated_quantity_limit"),
            "amount_limit": obj.get("amount_limit"),
            "aggregated_amount_limit": obj.get("aggregated_amount_limit"),
            "order_item_indices": obj.get("order_item_indices"),
            "order_item_units": [InapplicableToOrderItemUnitsItem.from_dict(_item) for _item in obj["order_item_units"]] if obj.get("order_item_units") is not None else None,
            "repeat": obj.get("repeat"),
            "skip_initially": obj.get("skip_initially"),
            "target": obj.get("target")
        })
        return _obj


