// File: crates/router/src/types/api/feature_matrix.rs

use std::str::FromStr;

use error_stack::{report, ResultExt};

use crate::{
    connector,
    core::errors::{self, CustomResult},
    services::connector_integration_interface::ConnectorEnum,
    types::api::enums,
};

#[derive(Clone)]
pub struct FeatureMatrixConnectorData {}

impl FeatureMatrixConnectorData {
    pub fn convert_connector(
        connector_name: &str,
    ) -> CustomResult<ConnectorEnum, errors::ApiErrorResponse> {
        match enums::Connector::from_str(connector_name) {
            Ok(name) => match name {
                enums::Connector::Aci => Ok(ConnectorEnum::Old(Box::new(connector::Aci::new()))),
                enums::Connector::Adyen => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Adyen::new())))
                }
                enums::Connector::Affirm => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Affirm::new())))
                }
                enums::Connector::Adyenplatform => Ok(ConnectorEnum::Old(Box::new(
                    connector::Adyenplatform::new(),
                ))),
                enums::Connector::Airwallex => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Airwallex::new())))
                }
                enums::Connector::Amazonpay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Amazonpay::new())))
                }
                enums::Connector::Archipel => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Archipel::new())))
                }
                enums::Connector::Authipay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Authipay::new())))
                }
                enums::Connector::Authorizedotnet => Ok(ConnectorEnum::Old(Box::new(
                    connector::Authorizedotnet::new(),
                ))),
                enums::Connector::Bambora => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Bambora::new())))
                }
                enums::Connector::Bamboraapac => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Bamboraapac::new())))
                }
                enums::Connector::Bankofamerica => Ok(ConnectorEnum::Old(Box::new(
                    connector::Bankofamerica::new(),
                ))),
                enums::Connector::Barclaycard => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Barclaycard::new())))
                }
                enums::Connector::Billwerk => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Billwerk::new())))
                }
                enums::Connector::Bitpay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Bitpay::new())))
                }
                enums::Connector::Blackhawknetwork => Ok(ConnectorEnum::Old(Box::new(
                    connector::Blackhawknetwork::new(),
                ))),
                enums::Connector::Bluesnap => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Bluesnap::new())))
                }
                enums::Connector::Calida => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Calida::new())))
                }
                enums::Connector::Boku => Ok(ConnectorEnum::Old(Box::new(connector::Boku::new()))),
                enums::Connector::Braintree => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Braintree::new())))
                }
                enums::Connector::Breadpay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Breadpay::new())))
                }
                enums::Connector::Cashtocode => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Cashtocode::new())))
                }
                enums::Connector::Celero => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Celero::new())))
                }
                enums::Connector::Chargebee => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Chargebee::new())))
                }
                enums::Connector::Checkbook => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Checkbook::new())))
                }
                enums::Connector::Checkout => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Checkout::new())))
                }
                enums::Connector::Coinbase => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Coinbase::new())))
                }
                enums::Connector::Coingate => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Coingate::new())))
                }
                enums::Connector::Cryptopay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Cryptopay::new())))
                }
                enums::Connector::CtpMastercard => {
                    Ok(ConnectorEnum::Old(Box::new(&connector::CtpMastercard)))
                }
                enums::Connector::Custombilling => Ok(ConnectorEnum::Old(Box::new(
                    connector::Custombilling::new(),
                ))),
                enums::Connector::CtpVisa => Ok(ConnectorEnum::Old(Box::new(
                    connector::UnifiedAuthenticationService::new(),
                ))),
                enums::Connector::Cybersource => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Cybersource::new())))
                }
                enums::Connector::Datatrans => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Datatrans::new())))
                }
                enums::Connector::Deutschebank => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Deutschebank::new())))
                }
                enums::Connector::Digitalvirgo => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Digitalvirgo::new())))
                }
                enums::Connector::Dlocal => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Dlocal::new())))
                }
                #[cfg(feature = "dummy_connector")]
                enums::Connector::DummyConnector1 => Ok(ConnectorEnum::Old(Box::new(
                    connector::DummyConnector::<1>::new(),
                ))),
                #[cfg(feature = "dummy_connector")]
                enums::Connector::DummyConnector2 => Ok(ConnectorEnum::Old(Box::new(
                    connector::DummyConnector::<2>::new(),
                ))),
                #[cfg(feature = "dummy_connector")]
                enums::Connector::DummyConnector3 => Ok(ConnectorEnum::Old(Box::new(
                    connector::DummyConnector::<3>::new(),
                ))),
                #[cfg(feature = "dummy_connector")]
                enums::Connector::DummyConnector4 => Ok(ConnectorEnum::Old(Box::new(
                    connector::DummyConnector::<4>::new(),
                ))),
                #[cfg(feature = "dummy_connector")]
                enums::Connector::DummyConnector5 => Ok(ConnectorEnum::Old(Box::new(
                    connector::DummyConnector::<5>::new(),
                ))),
                #[cfg(feature = "dummy_connector")]
                enums::Connector::DummyConnector6 => Ok(ConnectorEnum::Old(Box::new(
                    connector::DummyConnector::<6>::new(),
                ))),
                #[cfg(feature = "dummy_connector")]
                enums::Connector::DummyConnector7 => Ok(ConnectorEnum::Old(Box::new(
                    connector::DummyConnector::<7>::new(),
                ))),
                #[cfg(feature = "dummy_connector")]
                enums::Connector::DummyBillingConnector => Ok(ConnectorEnum::Old(Box::new(
                    connector::DummyConnector::<8>::new(),
                ))),
                enums::Connector::Dwolla => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Dwolla::new())))
                }
                enums::Connector::Ebanx => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Ebanx::new())))
                }
                enums::Connector::Elavon => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Elavon::new())))
                }
                enums::Connector::Facilitapay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Facilitapay::new())))
                }
                enums::Connector::Finix => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Finix::new())))
                }
                enums::Connector::Fiserv => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Fiserv::new())))
                }
                enums::Connector::Fiservemea => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Fiservemea::new())))
                }
                enums::Connector::Fiuu => Ok(ConnectorEnum::Old(Box::new(connector::Fiuu::new()))),
                enums::Connector::Forte => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Forte::new())))
                }
                enums::Connector::Flexiti => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Flexiti::new())))
                }
                enums::Connector::Getnet => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Getnet::new())))
                }
                enums::Connector::Gigadat => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Gigadat::new())))
                }
                enums::Connector::Globalpay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Globalpay::new())))
                }
                enums::Connector::Globepay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Globepay::new())))
                }
                enums::Connector::Gocardless => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Gocardless::new())))
                }
                enums::Connector::Hipay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Hipay::new())))
                }
                enums::Connector::Helcim => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Helcim::new())))
                }
                enums::Connector::HyperswitchVault => {
                    Ok(ConnectorEnum::Old(Box::new(&connector::HyperswitchVault)))
                }
                enums::Connector::Iatapay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Iatapay::new())))
                }
                enums::Connector::Inespay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Inespay::new())))
                }
                enums::Connector::Itaubank => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Itaubank::new())))
                }
                enums::Connector::Jpmorgan => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Jpmorgan::new())))
                }
                enums::Connector::Juspaythreedsserver => Ok(ConnectorEnum::Old(Box::new(
                    connector::Juspaythreedsserver::new(),
                ))),
                enums::Connector::Klarna => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Klarna::new())))
                }
                enums::Connector::Loonio => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Loonio::new())))
                }
                enums::Connector::Mollie => {
                    // enums::Connector::Moneris => Ok(ConnectorEnum::Old(Box::new(connector::Moneris))),
                    Ok(ConnectorEnum::Old(Box::new(connector::Mollie::new())))
                }
                enums::Connector::Moneris => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Moneris::new())))
                }
                enums::Connector::Nexixpay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Nexixpay::new())))
                }
                enums::Connector::Nmi => Ok(ConnectorEnum::Old(Box::new(connector::Nmi::new()))),
                enums::Connector::Nomupay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Nomupay::new())))
                }
                enums::Connector::Noon => Ok(ConnectorEnum::Old(Box::new(connector::Noon::new()))),
                enums::Connector::Nordea => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Nordea::new())))
                }
                enums::Connector::Novalnet => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Novalnet::new())))
                }
                enums::Connector::Nuvei => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Nuvei::new())))
                }
                enums::Connector::Opennode => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Opennode::new())))
                }
                enums::Connector::Phonepe => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Phonepe::new())))
                }
                enums::Connector::Paybox => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Paybox::new())))
                }
                enums::Connector::Paytm => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Paytm::new())))
                }
                // "payeezy" => Ok(ConnectorIntegrationEnum::Old(Box::new(&connector::Payeezy)), As psync and rsync are not supported by this connector, it is added as template code for future usage
                // enums::Connector::Payload => {
                //     Ok(ConnectorEnum::Old(Box::new(connector::Paybload::new())))
                // }
                enums::Connector::Payload => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Payload::new())))
                }
                enums::Connector::Payjustnow => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Payjustnow::new())))
                }
                enums::Connector::Payme => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Payme::new())))
                }
                enums::Connector::Payone => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Payone::new())))
                }
                enums::Connector::Payu => Ok(ConnectorEnum::Old(Box::new(connector::Payu::new()))),
                enums::Connector::Peachpayments => Ok(ConnectorEnum::Old(Box::new(
                    connector::Peachpayments::new(),
                ))),
                enums::Connector::Placetopay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Placetopay::new())))
                }
                enums::Connector::Powertranz => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Powertranz::new())))
                }
                enums::Connector::Prophetpay => {
                    Ok(ConnectorEnum::Old(Box::new(&connector::Prophetpay)))
                }
                enums::Connector::Razorpay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Razorpay::new())))
                }
                enums::Connector::Rapyd => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Rapyd::new())))
                }
                enums::Connector::Recurly => {
                    Ok(ConnectorEnum::New(Box::new(connector::Recurly::new())))
                }
                enums::Connector::Redsys => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Redsys::new())))
                }
                enums::Connector::Santander => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Santander::new())))
                }
                enums::Connector::Shift4 => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Shift4::new())))
                }
                enums::Connector::Square => Ok(ConnectorEnum::Old(Box::new(&connector::Square))),
                enums::Connector::Stax => Ok(ConnectorEnum::Old(Box::new(&connector::Stax))),
                enums::Connector::Stripe => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Stripe::new())))
                }
                enums::Connector::Stripebilling => Ok(ConnectorEnum::Old(Box::new(
                    connector::Stripebilling::new(),
                ))),
                enums::Connector::Wise => Ok(ConnectorEnum::Old(Box::new(connector::Wise::new()))),
                enums::Connector::Worldline => {
                    Ok(ConnectorEnum::Old(Box::new(&connector::Worldline)))
                }
                enums::Connector::Worldpay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Worldpay::new())))
                }
                enums::Connector::Worldpayvantiv => Ok(ConnectorEnum::Old(Box::new(
                    connector::Worldpayvantiv::new(),
                ))),
                enums::Connector::Worldpayxml => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Worldpayxml::new())))
                }
                enums::Connector::Xendit => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Xendit::new())))
                }
                enums::Connector::Mifinity => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Mifinity::new())))
                }
                enums::Connector::Multisafepay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Multisafepay::new())))
                }
                enums::Connector::Netcetera => {
                    Ok(ConnectorEnum::Old(Box::new(&connector::Netcetera)))
                }
                enums::Connector::Nexinets => {
                    Ok(ConnectorEnum::Old(Box::new(&connector::Nexinets)))
                }
                // enums::Connector::Nexixpay => {
                //     Ok(ConnectorEnum::Old(Box::new(&connector::Nexixpay)))
                // }
                enums::Connector::Paypal => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Paypal::new())))
                }
                enums::Connector::Paysafe => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Paysafe::new())))
                }
                enums::Connector::Paystack => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Paystack::new())))
                }
                // enums::Connector::Thunes => Ok(ConnectorEnum::Old(Box::new(connector::Thunes))),
                enums::Connector::Tesouro => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Tesouro::new())))
                }
                enums::Connector::Tokenex => Ok(ConnectorEnum::Old(Box::new(&connector::Tokenex))),
                enums::Connector::Tokenio => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Tokenio::new())))
                }
                enums::Connector::Trustpay => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Trustpay::new())))
                }
                enums::Connector::Trustpayments => Ok(ConnectorEnum::Old(Box::new(
                    connector::Trustpayments::new(),
                ))),
                enums::Connector::Tsys => Ok(ConnectorEnum::Old(Box::new(connector::Tsys::new()))),
                // enums::Connector::UnifiedAuthenticationService => Ok(ConnectorEnum::Old(Box::new(
                //     connector::UnifiedAuthenticationService,
                // ))),
                enums::Connector::Vgs => Ok(ConnectorEnum::Old(Box::new(&connector::Vgs))),
                enums::Connector::Volt => Ok(ConnectorEnum::Old(Box::new(connector::Volt::new()))),
                enums::Connector::Wellsfargo => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Wellsfargo::new())))
                }

                // enums::Connector::Wellsfargopayout => {
                //     Ok(Box::new(connector::Wellsfargopayout::new()))
                // }
                enums::Connector::Zen => Ok(ConnectorEnum::Old(Box::new(&connector::Zen))),
                enums::Connector::Zsl => Ok(ConnectorEnum::Old(Box::new(&connector::Zsl))),
                enums::Connector::Plaid => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Plaid::new())))
                }
                enums::Connector::Signifyd => {
                    Ok(ConnectorEnum::Old(Box::new(&connector::Signifyd)))
                }
                enums::Connector::Silverflow => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Silverflow::new())))
                }
                enums::Connector::Zift => Ok(ConnectorEnum::Old(Box::new(connector::Zift::new()))),
                enums::Connector::Riskified => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Riskified::new())))
                }
                enums::Connector::Gpayments => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Gpayments::new())))
                }
                enums::Connector::Threedsecureio => {
                    Ok(ConnectorEnum::Old(Box::new(&connector::Threedsecureio)))
                }
                enums::Connector::Taxjar => {
                    Ok(ConnectorEnum::Old(Box::new(connector::Taxjar::new())))
                }
                enums::Connector::Cardinal => {
                    Err(report!(errors::ConnectorError::InvalidConnectorName)
                        .attach_printable(format!("invalid connector name: {connector_name}")))
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                }
            },
            Err(_) => Err(report!(errors::ConnectorError::InvalidConnectorName)
                .attach_printable(format!("invalid connector name: {connector_name}")))
            .change_context(errors::ApiErrorResponse::InternalServerError),
        }
    }
}


