impl api::UnifiedAuthenticationService for UnifiedAuthenticationService {}

impl api::UnifiedAuthenticationService for for UnifiedAuthenticationService


pub struct Profile {
    pub merchant_id: common_utils::id_type::MerchantId,
    pub profile_name: String,
    pub created_at: time::PrimitiveDateTime,
    pub modified_at: time::PrimitiveDateTime,
    pub return_url: Option<common_utils::types::Url>,
    pub enable_payment_response_hash: bool,
    pub payment_response_hash_key: Option<String>,
    pub redirect_to_merchant_with_http_post: bool,
    pub webhook_details: Option<WebhookDetails>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub is_recon_enabled: bool,
    #[diesel(deserialize_as = super::OptionalDieselArray<String>)]
    pub applepay_verified_domains: Option<Vec<String>>,
    pub payment_link_config: Option<BusinessPaymentLinkConfig>,
    pub session_expiry: Option<i64>,
    pub authentication_connector_details: Option<AuthenticationConnectorDetails>,
    pub payout_link_config: Option<BusinessPayoutLinkConfig>,
    pub is_extended_card_info_enabled: Option<bool>,
    pub extended_card_info_config: Option<pii::SecretSerdeValue>,
    pub is_connector_agnostic_mit_enabled: Option<bool>,
    pub use_billing_as_payment_method_billing: Option<bool>,
    pub collect_shipping_details_from_wallet_connector: Option<bool>,
    pub collect_billing_details_from_wallet_connector: Option<bool>,
    pub outgoing_webhook_custom_http_headers: Option<Encryption>,
    pub always_collect_billing_details_from_wallet_connector: Option<bool>,
    pub always_collect_shipping_details_from_wallet_connector: Option<bool>,
    pub tax_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
    pub is_tax_connector_enabled: Option<bool>,
    pub version: common_enums::ApiVersion,
    pub dynamic_routing_algorithm: Option<serde_json::Value>,
    pub is_network_tokenization_enabled: bool,
    pub is_auto_retries_enabled: Option<bool>,
    pub max_auto_retries_enabled: Option<i16>,
    pub always_request_extended_authorization:
        Option<primitive_wrappers::AlwaysRequestExtendedAuthorization>,
    pub is_click_to_pay_enabled: bool,
    pub authentication_product_ids:
        Option<common_types::payments::AuthenticationConnectorAccountMap>,
    pub card_testing_guard_config: Option<CardTestingGuardConfig>,
    pub card_testing_secret_key: Option<Encryption>,
    pub is_clear_pan_retries_enabled: bool,
    pub force_3ds_challenge: Option<bool>,
    pub is_debit_routing_enabled: bool,
    pub merchant_business_country: Option<common_enums::CountryAlpha2>,
    pub id: common_utils::id_type::ProfileId,
    pub is_iframe_redirection_enabled: Option<bool>,
    pub three_ds_decision_rule_algorithm: Option<serde_json::Value>,
    pub acquirer_config_map: Option<common_types::domain::AcquirerConfigMap>,
    pub merchant_category_code: Option<common_enums::MerchantCategoryCode>,
    pub merchant_country_code: Option<common_types::payments::MerchantCountryCode>,
    pub dispute_polling_interval: Option<primitive_wrappers::DisputePollingIntervalInHours>,
    pub is_manual_retry_enabled: Option<bool>,
    pub routing_algorithm_id: Option<common_utils::id_type::RoutingId>,
    pub order_fulfillment_time: Option<i64>,
    pub order_fulfillment_time_origin: Option<common_enums::OrderFulfillmentTimeOrigin>,
    pub frm_routing_algorithm_id: Option<String>,
    pub payout_routing_algorithm_id: Option<common_utils::id_type::RoutingId>,
    pub default_fallback_routing: Option<pii::SecretSerdeValue>,
    pub three_ds_decision_manager_config: Option<common_types::payments::DecisionManagerRecord>,
    pub should_collect_cvv_during_payment:
        Option<primitive_wrappers::ShouldCollectCvvDuringPayment>,
    pub revenue_recovery_retry_algorithm_type: Option<common_enums::RevenueRecoveryAlgorithmType>,
    pub revenue_recovery_retry_algorithm_data: Option<RevenueRecoveryAlgorithmData>,
    pub is_external_vault_enabled: Option<bool>,
    pub external_vault_connector_details: Option<ExternalVaultConnectorDetails>,
    pub split_txns_enabled: Option<common_enums::SplitTxnsEnabled>,
}


pub struct PaymentStatus {
    pub authentication: String,
    pub authorization: SilverflowAuthorizationStatus,
    pub clearing: SilverflowClearingStatus,
}


impl api::PaymentsCompleteAuthorize for Redsys {}

impl api::PaymentsCompleteAuthorize for for Redsys


impl CardNetworkTokenizeExecutor<'_, domain::TokenizePaymentMethodRequest> {
    pub async fn fetch_payment_method(
        &self,
        payment_method_id: &str,
    ) -> RouterResult<domain::PaymentMethod> {
        self.state
            .store
            .find_payment_method(
                &self.state.into(),
                self.key_store,
                payment_method_id,
                self.merchant_account.storage_scheme,
            )
            .await
            .map_err(|err| match err.current_context() {
                errors::StorageError::DatabaseError(err)
                    if matches!(
                        err.current_context(),
                        diesel_models::errors::DatabaseError::NotFound
                    ) =>
                {
                    report!(errors::ApiErrorResponse::InvalidRequestData {
                        message: "Invalid payment_method_id".into(),
                    })
                }
                errors::StorageError::ValueNotFound(_) => {
                    report!(errors::ApiErrorResponse::InvalidRequestData {
                        message: "Invalid payment_method_id".to_string(),
                    })
                }
                err => {
                    logger::info!("Error fetching payment_method: {:?}", err);
                    report!(errors::ApiErrorResponse::InternalServerError)
                }
            })
    }
    pub async fn validate_request_and_locker_reference_and_customer(
        &self,
        payment_method: &domain::PaymentMethod,
    ) -> RouterResult<(String, api::CustomerDetails)> {
        // Ensure customer ID matches
        let customer_id_in_req = self
            .customer
            .customer_id
            .clone()
            .get_required_value("customer_id")
            .change_context(errors::ApiErrorResponse::MissingRequiredField {
                field_name: "customer",
            })?;
        when(payment_method.customer_id != customer_id_in_req, || {
            Err(report!(errors::ApiErrorResponse::InvalidRequestData {
                message: "Payment method does not belong to the customer".to_string()
            }))
        })?;

        // Ensure payment method is card
        match payment_method.payment_method {
            Some(api_enums::PaymentMethod::Card) => Ok(()),
            Some(_) => Err(report!(errors::ApiErrorResponse::InvalidRequestData {
                message: "Payment method is not card".to_string()
            })),
            None => Err(report!(errors::ApiErrorResponse::InvalidRequestData {
                message: "Payment method is empty".to_string()
            })),
        }?;

        // Ensure card is not tokenized already
        when(
            payment_method
                .network_token_requestor_reference_id
                .is_some(),
            || {
                Err(report!(errors::ApiErrorResponse::InvalidRequestData {
                    message: "Card is already tokenized".to_string()
                }))
            },
        )?;

        // Ensure locker reference is present
        let locker_id = payment_method.locker_id.clone().ok_or(report!(
            errors::ApiErrorResponse::InvalidRequestData {
                message: "locker_id not found for given payment_method_id".to_string()
            }
        ))?;

        // Fetch customer
        let db = &*self.state.store;
        let key_manager_state: &KeyManagerState = &self.state.into();
        let customer = db
            .find_customer_by_customer_id_merchant_id(
                key_manager_state,
                &payment_method.customer_id,
                self.merchant_account.get_id(),
                self.key_store,
                self.merchant_account.storage_scheme,
            )
            .await
            .inspect_err(|err| logger::info!("Error fetching customer: {:?}", err))
            .change_context(errors::ApiErrorResponse::InternalServerError)?;

        let customer_details = api::CustomerDetails {
            id: customer.customer_id.clone(),
            name: customer.name.clone().map(|name| name.into_inner()),
            email: customer.email.clone().map(Email::from),
            phone: customer.phone.clone().map(|phone| phone.into_inner()),
            phone_country_code: customer.phone_country_code.clone(),
            tax_registration_id: customer
                .tax_registration_id
                .clone()
                .map(|tax_registration_id| tax_registration_id.into_inner()),
        };

        Ok((locker_id, customer_details))
    }
    pub async fn update_payment_method(
        &self,
        store_token_response: &pm_transformers::StoreCardRespPayload,
        payment_method: domain::PaymentMethod,
        network_token_details: &NetworkTokenizationResponse,
        card_details: &domain::CardDetail,
    ) -> RouterResult<domain::PaymentMethod> {
        // Form encrypted network token data
        let enc_token_data = self
            .encrypt_network_token(network_token_details, card_details, true)
            .await?;

        // Update payment method
        let payment_method_update = diesel_models::PaymentMethodUpdate::NetworkTokenDataUpdate {
            network_token_requestor_reference_id: network_token_details.1.clone(),
            network_token_locker_id: Some(store_token_response.card_reference.clone()),
            network_token_payment_method_data: Some(enc_token_data.into()),
        };
        self.state
            .store
            .update_payment_method(
                &self.state.into(),
                self.key_store,
                payment_method,
                payment_method_update,
                self.merchant_account.storage_scheme,
            )
            .await
            .inspect_err(|err| logger::info!("Error updating payment method: {:?}", err))
            .change_context(errors::ApiErrorResponse::InternalServerError)
    }
}


impl PaymentIntentMetricAccumulator for PaymentsDistributionAccumulator {
    type MetricOutput = (Option<f64>, Option<f64>);

    fn add_metrics_bucket(&mut self, metrics: &PaymentIntentMetricRow) {
        let first_attempt = metrics.first_attempt.unwrap_or(0);
        if let Some(ref status) = metrics.status {
            if status.as_ref() == &storage_enums::IntentStatus::Succeeded {
                if let Some(success) = metrics
                    .count
                    .and_then(|success| u32::try_from(success).ok())
                {
                    if first_attempt == 1 {
                        self.success_without_retries += success;
                    }
                }
            }
            if let Some(failed) = metrics.count.and_then(|failed| u32::try_from(failed).ok()) {
                if first_attempt == 0
                    || (first_attempt == 1
                        && status.as_ref() == &storage_enums::IntentStatus::Failed)
                {
                    self.failed_without_retries += failed;
                }
            }

            if status.as_ref() != &storage_enums::IntentStatus::RequiresCustomerAction
                && status.as_ref() != &storage_enums::IntentStatus::RequiresPaymentMethod
                && status.as_ref() != &storage_enums::IntentStatus::RequiresMerchantAction
                && status.as_ref() != &storage_enums::IntentStatus::RequiresConfirmation
            {
                if let Some(total) = metrics.count.and_then(|total| u32::try_from(total).ok()) {
                    self.total += total;
                }
            }
        }
    }

