# 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, StrictInt, StrictStr
from typing import Any, ClassVar, Dict, List, Optional
from acre_api.models.cdm_client_account import CdmClientAccount
from acre_api.models.cdm_client_address import CdmClientAddress
from acre_api.models.cdm_client_calculated_values import CdmClientCalculatedValues
from acre_api.models.cdm_client_dependant import CdmClientDependant
from acre_api.models.cdm_client_deposit import CdmClientDeposit
from acre_api.models.cdm_client_details_default_event import CdmClientDetailsDefaultEvent
from acre_api.models.cdm_client_details_employment_status import CdmClientDetailsEmploymentStatus
from acre_api.models.cdm_client_income import CdmClientIncome
from acre_api.models.cdm_client_outstanding_debt import CdmClientOutstandingDebt
from acre_api.models.cdm_client_relationship import CdmClientRelationship
from acre_api.models.cdm_contact_history import CdmContactHistory
from acre_api.models.cdm_credit_report_retrievals import CdmCreditReportRetrievals
from acre_api.models.cdm_delete_reason import CdmDeleteReason
from acre_api.models.cdm_external import CdmExternal
from acre_api.models.cdm_external_id import CdmExternalID
from acre_api.models.cdm_gender import CdmGender
from acre_api.models.cdm_id_verification_status import CdmIDVerificationStatus
from acre_api.models.cdm_mortgage_application_refused import CdmMortgageApplicationRefused
from acre_api.models.cdm_non_natural import CdmNonNatural
from acre_api.models.cdm_previous_name import CdmPreviousName
from acre_api.models.cdm_sic2007 import CdmSIC2007
from acre_api.models.cdm_title import CdmTitle
from acre_api.models.cdm_unearned_income import CdmUnearnedIncome
from acre_api.models.client_details_arrear import ClientDetailsArrear
from acre_api.models.client_details_bankruptcy_event import ClientDetailsBankruptcyEvent
from acre_api.models.client_details_client_type import ClientDetailsClientType
from acre_api.models.client_details_contact_method import ClientDetailsContactMethod
from acre_api.models.client_details_county_court_judgement import ClientDetailsCountyCourtJudgement
from acre_api.models.client_details_debt_management_plan import ClientDetailsDebtManagementPlan
from acre_api.models.client_details_individual_voluntary_arrangement import ClientDetailsIndividualVoluntaryArrangement
from acre_api.models.client_details_marital_status import ClientDetailsMaritalStatus
from acre_api.models.client_details_non_natural_organisation_type import ClientDetailsNonNaturalOrganisationType
from acre_api.models.client_details_residency_status import ClientDetailsResidencyStatus
from acre_api.models.client_details_vulnerability import ClientDetailsVulnerability
from typing import Optional, Set
from typing_extensions import Self