// File: crates/router/src/types/api/files_v2.rs

pub use hyperswitch_domain_models::router_flow_types::files::{Retrieve, Upload};
pub use hyperswitch_interfaces::api::files_v2::{FileUploadV2, RetrieveFileV2, UploadFileV2};


// File: crates/router/src/types/api/webhook_events.rs

pub use api_models::webhook_events::{
    EventListConstraints, EventListConstraintsInternal, EventListItemResponse,
    EventListRequestInternal, EventRetrieveResponse, OutgoingWebhookRequestContent,
    OutgoingWebhookResponseContent, TotalEventsResponse, WebhookDeliveryAttemptListRequestInternal,
    WebhookDeliveryRetryRequestInternal,
};


// File: crates/router/src/types/api/admin.rs

use std::collections::HashMap;

#[cfg(feature = "v2")]
pub use api_models::admin;
pub use api_models::{
    admin::{
        MaskedHeaders, MerchantAccountCreate, MerchantAccountDeleteResponse,
        MerchantAccountResponse, MerchantAccountUpdate, MerchantConnectorCreate,
        MerchantConnectorDeleteResponse, MerchantConnectorDetails, MerchantConnectorDetailsWrap,
        MerchantConnectorId, MerchantConnectorResponse, MerchantDetails, MerchantId,
        PaymentMethodsEnabled, ProfileCreate, ProfileResponse, ProfileUpdate, ToggleAllKVRequest,
        ToggleAllKVResponse, ToggleKVRequest, ToggleKVResponse, WebhookDetails,
    },
    organization::{
        OrganizationCreateRequest, OrganizationId, OrganizationResponse, OrganizationUpdateRequest,
    },
};
use common_utils::{ext_traits::ValueExt, types::keymanager as km_types};
use diesel_models::{business_profile::CardTestingGuardConfig, organization::OrganizationBridge};
use error_stack::ResultExt;
use hyperswitch_domain_models::merchant_key_store::MerchantKeyStore;
use masking::{ExposeInterface, PeekInterface, Secret};

use crate::{
    consts,
    core::errors,
    routes::SessionState,
    types::{
        domain::{
            self,
            types::{self as domain_types, AsyncLift},
        },
        transformers::{ForeignInto, ForeignTryFrom},
        ForeignFrom,
    },
    utils,
};

#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct ProfileAcquirerConfigs {
    pub acquirer_config_map: Option<common_types::domain::AcquirerConfigMap>,
    pub profile_id: common_utils::id_type::ProfileId,
}

impl From<ProfileAcquirerConfigs>
    for Option<Vec<api_models::profile_acquirer::ProfileAcquirerResponse>>
{
    fn from(item: ProfileAcquirerConfigs) -> Self {
        item.acquirer_config_map.map(|config_map_val| {
            let mut vec: Vec<_> = config_map_val.0.into_iter().collect();
            vec.sort_by_key(|k| k.0.clone());
            vec.into_iter()
                .map(|(profile_acquirer_id, acquirer_config)| {
                    api_models::profile_acquirer::ProfileAcquirerResponse::from((
                        profile_acquirer_id,
                        &item.profile_id,
                        &acquirer_config,
                    ))
                })
                .collect::<Vec<api_models::profile_acquirer::ProfileAcquirerResponse>>()
        })
    }
}