    fn collect(self) -> Self::MetricOutput {
        if self.total == 0 {
            (None, None)
        } else {
            let success_without_retries = Some(self.success_without_retries);
            let failed_without_retries = Some(self.failed_without_retries);
            let total = Some(self.total);

            let success_rate_without_retries = match (success_without_retries, total) {
                (Some(s), Some(t)) if t > 0 => Some(f64::from(s) * 100.0 / f64::from(t)),
                _ => None,
            };

            let failed_rate_without_retries = match (failed_without_retries, total) {
                (Some(s), Some(t)) if t > 0 => Some(f64::from(s) * 100.0 / f64::from(t)),
                _ => None,
            };
            (success_rate_without_retries, failed_rate_without_retries)
        }
    }
}

impl PaymentIntentMetricAccumulator for for PaymentsDistributionAccumulator


impl NetworkTokenizationBuilder<'_, PaymentMethodCreated> {
    pub fn build(self) -> api::CardNetworkTokenizeResponse {
        api::CardNetworkTokenizeResponse {
            payment_method_response: self.payment_method_response,
            customer: self.customer.cloned(),
            card_tokenized: self.card_tokenized,
            error_code: self.error_code.cloned(),
            error_message: self.error_message.cloned(),
            // Below field is mutated by caller functions for batched API operations
            tokenization_data: None,
        }
    }
}


pub async fn routing_update_default_config(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<Vec<routing_types::RoutableConnectorChoice>>,
    transaction_type: &enums::TransactionType,
) -> impl Responder {
    Box::pin(oss_api::server_wrap(
        Flow::RoutingUpdateDefaultConfig,
        state,
        &req,
        json_payload.into_inner(),
        |state, auth: auth::AuthenticationData, updated_config, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            routing::update_default_routing_config(
                state,
                merchant_context,
                updated_config,
                transaction_type,
            )
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuth {
                permission: Permission::MerchantRoutingWrite,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub struct PaymentIntentsMetricsResponse<T> {
    pub query_data: Vec<T>,
    pub meta_data: [PaymentIntentsAnalyticsMetadata; 1],
}


pub struct AirwallexWebhookData {
    pub source_id: Option<String>,
    pub name: AirwallexWebhookEventType,
    pub data: AirwallexObjectData,
}


impl ConnectorValidation for Juspaythreedsserver {
    //TODO: implement functions when support enabled
}

impl ConnectorValidation for for Juspaythreedsserver


impl Refund for Wise {}


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


pub struct ClickToPayMetaData {
    pub dpa_id: String,
    pub dpa_name: String,
    pub locale: String,
    pub card_brands: Vec<String>,
    pub acquirer_bin: String,
    pub acquirer_merchant_id: String,
    pub merchant_category_code: String,
    pub merchant_country_code: String,
    pub dpa_client_id: Option<String>,
}


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

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

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

impl ConnectorSpecifications for for Deutschebank


    PomoravljeDistrict,

    #[strum(serialize = "14")]
    PčinjaDistrict,

    #[strum(serialize = "15")]
    RasinaDistrict,

    #[strum(serialize = "16")]
    RaškaDistrict,

    #[strum(serialize = "17")]
    SouthBanatDistrict,

    #[strum(serialize = "18")]
    SouthBačkaDistrict,

    #[strum(serialize = "19")]
    SremDistrict,

    #[strum(serialize = "20")]
    ToplicaDistrict,

    #[strum(serialize = "21")]
    Vojvodina,

    #[strum(serialize = "22")]
    WestBačkaDistrict,

    #[strum(serialize = "23")]
    ZaječarDistrict,

    #[strum(serialize = "24")]
    ZlatiborDistrict,

    #[strum(serialize = "25")]
    ŠumadijaDistrict,
}

#[derive(
    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, strum::Display, strum::EnumString,
)]
pub enum SlovakiaStatesAbbreviation {
    #[strum(serialize = "BC")]
    BanskaBystricaRegion,
    #[strum(serialize = "BL")]
    BratislavaRegion,
    #[strum(serialize = "KI")]
    KosiceRegion,
    #[strum(serialize = "NI")]
    NitraRegion,
    #[strum(serialize = "PV")]
    PresovRegion,
    #[strum(serialize = "TC")]
    TrencinRegion,
    #[strum(serialize = "TA")]
    TrnavaRegion,
    #[strum(serialize = "ZI")]
    ZilinaRegion,
}

#[derive(
    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, strum::Display, strum::EnumString,
)]
pub enum SloveniaStatesAbbreviation {
    #[strum(serialize = "001")]
    Ajdovščina,
    #[strum(serialize = "213")]
    Ankaran,
    #[strum(serialize = "002")]
    Beltinci,
    #[strum(serialize = "148")]
    Benedikt,
    #[strum(serialize = "149")]
    BistricaObSotli,
    #[strum(serialize = "003")]
    Bled,
    #[strum(serialize = "150")]
    Bloke,
    #[strum(serialize = "004")]
    Bohinj,
    #[strum(serialize = "005")]
    Borovnica,
    #[strum(serialize = "006")]
    Bovec,
    #[strum(serialize = "151")]
    Braslovče,
    #[strum(serialize = "007")]
    Brda,
    #[strum(serialize = "008")]
    Brezovica,
    #[strum(serialize = "009")]
    Brežice,
    #[strum(serialize = "152")]
    Cankova,
    #[strum(serialize = "012")]
    CerkljeNaGorenjskem,
    #[strum(serialize = "013")]
    Cerknica,
    #[strum(serialize = "014")]
    Cerkno,
    #[strum(serialize = "153")]
    Cerkvenjak,
    #[strum(serialize = "011")]
    CityMunicipalityOfCelje,
    #[strum(serialize = "085")]
    CityMunicipalityOfNovoMesto,
    #[strum(serialize = "018")]
    Destrnik,
    #[strum(serialize = "019")]
    Divača,
    #[strum(serialize = "154")]
    Dobje,
    #[strum(serialize = "020")]
    Dobrepolje,
    #[strum(serialize = "155")]
    Dobrna,
    #[strum(serialize = "021")]
    DobrovaPolhovGradec,
    #[strum(serialize = "156")]
    Dobrovnik,
    #[strum(serialize = "022")]
    DolPriLjubljani,
    #[strum(serialize = "157")]
    DolenjskeToplice,
    #[strum(serialize = "023")]
    Domžale,
    #[strum(serialize = "024")]
    Dornava,
    #[strum(serialize = "025")]
    Dravograd,
    #[strum(serialize = "026")]
    Duplek,
    #[strum(serialize = "027")]
    GorenjaVasPoljane,
    #[strum(serialize = "028")]
    Gorišnica,
    #[strum(serialize = "207")]
    Gorje,
    #[strum(serialize = "029")]
    GornjaRadgona,
    #[strum(serialize = "030")]
    GornjiGrad,
    #[strum(serialize = "031")]
    GornjiPetrovci,
    #[strum(serialize = "158")]
    Grad,
    #[strum(serialize = "032")]
    Grosuplje,
    #[strum(serialize = "159")]
    Hajdina,
    #[strum(serialize = "161")]
    Hodoš,
    #[strum(serialize = "162")]
    Horjul,
    #[strum(serialize = "160")]
    HočeSlivnica,
    #[strum(serialize = "034")]
    Hrastnik,
    #[strum(serialize = "035")]
    HrpeljeKozina,
    #[strum(serialize = "036")]
    Idrija,
    #[strum(serialize = "037")]
    Ig,
    #[strum(serialize = "039")]
    IvančnaGorica,
    #[strum(serialize = "040")]
    Izola,
    #[strum(serialize = "041")]
    Jesenice,
    #[strum(serialize = "163")]
    Jezersko,
    #[strum(serialize = "042")]
    Jursinci,
    #[strum(serialize = "043")]
    Kamnik,
    #[strum(serialize = "044")]
    KanalObSoci,
    #[strum(serialize = "045")]
    Kidricevo,
    #[strum(serialize = "046")]
    Kobarid,
    #[strum(serialize = "047")]
    Kobilje,
    #[strum(serialize = "049")]
    Komen,
    #[strum(serialize = "164")]
    Komenda,
    #[strum(serialize = "050")]
    Koper,
    #[strum(serialize = "197")]
    KostanjevicaNaKrki,
    #[strum(serialize = "165")]
    Kostel,
    #[strum(serialize = "051")]
    Kozje,
    #[strum(serialize = "048")]
    Kocevje,
    #[strum(serialize = "052")]
    Kranj,
    #[strum(serialize = "053")]
    KranjskaGora,
    #[strum(serialize = "166")]
    Krizevci,
    #[strum(serialize = "055")]
    Kungota,
    #[strum(serialize = "056")]
    Kuzma,
    #[strum(serialize = "057")]
    Lasko,
    #[strum(serialize = "058")]
    Lenart,
    #[strum(serialize = "059")]
    Lendava,
    #[strum(serialize = "060")]
    Litija,
    #[strum(serialize = "061")]
    Ljubljana,
    #[strum(serialize = "062")]
    Ljubno,
    #[strum(serialize = "063")]
    Ljutomer,
    #[strum(serialize = "064")]
    Logatec,
    #[strum(serialize = "208")]
    LogDragomer,
    #[strum(serialize = "167")]
    LovrencNaPohorju,
    #[strum(serialize = "065")]
    LoskaDolina,
    #[strum(serialize = "066")]
    LoskiPotok,
    #[strum(serialize = "068")]
    Lukovica,
    #[strum(serialize = "067")]
    Luče,
    #[strum(serialize = "069")]
    Majsperk,
    #[strum(serialize = "198")]
    Makole,
    #[strum(serialize = "070")]
    Maribor,
    #[strum(serialize = "168")]
    Markovci,
    #[strum(serialize = "071")]
    Medvode,
    #[strum(serialize = "072")]
    Menges,
    #[strum(serialize = "073")]
    Metlika,
    #[strum(serialize = "074")]
    Mezica,
    #[strum(serialize = "169")]
    MiklavzNaDravskemPolju,
    #[strum(serialize = "075")]
    MirenKostanjevica,
    #[strum(serialize = "212")]
    Mirna,
    #[strum(serialize = "170")]
    MirnaPec,
    #[strum(serialize = "076")]
    Mislinja,
    #[strum(serialize = "199")]
    MokronogTrebelno,
    #[strum(serialize = "078")]
    MoravskeToplice,
    #[strum(serialize = "077")]
    Moravce,
    #[strum(serialize = "079")]
    Mozirje,
    #[strum(serialize = "195")]
    Apače,
    #[strum(serialize = "196")]
    Cirkulane,
    #[strum(serialize = "038")]
    IlirskaBistrica,
    #[strum(serialize = "054")]
    Krsko,
    #[strum(serialize = "123")]
    Skofljica,
    #[strum(serialize = "080")]
    MurskaSobota,
    #[strum(serialize = "081")]
    Muta,
    #[strum(serialize = "082")]
    Naklo,
    #[strum(serialize = "083")]
    Nazarje,
    #[strum(serialize = "084")]
    NovaGorica,
    #[strum(serialize = "086")]
    Odranci,
    #[strum(serialize = "171")]
    Oplotnica,
    #[strum(serialize = "087")]
    Ormoz,
    #[strum(serialize = "088")]
    Osilnica,
    #[strum(serialize = "089")]
    Pesnica,
    #[strum(serialize = "090")]
    Piran,
    #[strum(serialize = "091")]
    Pivka,
    #[strum(serialize = "172")]
    Podlehnik,
    #[strum(serialize = "093")]
    Podvelka,
    #[strum(serialize = "092")]
    Podcetrtek,
    #[strum(serialize = "200")]
    Poljcane,
    #[strum(serialize = "173")]
    Polzela,
    #[strum(serialize = "094")]
    Postojna,
    #[strum(serialize = "174")]
    Prebold,
    #[strum(serialize = "095")]
    Preddvor,
    #[strum(serialize = "175")]
    Prevalje,
    #[strum(serialize = "096")]
    Ptuj,
    #[strum(serialize = "097")]
    Puconci,
    #[strum(serialize = "100")]
    Radenci,
    #[strum(serialize = "099")]
    Radece,
    #[strum(serialize = "101")]
    RadljeObDravi,
    #[strum(serialize = "102")]
    Radovljica,
    #[strum(serialize = "103")]
    RavneNaKoroskem,
    #[strum(serialize = "176")]
    Razkrizje,
    #[strum(serialize = "098")]
    RaceFram,
    #[strum(serialize = "201")]
    RenčeVogrsko,
    #[strum(serialize = "209")]
    RecicaObSavinji,
    #[strum(serialize = "104")]
    Ribnica,
    #[strum(serialize = "177")]
    RibnicaNaPohorju,
    #[strum(serialize = "107")]
    Rogatec,
    #[strum(serialize = "106")]
    RogaskaSlatina,
    #[strum(serialize = "105")]
    Rogasovci,
    #[strum(serialize = "108")]
    Ruse,
    #[strum(serialize = "178")]
    SelnicaObDravi,
    #[strum(serialize = "109")]
    Semic,
    #[strum(serialize = "110")]
    Sevnica,
    #[strum(serialize = "111")]
    Sezana,
    #[strum(serialize = "112")]
    SlovenjGradec,
    #[strum(serialize = "113")]
    SlovenskaBistrica,
    #[strum(serialize = "114")]
    SlovenskeKonjice,
    #[strum(serialize = "179")]
    Sodrazica,
    #[strum(serialize = "180")]
    Solcava,
    #[strum(serialize = "202")]
    SredisceObDravi,
    #[strum(serialize = "115")]
    Starse,
    #[strum(serialize = "203")]
    Straza,
    #[strum(serialize = "181")]
    SvetaAna,
    #[strum(serialize = "204")]
    SvetaTrojica,
    #[strum(serialize = "182")]
    SvetiAndraz,
    #[strum(serialize = "116")]
    SvetiJurijObScavnici,
    #[strum(serialize = "210")]
    SvetiJurijVSlovenskihGoricah,
    #[strum(serialize = "205")]
    SvetiTomaz,
    #[strum(serialize = "184")]
    Tabor,
    #[strum(serialize = "010")]
    Tišina,
    #[strum(serialize = "128")]
    Tolmin,
    #[strum(serialize = "129")]
    Trbovlje,
    #[strum(serialize = "130")]
    Trebnje,
    #[strum(serialize = "185")]
    TrnovskaVas,
    #[strum(serialize = "186")]
    Trzin,
    #[strum(serialize = "131")]
    Tržič,
    #[strum(serialize = "132")]
    Turnišče,
    #[strum(serialize = "187")]
    VelikaPolana,
    #[strum(serialize = "134")]
    VelikeLašče,
    #[strum(serialize = "188")]
    Veržej,
    #[strum(serialize = "135")]
    Videm,
    #[strum(serialize = "136")]
    Vipava,
    #[strum(serialize = "137")]
    Vitanje,
    #[strum(serialize = "138")]
    Vodice,
    #[strum(serialize = "139")]
    Vojnik,
    #[strum(serialize = "189")]
    Vransko,
    #[strum(serialize = "140")]
    Vrhnika,
    #[strum(serialize = "141")]
    Vuzenica,
    #[strum(serialize = "142")]
    ZagorjeObSavi,
    #[strum(serialize = "143")]
    Zavrč,
    #[strum(serialize = "144")]
    Zreče,
    #[strum(serialize = "015")]
    Črenšovci,
    #[strum(serialize = "016")]
    ČrnaNaKoroškem,
    #[strum(serialize = "017")]
    Črnomelj,
    #[strum(serialize = "033")]
    Šalovci,
    #[strum(serialize = "183")]
    ŠempeterVrtojba,
    #[strum(serialize = "118")]
    Šentilj,
    #[strum(serialize = "119")]
    Šentjernej,
    #[strum(serialize = "120")]
    Šentjur,
    #[strum(serialize = "211")]
    Šentrupert,
    #[strum(serialize = "117")]
    Šenčur,
    #[strum(serialize = "121")]
    Škocjan,
    #[strum(serialize = "122")]
    ŠkofjaLoka,
    #[strum(serialize = "124")]
    ŠmarjePriJelšah,
    #[strum(serialize = "206")]
    ŠmarješkeToplice,
    #[strum(serialize = "125")]
    ŠmartnoObPaki,
    #[strum(serialize = "194")]
    ŠmartnoPriLitiji,
    #[strum(serialize = "126")]
    Šoštanj,
    #[strum(serialize = "127")]
    Štore,
    #[strum(serialize = "190")]
    Žalec,
    #[strum(serialize = "146")]
    Železniki,
    #[strum(serialize = "191")]
    Žetale,
    #[strum(serialize = "147")]
    Žiri,
    #[strum(serialize = "192")]
    Žirovnica,
    #[strum(serialize = "193")]
    Žužemberk,
}

