# coding: utf-8

"""
    Acre Platform User API

    # CORS CORS is implemented by all Acre API endpoints and only certain hostnames are allowed for each deployment of the API. If your use case requires calling the Acre User API from a browser, please contact Acre to arrange the appropriate configuration. # API Authentication The primary method of authentication for users of the Acre API is with the use of JSON Web Tokens (JWTs), which are suplemented by an application specific API Key. The API key must be provided through the `X-API-KEY` HTTP header and will be provided by your Acre Customer Success Manager. The JWT must be provided through a cookie with key of `authorization`. The JWT must be generated and signed as per the following section. # Generating JWTs JWT must either be generated by a third-party such as Azure ADB2C that has been configured for the appropriate service and/or user account, or alternatively can be generated locally and signed by an private key for which the public key has been made available to Acre via a JWKS URL. In addition to being signed by your private key, the JWT will also need to contain at a minimum:  * An issuer `iss`, which must be a valid URI previously agreed with Acre.  * A subject `sub`, which must be a unique identifier for the user and/or service account previously agreed with Acre.  * An expiry time `exp` which must not be more than four hours in the future.  * A not before time `nbf` which must be in the past, but not greater than six hours in the past.  The JWT should be signed using RS256.

    The version of the OpenAPI document: 1.0
    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 acre_api.models.cdm_early_repayment_charge_periods import CdmEarlyRepaymentChargePeriods
from acre_api.models.cdm_mortgage_class import CdmMortgageClass
from acre_api.models.cdm_mortgage_product_details_mortgage_type import CdmMortgageProductDetailsMortgageType
from acre_api.models.cdm_mortgage_product_fee import CdmMortgageProductFee
from acre_api.models.mortgage_product_details_mortgage_club_proc_fee import MortgageProductDetailsMortgageClubProcFee
from acre_api.models.mortgage_product_details_rate_tier import MortgageProductDetailsRateTier
from acre_api.models.mortgage_product_details_stress_test_payment import MortgageProductDetailsStressTestPayment
from typing import Optional, Set
from typing_extensions import Self

class CdmMortgageProductDetails(BaseModel):
    """
    MortgageProductDetails are details about a mortgage product.
    """ # noqa: E501
    product_code: Optional[StrictStr] = Field(default=None, description="A unique identifier for each product within the engine.")
    product_name: Optional[StrictStr] = Field(default=None, description="Name of the product.")
    lender_code: Optional[StrictStr] = Field(default=None, description="Lender Code of the applicant’s existing mortgage lender.")
    lender_name: Optional[StrictStr] = Field(default=None, description="The mortgage lender’s name.")
    initial_pay_rate: Optional[StrictInt] = Field(default=None, description="The initial pay rate.")
    mortgage_class: Optional[CdmMortgageClass] = CdmMortgageClass.INVALID_MORTGAGE_CLASS
    applicant_type_conditions: Optional[StrictStr] = Field(default=None, description="Indicated who the product is available to - all applicants, existing borrowers only, First time buyers only etc.")
    full_rate_description: Optional[StrictStr] = Field(default=None, description="A summary of what the initial rate is (Fixed, Discount), the initial rate, how long it is for, then followed by what it then reverts to after this initial rate period.")
    apr_lenders: Optional[StrictInt] = Field(default=None, description="Lender’s illustrative APRC value, represented as 1/100000 of a percent (precision for up to 5 decimal places).  This value is provided by the lender and will be based on assumptions about term and loan amount that and therefore is illustrative only. The specific APRC value for a mortgage can be found on the mortgage, under its calculated values")
    max_ltv_available: Optional[StrictInt] = Field(default=None, description="The maximum loan to value available for the product.")
    applicant1_income_multiplier: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="The income multiple the lender will use against app1 income to calculate the maximum available based on income.")
    applicant2_income_multiplier: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="The income multiple the lender will use against app2 income to calculate the maximum available based on income.")
    joint_applicant_income_multiplier: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="The income multiple the lender will use against both applicants income to calculate the maximum available based on income.")
    standard_variable_rate: Optional[StrictInt] = Field(default=None, description="This is the lenders standard variable rate, represented as 1/100000 of a percent (precision for up to 5 decimal places).")
    initial_monthly_payment: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="The initial monthly mortgage payment based on loan amount and term at the mortgage product’s initial pay rate.")
    cashback: Optional[StrictStr] = Field(default=None, description="Total cashback amount available for the product (in pence, not GBP).")
    cashback_conditions: Optional[StrictStr] = Field(default=None, description="Conditions of when the cashback is available (i.e. For remortgage only, Purchase only).")
    valuation_fee: Optional[StrictStr] = Field(default=None, description="How the lender charges for a mortgage valuation depending on the value of the property (in pence, not GBP).")
    valuation_fee_conditions: Optional[StrictStr] = Field(default=None, description="Indicates if there is a free/refundable valuation and if so if it is for Purchase only, remortgage only or to both.")
    arrangement_fee: Optional[StrictStr] = Field(default=None, description="The amount of the arrangement fee for the product (in pence, not GBP).")
    arrangement_fee_conditions: Optional[StrictStr] = Field(default=None, description="Indicates if the Arrangement fee can be added to the loan, deducted from the loan etc.")
    booking_fee: Optional[StrictStr] = Field(default=None, description="The amount of the Booking fee for the product (in pence, not GBP).")
    booking_fee_conditions: Optional[StrictStr] = Field(default=None, description="Indicates if the Booking fee can be added to the loan, deducted from the loan etc. Normally has to be paid upfront.")
    higher_lending_charge: Optional[StrictStr] = Field(default=None, description="The amount of the Higher lending charge fee for the product (in pence, not GBP).")
    higher_lending_charge_conditions: Optional[StrictStr] = Field(default=None, description="Indicates if the Higher Lending Charge fee can be added to the loan, deducted from the loan etc. Normally has to be paid upfront.")
    free_legal_fees: Optional[StrictBool] = Field(default=None, description="Indicates if the product offers free legal fees as an incentive.")
    free_legal_fee_conditions: Optional[StrictStr] = Field(default=None, description="Indicates if the free legal fees incentive is available for Purchase only, remortgage only or to both.")
    chaps_fee: Optional[StrictStr] = Field(default=None, description="The amount of the telegraphic Transfer fee for transferring the monies on completion (in pence, not GBP).")
    fees_payable_on_application: Optional[StrictStr] = Field(default=None, description="The total amount of fees associated with the mortgage that are payable on Application (in pence, not GBP).")
    fees_payable_on_completion: Optional[StrictStr] = Field(default=None, description="The total amount of fees associated with the mortgage that are payable on Completion (in pence, not GBP).")
    fees_total: Optional[StrictStr] = Field(default=None, description="The total amount of fees associated with the mortgage that are payable (in pence, not GBP).")
    early_repayment_charge_applies_until: Optional[StrictStr] = Field(default=None, description="Indicates when any early repayment charges apply until for paying part or all of the mortgage off (attempts to convert to YYYY-MM-DD, otherwise leaves date unmodified).")
    early_repayment_charge_applies_until_calculated_date: Optional[StrictStr] = Field(default=None, description="A calculated YYYY-MM-DD for sorting of early_repayment_charge_applies_until.")
    product_notes: Optional[StrictStr] = Field(default=None, description="Any free-form notes for the specific product.")
    employed_prob_period: Optional[StrictStr] = Field(default=None, description="An Employed applicants available probationary period.")
    max_property_valuation: Optional[StrictStr] = Field(default=None, description="Max property valuation acceptable (in pence, not GBP).")
    studio_flat_flag: Optional[StrictStr] = Field(default=None, description="Studio flat acceptable.")
    proc_fee_code: Optional[StrictStr] = Field(default=None, description="The proc fee code. (This value is for the lender/packager proc fee).")
    proc_fee_fixed: Optional[StrictStr] = Field(default=None, description="If the proc fee is fixed, then it is fixed to this amount (in pence, not GBP). (This value is for the lender/packager proc fee).")
    proc_fee_percentage: Optional[StrictInt] = Field(default=None, description="Proc fee based on this percentage of loan amount, represented as 1/100000 of a percent (precision for up to 5 decimal places). (This value is for the lender/packager proc fee).")
    proc_fee_min: Optional[StrictStr] = Field(default=None, description="Minimum proc fee if using percentage (in pence, not GBP). (This value is for the lender/packager proc fee).")
    proc_fee_max: Optional[StrictStr] = Field(default=None, description="Maximum proc fee if using percentage (in pence, not GBP). (This value is for the lender/packager proc fee).")
    monthly_payment_after_initial_period_plus_1perc: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="This is the monthly payment after the initial period if the interest rate were to go up 1%.")
    monthly_payment_after_initial_period_plus_2perc: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="This is the monthly payment after the initial period if the interest rate were to go up 2%.")
    monthly_payment_after_initial_period_plus_3perc: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="This is the monthly payment after the initial period if the interest rate were to go up 3%.")
    self_build: Optional[StrictStr] = Field(default=None, description="Describes whether the product is available for Self-Build.")
    shared_ownership: Optional[StrictStr] = Field(default=None, description="Product available for Shared Ownership.")
    mortgage_discharge_fee: Optional[StrictStr] = Field(default=None, description="Mortgage Discharge Fee (in pence, not GBP).")
    deeds_release_fee: Optional[StrictStr] = Field(default=None, description="Deeds Release Fee (in pence, not GBP).")
    funds_transfer_fee_rule: Optional[StrictStr] = Field(default=None, description="Specifies the add to loan conditions for the Funds Transfer Fee.")
    capital_rest_period: Optional[StrictStr] = None
    help_to_buy_shared_equity: Optional[StrictBool] = Field(default=None, description="Denotes whether the product is available for HelpToBuy Shared Equity.")
    help_to_buy_mortgage_guarantee: Optional[StrictBool] = Field(default=None, description="Denotes whether the product is available for HelpToBuy Mortgage Guarantee.")
    broker_fee: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="**DEPRECATED** Will be moved to mortgage. The amount of the broker fee for the product.")
    broker_fee_conditions: Optional[StrictStr] = Field(default=None, description="**DEPRECATED** Will be moved to mortgage. Describes the conditions associated with the Broker Fee.")
    packager_reference: Optional[StrictStr] = Field(default=None, description="The organisation identifier of the Packager if relevant.")
    packager_name: Optional[StrictStr] = Field(default=None, description="The name of the Packager.")
    packager_tel_no: Optional[StrictStr] = Field(default=None, description="The telephone number of the Packager.")
    packager_web_address: Optional[StrictStr] = Field(default=None, description="The web address url of the Packager.")
    lender_criteria_url: Optional[StrictStr] = Field(default=None, description="A String specifying the url to use to navigate to the Lender’s own criteria.")
    lender_product_reference: Optional[StrictStr] = Field(default=None, description="Specifies the lender’s reference number or code for the product.")
    homebuyers_fee: Optional[StrictStr] = Field(default=None, description="The amount of the homebuyers fee for the product (in pence, not GBP).")
    homebuyers_fee_conditions: Optional[StrictStr] = Field(default=None, description="The conditions associated with the homebuyers fee.")
    legal_fee: Optional[StrictStr] = Field(default=None, description="The amount of the legal fee (in pence, not GBP).")
    legal_fee_conditions: Optional[StrictStr] = Field(default=None, description="The conditions associated with the legal fee.")
    product_type: Optional[StrictStr] = Field(default=None, description="The type of product. The possible values are: Residential, Buy To Let, Secured Loan, Secured Loan BTL, Bridging Loan, Commercial, Let To Buy, Equity Release.")
    net_proc_fee: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="The amount of the net proc fee. (This value is for the lender/packager proc fee).")
    net_proc_fee_fixed: Optional[StrictStr] = Field(default=None, description="The net proc fee is fixed to this amount (in pence, not GBP). (This value is for the lender/packager proc fee).")
    net_proc_fee_percentage: Optional[StrictInt] = Field(default=None, description="The net proc fee is this percentage of the loan amount, represented as 1/100000 of a percent (precision for up to 5 decimal places).. (This value is for the lender/packager proc fee).")
    net_proc_fee_min: Optional[StrictStr] = Field(default=None, description="The minimum amount for the net proc fee (in pence, not GBP). (This value is for the lender/packager proc fee).")
    net_proc_fee_max: Optional[StrictStr] = Field(default=None, description="The maximum amount for the net proc fee (in pence, not GBP). (This value is for the lender/packager proc fee).")
    mortgage_discharge_fee_when_to_pay: Optional[StrictStr] = Field(default=None, description="Describes when the mortgage discharge fee is payable.")
    product_match_status: Optional[StrictStr] = Field(default=None, description="This specifies the type of match the sourcing engine has made. Possible values are “Available” and “Near Miss”. “Near Miss” values will appear when an “Include_Near_Misses” search type has been selected and a product has fallen within the buffer zones specified in the NearMissesDetails object.")
    reject_reasons: Optional[StrictStr] = Field(default=None, description="A delimited list (|) of the reasons why the product was marked as a “Near Miss”. Example value: “Maximum LTV Available|Maximum Term Available”.")
    max_loan_available: Optional[StrictStr] = Field(default=None, description="The maximum calculated loan amount available for this product (in pence, not GBP).")
    buy_to_let_rental_income_calculation_rate: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="The rate value used in the calculation to determine the required rental income for BTL.")
    stress_test_payments: Optional[List[MortgageProductDetailsStressTestPayment]] = Field(default=None, description="The list of calculated stress test monthly payments, based on the details provided in the StressTestDetails object. This list is only populated when performing a ProductDetails request. The number of items in this list will match the NumberOfIncrements value provided in the StressTestDetails object.")
    disbursement_fee: Optional[StrictStr] = Field(default=None, description="The Disbursement Fee amount (in pence, not GBP).")
    disbursement_fee_conditions: Optional[StrictStr] = Field(default=None, description="Indicates if the Disbursement fee can be added to the loan, deducted from the loan etc.")
    true_cost_full_term: Optional[StrictStr] = Field(default=None, description="This is the True Cost of the mortgage over the full term as specified by the Term and TermUnit fields in the request. In order to have the system calculate this value, the loan amount and term values must be specified in the request (in pence, not GBP).")
    initial_monthly_payment_inc_existing_mortgage: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="When sourcing Secured Loans/Further Advances/Porting, if the ExistingMortgage object for Applicant 1 is provided, then this field will provide the cost of the initial monthly payment, plus the cost of the applicant’s existing mortgage as defined by the CurrentMonthlyPayment amount.")
    true_cost_full_term_inc_existing_mortgage: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="When sourcing Secured Loans/Further Advances/Porting, if the ExistingMortgage object for Applicant 1 is provided, then this field will provide the total cost of the loan over the full term as specified by the Term and TermUnit fields in the request, plus the cost of the applicant’s existing mortgage as defined by the CurrentMonthlyPayment and MonthsRemainingOnMortgage fields. If the MonthsRemainingOnMortgage field is not provided, then the existing mortgage’s CurrentMonthlyPayment value is considered to apply over the full term as specified by the request.")
    true_cost_initial_period_inc_existing_mortgage: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="When sourcing Secured Loans/Further Advances/Porting, if the ExistingMortgage object for Applicant 1 is provided, then this field will provide the total cost of the loan over the full term as specified by the Term and TermUnit fields in the request, plus the cost of the applicant’s existing mortgage as defined by the CurrentMonthlyPayment and MonthsRemainingOnMortgage fields. If the MonthsRemainingOnMortgage field is not provided, then the existing mortgage’s CurrentMonthlyPayment value is considered to apply over the full term as specified by the request.")
    true_cost_inc_existing_mortgage: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="When sourcing Secured Loans/Further Advances/Porting, if the ExistingMortgage object for Applicant 1 is provided, then this field will provide the total cost of the loan over the specified custom duration in CalculateOverNoOfMonths in the TrueCostDetails object or over the full term if a custom duration is not provided, plus the cost of the applicant’s existing mortgage as defined by the CurrentMonthlyPayment and MonthsRemainingOnMortgage fields. If the MonthsRemainingOnMortgage field is not provided, then the existing mortgage’s CurrentMonthlyPayment value is considered to apply over the full term as specified by the request.")
    mortgage_club_proc_fees: Optional[List[MortgageProductDetailsMortgageClubProcFee]] = Field(default=None, description="The list of proc fees available for this product through the various mortgage clubs. Only those mortgage clubs included on the user’s panel will be included in the results.")
    selected_mortgage_club_code: Optional[StrictStr] = Field(default=None, description="**DEPRECATED** moved to mortgage.  The selected mortgage club code.")
    max_overpayment_percent_no_erc: Optional[StrictInt] = Field(default=None, description="Describes the maximum overpayment percentage when no ERC.")
    overpayments_allowed: Optional[StrictBool] = Field(default=None, description="Indicates whether the product allows overpayments.")
    overpayment_conditions: Optional[StrictStr] = Field(default=None, description="Where a mortgage allows overpayments, provide details and conditions for overpayment.")
    underpayments_allowed: Optional[StrictBool] = Field(default=None, description="Indicates whether the product allows underpayments.")
    payment_holidays_allowed: Optional[StrictBool] = Field(default=None, description="Indicates whether the product allows payment holidays.")
    date_last_modified: Optional[StrictStr] = None
    optional_partial_repayment: Optional[StrictBool] = Field(default=None, description="Ability to make Optional Partial Repayments for the Equity Release Product.")
    apply_online: Optional[StrictBool] = Field(default=None, description="Indicates whether the product can be applied for online using MortgageApply.  more details")
    lender_tel_no: Optional[StrictStr] = Field(default=None, description="Telephone number of the lender.")
    lender_web_address: Optional[StrictStr] = Field(default=None, description="Web address of the lender.")
    initial_rate_period: Optional[StrictStr] = None
    initial_rate_period_months: Optional[StrictInt] = Field(default=None, description="The length of time (in months) of the product’s initial rate period.")
    repayment_acceptable: Optional[StrictBool] = Field(default=None, description="Indicates if Repayment Capital and Interest only is available as a repayment method.")
    product_availability: Optional[StrictStr] = Field(default=None, description="Who the product is available to - All, Direct Only Exclusive or intermediary.")
    available_to_purchase: Optional[StrictBool] = Field(default=None, description="Indicates if the product is available for Purchases.")
    available_to_remortgage: Optional[StrictBool] = Field(default=None, description="Indicates if the product is available for remortgages.")
    available_to_ftb: Optional[StrictBool] = Field(default=None, description="Indicates if the product is available to First Time Buyers.")
    max_loan: Optional[StrictStr] = Field(default=None, description="The Maximum Loan available for the product (in pence, not GBP).")
    min_loan: Optional[StrictStr] = Field(default=None, description="The Minimum Loan required for the product (in pence, not GBP).")
    min_time_in_current_position_months: Optional[StrictInt] = Field(default=None, description="The minimum time an applicant must be in their current employment to be considered for the mortgage.")
    min_time_in_continuous_service_months: Optional[StrictInt] = Field(default=None, description="The minimum time an applicant must be have been in continuous employment to be considered for the mortgage.")
    min_self_employed_accounts_years: Optional[StrictInt] = Field(default=None, description="The minimum years account a self-employed applicant will need to be considered.")
    early_repayment_charge_applies: Optional[StrictBool] = Field(default=None, description="**DEPRECATED** Use early_repayment_charge_periods.  Indicates if the product has any early repayment charges for paying part or all of the mortgage off.")
    early_repayment_charge: Optional[StrictStr] = Field(default=None, description="**DEPRECATED** Use early_repayment_charge_periods.  Shows what the early repayment charge is as a percentage of the loan amount for each year - 3% year one and 2 % year two etc.")
    ccj_maximum_number: Optional[StrictInt] = Field(default=None, description="Deprecated (All adverse sourcing has been replaced with more detailed criteria and this value should no longer be considered accurate) The maximum number of County Court Judgements indicated/recorded that will be acceptable.")
    ccj_maximum_amount: Optional[StrictInt] = Field(default=None, description="Deprecated (All adverse sourcing has been replaced with more detailed criteria and this value should no longer be considered accurate) The maximum amount of acceptable of County Court Judgements indicated/recorded that will be acceptable.")
    arrears_not_in_last_months: Optional[StrictInt] = Field(default=None, description="Deprecated (All adverse sourcing has been replaced with more detailed criteria and this value should no longer be considered accurate) Indicates that if there are mortgage arrears in the last x number of months the product will not be acceptable.")
    true_cost: Optional[StrictStr] = Field(default=None, description="This is how much the mortgage will cost over the custom duration specified by the true_cost_calculate_over_no_of_months field. Also referred to as Total Cost.  In order to have the system calculate this value, there must be a value set for true_cost_calculate_over_no_of_months, and load_required and term values must also be specified in the request. The amount is specified in pence and not GBP.")
    true_cost_over_initial_period: Optional[StrictStr] = Field(default=None, description="This is how much the mortgage will cost over just the product’s initial rate period. In order to have the system calculate this value, the field true_cost_disable_calculate_over_initial_period must not be true and there must also be loan amount and term values specified in the request. The amount is specified in pence and not GBP.")
    true_cost_over_calculated_period: Optional[StrictStr] = Field(default=None, description="This field abstracts true_cost and will be populated using the value of true_cost_over_initial_period when true_cost is not present (due to true_cost_calculate_over_no_of_months being omitted from the request).")
    cashback_paid_on: Optional[StrictStr] = Field(default=None, description="Point in time cashback is paid.")
    remort_home_improv_max_ltv: Optional[StrictInt] = Field(default=None, description="Max LTV for Remortgage with a reason for remortgage being Home Improvements.")
    remort_debt_con_max_ltv: Optional[StrictInt] = Field(default=None, description="Max LTV for Remortgage with a reason for remortgage being Debt Consolidation.")
    remort_bus_purpose_max_ltv: Optional[StrictInt] = Field(default=None, description="Max LTV for Remortgage with a reason for remortgage being Business Purposes.")
    remort_hol_cars_max_ltv: Optional[StrictInt] = Field(default=None, description="Max LTV for Remortgage with a reason for remortgage being Holidays, Cars, etc.")
    affordability_calculator: Optional[StrictStr] = Field(default=None, description="Link to lender’s affordability calculator.")
    self_years_avg_income: Optional[StrictInt] = Field(default=None, description="Average income acceptable for self-employed based on profits.")
    flat_over_shop_flag: Optional[StrictStr] = Field(default=None, description="Flat over shop acceptable. “Yes”, “No”, “Refer”.")
    flat_over_shop_notes: Optional[StrictStr] = Field(default=None, description="Notes on this arrangement.")
    flat_over_shop_owner: Optional[StrictStr] = Field(default=None, description="If the purchaser is required to own the shop that the flat is over. \"Yes\", \"No\", \"\".")
    flat_over_shop_sep_ent: Optional[StrictStr] = Field(default=None, description="Is separate entrance required? \"Yes\", \"No\", \"\".")
    flat_over_shop_sep_title: Optional[StrictStr] = Field(default=None, description="Is separate title required? \"Yes\", \"No\", \"\".")
    flat_over_shop_restaurant: Optional[StrictStr] = Field(default=None, description="Acceptable if above restaurant. \"Yes\", \"No\", \"\".")
    flat_over_shop_retail: Optional[StrictStr] = Field(default=None, description="Acceptable if above retail shop. \"Yes\", \"No\", \"\".")
    flat_over_shop_fast_food: Optional[StrictStr] = Field(default=None, description="Acceptable if above fast food. \"Yes\", \"No\", \"\".")
    flat_over_shop_fast_industry_unit: Optional[StrictStr] = Field(default=None, description="Acceptable if above Industrial unit.  \"Yes\", \"No\", \"\".")
    flat_max_floors: Optional[StrictInt] = Field(default=None, description="Max floors acceptable in a flat.")
    flat_max_floors_no_lift: Optional[StrictInt] = Field(default=None, description="Max floors acceptable in flat without a lift.")
    deeds_release_fee_when_to_pay: Optional[StrictStr] = Field(default=None, description="Describes when the deeds release fee is payable.")
    applicant1_minimum_age: Optional[StrictInt] = Field(default=None, description="The minimum age for the primary applicant.")
    applicant2_minimum_age: Optional[StrictInt] = Field(default=None, description="The minimum age for the secondary applicant.")
    applicant_maximum_age: Optional[StrictInt] = Field(default=None, description="The applicants' maximum age on expiry.")
    freehold_flag: Optional[StrictStr] = Field(default=None, description="Freehold acceptable. \"Yes\", \"No\", \"Refer\".")
    leasehold_flag: Optional[StrictStr] = Field(default=None, description="Leasehold acceptable. \"Yes\", \"No\", \"Refer\".")
    commonhold_flag: Optional[StrictStr] = Field(default=None, description="Commonhold acceptable. \"Yes\", \"No\", \"Refer\".")
    feudal_flag: Optional[StrictStr] = Field(default=None, description="Feudal hold acceptable. \"Yes\", \"No\", \"Refer\".")
    flying_freehold_flag: Optional[StrictStr] = Field(default=None, description="Flying freehold acceptable. \"Yes\", \"No\", \"Refer\".")
    flying_freehold_max_percentage: Optional[StrictInt] = Field(default=None, description="Allowable percentage as flying freehold, represented as 1/100000 of a percent (precision for up to 5 decimal places).")
    product_available_date: Optional[StrictStr] = Field(default=None, description="Date of product becoming available (YYYY-MM-DD).")
    product_discontinued_date: Optional[StrictStr] = Field(default=None, description="Date of product becoming discontinued (YYYY-MM-DD).")
    is_offset_product: Optional[StrictBool] = Field(default=None, description="Specifies whether this is an offset product.")
    is_further_advance: Optional[StrictBool] = Field(default=None, description="Specifies whether this is for a further advance product.")
    is_porting: Optional[StrictBool] = Field(default=None, description="Specifies whether this is for a porting product.")
    mortgage_type: Optional[CdmMortgageProductDetailsMortgageType] = CdmMortgageProductDetailsMortgageType.INVALID_MORTGAGE_TYPE
    sourcing_reference: Optional[StrictStr] = Field(default=None, description="Sourcing Engines Lender Reference.")
    sourcing_product_reference: Optional[StrictStr] = Field(default=None, description="SourceEngines Unique Product Reference.")
    lender_reference: Optional[StrictStr] = Field(default=None, description="Acre Organisation GUID of the mortgage lender.")
    early_repayment_charge_periods: Optional[List[CdmEarlyRepaymentChargePeriods]] = Field(default=None, description="Information associated with early repayment charge periods.")
    rate_tiers: Optional[List[MortgageProductDetailsRateTier]] = None
    portability_conditions: Optional[StrictStr] = Field(default=None, description="Where a mortgage is portable, provide details and conditions for portability.")
    incentive_description: Optional[StrictStr] = Field(default=None, description="Where a mortgage includes incentives, provides details on said incentives.")
    insurance_conditions: Optional[StrictStr] = Field(default=None, description="Where insurance is required as a condition of a mortgage, provides details of such.")
    is_interest_retained: Optional[StrictBool] = Field(default=None, description="False (default) Whether the interest is retained.")
    fees: Optional[List[CdmMortgageProductFee]] = Field(default=None, description="Fee data that IRESS provides.")
    __properties: ClassVar[List[str]] = ["product_code", "product_name", "lender_code", "lender_name", "initial_pay_rate", "mortgage_class", "applicant_type_conditions", "full_rate_description", "apr_lenders", "max_ltv_available", "applicant1_income_multiplier", "applicant2_income_multiplier", "joint_applicant_income_multiplier", "standard_variable_rate", "initial_monthly_payment", "cashback", "cashback_conditions", "valuation_fee", "valuation_fee_conditions", "arrangement_fee", "arrangement_fee_conditions", "booking_fee", "booking_fee_conditions", "higher_lending_charge", "higher_lending_charge_conditions", "free_legal_fees", "free_legal_fee_conditions", "chaps_fee", "fees_payable_on_application", "fees_payable_on_completion", "fees_total", "early_repayment_charge_applies_until", "early_repayment_charge_applies_until_calculated_date", "product_notes", "employed_prob_period", "max_property_valuation", "studio_flat_flag", "proc_fee_code", "proc_fee_fixed", "proc_fee_percentage", "proc_fee_min", "proc_fee_max", "monthly_payment_after_initial_period_plus_1perc", "monthly_payment_after_initial_period_plus_2perc", "monthly_payment_after_initial_period_plus_3perc", "self_build", "shared_ownership", "mortgage_discharge_fee", "deeds_release_fee", "funds_transfer_fee_rule", "capital_rest_period", "help_to_buy_shared_equity", "help_to_buy_mortgage_guarantee", "broker_fee", "broker_fee_conditions", "packager_reference", "packager_name", "packager_tel_no", "packager_web_address", "lender_criteria_url", "lender_product_reference", "homebuyers_fee", "homebuyers_fee_conditions", "legal_fee", "legal_fee_conditions", "product_type", "net_proc_fee", "net_proc_fee_fixed", "net_proc_fee_percentage", "net_proc_fee_min", "net_proc_fee_max", "mortgage_discharge_fee_when_to_pay", "product_match_status", "reject_reasons", "max_loan_available", "buy_to_let_rental_income_calculation_rate", "stress_test_payments", "disbursement_fee", "disbursement_fee_conditions", "true_cost_full_term", "initial_monthly_payment_inc_existing_mortgage", "true_cost_full_term_inc_existing_mortgage", "true_cost_initial_period_inc_existing_mortgage", "true_cost_inc_existing_mortgage", "mortgage_club_proc_fees", "selected_mortgage_club_code", "max_overpayment_percent_no_erc", "overpayments_allowed", "overpayment_conditions", "underpayments_allowed", "payment_holidays_allowed", "date_last_modified", "optional_partial_repayment", "apply_online", "lender_tel_no", "lender_web_address", "initial_rate_period", "initial_rate_period_months", "repayment_acceptable", "product_availability", "available_to_purchase", "available_to_remortgage", "available_to_ftb", "max_loan", "min_loan", "min_time_in_current_position_months", "min_time_in_continuous_service_months", "min_self_employed_accounts_years", "early_repayment_charge_applies", "early_repayment_charge", "ccj_maximum_number", "ccj_maximum_amount", "arrears_not_in_last_months", "true_cost", "true_cost_over_initial_period", "true_cost_over_calculated_period", "cashback_paid_on", "remort_home_improv_max_ltv", "remort_debt_con_max_ltv", "remort_bus_purpose_max_ltv", "remort_hol_cars_max_ltv", "affordability_calculator", "self_years_avg_income", "flat_over_shop_flag", "flat_over_shop_notes", "flat_over_shop_owner", "flat_over_shop_sep_ent", "flat_over_shop_sep_title", "flat_over_shop_restaurant", "flat_over_shop_retail", "flat_over_shop_fast_food", "flat_over_shop_fast_industry_unit", "flat_max_floors", "flat_max_floors_no_lift", "deeds_release_fee_when_to_pay", "applicant1_minimum_age", "applicant2_minimum_age", "applicant_maximum_age", "freehold_flag", "leasehold_flag", "commonhold_flag", "feudal_flag", "flying_freehold_flag", "flying_freehold_max_percentage", "product_available_date", "product_discontinued_date", "is_offset_product", "is_further_advance", "is_porting", "mortgage_type", "sourcing_reference", "sourcing_product_reference", "lender_reference", "early_repayment_charge_periods", "rate_tiers", "portability_conditions", "incentive_description", "insurance_conditions", "is_interest_retained", "fees"]

    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 CdmMortgageProductDetails 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 stress_test_payments (list)
        _items = []
        if self.stress_test_payments:
            for _item_stress_test_payments in self.stress_test_payments:
                if _item_stress_test_payments:
                    _items.append(_item_stress_test_payments.to_dict())
            _dict['stress_test_payments'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in mortgage_club_proc_fees (list)
        _items = []
        if self.mortgage_club_proc_fees:
            for _item_mortgage_club_proc_fees in self.mortgage_club_proc_fees:
                if _item_mortgage_club_proc_fees:
                    _items.append(_item_mortgage_club_proc_fees.to_dict())
            _dict['mortgage_club_proc_fees'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in early_repayment_charge_periods (list)
        _items = []
        if self.early_repayment_charge_periods:
            for _item_early_repayment_charge_periods in self.early_repayment_charge_periods:
                if _item_early_repayment_charge_periods:
                    _items.append(_item_early_repayment_charge_periods.to_dict())
            _dict['early_repayment_charge_periods'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in rate_tiers (list)
        _items = []
        if self.rate_tiers:
            for _item_rate_tiers in self.rate_tiers:
                if _item_rate_tiers:
                    _items.append(_item_rate_tiers.to_dict())
            _dict['rate_tiers'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in fees (list)
        _items = []
        if self.fees:
            for _item_fees in self.fees:
                if _item_fees:
                    _items.append(_item_fees.to_dict())
            _dict['fees'] = _items
        return _dict

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

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

        _obj = cls.model_validate({
            "product_code": obj.get("product_code"),
            "product_name": obj.get("product_name"),
            "lender_code": obj.get("lender_code"),
            "lender_name": obj.get("lender_name"),
            "initial_pay_rate": obj.get("initial_pay_rate"),
            "mortgage_class": obj.get("mortgage_class") if obj.get("mortgage_class") is not None else CdmMortgageClass.INVALID_MORTGAGE_CLASS,
            "applicant_type_conditions": obj.get("applicant_type_conditions"),
            "full_rate_description": obj.get("full_rate_description"),
            "apr_lenders": obj.get("apr_lenders"),
            "max_ltv_available": obj.get("max_ltv_available"),
            "applicant1_income_multiplier": obj.get("applicant1_income_multiplier"),
            "applicant2_income_multiplier": obj.get("applicant2_income_multiplier"),
            "joint_applicant_income_multiplier": obj.get("joint_applicant_income_multiplier"),
            "standard_variable_rate": obj.get("standard_variable_rate"),
            "initial_monthly_payment": obj.get("initial_monthly_payment"),
            "cashback": obj.get("cashback"),
            "cashback_conditions": obj.get("cashback_conditions"),
            "valuation_fee": obj.get("valuation_fee"),
            "valuation_fee_conditions": obj.get("valuation_fee_conditions"),
            "arrangement_fee": obj.get("arrangement_fee"),
            "arrangement_fee_conditions": obj.get("arrangement_fee_conditions"),
            "booking_fee": obj.get("booking_fee"),
            "booking_fee_conditions": obj.get("booking_fee_conditions"),
            "higher_lending_charge": obj.get("higher_lending_charge"),
            "higher_lending_charge_conditions": obj.get("higher_lending_charge_conditions"),
            "free_legal_fees": obj.get("free_legal_fees"),
            "free_legal_fee_conditions": obj.get("free_legal_fee_conditions"),
            "chaps_fee": obj.get("chaps_fee"),
            "fees_payable_on_application": obj.get("fees_payable_on_application"),
            "fees_payable_on_completion": obj.get("fees_payable_on_completion"),
            "fees_total": obj.get("fees_total"),
            "early_repayment_charge_applies_until": obj.get("early_repayment_charge_applies_until"),
            "early_repayment_charge_applies_until_calculated_date": obj.get("early_repayment_charge_applies_until_calculated_date"),
            "product_notes": obj.get("product_notes"),
            "employed_prob_period": obj.get("employed_prob_period"),
            "max_property_valuation": obj.get("max_property_valuation"),
            "studio_flat_flag": obj.get("studio_flat_flag"),
            "proc_fee_code": obj.get("proc_fee_code"),
            "proc_fee_fixed": obj.get("proc_fee_fixed"),
            "proc_fee_percentage": obj.get("proc_fee_percentage"),
            "proc_fee_min": obj.get("proc_fee_min"),
            "proc_fee_max": obj.get("proc_fee_max"),
            "monthly_payment_after_initial_period_plus_1perc": obj.get("monthly_payment_after_initial_period_plus_1perc"),
            "monthly_payment_after_initial_period_plus_2perc": obj.get("monthly_payment_after_initial_period_plus_2perc"),
            "monthly_payment_after_initial_period_plus_3perc": obj.get("monthly_payment_after_initial_period_plus_3perc"),
            "self_build": obj.get("self_build"),
            "shared_ownership": obj.get("shared_ownership"),
            "mortgage_discharge_fee": obj.get("mortgage_discharge_fee"),
            "deeds_release_fee": obj.get("deeds_release_fee"),
            "funds_transfer_fee_rule": obj.get("funds_transfer_fee_rule"),
            "capital_rest_period": obj.get("capital_rest_period"),
            "help_to_buy_shared_equity": obj.get("help_to_buy_shared_equity"),
            "help_to_buy_mortgage_guarantee": obj.get("help_to_buy_mortgage_guarantee"),
            "broker_fee": obj.get("broker_fee"),
            "broker_fee_conditions": obj.get("broker_fee_conditions"),
            "packager_reference": obj.get("packager_reference"),
            "packager_name": obj.get("packager_name"),
            "packager_tel_no": obj.get("packager_tel_no"),
            "packager_web_address": obj.get("packager_web_address"),
            "lender_criteria_url": obj.get("lender_criteria_url"),
            "lender_product_reference": obj.get("lender_product_reference"),
            "homebuyers_fee": obj.get("homebuyers_fee"),
            "homebuyers_fee_conditions": obj.get("homebuyers_fee_conditions"),
            "legal_fee": obj.get("legal_fee"),
            "legal_fee_conditions": obj.get("legal_fee_conditions"),
            "product_type": obj.get("product_type"),
            "net_proc_fee": obj.get("net_proc_fee"),
            "net_proc_fee_fixed": obj.get("net_proc_fee_fixed"),
            "net_proc_fee_percentage": obj.get("net_proc_fee_percentage"),
            "net_proc_fee_min": obj.get("net_proc_fee_min"),
            "net_proc_fee_max": obj.get("net_proc_fee_max"),
            "mortgage_discharge_fee_when_to_pay": obj.get("mortgage_discharge_fee_when_to_pay"),
            "product_match_status": obj.get("product_match_status"),
            "reject_reasons": obj.get("reject_reasons"),
            "max_loan_available": obj.get("max_loan_available"),
            "buy_to_let_rental_income_calculation_rate": obj.get("buy_to_let_rental_income_calculation_rate"),
            "stress_test_payments": [MortgageProductDetailsStressTestPayment.from_dict(_item) for _item in obj["stress_test_payments"]] if obj.get("stress_test_payments") is not None else None,
            "disbursement_fee": obj.get("disbursement_fee"),
            "disbursement_fee_conditions": obj.get("disbursement_fee_conditions"),
            "true_cost_full_term": obj.get("true_cost_full_term"),
            "initial_monthly_payment_inc_existing_mortgage": obj.get("initial_monthly_payment_inc_existing_mortgage"),
            "true_cost_full_term_inc_existing_mortgage": obj.get("true_cost_full_term_inc_existing_mortgage"),
            "true_cost_initial_period_inc_existing_mortgage": obj.get("true_cost_initial_period_inc_existing_mortgage"),
            "true_cost_inc_existing_mortgage": obj.get("true_cost_inc_existing_mortgage"),
            "mortgage_club_proc_fees": [MortgageProductDetailsMortgageClubProcFee.from_dict(_item) for _item in obj["mortgage_club_proc_fees"]] if obj.get("mortgage_club_proc_fees") is not None else None,
            "selected_mortgage_club_code": obj.get("selected_mortgage_club_code"),
            "max_overpayment_percent_no_erc": obj.get("max_overpayment_percent_no_erc"),
            "overpayments_allowed": obj.get("overpayments_allowed"),
            "overpayment_conditions": obj.get("overpayment_conditions"),
            "underpayments_allowed": obj.get("underpayments_allowed"),
            "payment_holidays_allowed": obj.get("payment_holidays_allowed"),
            "date_last_modified": obj.get("date_last_modified"),
            "optional_partial_repayment": obj.get("optional_partial_repayment"),
            "apply_online": obj.get("apply_online"),
            "lender_tel_no": obj.get("lender_tel_no"),
            "lender_web_address": obj.get("lender_web_address"),
            "initial_rate_period": obj.get("initial_rate_period"),
            "initial_rate_period_months": obj.get("initial_rate_period_months"),
            "repayment_acceptable": obj.get("repayment_acceptable"),
            "product_availability": obj.get("product_availability"),
            "available_to_purchase": obj.get("available_to_purchase"),
            "available_to_remortgage": obj.get("available_to_remortgage"),
            "available_to_ftb": obj.get("available_to_ftb"),
            "max_loan": obj.get("max_loan"),
            "min_loan": obj.get("min_loan"),
            "min_time_in_current_position_months": obj.get("min_time_in_current_position_months"),
            "min_time_in_continuous_service_months": obj.get("min_time_in_continuous_service_months"),
            "min_self_employed_accounts_years": obj.get("min_self_employed_accounts_years"),
            "early_repayment_charge_applies": obj.get("early_repayment_charge_applies"),
            "early_repayment_charge": obj.get("early_repayment_charge"),
            "ccj_maximum_number": obj.get("ccj_maximum_number"),
            "ccj_maximum_amount": obj.get("ccj_maximum_amount"),
            "arrears_not_in_last_months": obj.get("arrears_not_in_last_months"),
            "true_cost": obj.get("true_cost"),
            "true_cost_over_initial_period": obj.get("true_cost_over_initial_period"),
            "true_cost_over_calculated_period": obj.get("true_cost_over_calculated_period"),
            "cashback_paid_on": obj.get("cashback_paid_on"),
            "remort_home_improv_max_ltv": obj.get("remort_home_improv_max_ltv"),
            "remort_debt_con_max_ltv": obj.get("remort_debt_con_max_ltv"),
            "remort_bus_purpose_max_ltv": obj.get("remort_bus_purpose_max_ltv"),
            "remort_hol_cars_max_ltv": obj.get("remort_hol_cars_max_ltv"),
            "affordability_calculator": obj.get("affordability_calculator"),
            "self_years_avg_income": obj.get("self_years_avg_income"),
            "flat_over_shop_flag": obj.get("flat_over_shop_flag"),
            "flat_over_shop_notes": obj.get("flat_over_shop_notes"),
            "flat_over_shop_owner": obj.get("flat_over_shop_owner"),
            "flat_over_shop_sep_ent": obj.get("flat_over_shop_sep_ent"),
            "flat_over_shop_sep_title": obj.get("flat_over_shop_sep_title"),
            "flat_over_shop_restaurant": obj.get("flat_over_shop_restaurant"),
            "flat_over_shop_retail": obj.get("flat_over_shop_retail"),
            "flat_over_shop_fast_food": obj.get("flat_over_shop_fast_food"),
            "flat_over_shop_fast_industry_unit": obj.get("flat_over_shop_fast_industry_unit"),
            "flat_max_floors": obj.get("flat_max_floors"),
            "flat_max_floors_no_lift": obj.get("flat_max_floors_no_lift"),
            "deeds_release_fee_when_to_pay": obj.get("deeds_release_fee_when_to_pay"),
            "applicant1_minimum_age": obj.get("applicant1_minimum_age"),
            "applicant2_minimum_age": obj.get("applicant2_minimum_age"),
            "applicant_maximum_age": obj.get("applicant_maximum_age"),
            "freehold_flag": obj.get("freehold_flag"),
            "leasehold_flag": obj.get("leasehold_flag"),
            "commonhold_flag": obj.get("commonhold_flag"),
            "feudal_flag": obj.get("feudal_flag"),
            "flying_freehold_flag": obj.get("flying_freehold_flag"),
            "flying_freehold_max_percentage": obj.get("flying_freehold_max_percentage"),
            "product_available_date": obj.get("product_available_date"),
            "product_discontinued_date": obj.get("product_discontinued_date"),
            "is_offset_product": obj.get("is_offset_product"),
            "is_further_advance": obj.get("is_further_advance"),
            "is_porting": obj.get("is_porting"),
            "mortgage_type": obj.get("mortgage_type") if obj.get("mortgage_type") is not None else CdmMortgageProductDetailsMortgageType.INVALID_MORTGAGE_TYPE,
            "sourcing_reference": obj.get("sourcing_reference"),
            "sourcing_product_reference": obj.get("sourcing_product_reference"),
            "lender_reference": obj.get("lender_reference"),
            "early_repayment_charge_periods": [CdmEarlyRepaymentChargePeriods.from_dict(_item) for _item in obj["early_repayment_charge_periods"]] if obj.get("early_repayment_charge_periods") is not None else None,
            "rate_tiers": [MortgageProductDetailsRateTier.from_dict(_item) for _item in obj["rate_tiers"]] if obj.get("rate_tiers") is not None else None,
            "portability_conditions": obj.get("portability_conditions"),
            "incentive_description": obj.get("incentive_description"),
            "insurance_conditions": obj.get("insurance_conditions"),
            "is_interest_retained": obj.get("is_interest_retained"),
            "fees": [CdmMortgageProductFee.from_dict(_item) for _item in obj["fees"]] if obj.get("fees") is not None else None
        })
        return _obj