impl ForeignFrom<diesel_models::organization::Organization> for OrganizationResponse {
    fn foreign_from(org: diesel_models::organization::Organization) -> Self {
        Self {
            #[cfg(feature = "v2")]
            id: org.get_organization_id(),

            #[cfg(feature = "v1")]
            organization_id: org.get_organization_id(),
            organization_name: org.get_organization_name(),
            organization_details: org.organization_details,
            metadata: org.metadata,
            modified_at: org.modified_at,
            created_at: org.created_at,
            organization_type: org.organization_type,
        }
    }
}

#[cfg(feature = "v1")]
impl ForeignTryFrom<domain::MerchantAccount> for MerchantAccountResponse {
    type Error = error_stack::Report<errors::ParsingError>;
    fn foreign_try_from(item: domain::MerchantAccount) -> Result<Self, Self::Error> {
        let merchant_id = item.get_id().to_owned();
        let primary_business_details: Vec<api_models::admin::PrimaryBusinessDetails> = item
            .primary_business_details
            .parse_value("primary_business_details")?;

        let pm_collect_link_config: Option<api_models::admin::BusinessCollectLinkConfig> = item
            .pm_collect_link_config
            .map(|config| config.parse_value("pm_collect_link_config"))
            .transpose()?;

        Ok(Self {
            merchant_id,
            merchant_name: item.merchant_name,
            return_url: item.return_url,
            enable_payment_response_hash: item.enable_payment_response_hash,
            payment_response_hash_key: item.payment_response_hash_key,
            redirect_to_merchant_with_http_post: item.redirect_to_merchant_with_http_post,
            merchant_details: item.merchant_details,
            webhook_details: item.webhook_details.clone().map(ForeignInto::foreign_into),
            routing_algorithm: item.routing_algorithm,
            sub_merchants_enabled: item.sub_merchants_enabled,
            parent_merchant_id: item.parent_merchant_id,
            publishable_key: Some(item.publishable_key),
            metadata: item.metadata,
            locker_id: item.locker_id,
            primary_business_details,
            frm_routing_algorithm: item.frm_routing_algorithm,
            #[cfg(feature = "payouts")]
            payout_routing_algorithm: item.payout_routing_algorithm,
            organization_id: item.organization_id,
            is_recon_enabled: item.is_recon_enabled,
            default_profile: item.default_profile,
            recon_status: item.recon_status,
            pm_collect_link_config,
            product_type: item.product_type,
            merchant_account_type: item.merchant_account_type,
        })
    }
}

#[cfg(feature = "v2")]
impl ForeignTryFrom<domain::MerchantAccount> for MerchantAccountResponse {
    type Error = error_stack::Report<errors::ValidationError>;
    fn foreign_try_from(item: domain::MerchantAccount) -> Result<Self, Self::Error> {
        use common_utils::ext_traits::OptionExt;

        let id = item.get_id().to_owned();

        let merchant_name = item
            .merchant_name
            .get_required_value("merchant_name")?
            .into_inner();

        Ok(Self {
            id,
            merchant_name,
            merchant_details: item.merchant_details,
            publishable_key: item.publishable_key,
            metadata: item.metadata,
            organization_id: item.organization_id,
            recon_status: item.recon_status,
            product_type: item.product_type,
        })
    }
}
#[cfg(feature = "v1")]
impl ForeignTryFrom<domain::Profile> for ProfileResponse {
    type Error = error_stack::Report<errors::ParsingError>;

    fn foreign_try_from(item: domain::Profile) -> Result<Self, Self::Error> {
        let profile_id = item.get_id().to_owned();
        let outgoing_webhook_custom_http_headers = item
            .outgoing_webhook_custom_http_headers
            .map(|headers| {
                headers
                    .into_inner()
                    .expose()
                    .parse_value::<HashMap<String, Secret<String>>>(
                        "HashMap<String, Secret<String>>",
                    )
            })
            .transpose()?;
        let masked_outgoing_webhook_custom_http_headers =
            outgoing_webhook_custom_http_headers.map(MaskedHeaders::from_headers);

        let card_testing_guard_config = item
            .card_testing_guard_config
            .or(Some(CardTestingGuardConfig::default()));
        let (is_external_vault_enabled, external_vault_connector_details) =
            item.external_vault_details.into();

        Ok(Self {
            merchant_id: item.merchant_id,
            profile_id: profile_id.clone(),
            profile_name: item.profile_name,
            return_url: item.return_url,
            enable_payment_response_hash: item.enable_payment_response_hash,
            payment_response_hash_key: item.payment_response_hash_key,
            redirect_to_merchant_with_http_post: item.redirect_to_merchant_with_http_post,
            webhook_details: item.webhook_details.map(ForeignInto::foreign_into),
            metadata: item.metadata,
            routing_algorithm: item.routing_algorithm,
            intent_fulfillment_time: item.intent_fulfillment_time,
            frm_routing_algorithm: item.frm_routing_algorithm,
            #[cfg(feature = "payouts")]
            payout_routing_algorithm: item.payout_routing_algorithm,
            applepay_verified_domains: item.applepay_verified_domains,
            payment_link_config: item.payment_link_config.map(ForeignInto::foreign_into),
            session_expiry: item.session_expiry,
            authentication_connector_details: item
                .authentication_connector_details
                .map(ForeignInto::foreign_into),
            payout_link_config: item.payout_link_config.map(ForeignInto::foreign_into),
            use_billing_as_payment_method_billing: item.use_billing_as_payment_method_billing,
            extended_card_info_config: item
                .extended_card_info_config
                .map(|config| config.expose().parse_value("ExtendedCardInfoConfig"))
                .transpose()?,
            collect_shipping_details_from_wallet_connector: item
                .collect_shipping_details_from_wallet_connector,
            collect_billing_details_from_wallet_connector: item
                .collect_billing_details_from_wallet_connector,
            always_collect_billing_details_from_wallet_connector: item
                .always_collect_billing_details_from_wallet_connector,
            always_collect_shipping_details_from_wallet_connector: item
                .always_collect_shipping_details_from_wallet_connector,
            is_connector_agnostic_mit_enabled: item.is_connector_agnostic_mit_enabled,
            outgoing_webhook_custom_http_headers: masked_outgoing_webhook_custom_http_headers,
            tax_connector_id: item.tax_connector_id,
            is_tax_connector_enabled: item.is_tax_connector_enabled,
            is_network_tokenization_enabled: item.is_network_tokenization_enabled,
            is_auto_retries_enabled: item.is_auto_retries_enabled,
            max_auto_retries_enabled: item.max_auto_retries_enabled,
            always_request_extended_authorization: item.always_request_extended_authorization,
            is_click_to_pay_enabled: item.is_click_to_pay_enabled,
            authentication_product_ids: item.authentication_product_ids,
            card_testing_guard_config: card_testing_guard_config.map(ForeignInto::foreign_into),
            is_clear_pan_retries_enabled: item.is_clear_pan_retries_enabled,
            force_3ds_challenge: item.force_3ds_challenge,
            is_debit_routing_enabled: Some(item.is_debit_routing_enabled),
            merchant_business_country: item.merchant_business_country,
            is_pre_network_tokenization_enabled: item.is_pre_network_tokenization_enabled,
            acquirer_configs: ProfileAcquirerConfigs {
                acquirer_config_map: item.acquirer_config_map.clone(),
                profile_id: profile_id.clone(),
            }
            .into(),
            is_iframe_redirection_enabled: item.is_iframe_redirection_enabled,
            merchant_category_code: item.merchant_category_code,
            merchant_country_code: item.merchant_country_code,
            dispute_polling_interval: item.dispute_polling_interval,
            is_manual_retry_enabled: item.is_manual_retry_enabled,
            always_enable_overcapture: item.always_enable_overcapture,
            is_external_vault_enabled,
            external_vault_connector_details: external_vault_connector_details
                .map(ForeignFrom::foreign_from),
            billing_processor_id: item.billing_processor_id,
            is_l2_l3_enabled: Some(item.is_l2_l3_enabled),
        })
    }
}

#[cfg(feature = "v2")]
impl ForeignTryFrom<domain::Profile> for ProfileResponse {
    type Error = error_stack::Report<errors::ParsingError>;

