impl behaviour::Conversion for PaymentAttempt {
    type DstType = DieselPaymentAttempt;
    type NewDstType = DieselPaymentAttemptNew;

    async fn convert(self) -> CustomResult<Self::DstType, ValidationError> {
        use common_utils::encryption::Encryption;

        let card_network = self
            .payment_method_data
            .as_ref()
            .and_then(|data| data.peek().as_object())
            .and_then(|card| card.get("card"))
            .and_then(|data| data.as_object())
            .and_then(|card| card.get("card_network"))
            .and_then(|network| network.as_str())
            .map(|network| network.to_string());

        let Self {
            payment_id,
            merchant_id,
            status,
            error,
            amount_details,
            authentication_type,
            created_at,
            modified_at,
            last_synced,
            cancellation_reason,
            browser_info,
            payment_token,
            connector_metadata,
            payment_experience,
            payment_method_data,
            routing_result,
            preprocessing_step_id,
            multiple_capture_count,
            connector_response_reference_id,
            updated_by,
            redirection_data,
            encoded_data,
            merchant_connector_id,
            external_three_ds_authentication_attempted,
            authentication_connector,
            authentication_id,
            fingerprint_id,
            client_source,
            client_version,
            customer_acceptance,
            profile_id,
            organization_id,
            payment_method_type,
            connector_payment_id,
            payment_method_subtype,
            authentication_applied,
            external_reference_id,
            id,
            payment_method_id,
            payment_method_billing_address,
            connector,
            connector_token_details,
            card_discovery,
            charges,
            feature_metadata,
            processor_merchant_id,
            created_by,
            connector_request_reference_id,
            network_transaction_id,
        } = self;

        let AttemptAmountDetails {
            net_amount,
            tax_on_surcharge,
            surcharge_amount,
            order_tax_amount,
            shipping_cost,
            amount_capturable,
            amount_to_capture,
        } = amount_details;

        let (connector_payment_id, connector_payment_data) = connector_payment_id
            .map(ConnectorTransactionId::form_id_and_data)
            .map(|(txn_id, txn_data)| (Some(txn_id), txn_data))
            .unwrap_or((None, None));
        let feature_metadata = feature_metadata.as_ref().map(From::from);

        Ok(DieselPaymentAttempt {
            payment_id,
            merchant_id,
            id,
            status,
            error_message: error.as_ref().map(|details| details.message.clone()),
            payment_method_id,
            payment_method_type_v2: payment_method_type,
            connector_payment_id,
            authentication_type,
            created_at,
            modified_at,
            last_synced,
            cancellation_reason,
            amount_to_capture,
            browser_info,
            error_code: error.as_ref().map(|details| details.code.clone()),
            payment_token,
            connector_metadata,
            payment_experience,
            payment_method_subtype,
            payment_method_data,
            preprocessing_step_id,
            error_reason: error.as_ref().and_then(|details| details.reason.clone()),
            multiple_capture_count,
            connector_response_reference_id,
            amount_capturable,
            updated_by,
            merchant_connector_id,
            redirection_data: redirection_data.map(From::from),
            encoded_data,
            unified_code: error
                .as_ref()
                .and_then(|details| details.unified_code.clone()),
            unified_message: error
                .as_ref()
                .and_then(|details| details.unified_message.clone()),
            net_amount,
            external_three_ds_authentication_attempted,
            authentication_connector,
            authentication_id,
            fingerprint_id,
            client_source,
            client_version,
            customer_acceptance,
            profile_id,
            organization_id,
            card_network,
            order_tax_amount,
            shipping_cost,
            routing_result,
            authentication_applied,
            external_reference_id,
            connector,
            surcharge_amount,
            tax_on_surcharge,
            payment_method_billing_address: payment_method_billing_address.map(Encryption::from),
            connector_payment_data,
            connector_token_details,
            card_discovery,
            request_extended_authorization: None,
            extended_authorization_applied: None,
            capture_before: None,
            charges,
            feature_metadata,
            network_advice_code: error
                .as_ref()
                .and_then(|details| details.network_advice_code.clone()),
            network_decline_code: error
                .as_ref()
                .and_then(|details| details.network_decline_code.clone()),
            network_error_message: error
                .as_ref()
                .and_then(|details| details.network_error_message.clone()),
            processor_merchant_id: Some(processor_merchant_id),
            created_by: created_by.map(|cb| cb.to_string()),
            connector_request_reference_id,
            network_transaction_id,
        })
    }

    async fn convert_back(
        state: &KeyManagerState,
        storage_model: Self::DstType,
        key: &Secret<Vec<u8>>,
        key_manager_identifier: keymanager::Identifier,
    ) -> CustomResult<Self, ValidationError>
    where
        Self: Sized,
    {
        async {
            let connector_payment_id = storage_model
                .get_optional_connector_transaction_id()
                .cloned();

            let decrypted_data = crypto_operation(
                state,
                common_utils::type_name!(Self::DstType),
                CryptoOperation::BatchDecrypt(EncryptedPaymentAttempt::to_encryptable(
                    EncryptedPaymentAttempt {
                        payment_method_billing_address: storage_model
                            .payment_method_billing_address,
                    },
                )),
                key_manager_identifier,
                key.peek(),
            )
            .await
            .and_then(|val| val.try_into_batchoperation())?;

            let decrypted_data = EncryptedPaymentAttempt::from_encryptable(decrypted_data)
                .change_context(common_utils::errors::CryptoError::DecodingFailed)
                .attach_printable("Invalid batch operation data")?;

            let payment_method_billing_address = decrypted_data
                .payment_method_billing_address
                .map(|billing| {
                    billing.deserialize_inner_value(|value| value.parse_value("Address"))
                })
                .transpose()
                .change_context(common_utils::errors::CryptoError::DecodingFailed)
                .attach_printable("Error while deserializing Address")?;

            let amount_details = AttemptAmountDetails {
                net_amount: storage_model.net_amount,
                tax_on_surcharge: storage_model.tax_on_surcharge,
                surcharge_amount: storage_model.surcharge_amount,
                order_tax_amount: storage_model.order_tax_amount,
                shipping_cost: storage_model.shipping_cost,
                amount_capturable: storage_model.amount_capturable,
                amount_to_capture: storage_model.amount_to_capture,
            };

            let error = storage_model
                .error_code
                .zip(storage_model.error_message)
                .map(|(error_code, error_message)| ErrorDetails {
                    code: error_code,
                    message: error_message,
                    reason: storage_model.error_reason,
                    unified_code: storage_model.unified_code,
                    unified_message: storage_model.unified_message,
                    network_advice_code: storage_model.network_advice_code,
                    network_decline_code: storage_model.network_decline_code,
                    network_error_message: storage_model.network_error_message,
                });

            Ok::<Self, error_stack::Report<common_utils::errors::CryptoError>>(Self {
                payment_id: storage_model.payment_id,
                merchant_id: storage_model.merchant_id.clone(),
                id: storage_model.id,
                status: storage_model.status,
                amount_details,
                error,
                payment_method_id: storage_model.payment_method_id,
                payment_method_type: storage_model.payment_method_type_v2,
                connector_payment_id,
                authentication_type: storage_model.authentication_type,
                created_at: storage_model.created_at,
                modified_at: storage_model.modified_at,
                last_synced: storage_model.last_synced,
                cancellation_reason: storage_model.cancellation_reason,
                browser_info: storage_model.browser_info,
                payment_token: storage_model.payment_token,
                connector_metadata: storage_model.connector_metadata,
                payment_experience: storage_model.payment_experience,
                payment_method_data: storage_model.payment_method_data,
                routing_result: storage_model.routing_result,
                preprocessing_step_id: storage_model.preprocessing_step_id,
                multiple_capture_count: storage_model.multiple_capture_count,
                connector_response_reference_id: storage_model.connector_response_reference_id,
                updated_by: storage_model.updated_by,
                redirection_data: storage_model.redirection_data.map(From::from),
                encoded_data: storage_model.encoded_data,
                merchant_connector_id: storage_model.merchant_connector_id,
                external_three_ds_authentication_attempted: storage_model
                    .external_three_ds_authentication_attempted,
                authentication_connector: storage_model.authentication_connector,
                authentication_id: storage_model.authentication_id,
                fingerprint_id: storage_model.fingerprint_id,
                charges: storage_model.charges,
                client_source: storage_model.client_source,
                client_version: storage_model.client_version,
                customer_acceptance: storage_model.customer_acceptance,
                profile_id: storage_model.profile_id,
                organization_id: storage_model.organization_id,
                payment_method_subtype: storage_model.payment_method_subtype,
                authentication_applied: storage_model.authentication_applied,
                external_reference_id: storage_model.external_reference_id,
                connector: storage_model.connector,
                payment_method_billing_address,
                connector_token_details: storage_model.connector_token_details,
                card_discovery: storage_model.card_discovery,
                feature_metadata: storage_model.feature_metadata.map(From::from),
                processor_merchant_id: storage_model
                    .processor_merchant_id
                    .unwrap_or(storage_model.merchant_id),
                created_by: storage_model
                    .created_by
                    .and_then(|created_by| created_by.parse::<CreatedBy>().ok()),
                connector_request_reference_id: storage_model.connector_request_reference_id,
                network_transaction_id: storage_model.network_transaction_id,
            })
        }
        .await
        .change_context(ValidationError::InvalidValue {
            message: "Failed while decrypting payment attempt".to_string(),
        })
    }