#[derive(
    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, strum::Display, strum::EnumString,
)]
pub enum SwedenStatesAbbreviation {
    #[strum(serialize = "K")]
    Blekinge,
    #[strum(serialize = "W")]
    DalarnaCounty,
    #[strum(serialize = "I")]
    GotlandCounty,
    #[strum(serialize = "X")]
    GävleborgCounty,
    #[strum(serialize = "N")]
    HallandCounty,
    #[strum(serialize = "F")]
    JönköpingCounty,
    #[strum(serialize = "H")]
    KalmarCounty,
    #[strum(serialize = "G")]
    KronobergCounty,
    #[strum(serialize = "BD")]
    NorrbottenCounty,
    #[strum(serialize = "M")]
    SkåneCounty,
    #[strum(serialize = "AB")]
    StockholmCounty,
    #[strum(serialize = "D")]
    SödermanlandCounty,
    #[strum(serialize = "C")]
    UppsalaCounty,
    #[strum(serialize = "S")]
    VärmlandCounty,
    #[strum(serialize = "AC")]
    VästerbottenCounty,
    #[strum(serialize = "Y")]
    VästernorrlandCounty,
    #[strum(serialize = "U")]
    VästmanlandCounty,
    #[strum(serialize = "O")]
    VästraGötalandCounty,
    #[strum(serialize = "T")]
    ÖrebroCounty,
    #[strum(serialize = "E")]
    ÖstergötlandCounty,
}

#[derive(
    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, strum::Display, strum::EnumString,
)]
pub enum UkraineStatesAbbreviation {
    #[strum(serialize = "43")]
    AutonomousRepublicOfCrimea,
    #[strum(serialize = "71")]
    CherkasyOblast,
    #[strum(serialize = "74")]
    ChernihivOblast,
    #[strum(serialize = "77")]
    ChernivtsiOblast,
    #[strum(serialize = "12")]
    DnipropetrovskOblast,
    #[strum(serialize = "14")]
    DonetskOblast,
    #[strum(serialize = "26")]
    IvanoFrankivskOblast,
    #[strum(serialize = "63")]
    KharkivOblast,
    #[strum(serialize = "65")]
    KhersonOblast,
    #[strum(serialize = "68")]
    KhmelnytskyOblast,
    #[strum(serialize = "30")]
    Kiev,
    #[strum(serialize = "35")]
    KirovohradOblast,
    #[strum(serialize = "32")]
    KyivOblast,
    #[strum(serialize = "09")]
    LuhanskOblast,
    #[strum(serialize = "46")]
    LvivOblast,
    #[strum(serialize = "48")]
    MykolaivOblast,
    #[strum(serialize = "51")]
    OdessaOblast,
    #[strum(serialize = "56")]
    RivneOblast,
    #[strum(serialize = "59")]
    SumyOblast,
    #[strum(serialize = "61")]
    TernopilOblast,
    #[strum(serialize = "05")]
    VinnytsiaOblast,
    #[strum(serialize = "07")]
    VolynOblast,
    #[strum(serialize = "21")]
    ZakarpattiaOblast,
    #[strum(serialize = "23")]
    ZaporizhzhyaOblast,
    #[strum(serialize = "18")]
    ZhytomyrOblast,
}

#[derive(
    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, strum::Display, strum::EnumString,
)]
pub enum RomaniaStatesAbbreviation {
    #[strum(serialize = "AB")]
    Alba,
    #[strum(serialize = "AR")]
    AradCounty,
    #[strum(serialize = "AG")]
    Arges,
    #[strum(serialize = "BC")]
    BacauCounty,
    #[strum(serialize = "BH")]
    BihorCounty,
    #[strum(serialize = "BN")]
    BistritaNasaudCounty,
    #[strum(serialize = "BT")]
    BotosaniCounty,
    #[strum(serialize = "BR")]
    Braila,
    #[strum(serialize = "BV")]
    BrasovCounty,
    #[strum(serialize = "B")]
    Bucharest,
    #[strum(serialize = "BZ")]
    BuzauCounty,
    #[strum(serialize = "CS")]
    CarasSeverinCounty,
    #[strum(serialize = "CJ")]
    ClujCounty,
    #[strum(serialize = "CT")]
    ConstantaCounty,
    #[strum(serialize = "CV")]
    CovasnaCounty,
    #[strum(serialize = "CL")]
    CalarasiCounty,
    #[strum(serialize = "DJ")]
    DoljCounty,
    #[strum(serialize = "DB")]
    DambovitaCounty,
    #[strum(serialize = "GL")]
    GalatiCounty,
    #[strum(serialize = "GR")]
    GiurgiuCounty,
    #[strum(serialize = "GJ")]
    GorjCounty,
    #[strum(serialize = "HR")]
    HarghitaCounty,
    #[strum(serialize = "HD")]
    HunedoaraCounty,
    #[strum(serialize = "IL")]
    IalomitaCounty,
    #[strum(serialize = "IS")]
    IasiCounty,
    #[strum(serialize = "IF")]
    IlfovCounty,
    #[strum(serialize = "MH")]
    MehedintiCounty,
    #[strum(serialize = "MM")]
    MuresCounty,
    #[strum(serialize = "NT")]
    NeamtCounty,
    #[strum(serialize = "OT")]
    OltCounty,
    #[strum(serialize = "PH")]
    PrahovaCounty,
    #[strum(serialize = "SM")]
    SatuMareCounty,
    #[strum(serialize = "SB")]
    SibiuCounty,
    #[strum(serialize = "SV")]
    SuceavaCounty,
    #[strum(serialize = "SJ")]
    SalajCounty,
    #[strum(serialize = "TR")]
    TeleormanCounty,
    #[strum(serialize = "TM")]
    TimisCounty,
    #[strum(serialize = "TL")]
    TulceaCounty,
    #[strum(serialize = "VS")]
    VasluiCounty,
    #[strum(serialize = "VN")]
    VranceaCounty,
    #[strum(serialize = "VL")]
    ValceaCounty,
}