    fn foreign_try_from(item: domain::Profile) -> Result<Self, Self::Error> {
        let id = item.get_id().to_owned();

        let outgoing_webhook_custom_http_headers = item
            .outgoing_webhook_custom_http_headers
            .map(|headers| {
                headers
                    .into_inner()
                    .expose()
                    .parse_value::<HashMap<String, Secret<String>>>(
                        "HashMap<String, Secret<String>>",
                    )
            })
            .transpose()?;

        let order_fulfillment_time = item
            .order_fulfillment_time
            .map(admin::OrderFulfillmentTime::try_new)
            .transpose()
            .change_context(errors::ParsingError::IntegerOverflow)?;
        let masked_outgoing_webhook_custom_http_headers =
            outgoing_webhook_custom_http_headers.map(MaskedHeaders::from_headers);

        let card_testing_guard_config = item
            .card_testing_guard_config
            .or(Some(CardTestingGuardConfig::default()));

        Ok(Self {
            merchant_id: item.merchant_id,
            id,
            profile_name: item.profile_name,
            return_url: item.return_url,
            enable_payment_response_hash: item.enable_payment_response_hash,
            payment_response_hash_key: item.payment_response_hash_key,
            redirect_to_merchant_with_http_post: item.redirect_to_merchant_with_http_post,
            webhook_details: item.webhook_details.map(ForeignInto::foreign_into),
            metadata: item.metadata,
            applepay_verified_domains: item.applepay_verified_domains,
            payment_link_config: item.payment_link_config.map(ForeignInto::foreign_into),
            session_expiry: item.session_expiry,
            authentication_connector_details: item
                .authentication_connector_details
                .map(ForeignInto::foreign_into),
            payout_link_config: item.payout_link_config.map(ForeignInto::foreign_into),
            use_billing_as_payment_method_billing: item.use_billing_as_payment_method_billing,
            extended_card_info_config: item
                .extended_card_info_config
                .map(|config| config.expose().parse_value("ExtendedCardInfoConfig"))
                .transpose()?,
            collect_shipping_details_from_wallet_connector_if_required: item
                .collect_shipping_details_from_wallet_connector,
            collect_billing_details_from_wallet_connector_if_required: item
                .collect_billing_details_from_wallet_connector,
            always_collect_shipping_details_from_wallet_connector: item
                .always_collect_shipping_details_from_wallet_connector,
            always_collect_billing_details_from_wallet_connector: item
                .always_collect_billing_details_from_wallet_connector,
            is_connector_agnostic_mit_enabled: item.is_connector_agnostic_mit_enabled,
            outgoing_webhook_custom_http_headers: masked_outgoing_webhook_custom_http_headers,
            order_fulfillment_time,
            order_fulfillment_time_origin: item.order_fulfillment_time_origin,
            should_collect_cvv_during_payment: item.should_collect_cvv_during_payment,
            tax_connector_id: item.tax_connector_id,
            is_tax_connector_enabled: item.is_tax_connector_enabled,
            is_network_tokenization_enabled: item.is_network_tokenization_enabled,
            is_click_to_pay_enabled: item.is_click_to_pay_enabled,
            authentication_product_ids: item.authentication_product_ids,
            card_testing_guard_config: card_testing_guard_config.map(ForeignInto::foreign_into),
            is_clear_pan_retries_enabled: item.is_clear_pan_retries_enabled,
            is_debit_routing_enabled: Some(item.is_debit_routing_enabled),
            merchant_business_country: item.merchant_business_country,
            is_iframe_redirection_enabled: item.is_iframe_redirection_enabled,
            is_external_vault_enabled: item.is_external_vault_enabled,
            is_l2_l3_enabled: None,
            external_vault_connector_details: item
                .external_vault_connector_details
                .map(ForeignInto::foreign_into),
            merchant_category_code: item.merchant_category_code,
            merchant_country_code: item.merchant_country_code,
            split_txns_enabled: item.split_txns_enabled,
            revenue_recovery_retry_algorithm_type: item.revenue_recovery_retry_algorithm_type,
            billing_processor_id: item.billing_processor_id,
        })
    }
}

#[cfg(feature = "v1")]
pub async fn create_profile_from_merchant_account(
    state: &SessionState,
    merchant_account: domain::MerchantAccount,
    request: ProfileCreate,
    key_store: &MerchantKeyStore,
) -> Result<domain::Profile, error_stack::Report<errors::ApiErrorResponse>> {
    use common_utils::ext_traits::AsyncExt;
    use diesel_models::business_profile::CardTestingGuardConfig;

    use crate::core;

    // Generate a unique profile id
    let profile_id = common_utils::generate_profile_id_of_default_length();
    let merchant_id = merchant_account.get_id().to_owned();

    let current_time = common_utils::date_time::now();

    let webhook_details = request.webhook_details.map(ForeignInto::foreign_into);

    let payment_response_hash_key = request
        .payment_response_hash_key
        .or(merchant_account.payment_response_hash_key)
        .unwrap_or(common_utils::crypto::generate_cryptographically_secure_random_string(64));

    let payment_link_config = request.payment_link_config.map(ForeignInto::foreign_into);
    let key_manager_state = state.into();
    let outgoing_webhook_custom_http_headers = request
        .outgoing_webhook_custom_http_headers
        .async_map(|headers| {
            core::payment_methods::cards::create_encrypted_data(
                &key_manager_state,
                key_store,
                headers,
            )
        })
        .await
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to encrypt outgoing webhook custom HTTP headers")?;

    let payout_link_config = request
        .payout_link_config
        .map(|payout_conf| match payout_conf.config.validate() {
            Ok(_) => Ok(payout_conf.foreign_into()),
            Err(e) => Err(error_stack::report!(
                errors::ApiErrorResponse::InvalidRequestData {
                    message: e.to_string()
                }
            )),
        })
        .transpose()?;

    let key = key_store.key.clone().into_inner();
    let key_manager_state = state.into();

    let card_testing_secret_key = Some(Secret::new(utils::generate_id(
        consts::FINGERPRINT_SECRET_LENGTH,
        "fs",
    )));

    let card_testing_guard_config = request
        .card_testing_guard_config
        .map(CardTestingGuardConfig::foreign_from)
        .or(Some(CardTestingGuardConfig::default()));

    Ok(domain::Profile::from(domain::ProfileSetter {
        profile_id,
        merchant_id,
        profile_name: request.profile_name.unwrap_or("default".to_string()),
        created_at: current_time,
        modified_at: current_time,
        return_url: request
            .return_url
            .map(|return_url| return_url.to_string())
            .or(merchant_account.return_url),
        enable_payment_response_hash: request
            .enable_payment_response_hash
            .unwrap_or(merchant_account.enable_payment_response_hash),
        payment_response_hash_key: Some(payment_response_hash_key),
        redirect_to_merchant_with_http_post: request
            .redirect_to_merchant_with_http_post
            .unwrap_or(merchant_account.redirect_to_merchant_with_http_post),
        webhook_details: webhook_details.or(merchant_account.webhook_details),
        metadata: request.metadata,
        routing_algorithm: None,
        intent_fulfillment_time: request
            .intent_fulfillment_time
            .map(i64::from)
            .or(merchant_account.intent_fulfillment_time)
            .or(Some(common_utils::consts::DEFAULT_INTENT_FULFILLMENT_TIME)),
        frm_routing_algorithm: request
            .frm_routing_algorithm
            .or(merchant_account.frm_routing_algorithm),
        #[cfg(feature = "payouts")]
        payout_routing_algorithm: request
            .payout_routing_algorithm
            .or(merchant_account.payout_routing_algorithm),
        #[cfg(not(feature = "payouts"))]
        payout_routing_algorithm: None,
        is_recon_enabled: merchant_account.is_recon_enabled,
        applepay_verified_domains: request.applepay_verified_domains,
        payment_link_config,
        session_expiry: request
            .session_expiry
            .map(i64::from)
            .or(Some(common_utils::consts::DEFAULT_SESSION_EXPIRY)),
        authentication_connector_details: request
            .authentication_connector_details
            .map(ForeignInto::foreign_into),
        payout_link_config,
        is_connector_agnostic_mit_enabled: request.is_connector_agnostic_mit_enabled,
        is_extended_card_info_enabled: None,
        extended_card_info_config: None,
        use_billing_as_payment_method_billing: request
            .use_billing_as_payment_method_billing
            .or(Some(true)),
        collect_shipping_details_from_wallet_connector: request
            .collect_shipping_details_from_wallet_connector
            .or(Some(false)),
        collect_billing_details_from_wallet_connector: request
            .collect_billing_details_from_wallet_connector
            .or(Some(false)),
        always_collect_billing_details_from_wallet_connector: request
            .always_collect_billing_details_from_wallet_connector
            .or(Some(false)),
        always_collect_shipping_details_from_wallet_connector: request
            .always_collect_shipping_details_from_wallet_connector
            .or(Some(false)),
        outgoing_webhook_custom_http_headers,
        tax_connector_id: request.tax_connector_id,
        is_tax_connector_enabled: request.is_tax_connector_enabled,
        dynamic_routing_algorithm: None,
        is_network_tokenization_enabled: request.is_network_tokenization_enabled,
        is_auto_retries_enabled: request.is_auto_retries_enabled.unwrap_or_default(),
        max_auto_retries_enabled: request.max_auto_retries_enabled.map(i16::from),
        always_request_extended_authorization: request.always_request_extended_authorization,
        is_click_to_pay_enabled: request.is_click_to_pay_enabled,
        authentication_product_ids: request.authentication_product_ids,
        card_testing_guard_config,
        card_testing_secret_key: card_testing_secret_key
            .async_lift(|inner| async {
                domain_types::crypto_operation(
                    &key_manager_state,
                    common_utils::type_name!(domain::Profile),
                    domain_types::CryptoOperation::EncryptOptional(inner),
                    km_types::Identifier::Merchant(key_store.merchant_id.clone()),
                    key.peek(),
                )
                .await
                .and_then(|val| val.try_into_optionaloperation())
            })
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("error while generating card testing secret key")?,
        is_clear_pan_retries_enabled: request.is_clear_pan_retries_enabled.unwrap_or_default(),
        force_3ds_challenge: request.force_3ds_challenge.unwrap_or_default(),
        is_debit_routing_enabled: request.is_debit_routing_enabled.unwrap_or_default(),
        merchant_business_country: request.merchant_business_country,
        is_iframe_redirection_enabled: request.is_iframe_redirection_enabled,
        is_pre_network_tokenization_enabled: request
            .is_pre_network_tokenization_enabled
            .unwrap_or_default(),
        merchant_category_code: request.merchant_category_code,
        merchant_country_code: request.merchant_country_code,
        dispute_polling_interval: request.dispute_polling_interval,
        is_manual_retry_enabled: request.is_manual_retry_enabled,
        always_enable_overcapture: request.always_enable_overcapture,
        external_vault_details: domain::ExternalVaultDetails::try_from((
            request.is_external_vault_enabled,
            request
                .external_vault_connector_details
                .map(ForeignInto::foreign_into),
        ))
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("error while generating external_vault_details")?,
        billing_processor_id: request.billing_processor_id,
        is_l2_l3_enabled: request.is_l2_l3_enabled.unwrap_or(false),
    }))
}