    async fn construct_new(self) -> CustomResult<Self::NewDstType, ValidationError> {
        use common_utils::encryption::Encryption;
        let Self {
            payment_id,
            merchant_id,
            status,
            error,
            amount_details,
            authentication_type,
            created_at,
            modified_at,
            last_synced,
            cancellation_reason,
            browser_info,
            payment_token,
            connector_metadata,
            payment_experience,
            payment_method_data,
            routing_result: _,
            preprocessing_step_id,
            multiple_capture_count,
            connector_response_reference_id,
            updated_by,
            redirection_data,
            encoded_data,
            merchant_connector_id,
            external_three_ds_authentication_attempted,
            authentication_connector,
            authentication_id,
            fingerprint_id,
            client_source,
            client_version,
            customer_acceptance,
            profile_id,
            organization_id,
            payment_method_type,
            connector_payment_id,
            payment_method_subtype,
            authentication_applied: _,
            external_reference_id: _,
            id,
            payment_method_id,
            payment_method_billing_address,
            connector,
            connector_token_details,
            card_discovery,
            charges,
            feature_metadata,
            processor_merchant_id,
            created_by,
            connector_request_reference_id,
            network_transaction_id,
        } = self;

        let card_network = payment_method_data
            .as_ref()
            .and_then(|data| data.peek().as_object())
            .and_then(|card| card.get("card"))
            .and_then(|data| data.as_object())
            .and_then(|card| card.get("card_network"))
            .and_then(|network| network.as_str())
            .map(|network| network.to_string());

        let error_details = error;

        Ok(DieselPaymentAttemptNew {
            payment_id,
            merchant_id,
            status,
            network_transaction_id,
            error_message: error_details
                .as_ref()
                .map(|details| details.message.clone()),
            surcharge_amount: amount_details.surcharge_amount,
            tax_on_surcharge: amount_details.tax_on_surcharge,
            payment_method_id,
            authentication_type,
            created_at,
            modified_at,
            last_synced,
            cancellation_reason,
            browser_info,
            payment_token,
            error_code: error_details.as_ref().map(|details| details.code.clone()),
            connector_metadata,
            payment_experience,
            payment_method_data,
            preprocessing_step_id,
            error_reason: error_details
                .as_ref()
                .and_then(|details| details.reason.clone()),
            connector_response_reference_id,
            multiple_capture_count,
            amount_capturable: amount_details.amount_capturable,
            updated_by,
            merchant_connector_id,
            redirection_data: redirection_data.map(From::from),
            encoded_data,
            unified_code: error_details
                .as_ref()
                .and_then(|details| details.unified_code.clone()),
            unified_message: error_details
                .as_ref()
                .and_then(|details| details.unified_message.clone()),
            net_amount: amount_details.net_amount,
            external_three_ds_authentication_attempted,
            authentication_connector,
            authentication_id,
            fingerprint_id,
            client_source,
            client_version,
            customer_acceptance,
            profile_id,
            organization_id,
            card_network,
            order_tax_amount: amount_details.order_tax_amount,
            shipping_cost: amount_details.shipping_cost,
            amount_to_capture: amount_details.amount_to_capture,
            payment_method_billing_address: payment_method_billing_address.map(Encryption::from),
            payment_method_subtype,
            connector_payment_id: connector_payment_id
                .as_ref()
                .map(|txn_id| ConnectorTransactionId::TxnId(txn_id.clone())),
            payment_method_type_v2: payment_method_type,
            id,
            charges,
            connector_token_details,
            card_discovery,
            extended_authorization_applied: None,
            request_extended_authorization: None,
            capture_before: None,
            feature_metadata: feature_metadata.as_ref().map(From::from),
            connector,
            network_advice_code: error_details
                .as_ref()
                .and_then(|details| details.network_advice_code.clone()),
            network_decline_code: error_details
                .as_ref()
                .and_then(|details| details.network_decline_code.clone()),
            network_error_message: error_details
                .as_ref()
                .and_then(|details| details.network_error_message.clone()),
            processor_merchant_id: Some(processor_merchant_id),
            created_by: created_by.map(|cb| cb.to_string()),
            connector_request_reference_id,
        })
    }
}

impl behaviour::Conversion for for PaymentAttempt


OpenAPI Block Path: components.schemas.AttemptStatus
{
  "type": "string",
  "description": "The status of the attempt",
  "enum": [
    "started",
    "authentication_failed",
    "router_declined",
    "authentication_pending",
    "authentication_successful",
    "authorized",
    "authorization_failed",
    "charged",
    "authorizing",
    "cod_initiated",
    "voided",
    "voided_post_charge",
    "void_initiated",
    "capture_initiated",
    "capture_failed",
    "void_failed",
    "auto_refunded",
    "partial_charged",
    "partially_authorized",
    "partial_charged_and_chargeable",
    "unresolved",
    "pending",
    "failure",
    "payment_method_awaited",
    "confirmation_awaited",
    "device_data_collection_pending",
    "integrity_failure",
    "expired"
  ]
}


pub struct XenditAuthType {
    pub(super) api_key: Secret<String>,
}


impl api::PaymentsPreProcessing for Gocardless {}

impl api::PaymentsPreProcessing for for Gocardless


pub fn server(state: AppState) -> Scope {
        web::scope("/gsm")
            .app_data(web::Data::new(state))
            .service(web::resource("").route(web::post().to(gsm::create_gsm_rule)))
            .service(web::resource("/get").route(web::post().to(gsm::get_gsm_rule)))
            .service(web::resource("/update").route(web::post().to(gsm::update_gsm_rule)))
            .service(web::resource("/delete").route(web::post().to(gsm::delete_gsm_rule)))
    }


    #[strum(serialize = "120")]
    HorniPocernice,
    #[strum(serialize = "521")]
    HradecKraloveDistrict,
    #[strum(serialize = "52")]
    HradecKraloveRegion,
    #[strum(serialize = "512")]
    JablonecNadNisouDistrict,
    #[strum(serialize = "711")]
    JesenikDistrict,
    #[strum(serialize = "632")]
    JihlavaDistrict,
    #[strum(serialize = "313")]
    JindrichuvHradecDistrict,
    #[strum(serialize = "522")]
    JicinDistrict,
    #[strum(serialize = "412")]
    KarlovyVaryDistrict,
    #[strum(serialize = "41")]
    KarlovyVaryRegion,
    #[strum(serialize = "803")]
    KarvinaDistrict,
    #[strum(serialize = "203")]
    KladnoDistrict,
    #[strum(serialize = "322")]
    KlatovyDistrict,
    #[strum(serialize = "204")]
    KolinDistrict,
    #[strum(serialize = "721")]
    KromerizDistrict,
    #[strum(serialize = "513")]
    LiberecDistrict,
    #[strum(serialize = "51")]
    LiberecRegion,
    #[strum(serialize = "423")]
    LitomericeDistrict,
    #[strum(serialize = "424")]
    LounyDistrict,
    #[strum(serialize = "207")]
    MladaBoleslavDistrict,
    #[strum(serialize = "80")]
    MoravianSilesianRegion,
    #[strum(serialize = "425")]
    MostDistrict,
    #[strum(serialize = "206")]
    MelnikDistrict,
    #[strum(serialize = "804")]
    NovyJicinDistrict,
    #[strum(serialize = "208")]
    NymburkDistrict,
    #[strum(serialize = "523")]
    NachodDistrict,
    #[strum(serialize = "712")]
    OlomoucDistrict,
    #[strum(serialize = "71")]
    OlomoucRegion,
    #[strum(serialize = "805")]
    OpavaDistrict,
    #[strum(serialize = "806")]
    OstravaCityDistrict,
    #[strum(serialize = "532")]
    PardubiceDistrict,
    #[strum(serialize = "53")]
    PardubiceRegion,
    #[strum(serialize = "633")]
    PelhrimovDistrict,
    #[strum(serialize = "32")]
    PlzenRegion,
    #[strum(serialize = "323")]
    PlzenCityDistrict,
    #[strum(serialize = "325")]
    PlzenNorthDistrict,
    #[strum(serialize = "324")]
    PlzenSouthDistrict,
    #[strum(serialize = "315")]
    PrachaticeDistrict,
    #[strum(serialize = "10")]
    Prague,
    #[strum(serialize = "101")]
    Prague1,
    #[strum(serialize = "110")]
    Prague10,
    #[strum(serialize = "111")]
    Prague11,
    #[strum(serialize = "112")]
    Prague12,
    #[strum(serialize = "113")]
    Prague13,
    #[strum(serialize = "114")]
    Prague14,
    #[strum(serialize = "115")]
    Prague15,
    #[strum(serialize = "116")]
    Prague16,
    #[strum(serialize = "102")]
    Prague2,
    #[strum(serialize = "121")]
    Prague21,
    #[strum(serialize = "103")]
    Prague3,
    #[strum(serialize = "104")]
    Prague4,
    #[strum(serialize = "105")]
    Prague5,
    #[strum(serialize = "106")]
    Prague6,
    #[strum(serialize = "107")]
    Prague7,
    #[strum(serialize = "108")]
    Prague8,
    #[strum(serialize = "109")]
    Prague9,
    #[strum(serialize = "209")]
    PragueEastDistrict,
    #[strum(serialize = "20A")]
    PragueWestDistrict,
    #[strum(serialize = "713")]
    ProstejovDistrict,
    #[strum(serialize = "314")]
    PisekDistrict,
    #[strum(serialize = "714")]
    PrerovDistrict,
    #[strum(serialize = "20B")]
    PribramDistrict,
    #[strum(serialize = "20C")]
    RakovnikDistrict,
    #[strum(serialize = "326")]
    RokycanyDistrict,
    #[strum(serialize = "524")]
    RychnovNadKneznouDistrict,
    #[strum(serialize = "514")]
    SemilyDistrict,
    #[strum(serialize = "413")]
    SokolovDistrict,
    #[strum(serialize = "31")]
    SouthBohemianRegion,
    #[strum(serialize = "64")]
    SouthMoravianRegion,
    #[strum(serialize = "316")]
    StrakoniceDistrict,
    #[strum(serialize = "533")]
    SvitavyDistrict,
    #[strum(serialize = "327")]
    TachovDistrict,
    #[strum(serialize = "426")]
    TepliceDistrict,
    #[strum(serialize = "525")]
    TrutnovDistrict,
    #[strum(serialize = "317")]
    TaborDistrict,
    #[strum(serialize = "634")]
    TrebicDistrict,
    #[strum(serialize = "722")]
    UherskeHradisteDistrict,
    #[strum(serialize = "723")]
    VsetinDistrict,
    #[strum(serialize = "63")]
    VysocinaRegion,
    #[strum(serialize = "646")]
    VyskovDistrict,
    #[strum(serialize = "724")]
    ZlinDistrict,
    #[strum(serialize = "72")]
    ZlinRegion,
    #[strum(serialize = "647")]
    ZnojmoDistrict,
    #[strum(serialize = "427")]
    UstiNadLabemDistrict,
    #[strum(serialize = "42")]
    UstiNadLabemRegion,
    #[strum(serialize = "534")]
    UstiNadOrliciDistrict,
    #[strum(serialize = "511")]
    CeskaLipaDistrict,
    #[strum(serialize = "311")]
    CeskeBudejoviceDistrict,
    #[strum(serialize = "312")]
    CeskyKrumlovDistrict,
    #[strum(serialize = "715")]
    SumperkDistrict,
    #[strum(serialize = "635")]
    ZdarNadSazavouDistrict,
}

#[derive(
    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, strum::Display, strum::EnumString,
)]
pub enum DenmarkStatesAbbreviation {
    #[strum(serialize = "84")]
    CapitalRegionOfDenmark,
    #[strum(serialize = "82")]
    CentralDenmarkRegion,
    #[strum(serialize = "81")]
    NorthDenmarkRegion,
    #[strum(serialize = "85")]
    RegionZealand,
    #[strum(serialize = "83")]
    RegionOfSouthernDenmark,
}