#[derive(
    Debug, Clone, PartialEq, Eq, Serialize, Deserialize, strum::Display, strum::EnumString,
)]
pub enum BrazilStatesAbbreviation {
    #[strum(serialize = "AC")]
    Acre,
    #[strum(serialize = "AL")]
    Alagoas,
    #[strum(serialize = "AP")]
    Amapá,
    #[strum(serialize = "AM")]
    Amazonas,
    #[strum(serialize = "BA")]
    Bahia,
    #[strum(serialize = "CE")]
    Ceará,
    #[strum(serialize = "DF")]
    DistritoFederal,
    #[strum(serialize = "ES")]
    EspíritoSanto,
    #[strum(serialize = "GO")]
    Goiás,
    #[strum(serialize = "MA")]
    Maranhão,
    #[strum(serialize = "MT")]
    MatoGrosso,
    #[strum(serialize = "MS")]
    MatoGrossoDoSul,
    #[strum(serialize = "MG")]
    MinasGerais,
    #[strum(serialize = "PA")]
    Pará,
    #[strum(serialize = "PB")]
    Paraíba,
    #[strum(serialize = "PR")]
    Paraná,
    #[strum(serialize = "PE")]
    Pernambuco,
    #[strum(serialize = "PI")]
    Piauí,
    #[strum(serialize = "RJ")]
    RioDeJaneiro,
    #[strum(serialize = "RN")]
    RioGrandeDoNorte,
    #[strum(serialize = "RS")]
    RioGrandeDoSul,
    #[strum(serialize = "RO")]
    Rondônia,
    #[strum(serialize = "RR")]
    Roraima,
    #[strum(serialize = "SC")]
    SantaCatarina,
    #[strum(serialize = "SP")]
    SãoPaulo,
    #[strum(serialize = "SE")]
    Sergipe,
    #[strum(serialize = "TO")]
    Tocantins,
}

#[derive(
    Clone,
    Copy,
    Debug,
    Default,
    Eq,
    Hash,
    PartialEq,
    ToSchema,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumIter,
    strum::EnumString,
)]
#[router_derive::diesel_enum(storage_type = "db_enum")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum PayoutStatus {
    Success,
    Failed,
    Cancelled,
    Initiated,
    Expired,
    Reversed,
    Pending,
    Ineligible,
    #[default]
    RequiresCreation,
    RequiresConfirmation,
    RequiresPayoutMethodData,
    RequiresFulfillment,
    RequiresVendorAccountCreation,
}

/// The payout_type of the payout request is a mandatory field for confirming the payouts. It should be specified in the Create request. If not provided, it must be updated in the Payout Update request before it can be confirmed.
#[derive(
    Clone,
    Copy,
    Debug,
    Default,
    Eq,
    Hash,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::VariantNames,
    strum::EnumIter,
    strum::EnumString,
    ToSchema,
)]
#[router_derive::diesel_enum(storage_type = "db_enum")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum PayoutType {
    #[default]
    Card,
    Bank,
    Wallet,
}

/// Type of entity to whom the payout is being carried out to, select from the given list of options
#[derive(
    Clone,
    Copy,
    Debug,
    Default,
    Eq,
    Hash,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumString,
    ToSchema,
)]
#[router_derive::diesel_enum(storage_type = "text")]
#[serde(rename_all = "PascalCase")]
#[strum(serialize_all = "PascalCase")]
pub enum PayoutEntityType {
    /// Adyen
    #[default]
    Individual,
    Company,
    NonProfit,
    PublicSector,
    NaturalPerson,

    /// Wise
    #[strum(serialize = "lowercase")]
    #[serde(rename = "lowercase")]
    Business,
    Personal,
}

/// The send method which will be required for processing payouts, check options for better understanding.
#[derive(
    Clone,
    Copy,
    Debug,
    Eq,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumString,
    ToSchema,
    Hash,
)]
#[router_derive::diesel_enum(storage_type = "text")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum PayoutSendPriority {
    Instant,
    Fast,
    Regular,
    Wire,
    CrossBorder,
    Internal,
}

#[derive(
    Clone,
    Copy,
    Debug,
    Default,
    Eq,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumString,
    ToSchema,
    Hash,
)]
#[router_derive::diesel_enum(storage_type = "db_enum")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum PaymentSource {
    #[default]
    MerchantServer,
    Postman,
    Dashboard,
    Sdk,
    Webhook,
    ExternalAuthenticator,
}

#[derive(Default, Debug, Clone, serde::Deserialize, serde::Serialize, strum::EnumString)]
pub enum BrowserName {
    #[default]
    Safari,
    #[serde(other)]
    Unknown,
}

#[derive(Default, Debug, Clone, serde::Deserialize, serde::Serialize, strum::EnumString)]
#[strum(serialize_all = "snake_case")]
pub enum ClientPlatform {
    #[default]
    Web,
    Ios,
    Android,
    #[serde(other)]
    Unknown,
}

impl PaymentSource {
    pub fn is_for_internal_use_only(self) -> bool {
        match self {
            Self::Dashboard | Self::Sdk | Self::MerchantServer | Self::Postman => false,
            Self::Webhook | Self::ExternalAuthenticator => true,
        }
    }
}

#[derive(
    Clone,
    Copy,
    Debug,
    Eq,
    PartialEq,
    serde::Serialize,
    serde::Deserialize,
    strum::Display,
    strum::EnumString,
)]
#[router_derive::diesel_enum(storage_type = "text")]
#[strum(serialize_all = "snake_case")]
pub enum MerchantDecision {
    Approved,
    Rejected,
    AutoRefunded,
}
#[derive(
    Clone,
    Copy,
    Debug,
    Eq,
    PartialEq,
    serde::Serialize,
    serde::Deserialize,
    strum::Display,
    strum::EnumString,
    strum::EnumIter,
    ToSchema,
)]
#[router_derive::diesel_enum(storage_type = "text")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum TaxStatus {
    Taxable,
    Exempt,
}

#[derive(
    Clone,
    Copy,
    Default,
    Debug,
    Eq,
    Hash,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumString,
    ToSchema,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum FrmSuggestion {
    #[default]
    FrmCancelTransaction,
    FrmManualReview,
    FrmAuthorizeTransaction, // When manual capture payment which was marked fraud and held, when approved needs to be authorized.
}

#[derive(
    Clone,
    Debug,
    Eq,
    Hash,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumString,
    utoipa::ToSchema,
    Copy,
)]
#[router_derive::diesel_enum(storage_type = "db_enum")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum ReconStatus {
    NotRequested,
    Requested,
    Active,
    Disabled,
}

#[derive(
    Clone,
    Copy,
    Debug,
    Eq,
    Hash,
    PartialEq,
    serde::Serialize,
    serde::Deserialize,
    strum::Display,
    strum::EnumString,
    ToSchema,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum AuthenticationConnectors {
    Threedsecureio,
    Netcetera,
    Gpayments,
    CtpMastercard,
    UnifiedAuthenticationService,
    Juspaythreedsserver,
    CtpVisa,
}

impl AuthenticationConnectors {
    pub fn is_separate_version_call_required(self) -> bool {
        match self {
            Self::Threedsecureio
            | Self::Netcetera
            | Self::CtpMastercard
            | Self::UnifiedAuthenticationService
            | Self::Juspaythreedsserver
            | Self::CtpVisa => false,
            Self::Gpayments => true,
        }
    }
}

#[derive(
    Clone,
    Copy,
    Debug,
    Eq,
    Hash,
    PartialEq,
    serde::Serialize,
    serde::Deserialize,
    strum::Display,
    strum::EnumString,
    ToSchema,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum VaultSdk {
    VgsSdk,
    HyperswitchSdk,
}

#[derive(
    Clone,
    Debug,
    Eq,
    Default,
    Hash,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumString,
    utoipa::ToSchema,
    Copy,
)]
#[router_derive::diesel_enum(storage_type = "text")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum AuthenticationStatus {
    #[default]
    Started,
    Pending,
    Success,
    Failed,
}

impl AuthenticationStatus {
    pub fn is_terminal_status(self) -> bool {
        match self {
            Self::Started | Self::Pending => false,
            Self::Success | Self::Failed => true,
        }
    }

    pub fn is_failed(self) -> bool {
        self == Self::Failed
    }
}

#[derive(
    Clone,
    Debug,
    Eq,
    Default,
    Hash,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumString,
    utoipa::ToSchema,
    Copy,
)]
#[router_derive::diesel_enum(storage_type = "text")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum DecoupledAuthenticationType {
    #[default]
    Challenge,
    Frictionless,
}

#[derive(
    Clone,
    Debug,
    Eq,
    Default,
    Hash,
    PartialEq,
    serde::Deserialize,


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


pub struct FlexitiPaymentsRequest {
    merchant_order_id: Option<String>,
    lang: String,
    flow: FlexitiFlow,
    amount_requested: FloatMajorUnit,
    email: Option<Email>,
    fname: Secret<String>,
    billing_information: BillingInformation,
    shipping_information: ShippingInformation,
}


pub(crate) fn get_idempotent_event_id(
    primary_object_id: &str,
    event_type: types::storage::enums::EventType,
    delivery_attempt: types::storage::enums::WebhookDeliveryAttempt,
) -> String {
    use crate::types::storage::enums::WebhookDeliveryAttempt;

    const EVENT_ID_SUFFIX_LENGTH: usize = 8;

    let common_prefix = format!("{primary_object_id}_{event_type}");
    match delivery_attempt {
        WebhookDeliveryAttempt::InitialAttempt => common_prefix,
        WebhookDeliveryAttempt::AutomaticRetry | WebhookDeliveryAttempt::ManualRetry => {
            common_utils::generate_id(EVENT_ID_SUFFIX_LENGTH, &common_prefix)
        }
    }
}