// File: crates/router/src/types/api/connector_onboarding.rs

pub mod paypal;


// File: crates/router/src/types/api/connector_onboarding/paypal.rs

use api_models::connector_onboarding as api;
use error_stack::ResultExt;

use crate::core::errors::{ApiErrorResponse, RouterResult};

#[derive(serde::Deserialize, Debug)]
pub struct HateoasLink {
    pub href: String,
    pub rel: String,
    pub method: String,
}

#[derive(serde::Deserialize, Debug)]
pub struct PartnerReferralResponse {
    pub links: Vec<HateoasLink>,
}

#[derive(serde::Serialize, Debug)]
pub struct PartnerReferralRequest {
    pub tracking_id: String,
    pub operations: Vec<PartnerReferralOperations>,
    pub products: Vec<PayPalProducts>,
    pub capabilities: Vec<PayPalCapabilities>,
    pub partner_config_override: PartnerConfigOverride,
    pub legal_consents: Vec<LegalConsent>,
}

#[derive(serde::Serialize, Debug)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum PayPalProducts {
    Ppcp,
    AdvancedVaulting,
}

#[derive(serde::Serialize, Debug)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum PayPalCapabilities {
    PaypalWalletVaultingAdvanced,
}

#[derive(serde::Serialize, Debug)]
pub struct PartnerReferralOperations {
    pub operation: PayPalReferralOperationType,
    pub api_integration_preference: PartnerReferralIntegrationPreference,
}

#[derive(serde::Serialize, Debug)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum PayPalReferralOperationType {
    ApiIntegration,
}

#[derive(serde::Serialize, Debug)]
pub struct PartnerReferralIntegrationPreference {
    pub rest_api_integration: PartnerReferralRestApiIntegration,
}

#[derive(serde::Serialize, Debug)]
pub struct PartnerReferralRestApiIntegration {
    pub integration_method: IntegrationMethod,
    pub integration_type: PayPalIntegrationType,
    pub third_party_details: PartnerReferralThirdPartyDetails,
}

#[derive(serde::Serialize, Debug)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum IntegrationMethod {
    Paypal,
}

#[derive(serde::Serialize, Debug)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum PayPalIntegrationType {
    ThirdParty,
}

#[derive(serde::Serialize, Debug)]
pub struct PartnerReferralThirdPartyDetails {
    pub features: Vec<PayPalFeatures>,
}

#[derive(serde::Serialize, Debug)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum PayPalFeatures {
    Payment,
    Refund,
    Vault,
    AccessMerchantInformation,
    BillingAgreement,
    ReadSellerDispute,
}

#[derive(serde::Serialize, Debug)]
pub struct PartnerConfigOverride {
    pub partner_logo_url: String,
    pub return_url: String,
}

#[derive(serde::Serialize, Debug)]
pub struct LegalConsent {
    #[serde(rename = "type")]
    pub consent_type: LegalConsentType,
    pub granted: bool,
}

#[derive(serde::Serialize, Debug)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum LegalConsentType {
    ShareDataConsent,
}

impl PartnerReferralRequest {
    pub fn new(tracking_id: String, return_url: String) -> Self {
        Self {
            tracking_id,
            operations: vec![PartnerReferralOperations {
                operation: PayPalReferralOperationType::ApiIntegration,
                api_integration_preference: PartnerReferralIntegrationPreference {
                    rest_api_integration: PartnerReferralRestApiIntegration {
                        integration_method: IntegrationMethod::Paypal,
                        integration_type: PayPalIntegrationType::ThirdParty,
                        third_party_details: PartnerReferralThirdPartyDetails {
                            features: vec![
                                PayPalFeatures::Payment,
                                PayPalFeatures::Refund,
                                PayPalFeatures::Vault,
                                PayPalFeatures::AccessMerchantInformation,
                                PayPalFeatures::BillingAgreement,
                                PayPalFeatures::ReadSellerDispute,
                            ],
                        },
                    },
                },
            }],
            products: vec![PayPalProducts::Ppcp, PayPalProducts::AdvancedVaulting],
            capabilities: vec![PayPalCapabilities::PaypalWalletVaultingAdvanced],
            partner_config_override: PartnerConfigOverride {
                partner_logo_url: "https://hyperswitch.io/img/websiteIcon.svg".to_string(),
                return_url,
            },
            legal_consents: vec![LegalConsent {
                consent_type: LegalConsentType::ShareDataConsent,
                granted: true,
            }],
        }
    }
}

#[derive(serde::Deserialize, Debug)]
pub struct SellerStatusResponse {
    pub merchant_id: common_utils::id_type::MerchantId,
    pub links: Vec<HateoasLink>,
}

#[derive(serde::Deserialize, Debug)]
pub struct SellerStatusDetailsResponse {
    pub merchant_id: common_utils::id_type::MerchantId,
    pub primary_email_confirmed: bool,
    pub payments_receivable: bool,
    pub products: Vec<SellerStatusProducts>,
}

#[derive(serde::Deserialize, Debug)]
pub struct SellerStatusProducts {
    pub name: String,
    pub vetting_status: Option<VettingStatus>,
}

#[derive(serde::Deserialize, Debug, Clone)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum VettingStatus {
    NeedMoreData,
    Subscribed,
    Denied,
}

impl SellerStatusResponse {
    pub fn extract_merchant_details_url(self, paypal_base_url: &str) -> RouterResult<String> {
        self.links
            .first()
            .and_then(|link| link.href.strip_prefix('/'))
            .map(|link| format!("{paypal_base_url}{link}"))
            .ok_or(ApiErrorResponse::InternalServerError)
            .attach_printable("Merchant details not received in onboarding status")
    }
}

impl SellerStatusDetailsResponse {
    pub fn check_payments_receivable(&self) -> Option<api::PayPalOnboardingStatus> {
        if !self.payments_receivable {
            return Some(api::PayPalOnboardingStatus::PaymentsNotReceivable);
        }
        None
    }

    pub fn check_ppcp_custom_status(&self) -> Option<api::PayPalOnboardingStatus> {
        match self.get_ppcp_custom_status() {
            Some(VettingStatus::Denied) => Some(api::PayPalOnboardingStatus::PpcpCustomDenied),
            Some(VettingStatus::Subscribed) => None,
            _ => Some(api::PayPalOnboardingStatus::MorePermissionsNeeded),
        }
    }

    fn check_email_confirmation(&self) -> Option<api::PayPalOnboardingStatus> {
        if !self.primary_email_confirmed {
            return Some(api::PayPalOnboardingStatus::EmailNotVerified);
        }
        None
    }

    pub async fn get_eligibility_status(&self) -> RouterResult<api::PayPalOnboardingStatus> {
        Ok(self
            .check_payments_receivable()
            .or(self.check_email_confirmation())
            .or(self.check_ppcp_custom_status())
            .unwrap_or(api::PayPalOnboardingStatus::Success(
                api::PayPalOnboardingDone {
                    payer_id: self.get_payer_id(),
                },
            )))
    }

    fn get_ppcp_custom_status(&self) -> Option<VettingStatus> {
        self.products
            .iter()
            .find(|product| product.name == "PPCP_CUSTOM")
            .and_then(|ppcp_custom| ppcp_custom.vetting_status.clone())
    }

    fn get_payer_id(&self) -> common_utils::id_type::MerchantId {
        self.merchant_id.to_owned()
    }
}