#[derive(
    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, strum::Display, strum::EnumString,
)]
pub enum FinlandStatesAbbreviation {
    #[strum(serialize = "08")]
    CentralFinland,
    #[strum(serialize = "07")]
    CentralOstrobothnia,
    #[strum(serialize = "IS")]
    EasternFinlandProvince,
    #[strum(serialize = "19")]
    FinlandProper,
    #[strum(serialize = "05")]
    Kainuu,
    #[strum(serialize = "09")]
    Kymenlaakso,
    #[strum(serialize = "LL")]
    Lapland,
    #[strum(serialize = "13")]
    NorthKarelia,
    #[strum(serialize = "14")]
    NorthernOstrobothnia,
    #[strum(serialize = "15")]
    NorthernSavonia,
    #[strum(serialize = "12")]
    Ostrobothnia,
    #[strum(serialize = "OL")]
    OuluProvince,
    #[strum(serialize = "11")]
    Pirkanmaa,
    #[strum(serialize = "16")]
    PaijanneTavastia,
    #[strum(serialize = "17")]
    Satakunta,
    #[strum(serialize = "02")]
    SouthKarelia,
    #[strum(serialize = "03")]
    SouthernOstrobothnia,
    #[strum(serialize = "04")]
    SouthernSavonia,
    #[strum(serialize = "06")]
    TavastiaProper,
    #[strum(serialize = "18")]
    Uusimaa,
    #[strum(serialize = "01")]
    AlandIslands,
}

#[derive(
    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, strum::Display, strum::EnumString,
)]
pub enum FranceStatesAbbreviation {
    #[strum(serialize = "01")]
    Ain,
    #[strum(serialize = "02")]
    Aisne,
    #[strum(serialize = "03")]
    Allier,
    #[strum(serialize = "04")]
    AlpesDeHauteProvence,
    #[strum(serialize = "06")]
    AlpesMaritimes,
    #[strum(serialize = "6AE")]
    Alsace,
    #[strum(serialize = "07")]
    Ardeche,
    #[strum(serialize = "08")]
    Ardennes,
    #[strum(serialize = "09")]
    Ariege,
    #[strum(serialize = "10")]
    Aube,
    #[strum(serialize = "11")]
    Aude,
    #[strum(serialize = "ARA")]
    AuvergneRhoneAlpes,
    #[strum(serialize = "12")]
    Aveyron,
    #[strum(serialize = "67")]
    BasRhin,
    #[strum(serialize = "13")]
    BouchesDuRhone,
    #[strum(serialize = "BFC")]
    BourgogneFrancheComte,
    #[strum(serialize = "BRE")]
    Bretagne,
    #[strum(serialize = "14")]
    Calvados,
    #[strum(serialize = "15")]
    Cantal,
    #[strum(serialize = "CVL")]
    CentreValDeLoire,
    #[strum(serialize = "16")]
    Charente,
    #[strum(serialize = "17")]
    CharenteMaritime,
    #[strum(serialize = "18")]
    Cher,
    #[strum(serialize = "CP")]
    Clipperton,
    #[strum(serialize = "19")]
    Correze,
    #[strum(serialize = "20R")]
    Corse,
    #[strum(serialize = "2A")]
    CorseDuSud,
    #[strum(serialize = "21")]
    CoteDor,
    #[strum(serialize = "22")]
    CotesDarmor,
    #[strum(serialize = "23")]
    Creuse,
    #[strum(serialize = "79")]
    DeuxSevres,
    #[strum(serialize = "24")]
    Dordogne,
    #[strum(serialize = "25")]
    Doubs,
    #[strum(serialize = "26")]
    Drome,
    #[strum(serialize = "91")]
    Essonne,
    #[strum(serialize = "27")]
    Eure,
    #[strum(serialize = "28")]
    EureEtLoir,
    #[strum(serialize = "29")]
    Finistere,
    #[strum(serialize = "973")]
    FrenchGuiana,
    #[strum(serialize = "PF")]
    FrenchPolynesia,
    #[strum(serialize = "TF")]
    FrenchSouthernAndAntarcticLands,
    #[strum(serialize = "30")]
    Gard,
    #[strum(serialize = "32")]
    Gers,
    #[strum(serialize = "33")]
    Gironde,
    #[strum(serialize = "GES")]
    GrandEst,
    #[strum(serialize = "971")]
    Guadeloupe,
    #[strum(serialize = "68")]
    HautRhin,
    #[strum(serialize = "2B")]
    HauteCorse,
    #[strum(serialize = "31")]
    HauteGaronne,
    #[strum(serialize = "43")]
    HauteLoire,
    #[strum(serialize = "52")]
    HauteMarne,
    #[strum(serialize = "70")]
    HauteSaone,
    #[strum(serialize = "74")]
    HauteSavoie,
    #[strum(serialize = "87")]
    HauteVienne,
    #[strum(serialize = "05")]
    HautesAlpes,
    #[strum(serialize = "65")]
    HautesPyrenees,
    #[strum(serialize = "HDF")]
    HautsDeFrance,
    #[strum(serialize = "92")]
    HautsDeSeine,
    #[strum(serialize = "34")]
    Herault,
    #[strum(serialize = "IDF")]
    IleDeFrance,
    #[strum(serialize = "35")]
    IlleEtVilaine,
    #[strum(serialize = "36")]
    Indre,
    #[strum(serialize = "37")]
    IndreEtLoire,
    #[strum(serialize = "38")]
    Isere,
    #[strum(serialize = "39")]
    Jura,
    #[strum(serialize = "974")]
    LaReunion,
    #[strum(serialize = "40")]
    Landes,
    #[strum(serialize = "41")]
    LoirEtCher,
    #[strum(serialize = "42")]
    Loire,
    #[strum(serialize = "44")]
    LoireAtlantique,
    #[strum(serialize = "45")]
    Loiret,
    #[strum(serialize = "46")]
    Lot,
    #[strum(serialize = "47")]
    LotEtGaronne,
    #[strum(serialize = "48")]
    Lozere,
    #[strum(serialize = "49")]
    MaineEtLoire,
    #[strum(serialize = "50")]
    Manche,
    #[strum(serialize = "51")]
    Marne,
    #[strum(serialize = "972")]
    Martinique,
    #[strum(serialize = "53")]
    Mayenne,
    #[strum(serialize = "976")]
    Mayotte,
    #[strum(serialize = "69M")]
    MetropoleDeLyon,
    #[strum(serialize = "54")]
    MeurtheEtMoselle,
    #[strum(serialize = "55")]
    Meuse,
    #[strum(serialize = "56")]
    Morbihan,
    #[strum(serialize = "57")]
    Moselle,
    #[strum(serialize = "58")]
    Nievre,
    #[strum(serialize = "59")]
    Nord,
    #[strum(serialize = "NOR")]
    Normandie,
    #[strum(serialize = "NAQ")]
    NouvelleAquitaine,
    #[strum(serialize = "OCC")]
    Occitanie,
    #[strum(serialize = "60")]
    Oise,
    #[strum(serialize = "61")]
    Orne,
    #[strum(serialize = "75C")]
    Paris,
    #[strum(serialize = "62")]
    PasDeCalais,
    #[strum(serialize = "PDL")]
    PaysDeLaLoire,
    #[strum(serialize = "PAC")]
    ProvenceAlpesCoteDazur,
    #[strum(serialize = "63")]
    PuyDeDome,
    #[strum(serialize = "64")]
    PyreneesAtlantiques,
    #[strum(serialize = "66")]
    PyreneesOrientales,
    #[strum(serialize = "69")]
    Rhone,
    #[strum(serialize = "PM")]
    SaintPierreAndMiquelon,
    #[strum(serialize = "BL")]
    SaintBarthelemy,
    #[strum(serialize = "MF")]
    SaintMartin,
    #[strum(serialize = "71")]
    SaoneEtLoire,
    #[strum(serialize = "72")]
    Sarthe,
    #[strum(serialize = "73")]
    Savoie,
    #[strum(serialize = "77")]
    SeineEtMarne,
    #[strum(serialize = "76")]
    SeineMaritime,
    #[strum(serialize = "93")]
    SeineSaintDenis,
    #[strum(serialize = "80")]
    Somme,
    #[strum(serialize = "81")]
    Tarn,
    #[strum(serialize = "82")]
    TarnEtGaronne,
    #[strum(serialize = "90")]
    TerritoireDeBelfort,
    #[strum(serialize = "95")]
    ValDoise,
    #[strum(serialize = "94")]
    ValDeMarne,
    #[strum(serialize = "83")]
    Var,
    #[strum(serialize = "84")]
    Vaucluse,
    #[strum(serialize = "85")]
    Vendee,
    #[strum(serialize = "86")]
    Vienne,
    #[strum(serialize = "88")]
    Vosges,
    #[strum(serialize = "WF")]
    WallisAndFutuna,
    #[strum(serialize = "89")]
    Yonne,
    #[strum(serialize = "78")]
    Yvelines,
}

#[derive(
    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, strum::Display, strum::EnumString,
)]
pub enum GermanyStatesAbbreviation {
    BW,
    BY,
    BE,
    BB,
    HB,
    HH,
    HE,
    NI,
    MV,
    NW,
    RP,
    SL,
    SN,
    ST,
    SH,
    TH,
}

#[derive(
    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, strum::Display, strum::EnumString,
)]
pub enum GreeceStatesAbbreviation {
    #[strum(serialize = "13")]
    AchaeaRegionalUnit,
    #[strum(serialize = "01")]
    AetoliaAcarnaniaRegionalUnit,
    #[strum(serialize = "12")]
    ArcadiaPrefecture,
    #[strum(serialize = "11")]
    ArgolisRegionalUnit,
    #[strum(serialize = "I")]
    AtticaRegion,
    #[strum(serialize = "03")]
    BoeotiaRegionalUnit,
    #[strum(serialize = "H")]
    CentralGreeceRegion,
    #[strum(serialize = "B")]
    CentralMacedonia,
    #[strum(serialize = "94")]
    ChaniaRegionalUnit,
    #[strum(serialize = "22")]
    CorfuPrefecture,
    #[strum(serialize = "15")]
    CorinthiaRegionalUnit,
    #[strum(serialize = "M")]
    CreteRegion,
    #[strum(serialize = "52")]
    DramaRegionalUnit,
    #[strum(serialize = "A2")]
    EastAtticaRegionalUnit,
    #[strum(serialize = "A")]
    EastMacedoniaAndThrace,
    #[strum(serialize = "D")]
    EpirusRegion,
    #[strum(serialize = "04")]
    Euboea,
    #[strum(serialize = "51")]
    GrevenaPrefecture,
    #[strum(serialize = "53")]
    ImathiaRegionalUnit,
    #[strum(serialize = "33")]
    IoanninaRegionalUnit,
    #[strum(serialize = "F")]
    IonianIslandsRegion,
    #[strum(serialize = "41")]
    KarditsaRegionalUnit,
    #[strum(serialize = "56")]
    KastoriaRegionalUnit,
    #[strum(serialize = "23")]
    KefaloniaPrefecture,
    #[strum(serialize = "57")]
    KilkisRegionalUnit,
    #[strum(serialize = "58")]
    KozaniPrefecture,
    #[strum(serialize = "16")]
    Laconia,
    #[strum(serialize = "42")]
    LarissaPrefecture,
    #[strum(serialize = "24")]
    LefkadaRegionalUnit,
    #[strum(serialize = "59")]
    PellaRegionalUnit,
    #[strum(serialize = "J")]
    PeloponneseRegion,
    #[strum(serialize = "06")]
    PhthiotisPrefecture,
    #[strum(serialize = "34")]
    PrevezaPrefecture,
    #[strum(serialize = "62")]
    SerresPrefecture,
    #[strum(serialize = "L")]
    SouthAegean,
    #[strum(serialize = "54")]
    ThessalonikiRegionalUnit,
    #[strum(serialize = "G")]
    WestGreeceRegion,
    #[strum(serialize = "C")]
    WestMacedoniaRegion,
}