OpenAPI Block Path: components.schemas.UpiAdditionalData
{
  "oneOf": [
    {
      "type": "object",
      "required": [
        "upi_collect"
      ],
      "properties": {
        "upi_collect": {
          "$ref": "#/components/schemas/UpiCollectAdditionalData"
        }
      }
    },
    {
      "type": "object",
      "required": [
        "upi_intent"
      ],
      "properties": {
        "upi_intent": {
          "$ref": "#/components/schemas/UpiIntentData"
        }
      }
    }
  ]
}


pub struct TokenizedWalletValue2 {
    pub customer_id: Option<id_type::CustomerId>,
}


pub(super) struct SerializeVec<T: Serializer> {
        vec: Vec<Value>,
        ser: T,
    }


pub trait AnalyticsDataSource
where
    Self: Sized + Sync + Send,
{
    type Row;
    async fn load_results<T>(&self, query: &str) -> CustomResult<Vec<T>, QueryExecutionError>
    where
        Self: LoadRow<T>;

    fn get_table_engine(_table: AnalyticsCollection) -> TableEngine {
        TableEngine::BasicTree
    }
}


pub fn get_gsm_decision(
    option_gsm: Option<hyperswitch_domain_models::gsm::GatewayStatusMap>,
) -> storage_enums::GsmDecision {
    let option_gsm_decision = option_gsm
        .as_ref()
        .map(|gsm| gsm.feature_data.get_decision());

    if option_gsm_decision.is_some() {
        metrics::AUTO_RETRY_GSM_MATCH_COUNT.add(1, &[]);
    }
    option_gsm_decision.unwrap_or_default()
}


impl<const T: u8> PaymentVoid for DummyConnector<T> {}


pub async fn create_routing_algorithm_under_profile(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    authentication_profile_id: Option<common_utils::id_type::ProfileId>,
    request: routing_types::RoutingConfigRequest,
    transaction_type: enums::TransactionType,
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
    metrics::ROUTING_CREATE_REQUEST_RECEIVED.add(1, &[]);
    let db = &*state.store;
    let key_manager_state = &(&state).into();

    let business_profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&request.profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")?;
    let merchant_id = merchant_context.get_merchant_account().get_id();
    core_utils::validate_profile_id_from_auth_layer(authentication_profile_id, &business_profile)?;
    let all_mcas = state
        .store
        .find_merchant_connector_account_by_merchant_id_and_disabled_list(
            key_manager_state,
            merchant_id,
            true,
            merchant_context.get_merchant_key_store(),
        )
        .await
        .change_context(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
            id: merchant_id.get_string_repr().to_owned(),
        })?;

    let name_mca_id_set = helpers::ConnectNameAndMCAIdForProfile(
        all_mcas.filter_by_profile(business_profile.get_id(), |mca| {
            (&mca.connector_name, mca.get_id())
        }),
    );

    let name_set = helpers::ConnectNameForProfile(
        all_mcas.filter_by_profile(business_profile.get_id(), |mca| &mca.connector_name),
    );

    let algorithm_helper = helpers::RoutingAlgorithmHelpers {
        name_mca_id_set,
        name_set,
        routing_algorithm: &request.algorithm,
    };

    algorithm_helper.validate_connectors_in_routing_config()?;

    let algo = RoutingAlgorithmUpdate::create_new_routing_algorithm(
        &request,
        merchant_context.get_merchant_account().get_id(),
        business_profile.get_id().to_owned(),
        transaction_type,
    );

    let record = state
        .store
        .as_ref()
        .insert_routing_algorithm(algo.0)
        .await
        .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;

    let new_record = record.foreign_into();

    metrics::ROUTING_CREATE_SUCCESS_RESPONSE.add(1, &[]);
    Ok(service_api::ApplicationResponse::Json(new_record))
}


File: crates/hyperswitch_connectors/src/connectors/aci/transformers.rs
 Public structs: 28

use std::str::FromStr;

use common_enums::enums;
use common_utils::{id_type, pii::Email, request::Method, types::StringMajorUnit};
use error_stack::report;
use hyperswitch_domain_models::{
    payment_method_data::{BankRedirectData, Card, PayLaterData, PaymentMethodData, WalletData},
    router_data::{ConnectorAuthType, RouterData},
    router_request_types::{
        PaymentsAuthorizeData, PaymentsCancelData, PaymentsSyncData, ResponseId,
    },
    router_response_types::{
        MandateReference, PaymentsResponseData, RedirectForm, RefundsResponseData,
    },
    types::{
        PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
        RefundsRouterData,
    },
};
use hyperswitch_interfaces::errors;
use masking::{ExposeInterface, Secret};
use serde::{Deserialize, Serialize};
use url::Url;

use super::aci_result_codes::{FAILURE_CODES, PENDING_CODES, SUCCESSFUL_CODES};
use crate::{
    types::{RefundsResponseRouterData, ResponseRouterData},
    utils::{self, PhoneDetailsData, RouterData as _},
};

type Error = error_stack::Report<errors::ConnectorError>;

trait GetCaptureMethod {
    fn get_capture_method(&self) -> Option<enums::CaptureMethod>;
}

impl GetCaptureMethod for PaymentsAuthorizeData {
    fn get_capture_method(&self) -> Option<enums::CaptureMethod> {
        self.capture_method
    }
}

impl GetCaptureMethod for PaymentsSyncData {
    fn get_capture_method(&self) -> Option<enums::CaptureMethod> {
        self.capture_method
    }
}

impl GetCaptureMethod for PaymentsCancelData {
    fn get_capture_method(&self) -> Option<enums::CaptureMethod> {
        None
    }
}

#[derive(Debug, Serialize)]
pub struct AciRouterData<T> {
    amount: StringMajorUnit,
    router_data: T,
}

impl<T> From<(StringMajorUnit, T)> for AciRouterData<T> {
    fn from((amount, item): (StringMajorUnit, T)) -> Self {
        Self {
            amount,
            router_data: item,
        }
    }
}

pub struct AciAuthType {
    pub api_key: Secret<String>,
    pub entity_id: Secret<String>,
}

