# 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 pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictFloat, StrictInt, StrictStr
from typing import Any, ClassVar, Dict, List, Optional, Union
from zuora_sdk.models.failed_reason import FailedReason
from zuora_sdk.models.gateway_state import GatewayState
from zuora_sdk.models.get_payment_finance_information import GetPaymentFinanceInformation
from zuora_sdk.models.payment_schedule_payment_option_fields import PaymentSchedulePaymentOptionFields
from zuora_sdk.models.payment_status import PaymentStatus
from zuora_sdk.models.payment_type import PaymentType
from typing import Optional, Set
from typing_extensions import Self

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

    account_id: Optional[StrictStr] = Field(default=None, description="The ID of the customer account that the payment is for. ", alias="accountId")
    account_number: Optional[StrictStr] = Field(default=None, description="The number of the customer account that the payment is for. ", alias="accountNumber")
    amount: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="The total amount of the payment. ")
    applied_amount: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="The applied amount of the payment. ", alias="appliedAmount")
    auth_transaction_id: Optional[StrictStr] = Field(default=None, description="The authorization transaction ID from the payment gateway. ", alias="authTransactionId")
    bank_identification_number: Optional[StrictStr] = Field(default=None, description="The first six or eight digits of the credit card or debit card used for the payment, when applicable. ", alias="bankIdentificationNumber")
    cancelled_on: Optional[StrictStr] = Field(default=None, description="The date and time when the payment was cancelled, in `yyyy-mm-dd hh:mm:ss` format. ", alias="cancelledOn")
    comment: Optional[StrictStr] = Field(default=None, description="Comments about the payment. ")
    created_by_id: Optional[StrictStr] = Field(default=None, description="The ID of the Zuora user who created the payment. ", alias="createdById")
    created_date: Optional[StrictStr] = Field(default=None, description="The date and time when the payment was created, in `yyyy-mm-dd hh:mm:ss` format. For example, 2017-03-01 15:31:10. ", alias="createdDate")
    credit_balance_amount: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="The amount that the payment transfers to the credit balance. The value is not `0` only for those payments that come from legacy payment operations performed without the Invoice Settlement feature. ", alias="creditBalanceAmount")
    currency: Optional[StrictStr] = Field(default=None, description="When Standalone Payment is not enabled, the `currency` of the payment must be the same as the payment currency defined in the customer account settings through Zuora UI.  When Standalone Payment is enabled and `standalone` is `true`, the `currency` of the standalone payment can be different from the payment currency defined in the customer account settings. The amount will not be summed up to the account balance or key metrics regardless of currency. ")
    effective_date: Optional[StrictStr] = Field(default=None, description="The date and time when the payment takes effect, in `yyyy-mm-dd hh:mm:ss` format. ", alias="effectiveDate")
    finance_information: Optional[GetPaymentFinanceInformation] = Field(default=None, alias="financeInformation")
    gateway_id: Optional[StrictStr] = Field(default=None, description="The ID of the gateway instance that processes the payment. ", alias="gatewayId")
    gateway_order_id: Optional[StrictStr] = Field(default=None, description="A merchant-specified natural key value that can be passed to the electronic payment gateway when a payment is created.  If not specified, the payment number will be passed in instead. ", alias="gatewayOrderId")
    gateway_reconciliation_reason: Optional[StrictStr] = Field(default=None, description="The reason of gateway reconciliation. ", alias="gatewayReconciliationReason")
    gateway_reconciliation_status: Optional[StrictStr] = Field(default=None, description="The status of gateway reconciliation. ", alias="gatewayReconciliationStatus")
    gateway_response: Optional[StrictStr] = Field(default=None, description="The message returned from the payment gateway for the payment. This message is gateway-dependent. ", alias="gatewayResponse")
    gateway_response_code: Optional[StrictStr] = Field(default=None, description="The code returned from the payment gateway for the payment. This code is gateway-dependent. ", alias="gatewayResponseCode")
    gateway_state: Optional[StrictStr] = Field(default=None, alias="gatewayState")
    id: Optional[StrictStr] = Field(default=None, description="The unique ID of the created payment. For example, 4028905f5a87c0ff015a87eb6b75007f. ")
    marked_for_submission_on: Optional[StrictStr] = Field(default=None, description="The date and time when a payment was marked and waiting for batch submission to the payment process, in `yyyy-mm-dd hh:mm:ss` format. ", alias="markedForSubmissionOn")
    number: Optional[StrictStr] = Field(default=None, description="The unique identification number of the payment. For example, P-00000001. ")
    payment_method_id: Optional[StrictStr] = Field(default=None, description="The unique ID of the payment method that the customer used to make the payment. ", alias="paymentMethodId")
    payment_method_snapshot_id: Optional[StrictStr] = Field(default=None, description="The unique ID of the payment method snapshot which is a copy of the particular Payment Method used in a transaction. ", alias="paymentMethodSnapshotId")
    payment_option: Optional[List[PaymentSchedulePaymentOptionFields]] = Field(default=None, description="Container for the paymentOption items, which describe the transactional level rules for processing payments. Currently, only the Gateway Options type is supported.  `paymentOption` of the payment schedule takes precedence over `paymentOption` of the payment schedule item.  This field is only available if `zuora-version` is set to 337.0 or later. ", alias="paymentOption")
    payment_schedule_key: Optional[StrictStr] = Field(default=None, description="The unique ID or the number of the payment schedule that is linked to the payment. See [Link payments to payment schedules](https://knowledgecenter.zuora.com/Billing/Billing_and_Payments/Payment_Schedules/Link_payments_with_payment_schedules) for more information.", alias="paymentScheduleKey")
    payout_id: Optional[StrictStr] = Field(default=None, description="The payout ID of the payment from the gateway side. ", alias="payoutId")
    prepayment: Optional[StrictBool] = Field(default=None, description="Indicates whether the payment is used as a reserved payment. See [Prepaid Cash with Drawdown](https://knowledgecenter.zuora.com/Zuora_Billing/Billing_and_Invoicing/JA_Advanced_Consumption_Billing/Prepaid_Cash_with_Drawdown) for more information. ")
    reference_id: Optional[StrictStr] = Field(default=None, description="The transaction ID returned by the payment gateway. Use this field to reconcile payments between your gateway and Zuora Payments. ", alias="referenceId")
    refund_amount: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="The amount of the payment that is refunded. ", alias="refundAmount")
    second_payment_reference_id: Optional[StrictStr] = Field(default=None, description="The transaction ID returned by the payment gateway if there is an additional transaction for the payment. Use this field to reconcile payments between your gateway and Zuora Payments. ", alias="secondPaymentReferenceId")
    settled_on: Optional[StrictStr] = Field(default=None, description="The date and time when the payment was settled in the payment processor, in `yyyy-mm-dd hh:mm:ss` format. This field is used by the Spectrum gateway only and not applicable to other gateways. ", alias="settledOn")
    soft_descriptor: Optional[StrictStr] = Field(default=None, description="A payment gateway-specific field that maps to Zuora for the gateways, Orbital, Vantiv and Verifi. ", alias="softDescriptor")
    soft_descriptor_phone: Optional[StrictStr] = Field(default=None, description="A payment gateway-specific field that maps to Zuora for the gateways, Orbital, Vantiv and Verifi. ", alias="softDescriptorPhone")
    standalone: Optional[StrictBool] = Field(default=False, description="This field is only available if the support for standalone payment is enabled. This field is not available for transferring, applying, or unapplying a payment.  The value `true` indicates this is a standalone payment that is created and processed in Zuora through Zuora gateway integration but will be settled outside of Zuora. No settlement data will be created. The standalone payment cannot be applied, unapplied, or transferred.  The value `false` indicates this is an ordinary payment that is created, processed, and settled in Zuora. ")
    status: Optional[StrictStr] = None
    submitted_on: Optional[StrictStr] = Field(default=None, description="The date and time when the payment was submitted, in `yyyy-mm-dd hh:mm:ss` format. ", alias="submittedOn")
    success: Optional[StrictBool] = Field(default=None, description="Indicates whether the call succeeded. ")
    type: Optional[StrictStr] = None
    unapplied_amount: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="The unapplied amount of the payment. ", alias="unappliedAmount")
    updated_by_id: Optional[StrictStr] = Field(default=None, description="The ID of the Zuora user who last updated the payment. ", alias="updatedById")
    updated_date: Optional[StrictStr] = Field(default=None, description="The date and time when the payment was last updated, in `yyyy-mm-dd hh:mm:ss` format. For example, 2017-03-02 15:36:10. ", alias="updatedDate")
    process_id: Optional[StrictStr] = Field(default=None, description="The Id of the process that handle the operation. ", alias="processId")
    request_id: Optional[StrictStr] = Field(default=None, description="Unique request identifier. If you need to contact us about a specific request, providing the request identifier will ensure the fastest possible resolution. ", alias="requestId")
    reasons: Optional[List[FailedReason]] = None
    additional_properties: Dict[str, Any] = {}
    __properties: ClassVar[List[str]] = ["accountId", "accountNumber", "amount", "appliedAmount", "authTransactionId", "bankIdentificationNumber", "cancelledOn", "comment", "createdById", "createdDate", "creditBalanceAmount", "currency", "effectiveDate", "financeInformation", "gatewayId", "gatewayOrderId", "gatewayReconciliationReason", "gatewayReconciliationStatus", "gatewayResponse", "gatewayResponseCode", "gatewayState", "id", "markedForSubmissionOn", "number", "paymentMethodId", "paymentMethodSnapshotId", "paymentOption", "paymentScheduleKey", "payoutId", "prepayment", "referenceId", "refundAmount", "secondPaymentReferenceId", "settledOn", "softDescriptor", "softDescriptorPhone", "standalone", "status", "submittedOn", "success", "type", "unappliedAmount", "updatedById", "updatedDate", "processId", "requestId", "reasons"]

    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 PaymentResponse 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 finance_information
        if self.finance_information:
            _dict['financeInformation'] = self.finance_information.to_dict()
        # override the default output from pydantic by calling `to_dict()` of each item in payment_option (list)
        _items = []
        if self.payment_option:
            for _item_payment_option in self.payment_option:
                if _item_payment_option:
                    _items.append(_item_payment_option.to_dict())
            _dict['paymentOption'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in reasons (list)
        _items = []
        if self.reasons:
            for _item_reasons in self.reasons:
                if _item_reasons:
                    _items.append(_item_reasons.to_dict())
            _dict['reasons'] = _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 PaymentResponse 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 {
            "accountId": obj.get("accountId"),
            "accountNumber": obj.get("accountNumber"),
            "amount": obj.get("amount"),
            "appliedAmount": obj.get("appliedAmount"),
            "authTransactionId": obj.get("authTransactionId"),
            "bankIdentificationNumber": obj.get("bankIdentificationNumber"),
            "cancelledOn": obj.get("cancelledOn"),
            "comment": obj.get("comment"),
            "createdById": obj.get("createdById"),
            "createdDate": obj.get("createdDate"),
            "creditBalanceAmount": obj.get("creditBalanceAmount"),
            "currency": obj.get("currency"),
            "effectiveDate": obj.get("effectiveDate"),
            "financeInformation": GetPaymentFinanceInformation.from_dict(obj["financeInformation"]) if obj.get("financeInformation") is not None else None,
            "gatewayId": obj.get("gatewayId"),
            "gatewayOrderId": obj.get("gatewayOrderId"),
            "gatewayReconciliationReason": obj.get("gatewayReconciliationReason"),
            "gatewayReconciliationStatus": obj.get("gatewayReconciliationStatus"),
            "gatewayResponse": obj.get("gatewayResponse"),
            "gatewayResponseCode": obj.get("gatewayResponseCode"),
            "gatewayState": obj.get("gatewayState"),
            "id": obj.get("id"),
            "markedForSubmissionOn": obj.get("markedForSubmissionOn"),
            "number": obj.get("number"),
            "paymentMethodId": obj.get("paymentMethodId"),
            "paymentMethodSnapshotId": obj.get("paymentMethodSnapshotId"),
            "paymentOption": [PaymentSchedulePaymentOptionFields.from_dict(_item) for _item in obj["paymentOption"]] if obj.get("paymentOption") is not None else None,
            "paymentScheduleKey": obj.get("paymentScheduleKey"),
            "payoutId": obj.get("payoutId"),
            "prepayment": obj.get("prepayment"),
            "referenceId": obj.get("referenceId"),
            "refundAmount": obj.get("refundAmount"),
            "secondPaymentReferenceId": obj.get("secondPaymentReferenceId"),
            "settledOn": obj.get("settledOn"),
            "softDescriptor": obj.get("softDescriptor"),
            "softDescriptorPhone": obj.get("softDescriptorPhone"),
            "standalone": obj.get("standalone") if obj.get("standalone") is not None else False,
            "status": obj.get("status"),
            "submittedOn": obj.get("submittedOn"),
            "success": obj.get("success"),
            "type": obj.get("type"),
            "unappliedAmount": obj.get("unappliedAmount"),
            "updatedById": obj.get("updatedById"),
            "updatedDate": obj.get("updatedDate"),
            "processId": obj.get("processId"),
            "requestId": obj.get("requestId"),
            "reasons": [FailedReason.from_dict(_item) for _item in obj["reasons"]] if obj.get("reasons") is not None else None
        }
        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:])