#[derive(
    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, strum::Display, strum::EnumString,
)]
pub enum HungaryStatesAbbreviation {
    #[strum(serialize = "BA")]
    BaranyaCounty,
    #[strum(serialize = "BZ")]
    BorsodAbaujZemplenCounty,
    #[strum(serialize = "BU")]
    Budapest,
    #[strum(serialize = "BK")]
    BacsKiskunCounty,
    #[strum(serialize = "BE")]
    BekesCounty,
    #[strum(serialize = "BC")]
    Bekescsaba,
    #[strum(serialize = "CS")]
    CsongradCounty,
    #[strum(serialize = "DE")]
    Debrecen,
    #[strum(serialize = "DU")]
    Dunaujvaros,
    #[strum(serialize = "EG")]
    Eger,
    #[strum(serialize = "FE")]
    FejerCounty,
    #[strum(serialize = "GY")]
    Gyor,
    #[strum(serialize = "GS")]
    GyorMosonSopronCounty,
    #[strum(serialize = "HB")]
    HajduBiharCounty,
    #[strum(serialize = "HE")]
    HevesCounty,
    #[strum(serialize = "HV")]
    Hodmezovasarhely,
    #[strum(serialize = "JN")]
    JaszNagykunSzolnokCounty,
    #[strum(serialize = "KV")]
    Kaposvar,
    #[strum(serialize = "KM")]
    Kecskemet,
    #[strum(serialize = "MI")]
    Miskolc,
    #[strum(serialize = "NK")]
    Nagykanizsa,
    #[strum(serialize = "NY")]
    Nyiregyhaza,
    #[strum(serialize = "NO")]
    NogradCounty,
    #[strum(serialize = "PE")]
    PestCounty,
    #[strum(serialize = "PS")]
    Pecs,
    #[strum(serialize = "ST")]
    Salgotarjan,
    #[strum(serialize = "SO")]
    SomogyCounty,
    #[strum(serialize = "SN")]
    Sopron,
    #[strum(serialize = "SZ")]
    SzabolcsSzatmarBeregCounty,
    #[strum(serialize = "SD")]
    Szeged,
    #[strum(serialize = "SS")]
    Szekszard,
    #[strum(serialize = "SK")]
    Szolnok,
    #[strum(serialize = "SH")]
    Szombathely,
    #[strum(serialize = "SF")]
    Szekesfehervar,
    #[strum(serialize = "TB")]
    Tatabanya,
    #[strum(serialize = "TO")]
    TolnaCounty,
    #[strum(serialize = "VA")]
    VasCounty,
    #[strum(serialize = "VM")]
    Veszprem,
    #[strum(serialize = "VE")]
    VeszpremCounty,
    #[strum(serialize = "ZA")]
    ZalaCounty,
    #[strum(serialize = "ZE")]
    Zalaegerszeg,
    #[strum(serialize = "ER")]
    Erd,
}

#[derive(
    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, strum::Display, strum::EnumString,
)]
pub enum IcelandStatesAbbreviation {
    #[strum(serialize = "1")]
    CapitalRegion,
    #[strum(serialize = "7")]
    EasternRegion,
    #[strum(serialize = "6")]
    NortheasternRegion,
    #[strum(serialize = "5")]
    NorthwesternRegion,
    #[strum(serialize = "2")]
    SouthernPeninsulaRegion,
    #[strum(serialize = "8")]
    SouthernRegion,
    #[strum(serialize = "3")]
    WesternRegion,
    #[strum(serialize = "4")]
    Westfjords,
}

#[derive(
    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, strum::Display, strum::EnumString,
)]
pub enum IrelandStatesAbbreviation {
    #[strum(serialize = "C")]
    Connacht,
    #[strum(serialize = "CW")]
    CountyCarlow,
    #[strum(serialize = "CN")]
    CountyCavan,
    #[strum(serialize = "CE")]
    CountyClare,
    #[strum(serialize = "CO")]
    CountyCork,
    #[strum(serialize = "DL")]
    CountyDonegal,
    #[strum(serialize = "D")]
    CountyDublin,
    #[strum(serialize = "G")]
    CountyGalway,
    #[strum(serialize = "KY")]
    CountyKerry,
    #[strum(serialize = "KE")]
    CountyKildare,
    #[strum(serialize = "KK")]
    CountyKilkenny,
    #[strum(serialize = "LS")]
    CountyLaois,
    #[strum(serialize = "LK")]
    CountyLimerick,
    #[strum(serialize = "LD")]
    CountyLongford,
    #[strum(serialize = "LH")]
    CountyLouth,
    #[strum(serialize = "MO")]
    CountyMayo,
    #[strum(serialize = "MH")]
    CountyMeath,
    #[strum(serialize = "MN")]
    CountyMonaghan,
    #[strum(serialize = "OY")]
    CountyOffaly,
    #[strum(serialize = "RN")]
    CountyRoscommon,
    #[strum(serialize = "SO")]
    CountySligo,
    #[strum(serialize = "TA")]
    CountyTipperary,
    #[strum(serialize = "WD")]
    CountyWaterford,
    #[strum(serialize = "WH")]
    CountyWestmeath,
    #[strum(serialize = "WX")]
    CountyWexford,
    #[strum(serialize = "WW")]
    CountyWicklow,
    #[strum(serialize = "L")]
    Leinster,
    #[strum(serialize = "M")]
    Munster,
    #[strum(serialize = "U")]
    Ulster,
}