impl TryFrom<&ConnectorAuthType> for AciAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &ConnectorAuthType) -> Result<Self, Self::Error> {
        if let ConnectorAuthType::BodyKey { api_key, key1 } = item {
            Ok(Self {
                api_key: api_key.to_owned(),
                entity_id: key1.to_owned(),
            })
        } else {
            Err(errors::ConnectorError::FailedToObtainAuthType)?
        }
    }
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AciPaymentsRequest {
    #[serde(flatten)]
    pub txn_details: TransactionDetails,
    #[serde(flatten)]
    pub payment_method: PaymentDetails,
    #[serde(flatten)]
    pub instruction: Option<Instruction>,
    pub shopper_result_url: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TransactionDetails {
    pub entity_id: Secret<String>,
    pub amount: StringMajorUnit,
    pub currency: String,
    pub payment_type: AciPaymentType,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AciCancelRequest {
    pub entity_id: Secret<String>,
    pub payment_type: AciPaymentType,
}

#[derive(Debug, Clone, Serialize)]
#[serde(untagged)]
pub enum PaymentDetails {
    #[serde(rename = "card")]
    AciCard(Box<CardDetails>),
    BankRedirect(Box<BankRedirectionPMData>),
    Wallet(Box<WalletPMData>),
    Klarna,
    Mandate,
}

impl TryFrom<(&WalletData, &PaymentsAuthorizeRouterData)> for PaymentDetails {
    type Error = Error;
    fn try_from(value: (&WalletData, &PaymentsAuthorizeRouterData)) -> Result<Self, Self::Error> {
        let (wallet_data, item) = value;
        let payment_data = match wallet_data {
            WalletData::MbWayRedirect(_) => {
                let phone_details = item.get_billing_phone()?;
                Self::Wallet(Box::new(WalletPMData {
                    payment_brand: PaymentBrand::Mbway,
                    account_id: Some(phone_details.get_number_with_hash_country_code()?),
                }))
            }
            WalletData::AliPayRedirect { .. } => Self::Wallet(Box::new(WalletPMData {
                payment_brand: PaymentBrand::AliPay,
                account_id: None,
            })),
            WalletData::AliPayHkRedirect(_)
            | WalletData::AmazonPayRedirect(_)
            | WalletData::Paysera(_)
            | WalletData::Skrill(_)
            | WalletData::MomoRedirect(_)
            | WalletData::KakaoPayRedirect(_)
            | WalletData::GoPayRedirect(_)
            | WalletData::GcashRedirect(_)
            | WalletData::AmazonPay(_)
            | WalletData::ApplePay(_)
            | WalletData::ApplePayThirdPartySdk(_)
            | WalletData::DanaRedirect { .. }
            | WalletData::GooglePay(_)
            | WalletData::BluecodeRedirect {}
            | WalletData::GooglePayThirdPartySdk(_)
            | WalletData::MobilePayRedirect(_)
            | WalletData::PaypalRedirect(_)
            | WalletData::PaypalSdk(_)
            | WalletData::Paze(_)
            | WalletData::SamsungPay(_)
            | WalletData::TwintRedirect { .. }
            | WalletData::VippsRedirect { .. }
            | WalletData::TouchNGoRedirect(_)
            | WalletData::WeChatPayRedirect(_)
            | WalletData::WeChatPayQr(_)
            | WalletData::CashappQr(_)
            | WalletData::SwishQr(_)
            | WalletData::AliPayQr(_)
            | WalletData::ApplePayRedirect(_)
            | WalletData::GooglePayRedirect(_)
            | WalletData::Mifinity(_)
            | WalletData::RevolutPay(_) => Err(errors::ConnectorError::NotImplemented(
                "Payment method".to_string(),
            ))?,
        };
        Ok(payment_data)
    }
}

impl
    TryFrom<(
        &AciRouterData<&PaymentsAuthorizeRouterData>,
        &BankRedirectData,
    )> for PaymentDetails
{
    type Error = Error;
    fn try_from(
        value: (
            &AciRouterData<&PaymentsAuthorizeRouterData>,
            &BankRedirectData,
        ),
    ) -> Result<Self, Self::Error> {
        let (item, bank_redirect_data) = value;
        let payment_data = match bank_redirect_data {
            BankRedirectData::Eps { .. } => Self::BankRedirect(Box::new(BankRedirectionPMData {
                payment_brand: PaymentBrand::Eps,
                bank_account_country: Some(item.router_data.get_billing_country()?),
                bank_account_bank_name: None,
                bank_account_bic: None,
                bank_account_iban: None,
                billing_country: None,
                merchant_customer_id: None,
                merchant_transaction_id: None,
                customer_email: None,
            })),
            BankRedirectData::Eft { .. } => Self::BankRedirect(Box::new(BankRedirectionPMData {
                payment_brand: PaymentBrand::Eft,
                bank_account_country: Some(item.router_data.get_billing_country()?),
                bank_account_bank_name: None,
                bank_account_bic: None,
                bank_account_iban: None,
                billing_country: None,
                merchant_customer_id: None,
                merchant_transaction_id: None,
                customer_email: None,
            })),
            BankRedirectData::Giropay {
                bank_account_bic,
                bank_account_iban,
                ..
            } => Self::BankRedirect(Box::new(BankRedirectionPMData {
                payment_brand: PaymentBrand::Giropay,
                bank_account_country: Some(item.router_data.get_billing_country()?),
                bank_account_bank_name: None,
                bank_account_bic: bank_account_bic.clone(),
                bank_account_iban: bank_account_iban.clone(),
                billing_country: None,
                merchant_customer_id: None,
                merchant_transaction_id: None,
                customer_email: None,
            })),
            BankRedirectData::Ideal { bank_name, .. } => {
                Self::BankRedirect(Box::new(BankRedirectionPMData {
                    payment_brand: PaymentBrand::Ideal,
                    bank_account_country: Some(item.router_data.get_billing_country()?),
                    bank_account_bank_name: Some(bank_name.ok_or(
                        errors::ConnectorError::MissingRequiredField {
                            field_name: "ideal.bank_name",
                        },
                    )?),
                    bank_account_bic: None,
                    bank_account_iban: None,
                    billing_country: None,
                    merchant_customer_id: None,
                    merchant_transaction_id: None,
                    customer_email: None,
                }))
            }
            BankRedirectData::Sofort { .. } => {
                Self::BankRedirect(Box::new(BankRedirectionPMData {
                    payment_brand: PaymentBrand::Sofortueberweisung,
                    bank_account_country: Some(item.router_data.get_billing_country()?),
                    bank_account_bank_name: None,
                    bank_account_bic: None,
                    bank_account_iban: None,
                    billing_country: None,
                    merchant_customer_id: None,
                    merchant_transaction_id: None,
                    customer_email: None,
                }))
            }
            BankRedirectData::Przelewy24 { .. } => {
                Self::BankRedirect(Box::new(BankRedirectionPMData {
                    payment_brand: PaymentBrand::Przelewy,
                    bank_account_country: None,
                    bank_account_bank_name: None,
                    bank_account_bic: None,
                    bank_account_iban: None,
                    billing_country: None,
                    merchant_customer_id: None,
                    merchant_transaction_id: None,
                    customer_email: Some(item.router_data.get_billing_email()?),
                }))
            }
            BankRedirectData::Interac { .. } => {
                Self::BankRedirect(Box::new(BankRedirectionPMData {
                    payment_brand: PaymentBrand::InteracOnline,
                    bank_account_country: Some(item.router_data.get_billing_country()?),
                    bank_account_bank_name: None,
                    bank_account_bic: None,
                    bank_account_iban: None,
                    billing_country: None,
                    merchant_customer_id: None,
                    merchant_transaction_id: None,
                    customer_email: Some(item.router_data.get_billing_email()?),
                }))
            }
            BankRedirectData::Trustly { .. } => {
                Self::BankRedirect(Box::new(BankRedirectionPMData {
                    payment_brand: PaymentBrand::Trustly,
                    bank_account_country: None,
                    bank_account_bank_name: None,
                    bank_account_bic: None,
                    bank_account_iban: None,
                    billing_country: Some(item.router_data.get_billing_country()?),
                    merchant_customer_id: Some(Secret::new(item.router_data.get_customer_id()?)),
                    merchant_transaction_id: Some(Secret::new(
                        item.router_data.connector_request_reference_id.clone(),
                    )),
                    customer_email: None,
                }))
            }
            BankRedirectData::Bizum { .. }
            | BankRedirectData::Blik { .. }
            | BankRedirectData::BancontactCard { .. }
            | BankRedirectData::OnlineBankingCzechRepublic { .. }
            | BankRedirectData::OnlineBankingFinland { .. }
            | BankRedirectData::OnlineBankingFpx { .. }
            | BankRedirectData::OnlineBankingPoland { .. }
            | BankRedirectData::OnlineBankingSlovakia { .. }
            | BankRedirectData::OnlineBankingThailand { .. }
            | BankRedirectData::LocalBankRedirect {}
            | BankRedirectData::OpenBankingUk { .. } => Err(
                errors::ConnectorError::NotImplemented("Payment method".to_string()),
            )?,
        };
        Ok(payment_data)
    }
}

impl TryFrom<(Card, Option<Secret<String>>)> for PaymentDetails {
    type Error = Error;
    fn try_from(
        (card_data, card_holder_name): (Card, Option<Secret<String>>),
    ) -> Result<Self, Self::Error> {
        Ok(Self::AciCard(Box::new(CardDetails {
            card_number: card_data.card_number,
            card_holder: card_holder_name.unwrap_or(Secret::new("".to_string())),
            card_expiry_month: card_data.card_exp_month,
            card_expiry_year: card_data.card_exp_year,
            card_cvv: card_data.card_cvc,
        })))
    }
}

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BankRedirectionPMData {
    payment_brand: PaymentBrand,
    #[serde(rename = "bankAccount.country")]
    bank_account_country: Option<api_models::enums::CountryAlpha2>,
    #[serde(rename = "bankAccount.bankName")]
    bank_account_bank_name: Option<common_enums::BankNames>,
    #[serde(rename = "bankAccount.bic")]
    bank_account_bic: Option<Secret<String>>,
    #[serde(rename = "bankAccount.iban")]
    bank_account_iban: Option<Secret<String>>,
    #[serde(rename = "billing.country")]
    billing_country: Option<api_models::enums::CountryAlpha2>,
    #[serde(rename = "customer.email")]
    customer_email: Option<Email>,
    #[serde(rename = "customer.merchantCustomerId")]
    merchant_customer_id: Option<Secret<id_type::CustomerId>>,
    merchant_transaction_id: Option<Secret<String>>,
}

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct WalletPMData {
    payment_brand: PaymentBrand,
    #[serde(rename = "virtualAccount.accountId")]
    account_id: Option<Secret<String>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum PaymentBrand {
    Eps,
    Eft,
    Ideal,
    Giropay,
    Sofortueberweisung,
    InteracOnline,
    Przelewy,
    Trustly,
    Mbway,
    #[serde(rename = "ALIPAY")]
    AliPay,
}

#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
pub struct CardDetails {
    #[serde(rename = "card.number")]
    pub card_number: cards::CardNumber,
    #[serde(rename = "card.holder")]
    pub card_holder: Secret<String>,
    #[serde(rename = "card.expiryMonth")]
    pub card_expiry_month: Secret<String>,
    #[serde(rename = "card.expiryYear")]
    pub card_expiry_year: Secret<String>,
    #[serde(rename = "card.cvv")]
    pub card_cvv: Secret<String>,
}

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum InstructionMode {
    Initial,
    Repeated,
}

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum InstructionType {
    Unscheduled,
}

#[derive(Debug, Clone, Serialize)]
pub enum InstructionSource {
    #[serde(rename = "CIT")]
    CardholderInitiatedTransaction,
    #[serde(rename = "MIT")]
    MerchantInitiatedTransaction,
}

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Instruction {
    #[serde(rename = "standingInstruction.mode")]
    mode: InstructionMode,

    #[serde(rename = "standingInstruction.type")]
    transaction_type: InstructionType,

    #[serde(rename = "standingInstruction.source")]
    source: InstructionSource,

    create_registration: Option<bool>,
}

#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
pub struct BankDetails {
    #[serde(rename = "bankAccount.holder")]
    pub account_holder: Secret<String>,
}

#[allow(dead_code)]
#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub enum AciPaymentType {
    #[serde(rename = "PA")]
    Preauthorization,
    #[default]
    #[serde(rename = "DB")]
    Debit,
    #[serde(rename = "CD")]
    Credit,
    #[serde(rename = "CP")]
    Capture,
    #[serde(rename = "RV")]
    Reversal,
    #[serde(rename = "RF")]
    Refund,
}

impl TryFrom<&AciRouterData<&PaymentsAuthorizeRouterData>> for AciPaymentsRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &AciRouterData<&PaymentsAuthorizeRouterData>) -> Result<Self, Self::Error> {
        match item.router_data.request.payment_method_data.clone() {
            PaymentMethodData::Card(ref card_data) => Self::try_from((item, card_data)),
            PaymentMethodData::Wallet(ref wallet_data) => Self::try_from((item, wallet_data)),
            PaymentMethodData::PayLater(ref pay_later_data) => {
                Self::try_from((item, pay_later_data))
            }
            PaymentMethodData::BankRedirect(ref bank_redirect_data) => {
                Self::try_from((item, bank_redirect_data))
            }
            PaymentMethodData::MandatePayment => {
                let mandate_id = item.router_data.request.mandate_id.clone().ok_or(
                    errors::ConnectorError::MissingRequiredField {
                        field_name: "mandate_id",
                    },
                )?;
                Self::try_from((item, mandate_id))
            }
            PaymentMethodData::Crypto(_)
            | PaymentMethodData::BankDebit(_)
            | PaymentMethodData::BankTransfer(_)
            | PaymentMethodData::Reward
            | PaymentMethodData::RealTimePayment(_)
            | PaymentMethodData::MobilePayment(_)
            | PaymentMethodData::GiftCard(_)
            | PaymentMethodData::CardRedirect(_)
            | PaymentMethodData::Upi(_)
            | PaymentMethodData::Voucher(_)
            | PaymentMethodData::OpenBanking(_)
            | PaymentMethodData::CardToken(_)
            | PaymentMethodData::NetworkToken(_)
            | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => {
                Err(errors::ConnectorError::NotImplemented(
                    utils::get_unimplemented_payment_method_error_message("Aci"),
                ))?
            }
        }
    }
}

impl TryFrom<(&AciRouterData<&PaymentsAuthorizeRouterData>, &WalletData)> for AciPaymentsRequest {
    type Error = Error;
    fn try_from(
        value: (&AciRouterData<&PaymentsAuthorizeRouterData>, &WalletData),
    ) -> Result<Self, Self::Error> {
        let (item, wallet_data) = value;
        let txn_details = get_transaction_details(item)?;
        let payment_method = PaymentDetails::try_from((wallet_data, item.router_data))?;

        Ok(Self {
            txn_details,
            payment_method,
            instruction: None,
            shopper_result_url: item.router_data.request.router_return_url.clone(),
        })
    }
}