impl PartnerReferralResponse {
    pub fn extract_action_url(self) -> RouterResult<String> {
        Ok(self
            .links
            .into_iter()
            .find(|hateoas_link| hateoas_link.rel == "action_url")
            .ok_or(ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to get action_url from paypal response")?
            .href)
    }
}


// File: crates/router/src/types/api/verify_connector/paypal.rs

use error_stack::ResultExt;

use super::{VerifyConnector, VerifyConnectorData};
use crate::{
    connector,
    core::errors,
    routes::SessionState,
    services,
    types::{self, api},
};

#[async_trait::async_trait]
impl VerifyConnector for connector::Paypal {
    async fn get_access_token(
        state: &SessionState,
        connector_data: VerifyConnectorData,
    ) -> errors::CustomResult<Option<types::AccessToken>, errors::ApiErrorResponse> {
        let token_data: types::AccessTokenRequestData =
            connector_data.connector_auth.clone().try_into()?;
        let router_data = connector_data.get_router_data(state, token_data, None);

        let request = connector_data
            .connector
            .get_connector_integration()
            .build_request(&router_data, &state.conf.connectors)
            .change_context(errors::ApiErrorResponse::InvalidRequestData {
                message: "Payment request cannot be built".to_string(),
            })?
            .ok_or(errors::ApiErrorResponse::InternalServerError)?;

        let response = services::call_connector_api(&state.to_owned(), request, "get_access_token")
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)?;

        match response {
            Ok(res) => Some(
                connector_data
                    .connector
                    .get_connector_integration()
                    .handle_response(&router_data, None, res)
                    .change_context(errors::ApiErrorResponse::InternalServerError)?
                    .response
                    .map_err(|_| errors::ApiErrorResponse::InternalServerError.into()),
            )
            .transpose(),
            Err(response_data) => {
                Self::handle_access_token_error_response::<
                    api::AccessTokenAuth,
                    types::AccessTokenFlowData,
                    types::AccessTokenRequestData,
                    types::AccessToken,
                >(
                    connector_data.connector.get_connector_integration(),
                    response_data,
                )
                .await
            }
        }
    }
}


// File: crates/router/src/types/api/verify_connector/stripe.rs

use error_stack::ResultExt;
use router_env::env;

use super::VerifyConnector;
use crate::{
    connector, core::errors, services, types,
    types::api::verify_connector::BoxedConnectorIntegrationInterface,
};

#[async_trait::async_trait]
impl VerifyConnector for connector::Stripe {
    async fn handle_payment_error_response<F, ResourceCommonData, Req, Resp>(
        connector: BoxedConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp>,
        error_response: types::Response,
    ) -> errors::RouterResponse<()> {
        let error = connector
            .get_error_response(error_response, None)
            .change_context(errors::ApiErrorResponse::InternalServerError)?;
        match (env::which(), error.code.as_str()) {
            // In situations where an attempt is made to process a payment using a
            // Stripe production key along with a test card (which verify_connector is using),
            // Stripe will respond with a "card_declined" error. In production,
            // when this scenario occurs we will send back an "Ok" response.
            (env::Env::Production, "card_declined") => Ok(services::ApplicationResponse::StatusOk),
            _ => Err(errors::ApiErrorResponse::InvalidRequestData {
                message: error.reason.unwrap_or(error.message),
            }
            .into()),
        }
    }
}


// File: crates/router/src/types/domain/types.rs

use ::payment_methods::state as pm_state;
use common_utils::types::keymanager::KeyManagerState;
pub use hyperswitch_domain_models::type_encryption::{
    crypto_operation, AsyncLift, CryptoOperation, Lift, OptionalEncryptableJsonType,
};
use hyperswitch_interfaces::configs;

use crate::{
    routes::app,
    types::{api as api_types, ForeignFrom},
};

impl ForeignFrom<(&app::AppState, configs::Tenant)> for KeyManagerState {
    fn foreign_from((app_state, tenant): (&app::AppState, configs::Tenant)) -> Self {
        let conf = app_state.conf.key_manager.get_inner();
        Self {
            global_tenant_id: app_state.conf.multitenancy.global_tenant.tenant_id.clone(),
            tenant_id: tenant.tenant_id.clone(),
            enabled: conf.enabled,
            url: conf.url.clone(),
            client_idle_timeout: app_state.conf.proxy.idle_pool_connection_timeout,
            #[cfg(feature = "km_forward_x_request_id")]
            request_id: app_state.request_id.clone(),
            #[cfg(feature = "keymanager_mtls")]
            cert: conf.cert.clone(),
            #[cfg(feature = "keymanager_mtls")]
            ca: conf.ca.clone(),
            infra_values: app::AppState::process_env_mappings(app_state.conf.infra_values.clone()),
        }
    }
}
impl From<&app::SessionState> for KeyManagerState {
    fn from(state: &app::SessionState) -> Self {
        let conf = state.conf.key_manager.get_inner();
        Self {
            global_tenant_id: state.conf.multitenancy.global_tenant.tenant_id.clone(),
            tenant_id: state.tenant.tenant_id.clone(),
            enabled: conf.enabled,
            url: conf.url.clone(),
            client_idle_timeout: state.conf.proxy.idle_pool_connection_timeout,
            #[cfg(feature = "km_forward_x_request_id")]
            request_id: state.request_id.clone(),
            #[cfg(feature = "keymanager_mtls")]
            cert: conf.cert.clone(),
            #[cfg(feature = "keymanager_mtls")]
            ca: conf.ca.clone(),
            infra_values: app::AppState::process_env_mappings(state.conf.infra_values.clone()),
        }
    }
}

impl From<&app::SessionState> for pm_state::PaymentMethodsState {
    fn from(state: &app::SessionState) -> Self {
        Self {
            store: state.store.get_payment_methods_store(),
            key_store: None,
            key_manager_state: state.into(),
        }
    }
}

pub struct ConnectorConversionHandler;

impl hyperswitch_interfaces::api_client::ConnectorConverter for ConnectorConversionHandler {
    fn get_connector_enum_by_name(
        &self,
        connector: &str,
    ) -> common_utils::errors::CustomResult<
        hyperswitch_interfaces::connector_integration_interface::ConnectorEnum,
        hyperswitch_domain_models::errors::api_error_response::ApiErrorResponse,
    > {
        api_types::ConnectorData::convert_connector(connector)
    }
}

impl From<app::SessionState> for subscriptions::state::SubscriptionState {
    fn from(state: app::SessionState) -> Self {
        Self {
            store: state.store.get_subscription_store(),
            key_store: None,
            key_manager_state: (&state).into(),
            api_client: state.api_client.clone(),
            conf: subscriptions::state::SubscriptionConfig {
                proxy: state.conf.proxy.clone(),
                internal_merchant_id_profile_id_auth: state
                    .conf
                    .internal_merchant_id_profile_id_auth
                    .clone(),
                internal_services: state.conf.internal_services.clone(),
                connectors: state.conf.connectors.clone(),
            },
            tenant: state.tenant.clone(),
            event_handler: Box::new(state.event_handler.clone()),
            connector_converter: Box::new(ConnectorConversionHandler),
        }
    }
}


// File: crates/router/src/types/domain/merchant_connector_account.rs

pub use hyperswitch_domain_models::merchant_connector_account::*;


// File: crates/router/src/types/domain/payments.rs

pub use hyperswitch_domain_models::payment_method_data::{
    AliPayQr, ApplePayFlow, ApplePayThirdPartySdkData, ApplePayWalletData, ApplepayPaymentMethod,
    BankDebitData, BankRedirectData, BankTransferData, BoletoVoucherData, Card, CardDetail,
    CardRedirectData, CardToken, CashappQr, CryptoData, GcashRedirection, GiftCardData,
    GiftCardDetails, GoPayRedirection, GooglePayPaymentMethodInfo, GooglePayRedirectData,
    GooglePayThirdPartySdkData, GooglePayWalletData, IndomaretVoucherData, KakaoPayRedirection,
    MbWayRedirection, MifinityData, NetworkTokenData, OpenBankingData, PayLaterData,
    PaymentMethodData, RealTimePaymentData, RevolutPayData, SamsungPayWalletData,
    SepaAndBacsBillingDetails, SwishQrData, TokenizedBankDebitValue1, TokenizedBankDebitValue2,
    TokenizedBankRedirectValue1, TokenizedBankRedirectValue2, TokenizedBankTransferValue1,
    TokenizedBankTransferValue2, TokenizedCardValue1, TokenizedCardValue2, TokenizedWalletValue1,
    TokenizedWalletValue2, TouchNGoRedirection, UpiCollectData, UpiData, UpiIntentData,
    VoucherData, WalletData, WeChatPayQr,
};


// File: crates/router/src/types/domain/address.rs

use async_trait::async_trait;
use common_utils::{
    crypto::{self, Encryptable},
    date_time,
    encryption::Encryption,
    errors::{CustomResult, ValidationError},
    id_type, pii, type_name,
    types::keymanager::{Identifier, KeyManagerState, ToEncryptable},
};
use diesel_models::{address::AddressUpdateInternal, enums};
use error_stack::ResultExt;
use masking::{PeekInterface, Secret, SwitchStrategy};
use rustc_hash::FxHashMap;
use time::{OffsetDateTime, PrimitiveDateTime};