#[derive(
    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, strum::Display, strum::EnumString,
)]
pub enum LatviaStatesAbbreviation {
    #[strum(serialize = "001")]
    AglonaMunicipality,
    #[strum(serialize = "002")]
    AizkraukleMunicipality,
    #[strum(serialize = "003")]
    AizputeMunicipality,
    #[strum(serialize = "004")]
    AknīsteMunicipality,
    #[strum(serialize = "005")]
    AlojaMunicipality,
    #[strum(serialize = "006")]
    AlsungaMunicipality,
    #[strum(serialize = "007")]
    AlūksneMunicipality,
    #[strum(serialize = "008")]
    AmataMunicipality,
    #[strum(serialize = "009")]
    ApeMunicipality,
    #[strum(serialize = "010")]
    AuceMunicipality,
    #[strum(serialize = "012")]
    BabīteMunicipality,
    #[strum(serialize = "013")]
    BaldoneMunicipality,
    #[strum(serialize = "014")]
    BaltinavaMunicipality,
    #[strum(serialize = "015")]
    BalviMunicipality,
    #[strum(serialize = "016")]
    BauskaMunicipality,
    #[strum(serialize = "017")]
    BeverīnaMunicipality,
    #[strum(serialize = "018")]
    BrocēniMunicipality,
    #[strum(serialize = "019")]
    BurtniekiMunicipality,
    #[strum(serialize = "020")]
    CarnikavaMunicipality,
    #[strum(serialize = "021")]
    CesvaineMunicipality,
    #[strum(serialize = "023")]
    CiblaMunicipality,
    #[strum(serialize = "022")]
    CēsisMunicipality,
    #[strum(serialize = "024")]
    DagdaMunicipality,
    #[strum(serialize = "DGV")]
    Daugavpils,
    #[strum(serialize = "025")]
    DaugavpilsMunicipality,
    #[strum(serialize = "026")]
    DobeleMunicipality,
    #[strum(serialize = "027")]
    DundagaMunicipality,
    #[strum(serialize = "028")]
    DurbeMunicipality,
    #[strum(serialize = "029")]
    EngureMunicipality,
    #[strum(serialize = "031")]
    GarkalneMunicipality,
    #[strum(serialize = "032")]
    GrobiņaMunicipality,
    #[strum(serialize = "033")]
    GulbeneMunicipality,
    #[strum(serialize = "034")]
    IecavaMunicipality,
    #[strum(serialize = "035")]
    IkšķileMunicipality,
    #[strum(serialize = "036")]
    IlūksteMunicipality,
    #[strum(serialize = "037")]
    InčukalnsMunicipality,
    #[strum(serialize = "038")]
    JaunjelgavaMunicipality,
    #[strum(serialize = "039")]
    JaunpiebalgaMunicipality,
    #[strum(serialize = "040")]
    JaunpilsMunicipality,
    #[strum(serialize = "JEL")]
    Jelgava,
    #[strum(serialize = "041")]
    JelgavaMunicipality,
    #[strum(serialize = "JKB")]
    Jēkabpils,
    #[strum(serialize = "042")]
    JēkabpilsMunicipality,
    #[strum(serialize = "JUR")]
    Jūrmala,
    #[strum(serialize = "043")]
    KandavaMunicipality,
    #[strum(serialize = "045")]
    KocēniMunicipality,
    #[strum(serialize = "046")]
    KokneseMunicipality,
    #[strum(serialize = "048")]
    KrimuldaMunicipality,
    #[strum(serialize = "049")]
    KrustpilsMunicipality,
    #[strum(serialize = "047")]
    KrāslavaMunicipality,
    #[strum(serialize = "050")]
    KuldīgaMunicipality,
    #[strum(serialize = "044")]
    KārsavaMunicipality,
    #[strum(serialize = "053")]
    LielvārdeMunicipality,
    #[strum(serialize = "LPX")]
    Liepāja,
    #[strum(serialize = "054")]
    LimbažiMunicipality,
    #[strum(serialize = "057")]
    LubānaMunicipality,
    #[strum(serialize = "058")]
    LudzaMunicipality,
    #[strum(serialize = "055")]
    LīgatneMunicipality,
    #[strum(serialize = "056")]
    LīvāniMunicipality,
    #[strum(serialize = "059")]
    MadonaMunicipality,
    #[strum(serialize = "060")]
    MazsalacaMunicipality,
    #[strum(serialize = "061")]
    MālpilsMunicipality,
    #[strum(serialize = "062")]
    MārupeMunicipality,
    #[strum(serialize = "063")]
    MērsragsMunicipality,
    #[strum(serialize = "064")]
    NaukšēniMunicipality,
    #[strum(serialize = "065")]
    NeretaMunicipality,
    #[strum(serialize = "066")]
    NīcaMunicipality,
    #[strum(serialize = "067")]
    OgreMunicipality,
    #[strum(serialize = "068")]
    OlaineMunicipality,
    #[strum(serialize = "069")]
    OzolniekiMunicipality,
    #[strum(serialize = "073")]
    PreiļiMunicipality,
    #[strum(serialize = "074")]
    PriekuleMunicipality,
    #[strum(serialize = "075")]
    PriekuļiMunicipality,
    #[strum(serialize = "070")]
    PārgaujaMunicipality,
    #[strum(serialize = "071")]
    PāvilostaMunicipality,
    #[strum(serialize = "072")]
    PļaviņasMunicipality,
    #[strum(serialize = "076")]
    RaunaMunicipality,
    #[strum(serialize = "078")]
    RiebiņiMunicipality,
    #[strum(serialize = "RIX")]
    Riga,
    #[strum(serialize = "079")]
    RojaMunicipality,
    #[strum(serialize = "080")]
    RopažiMunicipality,
    #[strum(serialize = "081")]
    RucavaMunicipality,
    #[strum(serialize = "082")]
    RugājiMunicipality,
    #[strum(serialize = "083")]
    RundāleMunicipality,
    #[strum(serialize = "REZ")]
    Rēzekne,
    #[strum(serialize = "077")]
    RēzekneMunicipality,
    #[strum(serialize = "084")]
    RūjienaMunicipality,
    #[strum(serialize = "085")]


impl api::Payment for Nordea {}


pub fn validate(&self) -> Result<(), ApplicationError> {
        common_utils::fp_utils::when(self.lock_key.is_default_or_empty(), || {
            Err(ApplicationError::InvalidConfigurationValueError(
                "producer lock key must not be empty".into(),
            ))
        })
    }


pub struct CybersourceConsumerAuthInformationValidateRequest {
    authentication_transaction_id: String,
}


pub trait RequestBuilder: Send + Sync {
    fn json(&mut self, body: serde_json::Value);
    fn url_encoded_form(&mut self, body: serde_json::Value);
    fn timeout(&mut self, timeout: Duration);
    fn multipart(&mut self, form: Form);
    fn header(&mut self, key: String, value: Maskable<String>) -> CustomResult<(), ApiClientError>;
    fn send(
        self,
    ) -> CustomResult<
        Box<
            (dyn core::future::Future<Output = Result<reqwest::Response, reqwest::Error>>
                 + 'static),
        >,
        ApiClientError,
    >;
}


impl CustomerNew {
    pub async fn insert(self, conn: &PgPooledConn) -> StorageResult<Customer> {
        generics::generic_insert(conn, self).await
    }
}


pub struct MandateAmountData {
    pub amount: common_utils::types::MinorUnit,
    pub currency: Currency,
    pub start_date: Option<PrimitiveDateTime>,
    pub end_date: Option<PrimitiveDateTime>,
    pub metadata: Option<pii::SecretSerdeValue>,
}


OpenAPI Block Path: components.schemas.PaymentLinkStatus
{
  "type": "string",
  "description": "Status Of the Payment Link",
  "enum": [
    "active",
    "expired"
  ]
}


File: crates/api_models/src/connector_onboarding.rs
 Public structs: 6

use common_utils::id_type;

use super::{admin, enums};

#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)]
pub struct ActionUrlRequest {
    pub connector: enums::Connector,
    pub connector_id: id_type::MerchantConnectorAccountId,
    pub return_url: String,
}

#[derive(serde::Serialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub enum ActionUrlResponse {
    PayPal(PayPalActionUrlResponse),
}

#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)]
pub struct OnboardingSyncRequest {
    pub profile_id: id_type::ProfileId,
    pub connector_id: id_type::MerchantConnectorAccountId,
    pub connector: enums::Connector,
}

#[derive(serde::Serialize, Debug, Clone)]
pub struct PayPalActionUrlResponse {
    pub action_url: String,
}

#[derive(serde::Serialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub enum OnboardingStatus {
    PayPal(PayPalOnboardingStatus),
}

#[derive(serde::Serialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
pub enum PayPalOnboardingStatus {
    AccountNotFound,
    PaymentsNotReceivable,
    PpcpCustomDenied,
    MorePermissionsNeeded,
    EmailNotVerified,
    Success(PayPalOnboardingDone),
    ConnectorIntegrated(Box<admin::MerchantConnectorResponse>),
}

#[derive(serde::Serialize, Debug, Clone)]
pub struct PayPalOnboardingDone {
    pub payer_id: id_type::MerchantId,
}

#[derive(serde::Serialize, Debug, Clone)]
pub struct PayPalIntegrationDone {
    pub connector_id: String,
}

#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)]
pub struct ResetTrackingIdRequest {
    pub connector_id: id_type::MerchantConnectorAccountId,
    pub connector: enums::Connector,
}


File: crates/hyperswitch_connectors/src/connectors/cryptopay.rs
 Public functions: 1
 Public structs: 1

pub mod transformers;
use std::sync::LazyLock;

use base64::Engine;
use common_enums::enums;
use common_utils::{
    crypto::{self, GenerateDigest, SignMessage},
    date_time,
    errors::CustomResult,
    ext_traits::ByteSliceExt,
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{AmountConvertor, StringMajorUnit, StringMajorUnitForConnector},
};
use error_stack::ResultExt;
use hex::encode;
use hyperswitch_domain_models::{
    router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
    router_flow_types::{
        access_token_auth::AccessTokenAuth,
        payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void},
        refunds::{Execute, RSync},
    },
    router_request_types::{
        AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData,
        PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData,
        RefundsData, SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorInfo, PaymentMethodDetails, PaymentsResponseData, RefundsResponseData,
        SupportedPaymentMethods, SupportedPaymentMethodsExt,
    },
    types::{PaymentsAuthorizeRouterData, PaymentsSyncRouterData},
};
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorSpecifications,
        ConnectorValidation,
    },
    configs::Connectors,
    errors,
    events::connector_api_logs::ConnectorEvent,
    types::{PaymentsAuthorizeType, PaymentsSyncType, Response},
    webhooks,
};
use masking::{Mask, PeekInterface};
use transformers as cryptopay;

use self::cryptopay::CryptopayWebhookDetails;
use crate::{
    constants::headers,
    types::ResponseRouterData,
    utils::{self, ForeignTryFrom},
};

#[derive(Clone)]
pub struct Cryptopay {
    amount_converter: &'static (dyn AmountConvertor<Output = StringMajorUnit> + Sync),
}

impl Cryptopay {
    pub fn new() -> &'static Self {
        &Self {
            amount_converter: &StringMajorUnitForConnector,
        }
    }
}

impl api::Payment for Cryptopay {}
impl api::PaymentSession for Cryptopay {}
impl api::ConnectorAccessToken for Cryptopay {}
impl api::MandateSetup for Cryptopay {}
impl api::PaymentAuthorize for Cryptopay {}
impl api::PaymentSync for Cryptopay {}
impl api::PaymentCapture for Cryptopay {}
impl api::PaymentVoid for Cryptopay {}
impl api::Refund for Cryptopay {}
impl api::RefundExecute for Cryptopay {}
impl api::RefundSync for Cryptopay {}
impl api::PaymentToken for Cryptopay {}

impl ConnectorIntegration<PaymentMethodToken, PaymentMethodTokenizationData, PaymentsResponseData>
    for Cryptopay
{
    // Not Implemented (R)
}

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Cryptopay
where
    Self: ConnectorIntegration<Flow, Request, Response>,
{
    fn build_headers(
        &self,
        req: &RouterData<Flow, Request, Response>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let method = self.get_http_method();
        let payload = match method {
            Method::Get => String::default(),
            Method::Post | Method::Put | Method::Delete | Method::Patch => {
                let body = self
                    .get_request_body(req, connectors)?
                    .get_inner_value()
                    .peek()
                    .to_owned();
                let md5_payload = crypto::Md5
                    .generate_digest(body.as_bytes())
                    .change_context(errors::ConnectorError::RequestEncodingFailed)?;
                encode(md5_payload)
            }
        };
        let api_method = method.to_string();

        let now = date_time::date_as_yyyymmddthhmmssmmmz()
            .change_context(errors::ConnectorError::RequestEncodingFailed)?;
        let date = format!("{}+00:00", now.split_at(now.len() - 5).0);

        let content_type = self.get_content_type().to_string();

        let api = (self.get_url(req, connectors)?).replace(self.base_url(connectors), "");

        let auth = cryptopay::CryptopayAuthType::try_from(&req.connector_auth_type)?;

        let sign_req: String = format!("{api_method}\n{payload}\n{content_type}\n{date}\n{api}");
        let authz = crypto::HmacSha1::sign_message(
            &crypto::HmacSha1,
            auth.api_secret.peek().as_bytes(),
            sign_req.as_bytes(),
        )
        .change_context(errors::ConnectorError::RequestEncodingFailed)
        .attach_printable("Failed to sign the message")?;
        let authz = common_utils::consts::BASE64_ENGINE.encode(authz);
        let auth_string: String = format!("HMAC {}:{}", auth.api_key.peek(), authz);

        let headers = vec![
            (
                headers::AUTHORIZATION.to_string(),
                auth_string.into_masked(),
            ),
            (headers::DATE.to_string(), date.into()),
            (
                headers::CONTENT_TYPE.to_string(),
                self.get_content_type().to_string().into(),
            ),
        ];
        Ok(headers)
    }
}

impl ConnectorCommon for Cryptopay {
    fn id(&self) -> &'static str {
        "cryptopay"
    }

    fn get_currency_unit(&self) -> api::CurrencyUnit {
        api::CurrencyUnit::Base
    }

    fn common_get_content_type(&self) -> &'static str {
        "application/json"
    }

    fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str {
        connectors.cryptopay.base_url.as_ref()
    }

    fn get_auth_header(
        &self,
        auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let auth = cryptopay::CryptopayAuthType::try_from(auth_type)
            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
        Ok(vec![(
            headers::AUTHORIZATION.to_string(),
            auth.api_key.peek().to_owned().into_masked(),
        )])
    }

    fn build_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        let response: cryptopay::CryptopayErrorResponse = res
            .response
            .parse_struct("CryptopayErrorResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        event_builder.map(|i| i.set_error_response_body(&response));
        router_env::logger::info!(connector_response=?response);

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response.error.code,
            message: response.error.message,
            reason: response.error.reason,
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}