class CdmClientDetails(BaseModel):
    """
    ClientDetails maintains detail information about a client. This information is versioned. All fields can be updated / set via the API unless otherwise stated.
    """ # noqa: E501
    client_id: Optional[StrictStr] = Field(default=None, description="Client reference. This field is populated automatically and cannot be updated.")
    client_originator: Optional[StrictStr] = Field(default=None, description="The organisation that the client was originally created under. If not provided this field is populated automatically. If provided the caller must have necessary permissions over referenced organisation. **IMPORTANT:** This field cannot be updated.")
    client_user_originator: Optional[StrictStr] = Field(default=None, description="The ID of the user that created the client. This field is populated automatically. **IMPORTANT** This field cannot be updated.")
    has_seen_face_to_face: Optional[StrictBool] = Field(default=None, description="Whether this individual has been seen face-to-face by an employee of the Brokerage Firm. Deprecated and cannot be used but moved to CaseDetails due to compliance.")
    title: Optional[CdmTitle] = CdmTitle.INVALID_TITLE
    first_name: Optional[StrictStr] = Field(default=None, description="The applicant's first name.")
    middle_name: Optional[StrictStr] = Field(default=None, description="The applicant's middle name.")
    last_name: Optional[StrictStr] = Field(default=None, description="The applicant's last name.")
    maiden_or_previous_name: Optional[StrictStr] = Field(default=None, description="The applicant's maiden or previous name.")
    date_of_name_change: Optional[StrictStr] = Field(default=None, description="The date of the applicant's name change (YYYY-MM-DD).")
    previous_names: Optional[List[CdmPreviousName]] = Field(default=None, description="The applicant's maiden or previous names.")
    date_of_birth: Optional[StrictStr] = Field(default=None, description="The applicant's date of birth (YYYY-MM-DD).")
    country_of_birth: Optional[StrictStr] = Field(default=None, description="The applicant's country of birth (country code).")
    client_type: Optional[List[ClientDetailsClientType]] = Field(default=None, description="The applicant's client type.")
    gender: Optional[CdmGender] = CdmGender.INVALID_GENDER
    marital_status: Optional[ClientDetailsMaritalStatus] = ClientDetailsMaritalStatus.INVALID_MARITAL_STATUS
    contact_details_home_phone: Optional[StrictStr] = Field(default=None, description="Applicant's home phone number.")
    contact_details_work_phone: Optional[StrictStr] = Field(default=None, description="Applicant's work phone number.")
    contact_details_mobile_phone: Optional[StrictStr] = Field(default=None, description="Applicant's mobile phone number.")
    contact_details_email: Optional[StrictStr] = Field(default=None, description="Applicant's email address. Need not be unique across all clients in system.")
    addresses: Optional[List[CdmClientAddress]] = Field(default=None, description="Applicant's current and previous addresses.")
    retirement_age: Optional[StrictInt] = Field(default=None, description="The applicant's retirement age.")
    residency_status: Optional[ClientDetailsResidencyStatus] = ClientDetailsResidencyStatus.INVALID_RESIDENCY_STATUS
    years_lived_in_uk: Optional[StrictInt] = None
    is_politically_exposed: Optional[StrictBool] = Field(default=None, description="Flag indicating whether the applicant is politically exposed.")
    is_vulnerable: Optional[StrictBool] = Field(default=None, description="Flag indicating whether the applicant is vulnerable.")
    nationalities: Optional[List[StrictStr]] = Field(default=None, description="Applicant's nationalities (list of country codes).")
    employment_status: Optional[CdmClientDetailsEmploymentStatus] = CdmClientDetailsEmploymentStatus.INVALID_EMPLOYMENT_STATUS
    amount_of_savings: Optional[StrictStr] = Field(default=None, description="The amount of applicant's savings (in pence, not GBP).")
    applicants_are_high_tax_rate_payers: Optional[StrictBool] = None
    dependants: Optional[List[CdmClientDependant]] = Field(default=None, description="Applicant's dependants.")
    national_insurance_number: Optional[StrictStr] = None
    relationships: Optional[List[CdmClientRelationship]] = Field(default=None, description="Relationships to other clients.")
    deposits: Optional[List[CdmClientDeposit]] = Field(default=None, description="The applicant's deposits.")
    accounts: Optional[List[CdmClientAccount]] = Field(default=None, description="The applicant's accounts.  **IMPORTANT:** Due to the id<>item reconciliation behaviour it's not possible to delete individual fields with primitive types (string, int...) as we can't identify if it's nil (not given and need to copy from old) or empty value. In order to delete those fields, the whole item will have to be deleted.")
    debts: Optional[List[CdmClientOutstandingDebt]] = Field(default=None, description="The applicant's outstanding debts.")
    disposable_income: Optional[StrictStr] = Field(default=None, description="The applicant's monthly disposable income (in pence, not GBP).")
    agreed_budget: Optional[StrictStr] = Field(default=None, description="The applicant's agreed monthly budget (in pence, not GBP).")
    income_and_employment: Optional[List[CdmClientIncome]] = Field(default=None, description="Applicant's employment details and sources of income.")
    net_monthly_income: Optional[StrictStr] = Field(default=None, description="The applicant's net monthly income (in pence, not GBP).")
    outgoings_maintenance_payments: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on maintenance payments (in pence, not GBP).")
    outgoings_water: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on water (in pence, not GBP).")
    outgoings_communications: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on internet, phone, etc. (in pence, not GBP).")
    outgoings_mortgage_rent: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on mortgage/rent, including shared equity rent (in pence, not GBP).")
    outgoings_insurance: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on insurance (in pence, not GBP).")
    outgoings_investments: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on investments (in pence, not GBP).")
    outgoings_council_tax: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on council tax (in pence, not GBP).")
    outgoings_food: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on food (in pence, not GBP).")
    outgoings_clothing: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on clothing (in pence, not GBP).")
    outgoings_other_living_costs: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on other living costs (in pence, not GBP).")
    outgoings_entertainment: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on entertainment (in pence, not GBP).")
    outgoings_holidays: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on holidays (in pence, not GBP).")
    outgoings_sports: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on sports (in pence, not GBP).")
    outgoings_pension: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on pension (in pence, not GBP).")
    outgoings_car_costs: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on cars (in pence, not GBP).")
    outgoings_other_transport_costs: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on transport (commuting, leisure travel, petrol, cars, car insurance, etc.) (in pence, not GBP).")
    outgoings_child_care: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on child care including school fees (in pence, not GBP).")
    outgoings_fuel: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on fuel (gas, electricity, oil, etc.) (in pence, not GBP).")
    outgoings_ground_rent_service_charge_shared_equity_rent: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on leasehold service charge (ground rent, shared equity rent, etc.) (in pence, not GBP). Despite the name, shared equity rent should not be added to this field and should be added to `outgoings_mortgage_rent` instead.")
    outgoings_television_license: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on television license (in pence, not GBP).")
    outgoings_household_repairs: Optional[StrictStr] = Field(default=None, description="The applicant's monthly expense on household repairs (in pence, not GBP).")
    outgoings_additional_details: Optional[StrictStr] = Field(default=None, description="Additional details about the applicant's monthly expenses.")
    outgoings_material_change_details: Optional[StrictStr] = Field(default=None, description="Details of any expected material changes to the commitments and expenses.")
    id_verification_status: Optional[CdmIDVerificationStatus] = None
    prev_idv_start_time: Optional[StrictStr] = Field(default=None, description="Timestamp set when the previous eIDV was triggered. Used internally.")
    is_natural_person: Optional[StrictBool] = Field(default=None, description="Whether the client is a natural person. Defaults to true.")
    organisation_name: Optional[StrictStr] = None
    organisation_sic: Optional[CdmSIC2007] = CdmSIC2007.INVALID_SIC2007
    limited_company_registration_number: Optional[StrictStr] = Field(default=None, description="The registration number of the limited company.")
    contact_details_preferred_contact_method: Optional[ClientDetailsContactMethod] = ClientDetailsContactMethod.INVALID_CONTACT_METHOD
    credit_history_has_ever_surrendered_a_property_or_been_repossessed: Optional[StrictBool] = None
    credit_history_has_ever_surrendered_a_property_or_been_repossessed_details: Optional[StrictStr] = Field(default=None, description="Additional details on whether a property has ever been surrendered or repossessed.")
    credit_history_have_you_ever_had_an_application_denied_or_refused: Optional[StrictBool] = Field(default=None, description="DEPRECATED - Flag indicating whether the applicant has ever had an application denied or refused.")
    credit_history_adverse_details_has_client_missed_payments: Optional[StrictBool] = None
    credit_history_adverse_details_number_of_missed_payments: Optional[StrictInt] = Field(default=None, description="Number of missed rent/mortgage/credit payments.")
    credit_history_adverse_details_has_missed_payments_cleared: Optional[StrictBool] = Field(default=None, description="Has the client cleared any missed rent/mortgage/credit payments.")
    credit_history_adverse_details_missed_any_payments_on_commitments_details: Optional[StrictStr] = Field(default=None, description="Additional details on missed payments on commitments.")
    credit_history_adverse_details_has_client_had_ccj: Optional[StrictBool] = Field(default=None, description="DEPRECATED - credit_history_adverse_details_has_client_had_ccj indicates if the client ever received a County Court Judgement (CCJ).")
    credit_history_county_court_judgements: Optional[List[ClientDetailsCountyCourtJudgement]] = Field(default=None, description="Registered County Court Judgements (CCJs).")
    credit_history_adverse_details_has_client_had_default: Optional[StrictBool] = Field(default=None, description="DEPRECATED - credit_history_adverse_details_has_client_had_default indicates if the client ever defaulted on debts.")
    credit_history_default_events: Optional[List[CdmClientDetailsDefaultEvent]] = Field(default=None, description="DEPRECATED - use default event on a commitment instead.")
    credit_history_adverse_details_has_client_had_iva: Optional[StrictBool] = Field(default=None, description="DEPRECATED - credit_history_adverse_details_has_client_had_iva indicates if the client had an Individual Voluntary Arrangement.")
    credit_history_individual_voluntary_arrangements: Optional[List[ClientDetailsIndividualVoluntaryArrangement]] = Field(default=None, description="Registered IVAs.")
    credit_history_adverse_details_has_arrears: Optional[StrictBool] = Field(default=None, description="Flag indicating whether the client has ever been in payment arrears.")
    credit_history_arrears: Optional[List[ClientDetailsArrear]] = None
    credit_history_adverse_details_has_client_declared_bankruptcy: Optional[StrictBool] = Field(default=None, description="DEPRECATED - credit_history_adverse_details_has_client_declared_bankruptcy indicates if the client ever been declared bankruptcy.")
    credit_history_bankruptcy_events: Optional[List[ClientDetailsBankruptcyEvent]] = None
    credit_history_adverse_details_has_client_had_debt_management_plan: Optional[StrictBool] = Field(default=None, description="DEPRECATED - credit_history_adverse_details_has_client_had_debt_management_plan indicates if the client ever entered into a debt management plan.")
    credit_history_debt_management_plans: Optional[List[ClientDetailsDebtManagementPlan]] = None
    mortgage_application_refused: Optional[List[CdmMortgageApplicationRefused]] = Field(default=None, description="Instances where the application was denied.")
    import_metadata: Optional[Dict[str, StrictStr]] = Field(default=None, description="Object containing metadata created by import tool for migration from The Key.  client relationship with different organisations.  ClientOrganisationRelationship client_organisation_relationship = 123; // Deprecated due to nested fields.")
    total_guaranteed_annual: Optional[StrictStr] = Field(default=None, description="Total amount of guaranteed income. Includes current employment, self-employment and pension. **IMPORTANT:** This field cannot be updated and is populated automatically.")
    total_additional_annual: Optional[StrictStr] = Field(default=None, description="Total amount of non guaranteed income. **IMPORTANT:** This field cannot be updated and is populated automatically.")
    unearned_income: Optional[List[CdmUnearnedIncome]] = Field(default=None, description="Income from investments and other sources which is unrelated to employment.")
    modified_at: Optional[StrictStr] = None
    client_weight: Optional[StrictInt] = Field(default=None, description="The weight of the client in kilograms.")
    client_height: Optional[StrictInt] = Field(default=None, description="The height of the client in cm.")
    smoker_status: Optional[StrictBool] = Field(default=None, description="Has smoked or used any tobacco or nicotine replacement products in the last 12 months.")
    agreed_monthly_protection_budget: Optional[StrictStr] = None
    introducer_id: Optional[StrictStr] = Field(default=None, description="If this client was introduced the user id of the introducing user **IMPORTANT:** This field cannot be updated and is populated automatically.")
    client_ext_ids: Optional[List[CdmExternalID]] = Field(default=None, description="DEPRECATED - Identifiers for the client in third-party systems. To be replaced by external. Cannot be created or updated in conjunction with external.")
    external: Optional[List[CdmExternal]] = Field(default=None, description="Identifiers for the client in third-party systems. Cannot be created or updated in conjunction with client_ext_ids.")
    credit_report_retrievals: Optional[List[CdmCreditReportRetrievals]] = None
    non_natural: Optional[CdmNonNatural] = None
    calculated_values: Optional[CdmClientCalculatedValues] = None
    vulnerabilities: Optional[List[ClientDetailsVulnerability]] = Field(default=None, description="List of any potential vulnerabilities relating to the client that should be taken into account as part of the advice process.")
    additional_vulnerabilities_details: Optional[StrictStr] = Field(default=None, description="A string to specify additional details relating to clients potential vulnerabilities that should be taken into account as part of the advice process.")
    non_natural_organisation_type: Optional[ClientDetailsNonNaturalOrganisationType] = ClientDetailsNonNaturalOrganisationType.INVALID_NON_NATURAL_ORGANISATION_TYPE
    has_will: Optional[StrictBool] = None
    has_reviewed_will_in_last_five_years: Optional[StrictBool] = None
    delete_reason: Optional[CdmDeleteReason] = CdmDeleteReason.INVALID_DELETE_REASON
    contact_history: Optional[List[CdmContactHistory]] = Field(default=None, description="Contacts made regarding this case.")
    opt_out_credit_refresh: Optional[StrictBool] = None
    anticipated_retirement_income: Optional[List[CdmClientIncome]] = Field(default=None, description="Anticipated income in retirement.")
    anticipated_retirement_unearned_income: Optional[List[CdmUnearnedIncome]] = Field(default=None, description="Anticipated unearned income in retirement.")
    __properties: ClassVar[List[str]] = ["client_id", "client_originator", "client_user_originator", "has_seen_face_to_face", "title", "first_name", "middle_name", "last_name", "maiden_or_previous_name", "date_of_name_change", "previous_names", "date_of_birth", "country_of_birth", "client_type", "gender", "marital_status", "contact_details_home_phone", "contact_details_work_phone", "contact_details_mobile_phone", "contact_details_email", "addresses", "retirement_age", "residency_status", "years_lived_in_uk", "is_politically_exposed", "is_vulnerable", "nationalities", "employment_status", "amount_of_savings", "applicants_are_high_tax_rate_payers", "dependants", "national_insurance_number", "relationships", "deposits", "accounts", "debts", "disposable_income", "agreed_budget", "income_and_employment", "net_monthly_income", "outgoings_maintenance_payments", "outgoings_water", "outgoings_communications", "outgoings_mortgage_rent", "outgoings_insurance", "outgoings_investments", "outgoings_council_tax", "outgoings_food", "outgoings_clothing", "outgoings_other_living_costs", "outgoings_entertainment", "outgoings_holidays", "outgoings_sports", "outgoings_pension", "outgoings_car_costs", "outgoings_other_transport_costs", "outgoings_child_care", "outgoings_fuel", "outgoings_ground_rent_service_charge_shared_equity_rent", "outgoings_television_license", "outgoings_household_repairs", "outgoings_additional_details", "outgoings_material_change_details", "id_verification_status", "prev_idv_start_time", "is_natural_person", "organisation_name", "organisation_sic", "limited_company_registration_number", "contact_details_preferred_contact_method", "credit_history_has_ever_surrendered_a_property_or_been_repossessed", "credit_history_has_ever_surrendered_a_property_or_been_repossessed_details", "credit_history_have_you_ever_had_an_application_denied_or_refused", "credit_history_adverse_details_has_client_missed_payments", "credit_history_adverse_details_number_of_missed_payments", "credit_history_adverse_details_has_missed_payments_cleared", "credit_history_adverse_details_missed_any_payments_on_commitments_details", "credit_history_adverse_details_has_client_had_ccj", "credit_history_county_court_judgements", "credit_history_adverse_details_has_client_had_default", "credit_history_default_events", "credit_history_adverse_details_has_client_had_iva", "credit_history_individual_voluntary_arrangements", "credit_history_adverse_details_has_arrears", "credit_history_arrears", "credit_history_adverse_details_has_client_declared_bankruptcy", "credit_history_bankruptcy_events", "credit_history_adverse_details_has_client_had_debt_management_plan", "credit_history_debt_management_plans", "mortgage_application_refused", "import_metadata", "total_guaranteed_annual", "total_additional_annual", "unearned_income", "modified_at", "client_weight", "client_height", "smoker_status", "agreed_monthly_protection_budget", "introducer_id", "client_ext_ids", "external", "credit_report_retrievals", "non_natural", "calculated_values", "vulnerabilities", "additional_vulnerabilities_details", "non_natural_organisation_type", "has_will", "has_reviewed_will_in_last_five_years", "delete_reason", "contact_history", "opt_out_credit_refresh", "anticipated_retirement_income", "anticipated_retirement_unearned_income"]

    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 CdmClientDetails 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 previous_names (list)
        _items = []
        if self.previous_names:
            for _item_previous_names in self.previous_names:
                if _item_previous_names:
                    _items.append(_item_previous_names.to_dict())
            _dict['previous_names'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in addresses (list)
        _items = []
        if self.addresses:
            for _item_addresses in self.addresses:
                if _item_addresses:
                    _items.append(_item_addresses.to_dict())
            _dict['addresses'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in dependants (list)
        _items = []
        if self.dependants:
            for _item_dependants in self.dependants:
                if _item_dependants:
                    _items.append(_item_dependants.to_dict())
            _dict['dependants'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in relationships (list)
        _items = []
        if self.relationships:
            for _item_relationships in self.relationships:
                if _item_relationships:
                    _items.append(_item_relationships.to_dict())
            _dict['relationships'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in deposits (list)
        _items = []
        if self.deposits:
            for _item_deposits in self.deposits:
                if _item_deposits:
                    _items.append(_item_deposits.to_dict())
            _dict['deposits'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in accounts (list)
        _items = []
        if self.accounts:
            for _item_accounts in self.accounts:
                if _item_accounts:
                    _items.append(_item_accounts.to_dict())
            _dict['accounts'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in debts (list)
        _items = []
        if self.debts:
            for _item_debts in self.debts:
                if _item_debts:
                    _items.append(_item_debts.to_dict())
            _dict['debts'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in income_and_employment (list)
        _items = []
        if self.income_and_employment:
            for _item_income_and_employment in self.income_and_employment:
                if _item_income_and_employment:
                    _items.append(_item_income_and_employment.to_dict())
            _dict['income_and_employment'] = _items
        # override the default output from pydantic by calling `to_dict()` of id_verification_status
        if self.id_verification_status:
            _dict['id_verification_status'] = self.id_verification_status.to_dict()
        # override the default output from pydantic by calling `to_dict()` of each item in credit_history_county_court_judgements (list)
        _items = []
        if self.credit_history_county_court_judgements:
            for _item_credit_history_county_court_judgements in self.credit_history_county_court_judgements:
                if _item_credit_history_county_court_judgements:
                    _items.append(_item_credit_history_county_court_judgements.to_dict())
            _dict['credit_history_county_court_judgements'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in credit_history_default_events (list)
        _items = []
        if self.credit_history_default_events:
            for _item_credit_history_default_events in self.credit_history_default_events:
                if _item_credit_history_default_events:
                    _items.append(_item_credit_history_default_events.to_dict())
            _dict['credit_history_default_events'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in credit_history_individual_voluntary_arrangements (list)
        _items = []
        if self.credit_history_individual_voluntary_arrangements:
            for _item_credit_history_individual_voluntary_arrangements in self.credit_history_individual_voluntary_arrangements:
                if _item_credit_history_individual_voluntary_arrangements:
                    _items.append(_item_credit_history_individual_voluntary_arrangements.to_dict())
            _dict['credit_history_individual_voluntary_arrangements'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in credit_history_arrears (list)
        _items = []
        if self.credit_history_arrears:
            for _item_credit_history_arrears in self.credit_history_arrears:
                if _item_credit_history_arrears:
                    _items.append(_item_credit_history_arrears.to_dict())
            _dict['credit_history_arrears'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in credit_history_bankruptcy_events (list)
        _items = []
        if self.credit_history_bankruptcy_events:
            for _item_credit_history_bankruptcy_events in self.credit_history_bankruptcy_events:
                if _item_credit_history_bankruptcy_events:
                    _items.append(_item_credit_history_bankruptcy_events.to_dict())
            _dict['credit_history_bankruptcy_events'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in credit_history_debt_management_plans (list)
        _items = []
        if self.credit_history_debt_management_plans:
            for _item_credit_history_debt_management_plans in self.credit_history_debt_management_plans:
                if _item_credit_history_debt_management_plans:
                    _items.append(_item_credit_history_debt_management_plans.to_dict())
            _dict['credit_history_debt_management_plans'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in mortgage_application_refused (list)
        _items = []
        if self.mortgage_application_refused:
            for _item_mortgage_application_refused in self.mortgage_application_refused:
                if _item_mortgage_application_refused:
                    _items.append(_item_mortgage_application_refused.to_dict())
            _dict['mortgage_application_refused'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in unearned_income (list)
        _items = []
        if self.unearned_income:
            for _item_unearned_income in self.unearned_income:
                if _item_unearned_income:
                    _items.append(_item_unearned_income.to_dict())
            _dict['unearned_income'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in client_ext_ids (list)
        _items = []
        if self.client_ext_ids:
            for _item_client_ext_ids in self.client_ext_ids:
                if _item_client_ext_ids:
                    _items.append(_item_client_ext_ids.to_dict())
            _dict['client_ext_ids'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in external (list)
        _items = []
        if self.external:
            for _item_external in self.external:
                if _item_external:
                    _items.append(_item_external.to_dict())
            _dict['external'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in credit_report_retrievals (list)
        _items = []
        if self.credit_report_retrievals:
            for _item_credit_report_retrievals in self.credit_report_retrievals:
                if _item_credit_report_retrievals:
                    _items.append(_item_credit_report_retrievals.to_dict())
            _dict['credit_report_retrievals'] = _items
        # override the default output from pydantic by calling `to_dict()` of non_natural
        if self.non_natural:
            _dict['non_natural'] = self.non_natural.to_dict()
        # override the default output from pydantic by calling `to_dict()` of calculated_values
        if self.calculated_values:
            _dict['calculated_values'] = self.calculated_values.to_dict()
        # override the default output from pydantic by calling `to_dict()` of each item in contact_history (list)
        _items = []
        if self.contact_history:
            for _item_contact_history in self.contact_history:
                if _item_contact_history:
                    _items.append(_item_contact_history.to_dict())
            _dict['contact_history'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in anticipated_retirement_income (list)
        _items = []
        if self.anticipated_retirement_income:
            for _item_anticipated_retirement_income in self.anticipated_retirement_income:
                if _item_anticipated_retirement_income:
                    _items.append(_item_anticipated_retirement_income.to_dict())
            _dict['anticipated_retirement_income'] = _items
        # override the default output from pydantic by calling `to_dict()` of each item in anticipated_retirement_unearned_income (list)
        _items = []
        if self.anticipated_retirement_unearned_income:
            for _item_anticipated_retirement_unearned_income in self.anticipated_retirement_unearned_income:
                if _item_anticipated_retirement_unearned_income:
                    _items.append(_item_anticipated_retirement_unearned_income.to_dict())
            _dict['anticipated_retirement_unearned_income'] = _items
        return _dict

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

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

        _obj = cls.model_validate({
            "client_id": obj.get("client_id"),
            "client_originator": obj.get("client_originator"),
            "client_user_originator": obj.get("client_user_originator"),
            "has_seen_face_to_face": obj.get("has_seen_face_to_face"),
            "title": obj.get("title") if obj.get("title") is not None else CdmTitle.INVALID_TITLE,
            "first_name": obj.get("first_name"),
            "middle_name": obj.get("middle_name"),
            "last_name": obj.get("last_name"),
            "maiden_or_previous_name": obj.get("maiden_or_previous_name"),
            "date_of_name_change": obj.get("date_of_name_change"),
            "previous_names": [CdmPreviousName.from_dict(_item) for _item in obj["previous_names"]] if obj.get("previous_names") is not None else None,
            "date_of_birth": obj.get("date_of_birth"),
            "country_of_birth": obj.get("country_of_birth"),
            "client_type": obj.get("client_type"),
            "gender": obj.get("gender") if obj.get("gender") is not None else CdmGender.INVALID_GENDER,
            "marital_status": obj.get("marital_status") if obj.get("marital_status") is not None else ClientDetailsMaritalStatus.INVALID_MARITAL_STATUS,
            "contact_details_home_phone": obj.get("contact_details_home_phone"),
            "contact_details_work_phone": obj.get("contact_details_work_phone"),
            "contact_details_mobile_phone": obj.get("contact_details_mobile_phone"),
            "contact_details_email": obj.get("contact_details_email"),
            "addresses": [CdmClientAddress.from_dict(_item) for _item in obj["addresses"]] if obj.get("addresses") is not None else None,
            "retirement_age": obj.get("retirement_age"),
            "residency_status": obj.get("residency_status") if obj.get("residency_status") is not None else ClientDetailsResidencyStatus.INVALID_RESIDENCY_STATUS,
            "years_lived_in_uk": obj.get("years_lived_in_uk"),
            "is_politically_exposed": obj.get("is_politically_exposed"),
            "is_vulnerable": obj.get("is_vulnerable"),
            "nationalities": obj.get("nationalities"),
            "employment_status": obj.get("employment_status") if obj.get("employment_status") is not None else CdmClientDetailsEmploymentStatus.INVALID_EMPLOYMENT_STATUS,
            "amount_of_savings": obj.get("amount_of_savings"),
            "applicants_are_high_tax_rate_payers": obj.get("applicants_are_high_tax_rate_payers"),
            "dependants": [CdmClientDependant.from_dict(_item) for _item in obj["dependants"]] if obj.get("dependants") is not None else None,
            "national_insurance_number": obj.get("national_insurance_number"),
            "relationships": [CdmClientRelationship.from_dict(_item) for _item in obj["relationships"]] if obj.get("relationships") is not None else None,
            "deposits": [CdmClientDeposit.from_dict(_item) for _item in obj["deposits"]] if obj.get("deposits") is not None else None,
            "accounts": [CdmClientAccount.from_dict(_item) for _item in obj["accounts"]] if obj.get("accounts") is not None else None,
            "debts": [CdmClientOutstandingDebt.from_dict(_item) for _item in obj["debts"]] if obj.get("debts") is not None else None,
            "disposable_income": obj.get("disposable_income"),
            "agreed_budget": obj.get("agreed_budget"),
            "income_and_employment": [CdmClientIncome.from_dict(_item) for _item in obj["income_and_employment"]] if obj.get("income_and_employment") is not None else None,
            "net_monthly_income": obj.get("net_monthly_income"),
            "outgoings_maintenance_payments": obj.get("outgoings_maintenance_payments"),
            "outgoings_water": obj.get("outgoings_water"),
            "outgoings_communications": obj.get("outgoings_communications"),
            "outgoings_mortgage_rent": obj.get("outgoings_mortgage_rent"),
            "outgoings_insurance": obj.get("outgoings_insurance"),
            "outgoings_investments": obj.get("outgoings_investments"),
            "outgoings_council_tax": obj.get("outgoings_council_tax"),
            "outgoings_food": obj.get("outgoings_food"),
            "outgoings_clothing": obj.get("outgoings_clothing"),
            "outgoings_other_living_costs": obj.get("outgoings_other_living_costs"),
            "outgoings_entertainment": obj.get("outgoings_entertainment"),
            "outgoings_holidays": obj.get("outgoings_holidays"),
            "outgoings_sports": obj.get("outgoings_sports"),
            "outgoings_pension": obj.get("outgoings_pension"),
            "outgoings_car_costs": obj.get("outgoings_car_costs"),
            "outgoings_other_transport_costs": obj.get("outgoings_other_transport_costs"),
            "outgoings_child_care": obj.get("outgoings_child_care"),
            "outgoings_fuel": obj.get("outgoings_fuel"),
            "outgoings_ground_rent_service_charge_shared_equity_rent": obj.get("outgoings_ground_rent_service_charge_shared_equity_rent"),
            "outgoings_television_license": obj.get("outgoings_television_license"),
            "outgoings_household_repairs": obj.get("outgoings_household_repairs"),
            "outgoings_additional_details": obj.get("outgoings_additional_details"),
            "outgoings_material_change_details": obj.get("outgoings_material_change_details"),
            "id_verification_status": CdmIDVerificationStatus.from_dict(obj["id_verification_status"]) if obj.get("id_verification_status") is not None else None,
            "prev_idv_start_time": obj.get("prev_idv_start_time"),
            "is_natural_person": obj.get("is_natural_person"),
            "organisation_name": obj.get("organisation_name"),
            "organisation_sic": obj.get("organisation_sic") if obj.get("organisation_sic") is not None else CdmSIC2007.INVALID_SIC2007,
            "limited_company_registration_number": obj.get("limited_company_registration_number"),
            "contact_details_preferred_contact_method": obj.get("contact_details_preferred_contact_method") if obj.get("contact_details_preferred_contact_method") is not None else ClientDetailsContactMethod.INVALID_CONTACT_METHOD,
            "credit_history_has_ever_surrendered_a_property_or_been_repossessed": obj.get("credit_history_has_ever_surrendered_a_property_or_been_repossessed"),
            "credit_history_has_ever_surrendered_a_property_or_been_repossessed_details": obj.get("credit_history_has_ever_surrendered_a_property_or_been_repossessed_details"),
            "credit_history_have_you_ever_had_an_application_denied_or_refused": obj.get("credit_history_have_you_ever_had_an_application_denied_or_refused"),
            "credit_history_adverse_details_has_client_missed_payments": obj.get("credit_history_adverse_details_has_client_missed_payments"),
            "credit_history_adverse_details_number_of_missed_payments": obj.get("credit_history_adverse_details_number_of_missed_payments"),
            "credit_history_adverse_details_has_missed_payments_cleared": obj.get("credit_history_adverse_details_has_missed_payments_cleared"),
            "credit_history_adverse_details_missed_any_payments_on_commitments_details": obj.get("credit_history_adverse_details_missed_any_payments_on_commitments_details"),
            "credit_history_adverse_details_has_client_had_ccj": obj.get("credit_history_adverse_details_has_client_had_ccj"),
            "credit_history_county_court_judgements": [ClientDetailsCountyCourtJudgement.from_dict(_item) for _item in obj["credit_history_county_court_judgements"]] if obj.get("credit_history_county_court_judgements") is not None else None,
            "credit_history_adverse_details_has_client_had_default": obj.get("credit_history_adverse_details_has_client_had_default"),
            "credit_history_default_events": [CdmClientDetailsDefaultEvent.from_dict(_item) for _item in obj["credit_history_default_events"]] if obj.get("credit_history_default_events") is not None else None,
            "credit_history_adverse_details_has_client_had_iva": obj.get("credit_history_adverse_details_has_client_had_iva"),
            "credit_history_individual_voluntary_arrangements": [ClientDetailsIndividualVoluntaryArrangement.from_dict(_item) for _item in obj["credit_history_individual_voluntary_arrangements"]] if obj.get("credit_history_individual_voluntary_arrangements") is not None else None,
            "credit_history_adverse_details_has_arrears": obj.get("credit_history_adverse_details_has_arrears"),
            "credit_history_arrears": [ClientDetailsArrear.from_dict(_item) for _item in obj["credit_history_arrears"]] if obj.get("credit_history_arrears") is not None else None,
            "credit_history_adverse_details_has_client_declared_bankruptcy": obj.get("credit_history_adverse_details_has_client_declared_bankruptcy"),
            "credit_history_bankruptcy_events": [ClientDetailsBankruptcyEvent.from_dict(_item) for _item in obj["credit_history_bankruptcy_events"]] if obj.get("credit_history_bankruptcy_events") is not None else None,
            "credit_history_adverse_details_has_client_had_debt_management_plan": obj.get("credit_history_adverse_details_has_client_had_debt_management_plan"),
            "credit_history_debt_management_plans": [ClientDetailsDebtManagementPlan.from_dict(_item) for _item in obj["credit_history_debt_management_plans"]] if obj.get("credit_history_debt_management_plans") is not None else None,
            "mortgage_application_refused": [CdmMortgageApplicationRefused.from_dict(_item) for _item in obj["mortgage_application_refused"]] if obj.get("mortgage_application_refused") is not None else None,
            "import_metadata": obj.get("import_metadata"),
            "total_guaranteed_annual": obj.get("total_guaranteed_annual"),
            "total_additional_annual": obj.get("total_additional_annual"),
            "unearned_income": [CdmUnearnedIncome.from_dict(_item) for _item in obj["unearned_income"]] if obj.get("unearned_income") is not None else None,
            "modified_at": obj.get("modified_at"),
            "client_weight": obj.get("client_weight"),
            "client_height": obj.get("client_height"),
            "smoker_status": obj.get("smoker_status"),
            "agreed_monthly_protection_budget": obj.get("agreed_monthly_protection_budget"),
            "introducer_id": obj.get("introducer_id"),
            "client_ext_ids": [CdmExternalID.from_dict(_item) for _item in obj["client_ext_ids"]] if obj.get("client_ext_ids") is not None else None,
            "external": [CdmExternal.from_dict(_item) for _item in obj["external"]] if obj.get("external") is not None else None,
            "credit_report_retrievals": [CdmCreditReportRetrievals.from_dict(_item) for _item in obj["credit_report_retrievals"]] if obj.get("credit_report_retrievals") is not None else None,
            "non_natural": CdmNonNatural.from_dict(obj["non_natural"]) if obj.get("non_natural") is not None else None,
            "calculated_values": CdmClientCalculatedValues.from_dict(obj["calculated_values"]) if obj.get("calculated_values") is not None else None,
            "vulnerabilities": obj.get("vulnerabilities"),
            "additional_vulnerabilities_details": obj.get("additional_vulnerabilities_details"),
            "non_natural_organisation_type": obj.get("non_natural_organisation_type") if obj.get("non_natural_organisation_type") is not None else ClientDetailsNonNaturalOrganisationType.INVALID_NON_NATURAL_ORGANISATION_TYPE,
            "has_will": obj.get("has_will"),
            "has_reviewed_will_in_last_five_years": obj.get("has_reviewed_will_in_last_five_years"),
            "delete_reason": obj.get("delete_reason") if obj.get("delete_reason") is not None else CdmDeleteReason.INVALID_DELETE_REASON,
            "contact_history": [CdmContactHistory.from_dict(_item) for _item in obj["contact_history"]] if obj.get("contact_history") is not None else None,
            "opt_out_credit_refresh": obj.get("opt_out_credit_refresh"),
            "anticipated_retirement_income": [CdmClientIncome.from_dict(_item) for _item in obj["anticipated_retirement_income"]] if obj.get("anticipated_retirement_income") is not None else None,
            "anticipated_retirement_unearned_income": [CdmUnearnedIncome.from_dict(_item) for _item in obj["anticipated_retirement_unearned_income"]] if obj.get("anticipated_retirement_unearned_income") is not None else None
        })
        return _obj