use super::{behaviour, types};

#[derive(Clone, Debug, serde::Serialize, router_derive::ToEncryption)]
pub struct Address {
    pub address_id: String,
    pub city: Option<String>,
    pub country: Option<enums::CountryAlpha2>,
    #[encrypt]
    pub line1: Option<Encryptable<Secret<String>>>,
    #[encrypt]
    pub line2: Option<Encryptable<Secret<String>>>,
    #[encrypt]
    pub line3: Option<Encryptable<Secret<String>>>,
    #[encrypt]
    pub state: Option<Encryptable<Secret<String>>>,
    #[encrypt]
    pub zip: Option<Encryptable<Secret<String>>>,
    #[encrypt]
    pub first_name: Option<Encryptable<Secret<String>>>,
    #[encrypt]
    pub last_name: Option<Encryptable<Secret<String>>>,
    #[encrypt]
    pub phone_number: Option<Encryptable<Secret<String>>>,
    pub country_code: Option<String>,
    #[serde(skip_serializing)]
    #[serde(with = "custom_serde::iso8601")]
    pub created_at: PrimitiveDateTime,
    #[serde(skip_serializing)]
    #[serde(with = "custom_serde::iso8601")]
    pub modified_at: PrimitiveDateTime,
    pub merchant_id: id_type::MerchantId,
    pub updated_by: String,
    #[encrypt]
    pub email: Option<Encryptable<Secret<String, pii::EmailStrategy>>>,
    #[encrypt]
    pub origin_zip: Option<Encryptable<Secret<String>>>,
}

/// Based on the flow, appropriate address has to be used
/// In case of Payments, The `PaymentAddress`[PaymentAddress] has to be used
/// which contains only the `Address`[Address] object and `payment_id` and optional `customer_id`
#[derive(Debug, Clone)]
pub struct PaymentAddress {
    pub address: Address,
    pub payment_id: id_type::PaymentId,
    // This is present in `PaymentAddress` because even `payouts` uses `PaymentAddress`
    pub customer_id: Option<id_type::CustomerId>,
}

#[derive(Debug, Clone)]
pub struct CustomerAddress {
    pub address: Address,
    pub customer_id: id_type::CustomerId,
}

#[async_trait]
impl behaviour::Conversion for CustomerAddress {
    type DstType = diesel_models::address::Address;
    type NewDstType = diesel_models::address::AddressNew;

    async fn convert(self) -> CustomResult<Self::DstType, ValidationError> {
        let converted_address = Address::convert(self.address).await?;
        Ok(diesel_models::address::Address {
            customer_id: Some(self.customer_id),
            payment_id: None,
            ..converted_address
        })
    }

    async fn convert_back(
        state: &KeyManagerState,
        other: Self::DstType,
        key: &Secret<Vec<u8>>,
        key_manager_identifier: Identifier,
    ) -> CustomResult<Self, ValidationError> {
        let customer_id =
            other
                .customer_id
                .clone()
                .ok_or(ValidationError::MissingRequiredField {
                    field_name: "customer_id".to_string(),
                })?;

        let address = Address::convert_back(state, other, key, key_manager_identifier).await?;

        Ok(Self {
            address,
            customer_id,
        })
    }

    async fn construct_new(self) -> CustomResult<Self::NewDstType, ValidationError> {
        let address_new = Address::construct_new(self.address).await?;

        Ok(Self::NewDstType {
            customer_id: Some(self.customer_id),
            payment_id: None,
            ..address_new
        })
    }
}
#[async_trait]
impl behaviour::Conversion for PaymentAddress {
    type DstType = diesel_models::address::Address;
    type NewDstType = diesel_models::address::AddressNew;

    async fn convert(self) -> CustomResult<Self::DstType, ValidationError> {
        let converted_address = Address::convert(self.address).await?;
        Ok(diesel_models::address::Address {
            customer_id: self.customer_id,
            payment_id: Some(self.payment_id),
            ..converted_address
        })
    }

    async fn convert_back(
        state: &KeyManagerState,
        other: Self::DstType,
        key: &Secret<Vec<u8>>,
        key_manager_identifier: Identifier,
    ) -> CustomResult<Self, ValidationError> {
        let payment_id = other
            .payment_id
            .clone()
            .ok_or(ValidationError::MissingRequiredField {
                field_name: "payment_id".to_string(),
            })?;

        let customer_id = other.customer_id.clone();

        let address = Address::convert_back(state, other, key, key_manager_identifier).await?;

        Ok(Self {
            address,
            payment_id,
            customer_id,
        })
    }

    async fn construct_new(self) -> CustomResult<Self::NewDstType, ValidationError> {
        let address_new = Address::construct_new(self.address).await?;

        Ok(Self::NewDstType {
            customer_id: self.customer_id,
            payment_id: Some(self.payment_id),
            ..address_new
        })
    }
}

#[async_trait]
impl behaviour::Conversion for Address {
    type DstType = diesel_models::address::Address;
    type NewDstType = diesel_models::address::AddressNew;

    async fn convert(self) -> CustomResult<Self::DstType, ValidationError> {
        Ok(diesel_models::address::Address {
            address_id: self.address_id,
            city: self.city,
            country: self.country,
            line1: self.line1.map(Encryption::from),
            line2: self.line2.map(Encryption::from),
            line3: self.line3.map(Encryption::from),
            state: self.state.map(Encryption::from),
            zip: self.zip.map(Encryption::from),
            first_name: self.first_name.map(Encryption::from),
            last_name: self.last_name.map(Encryption::from),
            phone_number: self.phone_number.map(Encryption::from),
            country_code: self.country_code,
            created_at: self.created_at,
            modified_at: self.modified_at,
            merchant_id: self.merchant_id,
            updated_by: self.updated_by,
            email: self.email.map(Encryption::from),
            payment_id: None,
            customer_id: None,
            origin_zip: self.origin_zip.map(Encryption::from),
        })
    }

    async fn convert_back(
        state: &KeyManagerState,
        other: Self::DstType,
        key: &Secret<Vec<u8>>,
        _key_manager_identifier: Identifier,
    ) -> CustomResult<Self, ValidationError> {
        let identifier = Identifier::Merchant(other.merchant_id.clone());
        let decrypted: FxHashMap<String, Encryptable<Secret<String>>> = types::crypto_operation(
            state,
            type_name!(Self::DstType),
            types::CryptoOperation::BatchDecrypt(EncryptedAddress::to_encryptable(
                EncryptedAddress {
                    line1: other.line1,
                    line2: other.line2,
                    line3: other.line3,
                    state: other.state,
                    zip: other.zip,
                    first_name: other.first_name,
                    last_name: other.last_name,
                    phone_number: other.phone_number,
                    email: other.email,
                    origin_zip: other.origin_zip,
                },
            )),
            identifier.clone(),
            key.peek(),
        )
        .await
        .and_then(|val| val.try_into_batchoperation())
        .change_context(ValidationError::InvalidValue {
            message: "Failed while decrypting".to_string(),
        })?;
        let encryptable_address = EncryptedAddress::from_encryptable(decrypted).change_context(
            ValidationError::InvalidValue {
                message: "Failed while decrypting".to_string(),
            },
        )?;
        Ok(Self {
            address_id: other.address_id,
            city: other.city,
            country: other.country,
            line1: encryptable_address.line1,
            line2: encryptable_address.line2,
            line3: encryptable_address.line3,
            state: encryptable_address.state,
            zip: encryptable_address.zip,
            first_name: encryptable_address.first_name,
            last_name: encryptable_address.last_name,
            phone_number: encryptable_address.phone_number,
            country_code: other.country_code,
            created_at: other.created_at,
            modified_at: other.modified_at,
            updated_by: other.updated_by,
            merchant_id: other.merchant_id,
            email: encryptable_address.email.map(|email| {
                let encryptable: Encryptable<Secret<String, pii::EmailStrategy>> = Encryptable::new(
                    email.clone().into_inner().switch_strategy(),
                    email.into_encrypted(),
                );
                encryptable
            }),
            origin_zip: encryptable_address.origin_zip,
        })
    }

    async fn construct_new(self) -> CustomResult<Self::NewDstType, ValidationError> {
        let now = date_time::now();
        Ok(Self::NewDstType {
            address_id: self.address_id,
            city: self.city,
            country: self.country,
            line1: self.line1.map(Encryption::from),
            line2: self.line2.map(Encryption::from),
            line3: self.line3.map(Encryption::from),
            state: self.state.map(Encryption::from),
            zip: self.zip.map(Encryption::from),
            first_name: self.first_name.map(Encryption::from),
            last_name: self.last_name.map(Encryption::from),
            phone_number: self.phone_number.map(Encryption::from),
            country_code: self.country_code,
            merchant_id: self.merchant_id,
            created_at: now,
            modified_at: now,
            updated_by: self.updated_by,
            email: self.email.map(Encryption::from),
            customer_id: None,
            payment_id: None,
            origin_zip: self.origin_zip.map(Encryption::from),
        })
    }
}