impl ConnectorIntegration<Session, PaymentsSessionData, PaymentsResponseData> for Cryptopay {}

impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken> for Cryptopay {}

impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData>
    for Cryptopay
{
    fn build_request(
        &self,
        _req: &RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
        _connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Err(
            errors::ConnectorError::NotImplemented("Setup Mandate flow for Cryptopay".to_string())
                .into(),
        )
    }
}

impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Cryptopay {
    fn get_headers(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}/api/invoices", self.base_url(connectors)))
    }

    fn get_request_body(
        &self,
        req: &PaymentsAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = utils::convert_amount(
            self.amount_converter,
            req.request.minor_amount,
            req.request.currency,
        )?;
        let connector_router_data = cryptopay::CryptopayRouterData::from((amount, req));
        let connector_req = cryptopay::CryptopayPaymentsRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&PaymentsAuthorizeType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(PaymentsAuthorizeType::get_headers(self, req, connectors)?)
                .set_body(PaymentsAuthorizeType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsAuthorizeRouterData, errors::ConnectorError> {
        let response: cryptopay::CryptopayPaymentsResponse = res
            .response
            .parse_struct("Cryptopay PaymentsAuthorizeResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        let capture_amount_in_minor_units = match response.data.price_amount {
            Some(ref amount) => Some(utils::convert_back_amount_to_minor_units(
                self.amount_converter,
                amount.clone(),
                data.request.currency,
            )?),
            None => None,
        };
        RouterData::foreign_try_from((
            ResponseRouterData {
                response,
                data: data.clone(),
                http_code: res.status_code,
            },
            capture_amount_in_minor_units,
        ))
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorValidation for Cryptopay {
    fn validate_psync_reference_id(
        &self,
        _data: &PaymentsSyncData,
        _is_three_ds: bool,
        _status: enums::AttemptStatus,
        _connector_meta_data: Option<common_utils::pii::SecretSerdeValue>,
    ) -> CustomResult<(), errors::ConnectorError> {
        // since we can make psync call with our reference_id, having connector_transaction_id is not an mandatory criteria
        Ok(())
    }
}

impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Cryptopay {
    fn get_headers(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_http_method(&self) -> Method {
        Method::Get
    }

    fn get_url(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let custom_id = req.connector_request_reference_id.clone();
        Ok(format!(
            "{}/api/invoices/custom_id/{custom_id}",
            self.base_url(connectors)
        ))
    }

    fn build_request(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Get)
                .url(&PaymentsSyncType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(PaymentsSyncType::get_headers(self, req, connectors)?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
        let response: cryptopay::CryptopayPaymentsResponse = res
            .response
            .parse_struct("cryptopay PaymentsSyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        let capture_amount_in_minor_units = match response.data.price_amount {
            Some(ref amount) => Some(utils::convert_back_amount_to_minor_units(
                self.amount_converter,
                amount.clone(),
                data.request.currency,
            )?),
            None => None,
        };
        RouterData::foreign_try_from((
            ResponseRouterData {
                response,
                data: data.clone(),
                http_code: res.status_code,
            },
            capture_amount_in_minor_units,
        ))
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> for Cryptopay {}

impl ConnectorIntegration<Void, PaymentsCancelData, PaymentsResponseData> for Cryptopay {}

impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Cryptopay {}

impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Cryptopay {}

#[async_trait::async_trait]
impl webhooks::IncomingWebhook for Cryptopay {
    fn get_webhook_source_verification_algorithm(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn crypto::VerifySignature + Send>, errors::ConnectorError> {
        Ok(Box::new(crypto::HmacSha256))
    }

    fn get_webhook_source_verification_signature(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let base64_signature =
            utils::get_header_key_value("X-Cryptopay-Signature", request.headers)?;
        hex::decode(base64_signature)
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
    }

    fn get_webhook_source_verification_message(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
        _merchant_id: &common_utils::id_type::MerchantId,
        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let message = std::str::from_utf8(request.body)
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
        Ok(message.to_string().into_bytes())
    }

    fn get_webhook_object_reference_id(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        let notif: CryptopayWebhookDetails =
            request
                .body
                .parse_struct("CryptopayWebhookDetails")
                .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
        match notif.data.custom_id {
            Some(custom_id) => Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
                api_models::payments::PaymentIdType::PaymentAttemptId(custom_id),
            )),
            None => Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
                api_models::payments::PaymentIdType::ConnectorTransactionId(notif.data.id),
            )),
        }
    }

    fn get_webhook_event_type(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError> {
        let notif: CryptopayWebhookDetails =
            request
                .body
                .parse_struct("CryptopayWebhookDetails")
                .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
        match notif.data.status {
            cryptopay::CryptopayPaymentStatus::Completed => {
                Ok(api_models::webhooks::IncomingWebhookEvent::PaymentIntentSuccess)
            }
            cryptopay::CryptopayPaymentStatus::Unresolved => {
                Ok(api_models::webhooks::IncomingWebhookEvent::PaymentActionRequired)
            }
            cryptopay::CryptopayPaymentStatus::Cancelled => {
                Ok(api_models::webhooks::IncomingWebhookEvent::PaymentIntentFailure)
            }
            _ => Ok(api_models::webhooks::IncomingWebhookEvent::EventNotSupported),
        }
    }

    fn get_webhook_resource_object(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        let notif: CryptopayWebhookDetails =
            request
                .body
                .parse_struct("CryptopayWebhookDetails")
                .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;

        Ok(Box::new(notif))
    }
}

static CRYPTOPAY_SUPPORTED_PAYMENT_METHODS: LazyLock<SupportedPaymentMethods> =
    LazyLock::new(|| {
        let supported_capture_methods = vec![
            enums::CaptureMethod::Automatic,
            enums::CaptureMethod::SequentialAutomatic,
        ];

        let mut cryptopay_supported_payment_methods = SupportedPaymentMethods::new();

        cryptopay_supported_payment_methods.add(
            enums::PaymentMethod::Crypto,
            enums::PaymentMethodType::CryptoCurrency,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::NotSupported,
                supported_capture_methods,
                specific_features: None,
            },
        );

        cryptopay_supported_payment_methods
    });

static CRYPTOPAY_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Cryptopay",
    description: "Simple and secure solution to buy and manage crypto. Make quick international transfers, spend your BTC, ETH and other crypto assets.",
    connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
    integration_status: enums::ConnectorIntegrationStatus::Live,
};

static CRYPTOPAY_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 1] = [enums::EventClass::Payments];

impl ConnectorSpecifications for Cryptopay {
    fn get_connector_about(&self) -> Option<&'static ConnectorInfo> {
        Some(&CRYPTOPAY_CONNECTOR_INFO)
    }

    fn get_supported_payment_methods(&self) -> Option<&'static SupportedPaymentMethods> {
        Some(&*CRYPTOPAY_SUPPORTED_PAYMENT_METHODS)
    }

    fn get_supported_webhook_flows(&self) -> Option<&'static [enums::EventClass]> {
        Some(&CRYPTOPAY_SUPPORTED_WEBHOOK_FLOWS)
    }
}


impl api::Refund for Checkbook {}


pub struct UserFromEmailRequest {
    pub token: Secret<String>,
}


    /// Time difference between UTC time and the Cardholder browser local time, in minutes. The field is limited to 1-5
    /// characters where the vauyes is returned from the getTimezoneOffset() method.
    ///
    /// Depending on the message version, the field is required for requests:
    /// - with message version = 2.1.0 and deviceChannel = 02 (BRW).
    /// - with message version = 2.2.0 and deviceChannel = 02 (BRW) and browserJavascriptEnabled = true.
    #[serde(rename = "browserTZ")]
    browser_tz: Option<i32>,

    /// Exact content of the HTTP user-agent header. The field is limited to maximum 2048 characters. If the total length of
    /// the User-Agent sent by the browser exceeds 2048 characters, the 3DS Server truncates the excess portion.
    ///
    /// This field is required for requests where deviceChannel = 02 (BRW).
    browser_user_agent: Option<String>,

    /// Dimensions of the challenge window that has been displayed to the Cardholder. The ACS shall reply with content
    /// that is formatted to appropriately render in this window to provide the best possible user experience.
    ///
    /// Preconfigured sizes are width X height in pixels of the window displayed in the Cardholder browser window. This is
    /// used only to prepare the CReq request and it is not part of the AReq flow. If not present it will be omitted.
    ///
    /// However, when sending the Challenge Request, this field is required when deviceChannel = 02 (BRW).
    ///
    /// Accepted values are:
    ///  - 01 -> 250 x 400
    ///  - 02 -> 390 x 400
    ///  - 03 -> 500 x 600
    ///  - 04 -> 600 x 400
    ///  - 05 -> Full screen
    challenge_window_size: Option<ChallengeWindowSizeEnum>,

    /// Boolean that represents the ability of the cardholder browser to execute JavaScript.
    ///
    /// This field is required for requests where deviceChannel = 02 (BRW).
    /// Available for supporting EMV 3DS 2.2.0 and later versions.
    browser_javascript_enabled: Option<bool>,

    /// Value representing the browser language preference present in the http header, as defined in IETF BCP 47.
    ///
    /// The value is limited to 1-99 elements. Each element should contain a maximum of 100 characters.
    ///
    /// This field is required for requests where deviceChannel = 02 (BRW).
    /// Available for supporting EMV 3DS 2.3.1 and later versions.
    accept_language: Option<Vec<String>>,
}

// Split by comma and return the list of accept languages
// If Accept-Language is : fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, List should be [fr-CH, fr, en, de]
pub fn get_list_of_accept_languages(accept_language: String) -> Vec<String> {
    accept_language
        .split(',')
        .map(|lang| lang.split(';').next().unwrap_or(lang).trim().to_string())
        .collect()
}