impl
    TryFrom<(
        &AciRouterData<&PaymentsAuthorizeRouterData>,
        &BankRedirectData,
    )> for AciPaymentsRequest
{
    type Error = Error;
    fn try_from(
        value: (
            &AciRouterData<&PaymentsAuthorizeRouterData>,
            &BankRedirectData,
        ),
    ) -> Result<Self, Self::Error> {
        let (item, bank_redirect_data) = value;
        let txn_details = get_transaction_details(item)?;
        let payment_method = PaymentDetails::try_from((item, bank_redirect_data))?;

        Ok(Self {
            txn_details,
            payment_method,
            instruction: None,
            shopper_result_url: item.router_data.request.router_return_url.clone(),
        })
    }
}

impl TryFrom<(&AciRouterData<&PaymentsAuthorizeRouterData>, &PayLaterData)> for AciPaymentsRequest {
    type Error = Error;
    fn try_from(
        value: (&AciRouterData<&PaymentsAuthorizeRouterData>, &PayLaterData),
    ) -> Result<Self, Self::Error> {
        let (item, _pay_later_data) = value;
        let txn_details = get_transaction_details(item)?;
        let payment_method = PaymentDetails::Klarna;

        Ok(Self {
            txn_details,
            payment_method,
            instruction: None,
            shopper_result_url: item.router_data.request.router_return_url.clone(),
        })
    }
}

impl TryFrom<(&AciRouterData<&PaymentsAuthorizeRouterData>, &Card)> for AciPaymentsRequest {
    type Error = Error;
    fn try_from(
        value: (&AciRouterData<&PaymentsAuthorizeRouterData>, &Card),
    ) -> Result<Self, Self::Error> {
        let (item, card_data) = value;
        let card_holder_name = item.router_data.get_optional_billing_full_name();
        let txn_details = get_transaction_details(item)?;
        let payment_method = PaymentDetails::try_from((card_data.clone(), card_holder_name))?;
        let instruction = get_instruction_details(item);

        Ok(Self {
            txn_details,
            payment_method,
            instruction,
            shopper_result_url: None,
        })
    }
}

impl
    TryFrom<(
        &AciRouterData<&PaymentsAuthorizeRouterData>,
        api_models::payments::MandateIds,
    )> for AciPaymentsRequest
{
    type Error = Error;
    fn try_from(
        value: (
            &AciRouterData<&PaymentsAuthorizeRouterData>,
            api_models::payments::MandateIds,
        ),
    ) -> Result<Self, Self::Error> {
        let (item, _mandate_data) = value;
        let instruction = get_instruction_details(item);
        let txn_details = get_transaction_details(item)?;

        Ok(Self {
            txn_details,
            payment_method: PaymentDetails::Mandate,
            instruction,
            shopper_result_url: item.router_data.request.router_return_url.clone(),
        })
    }
}

fn get_transaction_details(
    item: &AciRouterData<&PaymentsAuthorizeRouterData>,
) -> Result<TransactionDetails, error_stack::Report<errors::ConnectorError>> {
    let auth = AciAuthType::try_from(&item.router_data.connector_auth_type)?;
    Ok(TransactionDetails {
        entity_id: auth.entity_id,
        amount: item.amount.to_owned(),
        currency: item.router_data.request.currency.to_string(),
        payment_type: AciPaymentType::Debit,
    })
}

fn get_instruction_details(
    item: &AciRouterData<&PaymentsAuthorizeRouterData>,
) -> Option<Instruction> {
    if item.router_data.request.setup_mandate_details.is_some() {
        return Some(Instruction {
            mode: InstructionMode::Initial,
            transaction_type: InstructionType::Unscheduled,
            source: InstructionSource::CardholderInitiatedTransaction,
            create_registration: Some(true),
        });
    } else if item.router_data.request.mandate_id.is_some() {
        return Some(Instruction {
            mode: InstructionMode::Repeated,
            transaction_type: InstructionType::Unscheduled,
            source: InstructionSource::MerchantInitiatedTransaction,
            create_registration: None,
        });
    }
    None
}

impl TryFrom<&PaymentsCancelRouterData> for AciCancelRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &PaymentsCancelRouterData) -> Result<Self, Self::Error> {
        let auth = AciAuthType::try_from(&item.connector_auth_type)?;
        let aci_payment_request = Self {
            entity_id: auth.entity_id,
            payment_type: AciPaymentType::Reversal,
        };
        Ok(aci_payment_request)
    }
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum AciPaymentStatus {
    Succeeded,
    Failed,
    #[default]
    Pending,
    RedirectShopper,
}

fn map_aci_attempt_status(item: AciPaymentStatus, auto_capture: bool) -> enums::AttemptStatus {
    match item {
        AciPaymentStatus::Succeeded => {
            if auto_capture {
                enums::AttemptStatus::Charged
            } else {
                enums::AttemptStatus::Authorized
            }
        }
        AciPaymentStatus::Failed => enums::AttemptStatus::Failure,
        AciPaymentStatus::Pending => enums::AttemptStatus::Authorizing,
        AciPaymentStatus::RedirectShopper => enums::AttemptStatus::AuthenticationPending,
    }
}
impl FromStr for AciPaymentStatus {
    type Err = error_stack::Report<errors::ConnectorError>;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if FAILURE_CODES.contains(&s) {
            Ok(Self::Failed)
        } else if PENDING_CODES.contains(&s) {
            Ok(Self::Pending)
        } else if SUCCESSFUL_CODES.contains(&s) {
            Ok(Self::Succeeded)
        } else {
            Err(report!(errors::ConnectorError::UnexpectedResponseError(
                bytes::Bytes::from(s.to_owned())
            )))
        }
    }
}

#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AciPaymentsResponse {
    id: String,
    registration_id: Option<Secret<String>>,
    // ndc is an internal unique identifier for the request.
    ndc: String,
    timestamp: String,
    // Number useful for support purposes.
    build_number: String,
    pub(super) result: ResultCode,
    pub(super) redirect: Option<AciRedirectionData>,
}

#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AciErrorResponse {
    ndc: String,
    timestamp: String,
    build_number: String,
    pub(super) result: ResultCode,
}

#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AciRedirectionData {
    method: Option<Method>,
    parameters: Vec<Parameters>,
    url: Url,
}

#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
pub struct Parameters {
    name: String,
    value: String,
}

#[derive(Default, Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ResultCode {
    pub(super) code: String,
    pub(super) description: String,
    pub(super) parameter_errors: Option<Vec<ErrorParameters>>,
}

#[derive(Default, Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
pub struct ErrorParameters {
    pub(super) name: String,
    pub(super) value: Option<String>,
    pub(super) message: String,
}

impl<F, Req> TryFrom<ResponseRouterData<F, AciPaymentsResponse, Req, PaymentsResponseData>>
    for RouterData<F, Req, PaymentsResponseData>
where
    Req: GetCaptureMethod,
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, AciPaymentsResponse, Req, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        let redirection_data = item.response.redirect.map(|data| {
            let form_fields = std::collections::HashMap::<_, _>::from_iter(
                data.parameters
                    .iter()
                    .map(|parameter| (parameter.name.clone(), parameter.value.clone())),
            );

            // If method is Get, parameters are appended to URL
            // If method is post, we http Post the method to URL
            RedirectForm::Form {
                endpoint: data.url.to_string(),
                // Handles method for Bank redirects currently.
                // 3DS response have method within preconditions. That would require replacing below line with a function.
                method: data.method.unwrap_or(Method::Post),
                form_fields,
            }
        });

        let mandate_reference = item.response.registration_id.map(|id| MandateReference {
            connector_mandate_id: Some(id.expose()),
            payment_method_id: None,
            mandate_metadata: None,
            connector_mandate_request_reference_id: None,
        });

        let auto_capture = matches!(
            item.data.request.get_capture_method(),
            Some(enums::CaptureMethod::Automatic) | None
        );

        let status = if redirection_data.is_some() {
            map_aci_attempt_status(AciPaymentStatus::RedirectShopper, auto_capture)
        } else {
            map_aci_attempt_status(
                AciPaymentStatus::from_str(&item.response.result.code)?,
                auto_capture,
            )
        };

        Ok(Self {
            status,
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.id.clone()),
                redirection_data: Box::new(redirection_data),
                mandate_reference: Box::new(mandate_reference),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: Some(item.response.id),
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AciCaptureRequest {
    #[serde(flatten)]
    pub txn_details: TransactionDetails,
}

impl TryFrom<&AciRouterData<&PaymentsCaptureRouterData>> for AciCaptureRequest {
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(item: &AciRouterData<&PaymentsCaptureRouterData>) -> Result<Self, Self::Error> {
        let auth = AciAuthType::try_from(&item.router_data.connector_auth_type)?;
        Ok(Self {
            txn_details: TransactionDetails {
                entity_id: auth.entity_id,
                amount: item.amount.to_owned(),
                currency: item.router_data.request.currency.to_string(),
                payment_type: AciPaymentType::Capture,
            },
        })
    }
}

#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AciCaptureResponse {
    id: String,
    referenced_id: String,
    payment_type: AciPaymentType,
    amount: StringMajorUnit,
    currency: String,
    descriptor: String,
    result: AciCaptureResult,
    result_details: AciCaptureResultDetails,
    build_number: String,
    timestamp: String,
    ndc: Secret<String>,
    source: Secret<String>,
    payment_method: String,
    short_id: String,
}

#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AciCaptureResult {
    code: String,
    description: String,
}

#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(rename_all = "PascalCase")]
pub struct AciCaptureResultDetails {
    extended_description: String,
    #[serde(rename = "clearingInstituteName")]
    clearing_institute_name: String,
    connector_tx_id1: String,
    connector_tx_id3: String,
    connector_tx_id2: String,
    acquirer_response: String,
}

impl<F, T> TryFrom<ResponseRouterData<F, AciCaptureResponse, T, PaymentsResponseData>>
    for RouterData<F, T, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, AciCaptureResponse, T, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: map_aci_attempt_status(
                AciPaymentStatus::from_str(&item.response.result.code)?,
                false,
            ),
            reference_id: Some(item.response.referenced_id.clone()),
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.id.clone()),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: Some(item.response.referenced_id),
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

#[derive(Default, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AciRefundRequest {
    pub amount: StringMajorUnit,
    pub currency: String,
    pub payment_type: AciPaymentType,
    pub entity_id: Secret<String>,
}

impl<F> TryFrom<&AciRouterData<&RefundsRouterData<F>>> for AciRefundRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &AciRouterData<&RefundsRouterData<F>>) -> Result<Self, Self::Error> {
        let amount = item.amount.to_owned();
        let currency = item.router_data.request.currency;
        let payment_type = AciPaymentType::Refund;
        let auth = AciAuthType::try_from(&item.router_data.connector_auth_type)?;

        Ok(Self {
            amount,
            currency: currency.to_string(),
            payment_type,
            entity_id: auth.entity_id,
        })
    }
}

#[derive(Debug, Default, Deserialize, Clone)]
pub enum AciRefundStatus {
    Succeeded,
    Failed,
    #[default]
    Pending,
}