#[derive(Debug, Clone)]
pub enum AddressUpdate {
    Update {
        city: Option<String>,
        country: Option<enums::CountryAlpha2>,
        line1: crypto::OptionalEncryptableSecretString,
        line2: crypto::OptionalEncryptableSecretString,
        line3: crypto::OptionalEncryptableSecretString,
        state: crypto::OptionalEncryptableSecretString,
        zip: crypto::OptionalEncryptableSecretString,
        first_name: crypto::OptionalEncryptableSecretString,
        last_name: crypto::OptionalEncryptableSecretString,
        phone_number: crypto::OptionalEncryptableSecretString,
        country_code: Option<String>,
        updated_by: String,
        email: crypto::OptionalEncryptableEmail,
        origin_zip: crypto::OptionalEncryptableSecretString,
    },
}

impl From<AddressUpdate> for AddressUpdateInternal {
    fn from(address_update: AddressUpdate) -> Self {
        match address_update {
            AddressUpdate::Update {
                city,
                country,
                line1,
                line2,
                line3,
                state,
                zip,
                first_name,
                last_name,
                phone_number,
                country_code,
                updated_by,
                email,
                origin_zip,
            } => Self {
                city,
                country,
                line1: line1.map(Encryption::from),
                line2: line2.map(Encryption::from),
                line3: line3.map(Encryption::from),
                state: state.map(Encryption::from),
                zip: zip.map(Encryption::from),
                first_name: first_name.map(Encryption::from),
                last_name: last_name.map(Encryption::from),
                phone_number: phone_number.map(Encryption::from),
                country_code,
                modified_at: date_time::convert_to_pdt(OffsetDateTime::now_utc()),
                updated_by,
                email: email.map(Encryption::from),
                origin_zip: origin_zip.map(Encryption::from),
            },
        }
    }
}


// File: crates/router/src/types/domain/event.rs

use common_utils::{
    crypto::{Encryptable, OptionalEncryptableSecretString},
    encryption::Encryption,
    type_name,
    types::keymanager::{KeyManagerState, ToEncryptable},
};
use diesel_models::{
    enums::{EventClass, EventObjectType, EventType, WebhookDeliveryAttempt},
    events::{EventMetadata, EventUpdateInternal},
};
use error_stack::ResultExt;
use masking::{PeekInterface, Secret};
use rustc_hash::FxHashMap;

use crate::{
    errors::{CustomResult, ValidationError},
    types::domain::types,
};

#[derive(Clone, Debug, router_derive::ToEncryption)]
pub struct Event {
    /// A string that uniquely identifies the event.
    pub event_id: String,

    /// Represents the type of event for the webhook.
    pub event_type: EventType,

    /// Represents the class of event for the webhook.
    pub event_class: EventClass,

    /// Indicates whether the current webhook delivery was successful.
    pub is_webhook_notified: bool,

    /// Reference to the object for which the webhook was created.
    pub primary_object_id: String,

    /// Type of the object type for which the webhook was created.
    pub primary_object_type: EventObjectType,

    /// The timestamp when the webhook was created.
    pub created_at: time::PrimitiveDateTime,

    /// Merchant Account identifier to which the object is associated with.
    pub merchant_id: Option<common_utils::id_type::MerchantId>,

    /// Business Profile identifier to which the object is associated with.
    pub business_profile_id: Option<common_utils::id_type::ProfileId>,

    /// The timestamp when the primary object was created.
    pub primary_object_created_at: Option<time::PrimitiveDateTime>,

    /// This allows the event to be uniquely identified to prevent multiple processing.
    pub idempotent_event_id: Option<String>,

    /// Links to the initial attempt of the event.
    pub initial_attempt_id: Option<String>,

    /// This field contains the encrypted request data sent as part of the event.
    #[encrypt]
    pub request: Option<Encryptable<Secret<String>>>,

    /// This field contains the encrypted response data received as part of the event.
    #[encrypt]
    pub response: Option<Encryptable<Secret<String>>>,

    /// Represents the event delivery type.
    pub delivery_attempt: Option<WebhookDeliveryAttempt>,

    /// Holds any additional data related to the event.
    pub metadata: Option<EventMetadata>,

    /// Indicates whether the event was ultimately delivered.
    pub is_overall_delivery_successful: Option<bool>,
}

#[derive(Debug)]
pub enum EventUpdate {
    UpdateResponse {
        is_webhook_notified: bool,
        response: OptionalEncryptableSecretString,
    },
    OverallDeliveryStatusUpdate {
        is_overall_delivery_successful: bool,
    },
}

impl From<EventUpdate> for EventUpdateInternal {
    fn from(event_update: EventUpdate) -> Self {
        match event_update {
            EventUpdate::UpdateResponse {
                is_webhook_notified,
                response,
            } => Self {
                is_webhook_notified: Some(is_webhook_notified),
                response: response.map(Into::into),
                is_overall_delivery_successful: None,
            },
            EventUpdate::OverallDeliveryStatusUpdate {
                is_overall_delivery_successful,
            } => Self {
                is_webhook_notified: None,
                response: None,
                is_overall_delivery_successful: Some(is_overall_delivery_successful),
            },
        }
    }
}

#[async_trait::async_trait]
impl super::behaviour::Conversion for Event {
    type DstType = diesel_models::events::Event;
    type NewDstType = diesel_models::events::EventNew;

    async fn convert(self) -> CustomResult<Self::DstType, ValidationError> {
        Ok(diesel_models::events::Event {
            event_id: self.event_id,
            event_type: self.event_type,
            event_class: self.event_class,
            is_webhook_notified: self.is_webhook_notified,
            primary_object_id: self.primary_object_id,
            primary_object_type: self.primary_object_type,
            created_at: self.created_at,
            merchant_id: self.merchant_id,
            business_profile_id: self.business_profile_id,
            primary_object_created_at: self.primary_object_created_at,
            idempotent_event_id: self.idempotent_event_id,
            initial_attempt_id: self.initial_attempt_id,
            request: self.request.map(Into::into),
            response: self.response.map(Into::into),
            delivery_attempt: self.delivery_attempt,
            metadata: self.metadata,
            is_overall_delivery_successful: self.is_overall_delivery_successful,
        })
    }

    async fn convert_back(
        state: &KeyManagerState,
        item: Self::DstType,
        key: &Secret<Vec<u8>>,
        key_manager_identifier: common_utils::types::keymanager::Identifier,
    ) -> CustomResult<Self, ValidationError>
    where
        Self: Sized,
    {
        let decrypted = types::crypto_operation(
            state,
            type_name!(Self::DstType),
            types::CryptoOperation::BatchDecrypt(EncryptedEvent::to_encryptable(EncryptedEvent {
                request: item.request.clone(),
                response: item.response.clone(),
            })),
            key_manager_identifier,
            key.peek(),
        )
        .await
        .and_then(|val| val.try_into_batchoperation())
        .change_context(ValidationError::InvalidValue {
            message: "Failed while decrypting event data".to_string(),
        })?;
        let encryptable_event = EncryptedEvent::from_encryptable(decrypted).change_context(
            ValidationError::InvalidValue {
                message: "Failed while decrypting event data".to_string(),
            },
        )?;
        Ok(Self {
            event_id: item.event_id,
            event_type: item.event_type,
            event_class: item.event_class,
            is_webhook_notified: item.is_webhook_notified,
            primary_object_id: item.primary_object_id,
            primary_object_type: item.primary_object_type,
            created_at: item.created_at,
            merchant_id: item.merchant_id,
            business_profile_id: item.business_profile_id,
            primary_object_created_at: item.primary_object_created_at,
            idempotent_event_id: item.idempotent_event_id,
            initial_attempt_id: item.initial_attempt_id,
            request: encryptable_event.request,
            response: encryptable_event.response,
            delivery_attempt: item.delivery_attempt,
            metadata: item.metadata,
            is_overall_delivery_successful: item.is_overall_delivery_successful,
        })
    }

    async fn construct_new(self) -> CustomResult<Self::NewDstType, ValidationError> {
        Ok(diesel_models::events::EventNew {
            event_id: self.event_id,
            event_type: self.event_type,
            event_class: self.event_class,
            is_webhook_notified: self.is_webhook_notified,
            primary_object_id: self.primary_object_id,
            primary_object_type: self.primary_object_type,
            created_at: self.created_at,
            merchant_id: self.merchant_id,
            business_profile_id: self.business_profile_id,
            primary_object_created_at: self.primary_object_created_at,
            idempotent_event_id: self.idempotent_event_id,
            initial_attempt_id: self.initial_attempt_id,
            request: self.request.map(Into::into),
            response: self.response.map(Into::into),
            delivery_attempt: self.delivery_attempt,
            metadata: self.metadata,
            is_overall_delivery_successful: self.is_overall_delivery_successful,
        })
    }
}