impl From<BrowserInformation> for Browser {
    fn from(value: BrowserInformation) -> Self {
        Self {
            browser_accept_header: value.accept_header,
            browser_ip: value
                .ip_address
                .map(|ip| masking::Secret::new(ip.to_string())),
            browser_java_enabled: value.java_enabled,
            browser_language: value.language,
            browser_color_depth: value.color_depth.map(|cd| cd.to_string()),
            browser_screen_height: value.screen_height,
            browser_screen_width: value.screen_width,
            browser_tz: value.time_zone,
            browser_user_agent: value.user_agent,
            challenge_window_size: Some(ChallengeWindowSizeEnum::FullScreen),
            browser_javascript_enabled: value.java_script_enabled,
            // Default to ["en"] locale if accept_language is not provided
            accept_language: value
                .accept_language
                .map(get_list_of_accept_languages)
                .or(Some(vec!["en".to_string()])),
        }
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum ChallengeWindowSizeEnum {
    #[serde(rename = "01")]
    Size250x400,
    #[serde(rename = "02")]
    Size390x400,
    #[serde(rename = "03")]
    Size500x600,
    #[serde(rename = "04")]
    Size600x400,
    #[serde(rename = "05")]
    FullScreen,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Sdk {
    /// Universally unique ID created upon all installations and updates of the 3DS Requestor App on a Customer Device.
    /// This will be newly generated and stored by the 3DS SDK for each installation or update. The field is limited to 36
    /// characters and it shall have a canonical format as defined in IETF RFC 4122. This may utilize any of the specified
    /// versions as long as the output meets specified requirements.
    ///
    /// Starting from EMV 3DS 2.3.1:
    /// In case of Browser-SDK, the SDK App ID value is not reliable, and may change for each transaction.
    #[serde(rename = "sdkAppID")]
    sdk_app_id: Option<String>,

    /// JWE Object as defined Section 6.2.2.1 containing data encrypted by the SDK for the DS to decrypt. This element is
    /// the only field encrypted in this version of the EMV 3-D Secure specification. The field is sent from the SDK and it
    /// is limited to 64.000 characters. The data will be present when sending to DS, but not present from DS to ACS.
    sdk_enc_data: Option<String>,

    /// Public key component of the ephemeral key pair generated by the 3DS SDK and used to establish session keys between
    /// the 3DS SDK and ACS. In AReq, this data element is contained within the ACS Signed Content JWS Object. The field is
    /// limited to maximum 256 characters.
    sdk_ephem_pub_key: Option<HashMap<String, String>>,

    /// Indicates the maximum amount of time (in minutes) for all exchanges. The field shall have value greater or equals
    /// than 05.
    sdk_max_timeout: Option<u8>,

    /// Identifies the vendor and version of the 3DS SDK that is integrated in a 3DS Requestor App, assigned by EMVCo when
    /// the 3DS SDK is approved. The field is limited to 32 characters.
    ///
    /// Starting from EMV 3DS 2.3.1:
    /// Identifies the vendor and version of the 3DS SDK that is utilised for a specific transaction. The value is
    /// assigned by EMVCo when the Letter of Approval of the specific 3DS SDK is issued.
    sdk_reference_number: Option<String>,

    /// Universally unique transaction identifier assigned by the 3DS SDK to identify a single transaction. The field is
    /// limited to 36 characters and it shall be in a canonical format as defined in IETF RFC 4122. This may utilize any of
    /// the specified versions as long as the output meets specific requirements.
    #[serde(rename = "sdkTransID")]
    sdk_trans_id: Option<String>,

    /// Contains the JWS object(represented as a string) created by the Split-SDK Server for the AReq message. A
    /// Split-SDK Server creates a time-stamped signature on certain transaction data that is sent to the DS for
    /// verification. As a prerequisite, the Split-SDK Server has a key pair PbSDK, PvSDK certificate Cert (PbSDK). This
    /// certificate is an X.509 certificate signed by a DS CA whose public key is known to the DS.
    ///
    /// The Split-SDK Server:
    ///    Creates a JSON object of the following data as the JWS payload to be signed:
    ///
    ///    - SDK Reference Number -> Identifies the vendor and version of the 3DS SDK that is utilised for a specific
    ///      transaction. The value is assigned by EMVCo when the Letter of Approval of the
    ///      specific 3DS SDK is issued. The field is limited to 32 characters.
    ///    - SDK Signature Timestamp -> Date and time indicating when the 3DS SDK generated the Split-SDK Server Signed
    ///      Content converted into UTC. The value is limited to 14 characters. Accepted
    ///      format: YYYYMMDDHHMMSS.
    ///    - SDK Transaction ID -> Universally unique transaction identifier assigned by the 3DS SDK to identify a
    ///      single transaction. The field is limited to 36 characters and it shall be in a
    ///      canonical format as defined in IETF RFC 4122. This may utilize any of the specified
    ///      versions as long as the output meets specific requirements.
    ///    - Split-SDK Server ID -> DS assigned Split-SDK Server identifier. Each DS can provide a unique ID to each
    ///      Split-SDK Server on an individual basis. The field is limited to 32 characters.
    ///      Any individual DS may impose specific formatting and character requirements on the
    ///      contents of this field.
    ///
    ///    Generates a digital signature of the full JSON object according to JWS (RFC 7515) using JWS Compact
    ///    Serialization. The parameter values for this version of the specification and to be included in the JWS
    ///    header are:
    ///
    ///    - `alg`: PS2567 or ES256
    ///    - `x5c`: X.5C v3: Cert (PbSDK) and chaining certificates if present
    ///
    ///    All other parameters: optional
    ///
    ///    Includes the resulting JWS in the AReq message as SDK Server Signed Content
    ///
    /// This field is required if sdkType = 02 or 03 and deviceChannel = 01 (APP)
    /// Available for supporting EMV 3DS 2.3.1 and later versions.
    sdk_server_signed_content: Option<String>,

    /// Indicates the type of 3DS SDK.
    /// This data element provides additional information to the DS and ACS to determine the best approach for handling
    /// the transaction. Accepted values are:
    ///
    ///    - 01 -> Default SDK
    ///    - 02 -> Split-SDK
    ///    - 03 -> Limited-SDK
    ///    - 04 -> Browser-SDK
    ///    - 05 -> Shell-SDK
    ///    - 80-99 -> PS-specific value (dependent on the payment scheme type)
    ///
    /// This field is required for requests where deviceChannel = 01 (APP).
    /// Available for supporting EMV 3DS 2.3.1 and later versions.
    sdk_type: Option<SdkType>,

    /// Indicates the characteristics of a Default-SDK.
    ///
    /// This field is required for requests where deviceChannel = 01 (APP) and SDK Type = 01.
    /// Available for supporting EMV 3DS 2.3.1 and later versions.
    default_sdk_type: Option<DefaultSdkType>,

    /// Indicates the characteristics of a Split-SDK.
    ///
    /// This field is required for requests where deviceChannel = 01 (APP) and SDK Type = 02.
    /// Available for supporting EMV 3DS 2.3.1 and later versions.
    split_sdk_type: Option<SplitSdkType>,
}

impl From<api_models::payments::SdkInformation> for Sdk {
    fn from(sdk_info: api_models::payments::SdkInformation) -> Self {
        Self {
            sdk_app_id: Some(sdk_info.sdk_app_id),
            sdk_enc_data: Some(sdk_info.sdk_enc_data),
            sdk_ephem_pub_key: Some(sdk_info.sdk_ephem_pub_key),
            sdk_max_timeout: Some(sdk_info.sdk_max_timeout),
            sdk_reference_number: Some(sdk_info.sdk_reference_number),
            sdk_trans_id: Some(sdk_info.sdk_trans_id),
            sdk_server_signed_content: None,
            sdk_type: sdk_info
                .sdk_type
                .map(SdkType::from)
                .or(Some(SdkType::DefaultSdk)),
            default_sdk_type: Some(DefaultSdkType {
                // hardcoding this value because, it's the only value that is accepted
                sdk_variant: "01".to_string(),
                wrapped_ind: None,
            }),
            split_sdk_type: None,
        }
    }
}

impl From<api_models::payments::SdkType> for SdkType {
    fn from(sdk_type: api_models::payments::SdkType) -> Self {
        match sdk_type {
            api_models::payments::SdkType::DefaultSdk => Self::DefaultSdk,
            api_models::payments::SdkType::SplitSdk => Self::SplitSdk,
            api_models::payments::SdkType::LimitedSdk => Self::LimitedSdk,
            api_models::payments::SdkType::BrowserSdk => Self::BrowserSdk,
            api_models::payments::SdkType::ShellSdk => Self::ShellSdk,
        }
    }
}

/// Enum representing the type of 3DS SDK.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum SdkType {
    #[serde(rename = "01")]
    DefaultSdk,
    #[serde(rename = "02")]
    SplitSdk,
    #[serde(rename = "03")]
    LimitedSdk,
    #[serde(rename = "04")]
    BrowserSdk,
    #[serde(rename = "05")]
    ShellSdk,
    ///    - 80-99 -> PS-specific value (dependent on the payment scheme type)
    #[serde(untagged)]
    PsSpecific(String),
}

/// Struct representing characteristics of a Default-SDK.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct DefaultSdkType {
    /// SDK Variant: SDK implementation characteristics
    ///    - Length: 2 characters
    ///    - Values accepted:
    ///       - 01 = Native
    ///       - 02–79 = Reserved for EMVCo future use (values invalid until defined by EMVCo)
    ///       - 80–99 = Reserved for DS use
    sdk_variant: String,

    /// Wrapped Indicator: If the Default-SDK is embedded as a wrapped component in the 3DS Requestor App
    ///    - Length: 1 character
    ///    - Value accepted: Y = Wrapped
    ///    - Only present if value = Y
    wrapped_ind: Option<String>,
}

/// Struct representing characteristics of a Split-SDK.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct SplitSdkType {
    /// Split-SDK Variant: Implementation characteristics of the Split-SDK client
    ///    - Length: 2 characters
    ///    - Values accepted:
    ///       - 01 = Native Client
    ///       - 02 = Browser
    ///       - 03 = Shell
    ///       - 04–79 = Reserved for EMVCo future use (values invalid until defined by EMVCo)
    ///       - 80–99 = Reserved for DS use
    sdk_variant: String,