impl FromStr for AciRefundStatus {
    type Err = error_stack::Report<errors::ConnectorError>;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if FAILURE_CODES.contains(&s) {
            Ok(Self::Failed)
        } else if PENDING_CODES.contains(&s) {
            Ok(Self::Pending)
        } else if SUCCESSFUL_CODES.contains(&s) {
            Ok(Self::Succeeded)
        } else {
            Err(report!(errors::ConnectorError::UnexpectedResponseError(
                bytes::Bytes::from(s.to_owned())
            )))
        }
    }
}

impl From<AciRefundStatus> for enums::RefundStatus {
    fn from(item: AciRefundStatus) -> Self {
        match item {
            AciRefundStatus::Succeeded => Self::Success,
            AciRefundStatus::Failed => Self::Failure,
            AciRefundStatus::Pending => Self::Pending,
        }
    }
}

#[allow(dead_code)]
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AciRefundResponse {
    id: String,
    //ndc is an internal unique identifier for the request.
    ndc: String,
    timestamp: String,
    build_number: String,
    pub(super) result: ResultCode,
}

impl<F> TryFrom<RefundsResponseRouterData<F, AciRefundResponse>> for RefundsRouterData<F> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<F, AciRefundResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.id,
                refund_status: enums::RefundStatus::from(AciRefundStatus::from_str(
                    &item.response.result.code,
                )?),
            }),
            ..item.data
        })
    }
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub enum AciWebhookEventType {
    Payment,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub enum AciWebhookAction {
    Created,
    Updated,
    Deleted,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AciWebhookCardDetails {
    pub bin: Option<String>,
    #[serde(rename = "last4Digits")]
    pub last4_digits: Option<String>,
    pub holder: Option<String>,
    pub expiry_month: Option<Secret<String>>,
    pub expiry_year: Option<Secret<String>>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AciWebhookCustomerDetails {
    #[serde(rename = "givenName")]
    pub given_name: Option<Secret<String>>,
    pub surname: Option<Secret<String>>,
    #[serde(rename = "merchantCustomerId")]
    pub merchant_customer_id: Option<Secret<String>>,
    pub sex: Option<Secret<String>>,
    pub email: Option<Email>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AciWebhookAuthenticationDetails {
    #[serde(rename = "entityId")]
    pub entity_id: Secret<String>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AciWebhookRiskDetails {
    pub score: Option<String>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AciPaymentWebhookPayload {
    pub id: String,
    pub payment_type: String,
    pub payment_brand: String,
    pub amount: StringMajorUnit,
    pub currency: String,
    pub presentation_amount: Option<StringMajorUnit>,
    pub presentation_currency: Option<String>,
    pub descriptor: Option<String>,
    pub result: ResultCode,
    pub authentication: Option<AciWebhookAuthenticationDetails>,
    pub card: Option<AciWebhookCardDetails>,
    pub customer: Option<AciWebhookCustomerDetails>,
    #[serde(rename = "customParameters")]
    pub custom_parameters: Option<serde_json::Value>,
    pub risk: Option<AciWebhookRiskDetails>,
    pub build_number: Option<String>,
    pub timestamp: String,
    pub ndc: String,
    #[serde(rename = "channelName")]
    pub channel_name: Option<String>,
    pub source: Option<String>,
    pub payment_method: Option<String>,
    #[serde(rename = "shortId")]
    pub short_id: Option<String>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AciWebhookNotification {
    #[serde(rename = "type")]
    pub event_type: AciWebhookEventType,
    pub action: Option<AciWebhookAction>,
    pub payload: serde_json::Value,
}


    payme_transaction_id: Option<String>,
    status_error_code: Option<u32>,
}

impl TryFrom<RefundsResponseRouterData<Execute, PaymeRefundResponse>>
    for RefundsRouterData<Execute>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<Execute, PaymeRefundResponse>,
    ) -> Result<Self, Self::Error> {
        let refund_status = enums::RefundStatus::try_from(item.response.sale_status.clone())?;
        let response = if utils::is_refund_failure(refund_status) {
            let payme_response = &item.response;
            let status_error_code = payme_response
                .status_error_code
                .map(|error_code| error_code.to_string());
            Err(ErrorResponse {
                code: status_error_code
                    .clone()
                    .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()),
                message: status_error_code
                    .clone()
                    .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
                reason: status_error_code,
                status_code: item.http_code,
                attempt_status: None,
                connector_transaction_id: payme_response.payme_transaction_id.clone(),
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            })
        } else {
            Ok(RefundsResponseData {
                connector_refund_id: item
                    .response
                    .payme_transaction_id
                    .ok_or(errors::ConnectorError::MissingConnectorRefundID)?,
                refund_status,
            })
        };
        Ok(Self {
            response,
            ..item.data
        })
    }
}

#[derive(Debug, Serialize)]
pub struct PaymeVoidRequest {
    sale_currency: enums::Currency,
    payme_sale_id: String,
    seller_payme_id: Secret<String>,
    language: String,
}

impl TryFrom<&PaymeRouterData<&RouterData<Void, PaymentsCancelData, PaymentsResponseData>>>
    for PaymeVoidRequest
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &PaymeRouterData<&RouterData<Void, PaymentsCancelData, PaymentsResponseData>>,
    ) -> Result<Self, Self::Error> {
        let auth_type = PaymeAuthType::try_from(&item.router_data.connector_auth_type)?;
        Ok(Self {
            payme_sale_id: item.router_data.request.connector_transaction_id.clone(),
            seller_payme_id: auth_type.seller_payme_id,
            sale_currency: item.router_data.request.get_currency()?,
            language: LANGUAGE.to_string(),
        })
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct PaymeVoidResponse {
    sale_status: SaleStatus,
    payme_transaction_id: Option<String>,
    status_error_code: Option<u32>,
}

impl TryFrom<PaymentsCancelResponseRouterData<PaymeVoidResponse>> for PaymentsCancelRouterData {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: PaymentsCancelResponseRouterData<PaymeVoidResponse>,
    ) -> Result<Self, Self::Error> {
        let status = enums::AttemptStatus::from(item.response.sale_status.clone());
        let response = if utils::is_payment_failure(status) {
            let payme_response = &item.response;
            let status_error_code = payme_response
                .status_error_code
                .map(|error_code| error_code.to_string());
            Err(ErrorResponse {
                code: status_error_code
                    .clone()
                    .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()),
                message: status_error_code
                    .clone()
                    .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
                reason: status_error_code,
                status_code: item.http_code,
                attempt_status: None,
                connector_transaction_id: payme_response.payme_transaction_id.clone(),
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            })
        } else {
            // Since we are not receiving payme_sale_id, we are not populating the transaction response
            Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::NoResponseId,
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
                charges: None,
            })
        };
        Ok(Self {
            status,
            response,
            ..item.data
        })
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct PaymeQueryTransactionResponse {
    items: Vec<TransactionQuery>,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TransactionQuery {
    sale_status: SaleStatus,
    payme_transaction_id: String,
}

impl<F, T> TryFrom<ResponseRouterData<F, PaymeQueryTransactionResponse, T, RefundsResponseData>>
    for RouterData<F, T, RefundsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, PaymeQueryTransactionResponse, T, RefundsResponseData>,
    ) -> Result<Self, Self::Error> {
        let pay_sale_response = item
            .response
            .items
            .first()
            .ok_or(errors::ConnectorError::ResponseHandlingFailed)?;
        let refund_status = enums::RefundStatus::try_from(pay_sale_response.sale_status.clone())?;
        let response = if utils::is_refund_failure(refund_status) {
            Err(ErrorResponse {
                code: consts::NO_ERROR_CODE.to_string(),
                message: consts::NO_ERROR_CODE.to_string(),
                reason: None,
                status_code: item.http_code,
                attempt_status: None,
                connector_transaction_id: Some(pay_sale_response.payme_transaction_id.clone()),
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            })
        } else {
            Ok(RefundsResponseData {
                refund_status,
                connector_refund_id: pay_sale_response.payme_transaction_id.clone(),
            })
        };
        Ok(Self {
            response,
            ..item.data
        })
    }
}

fn get_services(item: &PaymentsPreProcessingRouterData) -> Option<ThreeDs> {
    match item.auth_type {
        AuthenticationType::ThreeDs => {
            let settings = ThreeDsSettings { active: true };
            Some(ThreeDs {
                name: ThreeDsType::ThreeDs,
                settings,
            })
        }
        AuthenticationType::NoThreeDs => None,
    }
}

#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
pub struct PaymeErrorResponse {
    pub status_code: u16,
    pub status_error_details: String,
    pub status_additional_info: serde_json::Value,
    pub status_error_code: u32,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum NotifyType {
    SaleComplete,
    SaleAuthorized,
    Refund,
    SaleFailure,
    SaleChargeback,
    SaleChargebackRefund,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct WebhookEventDataResource {
    pub sale_status: SaleStatus,
    pub payme_signature: Secret<String>,
    pub buyer_key: Option<Secret<String>>,
    pub notify_type: NotifyType,
    pub payme_sale_id: String,
    pub payme_transaction_id: String,
    pub status_error_details: Option<String>,
    pub status_error_code: Option<u32>,
    pub price: MinorUnit,
    pub currency: enums::Currency,
}

#[derive(Debug, Deserialize)]
pub struct WebhookEventDataResourceEvent {
    pub notify_type: NotifyType,
}

#[derive(Debug, Deserialize)]
pub struct WebhookEventDataResourceSignature {
    pub payme_signature: Secret<String>,
}

/// This try_from will ensure that webhook body would be properly parsed into PSync response
impl From<WebhookEventDataResource> for PaymePaySaleResponse {
    fn from(value: WebhookEventDataResource) -> Self {
        Self {
            sale_status: value.sale_status,
            payme_sale_id: value.payme_sale_id,
            payme_transaction_id: Some(value.payme_transaction_id),
            buyer_key: value.buyer_key,
            sale_3ds: None,
            redirect_url: None,
            status_error_code: value.status_error_code,
            status_error_details: value.status_error_details,
        }
    }
}

/// This try_from will ensure that webhook body would be properly parsed into RSync response
impl From<WebhookEventDataResource> for PaymeQueryTransactionResponse {
    fn from(value: WebhookEventDataResource) -> Self {
        let item = TransactionQuery {
            sale_status: value.sale_status,
            payme_transaction_id: value.payme_transaction_id,
        };
        Self { items: vec![item] }
    }
}

impl From<NotifyType> for api_models::webhooks::IncomingWebhookEvent {
    fn from(value: NotifyType) -> Self {
        match value {
            NotifyType::SaleComplete => Self::PaymentIntentSuccess,
            NotifyType::Refund => Self::RefundSuccess,
            NotifyType::SaleFailure => Self::PaymentIntentFailure,
            NotifyType::SaleChargeback => Self::DisputeOpened,
            NotifyType::SaleChargebackRefund => Self::DisputeWon,
            NotifyType::SaleAuthorized => Self::EventNotSupported,
        }
    }
}