    /// Limited Split-SDK Indicator: If the Split-SDK client has limited capabilities
    ///    - Length: 1 character
    ///    - Value accepted:
    ///      • Y = Limited
    ///    - Only present if value = Y
    limited_ind: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum ThreeDSReqAuthMethod {
    /// No 3DS Requestor authentication occurred (i.e. cardholder "logged in" as guest)
    #[serde(rename = "01")]
    Guest,
    /// Login to the cardholder account at the 3DS Requestor system using 3DS Requestor's own credentials
    #[serde(rename = "02")]
    ThreeDsRequestorCredentials,
    /// Login to the cardholder account at the 3DS Requestor system using federated ID
    #[serde(rename = "03")]
    FederatedID,
    /// Login to the cardholder account at the 3DS Requestor system using issuer credentials
    #[serde(rename = "04")]
    IssuerCredentials,
    /// Login to the cardholder account at the 3DS Requestor system using third-party authentication
    #[serde(rename = "05")]
    ThirdPartyAuthentication,
    /// Login to the cardholder account at the 3DS Requestor system using FIDO Authenticator.
    #[serde(rename = "06")]
    FidoAuthenticator,
    /// Login to the cardholder account at the 3DS Requestor system using FIDO Authenticator(FIDO assurance data signed).
    #[serde(rename = "07")]
    FidoAssuranceData,
    /// SRC Assurance Data.
    #[serde(rename = "08")]
    SRCAssuranceData,
    /// Additionally, 80-99 can be used for PS-specific values, regardless of protocol version.
    #[serde(untagged)]
    PsSpecificValue(String),
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct DeviceRenderingOptionsSupported {
    pub sdk_interface: SdkInterface,
    /// For Native UI SDK Interface accepted values are 01-04 and for HTML UI accepted values are 01-05.
    pub sdk_ui_type: Vec<SdkUiType>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum SdkInterface {
    #[serde(rename = "01")]
    Native,
    #[serde(rename = "02")]
    Html,
    #[serde(rename = "03")]
    Both,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum SdkUiType {
    #[serde(rename = "01")]
    Text,
    #[serde(rename = "02")]
    SingleSelect,
    #[serde(rename = "03")]
    MultiSelect,
    #[serde(rename = "04")]
    Oob,
    #[serde(rename = "05")]
    HtmlOther,
}


pub async fn files_delete(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<String>,
) -> HttpResponse {
    let flow = Flow::DeleteFile;
    let file_id = files::FileId {
        file_id: path.into_inner(),
    };
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        file_id,
        |state, auth: auth::AuthenticationData, req, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            files_delete_core(state, merchant_context, req)
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::DashboardNoPermissionAuth,
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub struct BluecodePaymentsResponse {
    pub id: i64,
    pub order_id: String,
    pub amount: FloatMajorUnit,
    pub currency: enums::Currency,
    pub charged_amount: FloatMajorUnit,
    pub charged_currency: enums::Currency,
    pub status: BluecodePaymentStatus,
    pub payment_link: url::Url,
    pub etoken: Secret<String>,
    pub payment_request_id: String,
}


File: crates/common_types/src/customers.rs
 Public functions: 1
 Public structs: 1

//! Customer related types

/// HashMap containing MerchantConnectorAccountId and corresponding customer id
#[cfg(feature = "v2")]
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize, diesel::AsExpression)]
#[diesel(sql_type = diesel::sql_types::Jsonb)]
#[serde(transparent)]
pub struct ConnectorCustomerMap(
    std::collections::HashMap<common_utils::id_type::MerchantConnectorAccountId, String>,
);

#[cfg(feature = "v2")]
impl ConnectorCustomerMap {
    /// Creates a new `ConnectorCustomerMap` from a HashMap
    pub fn new(
        map: std::collections::HashMap<common_utils::id_type::MerchantConnectorAccountId, String>,
    ) -> Self {
        Self(map)
    }
}

#[cfg(feature = "v2")]
common_utils::impl_to_sql_from_sql_json!(ConnectorCustomerMap);

#[cfg(feature = "v2")]
impl std::ops::Deref for ConnectorCustomerMap {
    type Target =
        std::collections::HashMap<common_utils::id_type::MerchantConnectorAccountId, String>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[cfg(feature = "v2")]
impl std::ops::DerefMut for ConnectorCustomerMap {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}


pub struct AdyenplatformIncomingWebhookData {
    pub status: AdyenplatformWebhookStatus,
    pub reference: String,
    pub tracking: Option<AdyenplatformInstantStatus>,
    pub category: Option<AdyenPayoutMethod>,
}


pub fn get_default_customer_shipping_address(&self) -> Option<payments::AddressDetails> {
        self.default_shipping_address.clone()
    }


pub struct CardDetailUpdate {
    /// Card Expiry Month
    #[schema(value_type = String,example = "10")]
    pub card_exp_month: Option<masking::Secret<String>>,

    /// Card Expiry Year
    #[schema(value_type = String,example = "25")]
    pub card_exp_year: Option<masking::Secret<String>>,

    /// Card Holder Name
    #[schema(value_type = String,example = "John Doe")]
    pub card_holder_name: Option<masking::Secret<String>>,

    /// Card Holder's Nick Name
    #[schema(value_type = Option<String>,example = "John Doe")]
    pub nick_name: Option<masking::Secret<String>>,
}


pub struct AuthenticationDataWithMultipleProfiles {
    pub merchant_account: domain::MerchantAccount,
    pub key_store: domain::MerchantKeyStore,
    pub profile_id_list: Option<Vec<id_type::ProfileId>>,
}


pub struct RefundReasonAccumulator {
    pub count: u64,
}


pub struct CustomerRequest {
    create_customer_profile_request: CreateCustomerRequest,
}


impl api::PaymentSession for Elavon {}


pub struct SaleQueryResponse {
    items: Vec<SaleQuery>,
}


impl Origin {
    fn get_flows(&self) -> &'static [UserFlow] {
        match self {
            Self::SignInWithSSO => &SIGNIN_WITH_SSO_FLOW,
            Self::SignIn => &SIGNIN_FLOW,
            Self::SignUp => &SIGNUP_FLOW,
            Self::VerifyEmail => &VERIFY_EMAIL_FLOW,
            Self::MagicLink => &MAGIC_LINK_FLOW,
            Self::AcceptInvitationFromEmail => &ACCEPT_INVITATION_FROM_EMAIL_FLOW,
            Self::ResetPassword => &RESET_PASSWORD_FLOW,
        }
    }
}


pub struct AdyenBankAccountIdentification {
    #[serde(rename = "type")]
    bank_type: String,
    #[serde(flatten)]
    account_details: AdyenBankAccountIdentificationDetails,
}


/// Default limit for payments list API
pub fn default_payments_list_limit() -> u32 {
    10
}


pub fn get_surcharge_results_size(&self) -> usize {
        self.surcharge_results.len()
    }


pub struct AuthenticationResponse {
    pub trans_status: common_enums::TransactionStatus,
    pub acs_url: Option<url::Url>,
    pub challenge_request: Option<String>,
    pub acs_reference_number: Option<String>,
    pub acs_trans_id: Option<String>,
    pub three_dsserver_trans_id: Option<String>,
    pub acs_signed_content: Option<String>,
}


impl EventClass {
    #[inline]
    pub fn event_types(self) -> HashSet<EventType> {
        match self {
            Self::Payments => HashSet::from([
                EventType::PaymentSucceeded,
                EventType::PaymentFailed,
                EventType::PaymentProcessing,
                EventType::PaymentCancelled,
                EventType::PaymentCancelledPostCapture,
                EventType::PaymentAuthorized,
                EventType::PaymentCaptured,
                EventType::PaymentExpired,
                EventType::ActionRequired,
            ]),
            Self::Refunds => HashSet::from([EventType::RefundSucceeded, EventType::RefundFailed]),
            Self::Disputes => HashSet::from([
                EventType::DisputeOpened,
                EventType::DisputeExpired,
                EventType::DisputeAccepted,
                EventType::DisputeCancelled,
                EventType::DisputeChallenged,
                EventType::DisputeWon,
                EventType::DisputeLost,
            ]),
            Self::Mandates => HashSet::from([EventType::MandateActive, EventType::MandateRevoked]),
            #[cfg(feature = "payouts")]
            Self::Payouts => HashSet::from([
                EventType::PayoutSuccess,
                EventType::PayoutFailed,
                EventType::PayoutInitiated,
                EventType::PayoutProcessing,
                EventType::PayoutCancelled,
                EventType::PayoutExpired,
                EventType::PayoutReversed,
            ]),
        }
    }
}


impl super::disputes::filters::DisputeFilterAnalytics for SqlxClient {}

impl super::disputes::filters::DisputeFilterAnalytics for for SqlxClient


pub struct ShippingData {
    ship_addr_city: Option<String>,
    ship_addr_country: Option<String>,
    ship_addr_line1: Option<Secret<String>>,
    ship_addr_line2: Option<Secret<String>>,
    ship_addr_line3: Option<Secret<String>>,
    ship_addr_postal_code: Option<Secret<String>>,
    ship_addr_state: Option<Secret<String>>,
}


pub fn server(config: AppState) -> Scope {
        web::scope("/ephemeral_keys")
            .app_data(web::Data::new(config))
            .service(web::resource("").route(web::post().to(ephemeral_key_create)))
            .service(web::resource("/{id}").route(web::delete().to(ephemeral_key_delete)))
    }


pub async fn execute_payment_method_tokenization(
    executor: tokenize::CardNetworkTokenizeExecutor<'_, domain::TokenizePaymentMethodRequest>,
    builder: tokenize::NetworkTokenizationBuilder<'_, tokenize::TokenizeWithPmId>,
    req: &domain::TokenizePaymentMethodRequest,
) -> errors::RouterResult<api::CardNetworkTokenizeResponse> {
    // Fetch payment method
    let payment_method = executor
        .fetch_payment_method(&req.payment_method_id)
        .await?;
    let builder = builder.set_payment_method(&payment_method);

    // Validate payment method and customer
    let (locker_id, customer) = executor
        .validate_request_and_locker_reference_and_customer(&payment_method)
        .await?;
    let builder = builder.set_validate_result(&customer);

    // Fetch card from locker
    let card_details = get_card_from_locker(
        executor.state,
        &customer.id,
        executor.merchant_account.get_id(),
        &locker_id,
    )
    .await?;

    // Perform BIN lookup and validate card network
    let optional_card_info = executor
        .fetch_bin_details_and_validate_card_network(
            card_details.card_number.clone(),
            None,
            None,
            None,
            None,
        )
        .await?;
    let builder = builder.set_card_details(&card_details, optional_card_info, req.card_cvc.clone());

    // Tokenize card
    let (optional_card, optional_cvc) = builder.get_optional_card_and_cvc();
    let domain_card = optional_card.get_required_value("card")?;
    let network_token_details = executor
        .tokenize_card(&customer.id, &domain_card, optional_cvc)
        .await?;
    let builder = builder.set_token_details(&network_token_details);

    // Store token in locker
    let store_token_resp = executor
        .store_network_token_in_locker(
            &network_token_details,
            &customer.id,
            card_details.name_on_card.clone(),
            card_details.nick_name.clone().map(Secret::new),
        )
        .await?;
    let builder = builder.set_stored_token_response(&store_token_resp);

    // Update payment method
    let updated_payment_method = executor
        .update_payment_method(
            &store_token_resp,
            payment_method,
            &network_token_details,
            &domain_card,
        )
        .await?;
    let builder = builder.set_payment_method(&updated_payment_method);

    Ok(builder.build())
}


impl api::PaymentCapture for Stripe {}