File: crates/router_derive/src/macros/operation.rs
 Public functions: 1
 Public structs: 1

use std::str::FromStr;

use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens};
use strum::IntoEnumIterator;
use syn::{self, parse::Parse, DeriveInput};

use crate::macros::helpers;

#[derive(Debug, Clone, Copy, strum::EnumString, strum::EnumIter, strum::Display)]
#[strum(serialize_all = "snake_case")]
pub enum Derives {
    Sync,
    Cancel,
    Reject,
    Capture,
    ApproveData,
    Authorize,
    AuthorizeData,
    SyncData,
    CancelData,
    CancelPostCapture,
    CancelPostCaptureData,
    CaptureData,
    CompleteAuthorizeData,
    RejectData,
    SetupMandateData,
    Start,
    Verify,
    Session,
    SessionData,
    IncrementalAuthorization,
    IncrementalAuthorizationData,
    SdkSessionUpdate,
    SdkSessionUpdateData,
    PostSessionTokens,
    PostSessionTokensData,
    UpdateMetadata,
    UpdateMetadataData,
}

impl Derives {
    fn to_operation(
        self,
        fns: impl Iterator<Item = TokenStream> + Clone,
        struct_name: &syn::Ident,
    ) -> TokenStream {
        let req_type = Conversion::get_req_type(self);
        quote! {
            #[automatically_derived]
            impl<F:Send+Clone+Sync> Operation<F,#req_type> for #struct_name {
                type Data = PaymentData<F>;
                #(#fns)*
            }
        }
    }

    fn to_ref_operation(
        self,
        ref_fns: impl Iterator<Item = TokenStream> + Clone,
        struct_name: &syn::Ident,
    ) -> TokenStream {
        let req_type = Conversion::get_req_type(self);
        quote! {
            #[automatically_derived]
            impl<F:Send+Clone+Sync> Operation<F,#req_type> for &#struct_name {
                type Data = PaymentData<F>;
                #(#ref_fns)*
            }
        }
    }
}

#[derive(Debug, Clone, strum::EnumString, strum::EnumIter, strum::Display)]
#[strum(serialize_all = "snake_case")]
pub enum Conversion {
    ValidateRequest,
    GetTracker,
    Domain,
    UpdateTracker,
    PostUpdateTracker,
    All,
    Invalid(String),
}

impl Conversion {
    fn get_req_type(ident: Derives) -> syn::Ident {
        match ident {
            Derives::Authorize => syn::Ident::new("PaymentsRequest", Span::call_site()),
            Derives::AuthorizeData => syn::Ident::new("PaymentsAuthorizeData", Span::call_site()),
            Derives::Sync => syn::Ident::new("PaymentsRetrieveRequest", Span::call_site()),
            Derives::SyncData => syn::Ident::new("PaymentsSyncData", Span::call_site()),
            Derives::Cancel => syn::Ident::new("PaymentsCancelRequest", Span::call_site()),
            Derives::CancelData => syn::Ident::new("PaymentsCancelData", Span::call_site()),
            Derives::ApproveData => syn::Ident::new("PaymentsApproveData", Span::call_site()),
            Derives::Reject => syn::Ident::new("PaymentsRejectRequest", Span::call_site()),
            Derives::RejectData => syn::Ident::new("PaymentsRejectData", Span::call_site()),
            Derives::Capture => syn::Ident::new("PaymentsCaptureRequest", Span::call_site()),
            Derives::CaptureData => syn::Ident::new("PaymentsCaptureData", Span::call_site()),
            Derives::CompleteAuthorizeData => {
                syn::Ident::new("CompleteAuthorizeData", Span::call_site())
            }
            Derives::Start => syn::Ident::new("PaymentsStartRequest", Span::call_site()),
            Derives::Verify => syn::Ident::new("VerifyRequest", Span::call_site()),
            Derives::SetupMandateData => {
                syn::Ident::new("SetupMandateRequestData", Span::call_site())
            }
            Derives::Session => syn::Ident::new("PaymentsSessionRequest", Span::call_site()),
            Derives::SessionData => syn::Ident::new("PaymentsSessionData", Span::call_site()),
            Derives::IncrementalAuthorization => {
                syn::Ident::new("PaymentsIncrementalAuthorizationRequest", Span::call_site())
            }
            Derives::IncrementalAuthorizationData => {
                syn::Ident::new("PaymentsIncrementalAuthorizationData", Span::call_site())
            }
            Derives::SdkSessionUpdate => {
                syn::Ident::new("PaymentsDynamicTaxCalculationRequest", Span::call_site())
            }
            Derives::SdkSessionUpdateData => {
                syn::Ident::new("SdkPaymentsSessionUpdateData", Span::call_site())
            }
            Derives::PostSessionTokens => {
                syn::Ident::new("PaymentsPostSessionTokensRequest", Span::call_site())
            }
            Derives::PostSessionTokensData => {
                syn::Ident::new("PaymentsPostSessionTokensData", Span::call_site())
            }
            Derives::UpdateMetadata => {
                syn::Ident::new("PaymentsUpdateMetadataRequest", Span::call_site())
            }
            Derives::UpdateMetadataData => {
                syn::Ident::new("PaymentsUpdateMetadataData", Span::call_site())
            }
            Derives::CancelPostCapture => {
                syn::Ident::new("PaymentsCancelPostCaptureRequest", Span::call_site())
            }
            Derives::CancelPostCaptureData => {
                syn::Ident::new("PaymentsCancelPostCaptureData", Span::call_site())
            }
        }
    }

    fn to_function(&self, ident: Derives) -> TokenStream {
        let req_type = Self::get_req_type(ident);
        match self {
            Self::ValidateRequest => quote! {
                fn to_validate_request(&self) -> RouterResult<&(dyn ValidateRequest<F,#req_type, Self::Data> + Send + Sync)> {
                    Ok(self)
                }
            },
            Self::GetTracker => quote! {
                fn to_get_tracker(&self) -> RouterResult<&(dyn GetTracker<F, Self::Data, #req_type> + Send + Sync)> {
                    Ok(self)
                }
            },
            Self::Domain => quote! {
                fn to_domain(&self) -> RouterResult<&dyn Domain<F,#req_type, Self::Data>> {
                    Ok(self)
                }
            },
            Self::UpdateTracker => quote! {
                fn to_update_tracker(&self) -> RouterResult<&(dyn UpdateTracker<F, Self::Data, #req_type> + Send + Sync)> {
                    Ok(self)
                }
            },
            Self::PostUpdateTracker => quote! {
                fn to_post_update_tracker(&self) -> RouterResult<&(dyn PostUpdateTracker<F, Self::Data, #req_type> + Send + Sync)> {
                    Ok(self)
                }
            },
            Self::Invalid(s) => {
                helpers::syn_error(Span::call_site(), &format!("Invalid identifier {s}"))
                    .to_compile_error()
            }
            Self::All => {
                let validate_request = Self::ValidateRequest.to_function(ident);
                let get_tracker = Self::GetTracker.to_function(ident);
                let domain = Self::Domain.to_function(ident);
                let update_tracker = Self::UpdateTracker.to_function(ident);

                quote! {
                    #validate_request
                    #get_tracker
                    #domain
                    #update_tracker
                }
            }
        }
    }

    fn to_ref_function(&self, ident: Derives) -> TokenStream {
        let req_type = Self::get_req_type(ident);
        match self {
            Self::ValidateRequest => quote! {
                fn to_validate_request(&self) -> RouterResult<&(dyn ValidateRequest<F, #req_type, Self::Data> + Send + Sync)> {
                    Ok(*self)
                }
            },
            Self::GetTracker => quote! {
                fn to_get_tracker(&self) -> RouterResult<&(dyn GetTracker<F, Self::Data,#req_type> + Send + Sync)> {
                    Ok(*self)
                }
            },
            Self::Domain => quote! {
                fn to_domain(&self) -> RouterResult<&(dyn Domain<F,#req_type, Self::Data>)> {
                    Ok(*self)
                }
            },
            Self::UpdateTracker => quote! {
                fn to_update_tracker(&self) -> RouterResult<&(dyn UpdateTracker<F, Self::Data,#req_type> + Send + Sync)> {
                    Ok(*self)
                }
            },
            Self::PostUpdateTracker => quote! {
                fn to_post_update_tracker(&self) -> RouterResult<&(dyn PostUpdateTracker<F, Self::Data, #req_type> + Send + Sync)> {
                    Ok(*self)
                }
            },
            Self::Invalid(s) => {
                helpers::syn_error(Span::call_site(), &format!("Invalid identifier {s}"))
                    .to_compile_error()
            }
            Self::All => {
                let validate_request = Self::ValidateRequest.to_ref_function(ident);
                let get_tracker = Self::GetTracker.to_ref_function(ident);
                let domain = Self::Domain.to_ref_function(ident);
                let update_tracker = Self::UpdateTracker.to_ref_function(ident);

                quote! {
                    #validate_request
                    #get_tracker
                    #domain
                    #update_tracker
                }
            }
        }
    }
}

mod operations_keyword {
    use syn::custom_keyword;

    custom_keyword!(operations);
    custom_keyword!(flow);
}

#[derive(Debug)]
pub enum OperationsEnumMeta {
    Operations {
        keyword: operations_keyword::operations,
        value: Vec<Conversion>,
    },
    Flow {
        keyword: operations_keyword::flow,
        value: Vec<Derives>,
    },
}

#[derive(Clone)]
pub struct OperationProperties {
    operations: Vec<Conversion>,
    flows: Vec<Derives>,
}

fn get_operation_properties(
    operation_enums: Vec<OperationsEnumMeta>,
) -> syn::Result<OperationProperties> {
    let mut operations = vec![];
    let mut flows = vec![];

    for operation in operation_enums {
        match operation {
            OperationsEnumMeta::Operations { value, .. } => {
                operations = value;
            }
            OperationsEnumMeta::Flow { value, .. } => {
                flows = value;
            }
        }
    }

    if operations.is_empty() {
        Err(syn::Error::new(
            Span::call_site(),
            "atleast one operation must be specitied",
        ))?;
    }

    if flows.is_empty() {
        Err(syn::Error::new(
            Span::call_site(),
            "atleast one flow must be specitied",
        ))?;
    }

    Ok(OperationProperties { operations, flows })
}

impl Parse for Derives {
    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
        let text = input.parse::<syn::LitStr>()?;
        let value = text.value();

        value.as_str().parse().map_err(|_| {
            syn::Error::new_spanned(
                &text,
                format!(
                    "Unexpected value for flow: `{value}`. Possible values are `{}`",
                    helpers::get_possible_values_for_enum::<Self>()
                ),
            )
        })
    }
}

impl Parse for Conversion {
    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
        let text = input.parse::<syn::LitStr>()?;
        let value = text.value();

        value.as_str().parse().map_err(|_| {
            syn::Error::new_spanned(
                &text,
                format!(
                    "Unexpected value for operation: `{value}`. Possible values are `{}`",
                    helpers::get_possible_values_for_enum::<Self>()
                ),
            )
        })
    }
}

fn parse_list_string<T>(list_string: String, keyword: &str) -> syn::Result<Vec<T>>
where
    T: FromStr + IntoEnumIterator + ToString,
{
    list_string
        .split(',')
        .map(str::trim)
        .map(T::from_str)
        .map(|result| {
            result.map_err(|_| {
                syn::Error::new(
                    Span::call_site(),
                    format!(
                        "Unexpected {keyword}, possible values are {}",
                        helpers::get_possible_values_for_enum::<T>()
                    ),
                )
            })
        })
        .collect()
}

fn get_conversions(input: syn::parse::ParseStream<'_>) -> syn::Result<Vec<Conversion>> {
    let lit_str_list = input.parse::<syn::LitStr>()?;
    parse_list_string(lit_str_list.value(), "operation")
}

fn get_derives(input: syn::parse::ParseStream<'_>) -> syn::Result<Vec<Derives>> {
    let lit_str_list = input.parse::<syn::LitStr>()?;
    parse_list_string(lit_str_list.value(), "flow")
}

impl Parse for OperationsEnumMeta {
    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
        let lookahead = input.lookahead1();
        if lookahead.peek(operations_keyword::operations) {
            let keyword = input.parse()?;
            input.parse::<syn::Token![=]>()?;
            let value = get_conversions(input)?;
            Ok(Self::Operations { keyword, value })
        } else if lookahead.peek(operations_keyword::flow) {
            let keyword = input.parse()?;
            input.parse::<syn::Token![=]>()?;
            let value = get_derives(input)?;
            Ok(Self::Flow { keyword, value })
        } else {
            Err(lookahead.error())
        }
    }
}

trait OperationsDeriveInputExt {
    /// Get all the error metadata associated with an enum.
    fn get_metadata(&self) -> syn::Result<Vec<OperationsEnumMeta>>;
}

impl OperationsDeriveInputExt for DeriveInput {
    fn get_metadata(&self) -> syn::Result<Vec<OperationsEnumMeta>> {
        helpers::get_metadata_inner("operation", &self.attrs)
    }
}

impl ToTokens for OperationsEnumMeta {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        match self {
            Self::Operations { keyword, .. } => keyword.to_tokens(tokens),
            Self::Flow { keyword, .. } => keyword.to_tokens(tokens),
        }
    }
}

pub fn operation_derive_inner(input: DeriveInput) -> syn::Result<proc_macro::TokenStream> {
    let struct_name = &input.ident;
    let operations_meta = input.get_metadata()?;
    let operation_properties = get_operation_properties(operations_meta)?;

    let current_crate = syn::Ident::new("crate", Span::call_site());

    let trait_derive = operation_properties
        .clone()
        .flows
        .into_iter()
        .map(|derive| {
            let fns = operation_properties
                .operations
                .iter()
                .map(|conversion| conversion.to_function(derive));
            derive.to_operation(fns, struct_name)
        })
        .collect::<Vec<_>>();

    let ref_trait_derive = operation_properties
        .flows
        .into_iter()
        .map(|derive| {
            let fns = operation_properties
                .operations
                .iter()
                .map(|conversion| conversion.to_ref_function(derive));
            derive.to_ref_operation(fns, struct_name)
        })
        .collect::<Vec<_>>();

    let trait_derive = quote! {
            #(#ref_trait_derive)* #(#trait_derive)*
    };

    let output = quote! {
        const _: () = {
                use #current_crate::core::errors::RouterResult;
                use #current_crate::core::payments::{PaymentData,operations::{
                    ValidateRequest,
                    PostUpdateTracker,
                    GetTracker,
                    UpdateTracker,
                }};
                use #current_crate::types::{
                    SetupMandateRequestData,
                    PaymentsSyncData,
                    PaymentsCaptureData,
                    PaymentsCancelData,
                    PaymentsApproveData,
                    PaymentsRejectData,
                    PaymentsAuthorizeData,
                    PaymentsSessionData,
                    CompleteAuthorizeData,
                    PaymentsIncrementalAuthorizationData,
                    SdkPaymentsSessionUpdateData,
                    PaymentsPostSessionTokensData,
                    PaymentsUpdateMetadataData,
                    PaymentsCancelPostCaptureData,

                    api::{
                        PaymentsCaptureRequest,
                        PaymentsCancelRequest,
                        PaymentsApproveRequest,
                        PaymentsRejectRequest,
                        PaymentsRetrieveRequest,
                        PaymentsRequest,
                        PaymentsStartRequest,
                        PaymentsSessionRequest,
                        VerifyRequest,
                        PaymentsDynamicTaxCalculationRequest,
                        PaymentsIncrementalAuthorizationRequest,
                        PaymentsPostSessionTokensRequest,
                        PaymentsUpdateMetadataRequest,
                        PaymentsCancelPostCaptureRequest,
                    }
                };
                #trait_derive
            };
    };
    Ok(proc_macro::TokenStream::from(output))
}


pub fn new() -> &'static Self {
        &Self {
            amount_convertor: &FloatMajorUnitForConnector,
        }
    }


pub struct CybersourceVoidRequest {
    client_reference_information: ClientReferenceInformation,
    reversal_information: ReversalInformation,
    #[serde(skip_serializing_if = "Option::is_none")]
    merchant_defined_information: Option<Vec<MerchantDefinedInformation>>,
    // The connector documentation does not mention the merchantDefinedInformation field for Void requests. But this has been still added because it works!
}


pub struct ActivePaymentsMetricsBucketValue {
    pub active_payments: Option<u64>,
}


pub fn get_user_id(&self) -> &str {
        self.0.user_id.as_str()
    }


pub struct ExternalVaultCreateFlow;


pub fn new(reference: String) -> Self {
        Self { reference }
    }


impl ConnectorErrorTypeMapping for Payone {
    fn get_connector_error_type(
        &self,
        error_code: String,
        _error_message: String,
    ) -> ConnectorErrorType {
        match error_code.as_str() {
            "30001101" => ConnectorErrorType::BusinessError,
            "30001100" => ConnectorErrorType::BusinessError,
            "30001102" => ConnectorErrorType::BusinessError,
            "30001104" => ConnectorErrorType::BusinessError,
            "30001105" => ConnectorErrorType::BusinessError,
            "30001106" => ConnectorErrorType::TechnicalError,
            "30001120" => ConnectorErrorType::BusinessError,
            "30001130" => ConnectorErrorType::BusinessError,
            "30001140" => ConnectorErrorType::BusinessError,
            "30001141" => ConnectorErrorType::BusinessError,
            "30001142" => ConnectorErrorType::BusinessError,
            "30001143" => ConnectorErrorType::BusinessError,
            "30001158" => ConnectorErrorType::UserError,
            "30001180" => ConnectorErrorType::TechnicalError,
            "30031001" => ConnectorErrorType::UserError,
            "30041001" => ConnectorErrorType::UserError,
            "30051001" => ConnectorErrorType::BusinessError,
            "30141001" => ConnectorErrorType::UserError,
            "30431001" => ConnectorErrorType::UserError,
            "30511001" => ConnectorErrorType::UserError,
            "30581001" => ConnectorErrorType::UserError,
            "30591001" => ConnectorErrorType::BusinessError,
            "30621001" => ConnectorErrorType::BusinessError,
            "30921001" => ConnectorErrorType::TechnicalError,
            "40001134" => ConnectorErrorType::BusinessError,
            "40001135" => ConnectorErrorType::BusinessError,
            "50001081" => ConnectorErrorType::TechnicalError,
            "40001137" => ConnectorErrorType::TechnicalError,
            "40001138" => ConnectorErrorType::TechnicalError,
            "40001139" => ConnectorErrorType::UserError,
            "50001054" => ConnectorErrorType::TechnicalError,
            "50001087" => ConnectorErrorType::TechnicalError,
            _ => ConnectorErrorType::UnknownError,
        }
    }
}

impl ConnectorErrorTypeMapping for for Payone


impl api::RefundSync for Santander {}


pub async fn refunds_list(
    state: web::Data<AppState>,
    req: HttpRequest,
    payload: web::Json<api_models::refunds::RefundListRequest>,
) -> HttpResponse {
    let flow = Flow::RefundsList;
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload.into_inner(),
        |state, auth: auth::AuthenticationData, req, _| {
            refund_list(state, auth.merchant_account, auth.profile, req)
        },
        auth::auth_type(
            &auth::V2ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            },
            &auth::JWTAuth {
                permission: Permission::MerchantRefundRead,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub async fn refund_filter_list(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    req: common_utils::types::TimeRange,
) -> RouterResponse<api_models::refunds::RefundListMetaData> {
    let db = state.store;
    let filter_list = db
        .filter_refund_by_meta_constraints(
            merchant_context.get_merchant_account().get_id(),
            &req,
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::RefundNotFound)?;

    Ok(services::ApplicationResponse::Json(filter_list))
}


pub struct KafkaPaymentIntent<'a> {
    pub payment_id: &'a id_type::GlobalPaymentId,
    pub merchant_id: &'a id_type::MerchantId,
    pub status: storage_enums::IntentStatus,
    pub amount: common_types::MinorUnit,
    pub currency: storage_enums::Currency,
    pub amount_captured: Option<common_types::MinorUnit>,
    pub customer_id: Option<&'a id_type::GlobalCustomerId>,
    pub description: Option<&'a common_types::Description>,
    pub return_url: Option<&'a common_types::Url>,
    pub metadata: Option<&'a Secret<Value>>,
    pub statement_descriptor: Option<&'a common_types::StatementDescriptor>,
    #[serde(with = "time::serde::timestamp")]
    pub created_at: OffsetDateTime,
    #[serde(with = "time::serde::timestamp")]
    pub modified_at: OffsetDateTime,
    #[serde(default, with = "time::serde::timestamp::option")]
    pub last_synced: Option<OffsetDateTime>,
    pub setup_future_usage: storage_enums::FutureUsage,
    pub off_session: bool,
    pub active_attempt_id: Option<&'a id_type::GlobalAttemptId>,
    pub attempt_count: i16,
    pub profile_id: &'a id_type::ProfileId,
    pub customer_email: Option<HashedString<pii::EmailStrategy>>,
    pub feature_metadata: Option<&'a diesel_types::FeatureMetadata>,
    pub organization_id: &'a id_type::OrganizationId,
    pub order_details: Option<&'a Vec<Secret<OrderDetailsWithAmount>>>,

    pub allowed_payment_method_types: Option<&'a Vec<common_enums::PaymentMethodType>>,
    pub connector_metadata: Option<&'a Secret<Value>>,
    pub payment_link_id: Option<&'a String>,
    pub updated_by: &'a String,
    pub surcharge_applicable: Option<bool>,
    pub request_incremental_authorization: RequestIncrementalAuthorization,
    pub split_txns_enabled: common_enums::SplitTxnsEnabled,
    pub authorization_count: Option<i32>,
    #[serde(with = "time::serde::timestamp")]
    pub session_expiry: OffsetDateTime,
    pub request_external_three_ds_authentication: common_enums::External3dsAuthenticationRequest,
    pub frm_metadata: Option<Secret<&'a Value>>,
    pub customer_details: Option<Secret<&'a Value>>,
    pub shipping_cost: Option<common_types::MinorUnit>,
    pub tax_details: Option<TaxDetails>,
    pub skip_external_tax_calculation: bool,
    pub request_extended_authorization: Option<RequestExtendedAuthorizationBool>,
    pub psd2_sca_exemption_type: Option<storage_enums::ScaExemptionType>,
    pub split_payments: Option<&'a payments::SplitPaymentsRequest>,
    pub platform_merchant_id: Option<&'a id_type::MerchantId>,
    pub force_3ds_challenge: Option<bool>,
    pub force_3ds_challenge_trigger: Option<bool>,
    pub processor_merchant_id: &'a id_type::MerchantId,
    pub created_by: Option<&'a common_types::CreatedBy>,
    pub is_iframe_redirection_enabled: Option<bool>,
    pub merchant_reference_id: Option<&'a id_type::PaymentReferenceId>,
    pub capture_method: storage_enums::CaptureMethod,
    pub authentication_type: Option<common_enums::AuthenticationType>,
    pub prerouting_algorithm: Option<&'a routing::PaymentRoutingInfo>,
    pub surcharge_amount: Option<common_types::MinorUnit>,
    pub billing_address: Option<Secret<&'a address::Address>>,
    pub shipping_address: Option<Secret<&'a address::Address>>,
    pub tax_on_surcharge: Option<common_types::MinorUnit>,
    pub frm_merchant_decision: Option<common_enums::MerchantDecision>,
    pub enable_payment_link: common_enums::EnablePaymentLinkRequest,
    pub apply_mit_exemption: common_enums::MitExemptionRequest,
    pub customer_present: common_enums::PresenceOfCustomerDuringPayment,
    pub routing_algorithm_id: Option<&'a id_type::RoutingId>,
    pub payment_link_config: Option<&'a PaymentLinkConfigRequestForPayments>,

    #[serde(flatten)]
    infra_values: Option<Value>,
}


## 2024.06.04.0

### Features

- **connector:** [AUTHORIZEDOTNET] Support payment_method_id in recurring mandate payment ([#4841](https://github.com/juspay/hyperswitch/pull/4841)) ([`a1788b8`](https://github.com/juspay/hyperswitch/commit/a1788b8da942f0e32a80b37eac4eecece2bef77d))
- **consolidated-kafka-events:** Add consolidated kafka payment events ([#4798](https://github.com/juspay/hyperswitch/pull/4798)) ([`ccee1a9`](https://github.com/juspay/hyperswitch/commit/ccee1a9ce9e860bfa04e74329fb47fd73f010b23))
- **multitenancy:** Add support for multitenancy and handle the same in router, producer, consumer, drainer and analytics ([#4630](https://github.com/juspay/hyperswitch/pull/4630)) ([`15d6c3e`](https://github.com/juspay/hyperswitch/commit/15d6c3e846a77dec6b6a5165d86044a9b9fd52f1))
- **router:** Send `three_ds_requestor_url` in authentication_response for external 3ds flow ([#4828](https://github.com/juspay/hyperswitch/pull/4828)) ([`67f017f`](https://github.com/juspay/hyperswitch/commit/67f017f6f035b102ce7a0102b157a884ce9d4109))
- **users:** Create config for TOTP Issuer ([#4776](https://github.com/juspay/hyperswitch/pull/4776)) ([`0cbb292`](https://github.com/juspay/hyperswitch/commit/0cbb2928bd054cb8e98c3811f397a837a8887486))

### Bug Fixes

- **connector:** Make few fields optional in struct NetceteraErrorDetails ([#4827](https://github.com/juspay/hyperswitch/pull/4827)) ([`69b2f76`](https://github.com/juspay/hyperswitch/commit/69b2f76be7a2c0deba2c069a87c10a33253e2216))
- Include client_version and client_source in retried payments ([#4826](https://github.com/juspay/hyperswitch/pull/4826)) ([`fa5f5a4`](https://github.com/juspay/hyperswitch/commit/fa5f5a4eddecd072f974738d2168cd0b7c277d2e))

### Refactors

- **connector:**
  - [Klarna] Add shipping Address in Klarna Session and Payment Request ([#4836](https://github.com/juspay/hyperswitch/pull/4836)) ([`8650077`](https://github.com/juspay/hyperswitch/commit/865007717c5c7e617ca1b447ea5f9bb3d274cac3))
  - Airwallex convert init payment to preprocessing ([#4842](https://github.com/juspay/hyperswitch/pull/4842)) ([`e5da133`](https://github.com/juspay/hyperswitch/commit/e5da133fe00b5736dc3c55bf4ee86fa77158dbe7))
- **users:** Changes for Home and Signout APIs for TOTP Redis flows ([#4851](https://github.com/juspay/hyperswitch/pull/4851)) ([`d242850`](https://github.com/juspay/hyperswitch/commit/d242850b63173f314fb259451139464f09e0a9e9))

### Miscellaneous Tasks

- **cypress:** Remove logs that expose `globalState` ([#4844](https://github.com/juspay/hyperswitch/pull/4844)) ([`d84e624`](https://github.com/juspay/hyperswitch/commit/d84e62441f39c165af7dc1c8d893344ff85c1711))

**Full Changelog:** [`2024.05.31.1...2024.06.04.0`](https://github.com/juspay/hyperswitch/compare/2024.05.31.1...2024.06.04.0)

- - -

## 2024.05.31.1

### Features

- **cypress:** Add trustpay, adyen bank redirects and corresponding refactor ([#4766](https://github.com/juspay/hyperswitch/pull/4766)) ([`48dac12`](https://github.com/juspay/hyperswitch/commit/48dac12cedc7f11b76c6a9ef8ba4ce04ae2456bf))

### Refactors

- **core:** Reverts Inclusion of constraint graph for merchant Payment Method list ([#4839](https://github.com/juspay/hyperswitch/pull/4839)) ([`f74b9b6`](https://github.com/juspay/hyperswitch/commit/f74b9b622e5565a00bf9ee8223c64a3def37b776))
- **first_name:** Check if first_name is sent as empty string ([#4832](https://github.com/juspay/hyperswitch/pull/4832)) ([`5cb84f6`](https://github.com/juspay/hyperswitch/commit/5cb84f66e4c59f6ffbd12bf4e91ab0152ac1c2c5))

### Miscellaneous Tasks

- **euclid_wasm:** Update paypal payment experience ([#4811](https://github.com/juspay/hyperswitch/pull/4811)) ([`121b611`](https://github.com/juspay/hyperswitch/commit/121b61123f31db9d94888fa708532cdabca4bbc8))
- Enable `clippy::large_futures` lint ([#4822](https://github.com/juspay/hyperswitch/pull/4822)) ([`d2d317c`](https://github.com/juspay/hyperswitch/commit/d2d317ce61c0c00ca38af9774bd1b45247d30c82))

**Full Changelog:** [`2024.05.31.0...2024.05.31.1`](https://github.com/juspay/hyperswitch/compare/2024.05.31.0...2024.05.31.1)

- - -

## 2024.05.31.0

### Features

- **connector:** Implement pre auth flow for gpayments ([#4692](https://github.com/juspay/hyperswitch/pull/4692)) ([`bed42ce`](https://github.com/juspay/hyperswitch/commit/bed42ce4be901f2b8f46033dd395dee8dbe807c9))
- **payout:** [Payone] add payone connector ([#4553](https://github.com/juspay/hyperswitch/pull/4553)) ([`832968c`](https://github.com/juspay/hyperswitch/commit/832968c0c444af74fb6398950159847d639eb50e))
- **router:** Added amount conversion function in core for connector module ([#4710](https://github.com/juspay/hyperswitch/pull/4710)) ([`08eefdb`](https://github.com/juspay/hyperswitch/commit/08eefdba4a7f428ffe7f0dac9799c46b82c49864))
- **users:** Add support to reset totp ([#4821](https://github.com/juspay/hyperswitch/pull/4821)) ([`aca6ad1`](https://github.com/juspay/hyperswitch/commit/aca6ad1bd1f43758b22638a7a2e7e4a99b66e5ff))
- Add a domain type for `customer_id` ([#4705](https://github.com/juspay/hyperswitch/pull/4705)) ([`93d61d1`](https://github.com/juspay/hyperswitch/commit/93d61d1053a834ac1e7bf6d5dd70053d28f3e7d5))

### Bug Fixes

- **netcetera:** Handle non-ascii characters for cardholdername, error message and send missing fields ([#4755](https://github.com/juspay/hyperswitch/pull/4755)) ([`5d1900e`](https://github.com/juspay/hyperswitch/commit/5d1900e1d96da1e8bb72dadfa1132a2340733fdc))
- **routing:** Added routing validation for payments req ([#4762](https://github.com/juspay/hyperswitch/pull/4762)) ([`21a3a2e`](https://github.com/juspay/hyperswitch/commit/21a3a2ea8ada838c67b0e5871f01d09bd5a8b9ed))

### Refactors

- **connector:** [Klarna] Refactor configs for sandbox and production and update payment status ([#4819](https://github.com/juspay/hyperswitch/pull/4819)) ([`f7e99e1`](https://github.com/juspay/hyperswitch/commit/f7e99e1eda4bea68351f4249074e35877a95e6ee))
- **core:** Move router data flow types to hyperswitch domain models crate ([#4801](https://github.com/juspay/hyperswitch/pull/4801)) ([`61e67e4`](https://github.com/juspay/hyperswitch/commit/61e67e42724525660df1d1076d2422f28d58a637))

### Miscellaneous Tasks

- **euclid_wasm:** Update klarna metadata ([#4823](https://github.com/juspay/hyperswitch/pull/4823)) ([`f192fa3`](https://github.com/juspay/hyperswitch/commit/f192fa3866c2ea21555aed8783fad2ac022091ad))
- **postman:** Update Postman collection files ([`4833f1a`](https://github.com/juspay/hyperswitch/commit/4833f1ac31b725c275465cf9fba34c5950b3c500))
- Remove redundant caching code ([#4804](https://github.com/juspay/hyperswitch/pull/4804)) ([`971ef1f`](https://github.com/juspay/hyperswitch/commit/971ef1fb8fd16f5af89071ddf4d143330d32f056))

**Full Changelog:** [`2024.05.30.0...2024.05.31.0`](https://github.com/juspay/hyperswitch/compare/2024.05.30.0...2024.05.31.0)

- - -

## 2024.05.30.0

### Features

- **connector:**
  - [ZSL] handle partial payments in Local Bank Transfer ([#4777](https://github.com/juspay/hyperswitch/pull/4777)) ([`e410eba`](https://github.com/juspay/hyperswitch/commit/e410eba6ed4894b4d0d505188d89016b93391d57))
  - Add support for external authentication for cybersource ([#4714](https://github.com/juspay/hyperswitch/pull/4714)) ([`97f2ff0`](https://github.com/juspay/hyperswitch/commit/97f2ff0e7051025e397c645fd67a579d0bb492f0))
  - [Klarna] Add support for Capture, Psync, Refunds and Rsync flows ([#4799](https://github.com/juspay/hyperswitch/pull/4799)) ([`e41d5e2`](https://github.com/juspay/hyperswitch/commit/e41d5e25dfd4d3113edac11b249e847f8718b263))
- **users:**
  - Add redis in Begin and Verify TOTP and create a new API that updates TOTP ([#4765](https://github.com/juspay/hyperswitch/pull/4765)) ([`cd9c9b6`](https://github.com/juspay/hyperswitch/commit/cd9c9b609c8d5d7c77658d973f7922ae71af9a4d))
  - Add endpoint to check 2fa status ([#4810](https://github.com/juspay/hyperswitch/pull/4810)) ([`0f7f3d9`](https://github.com/juspay/hyperswitch/commit/0f7f3d9e74f0dad5112d6045089c8bfa12f4767f))

### Bug Fixes

- **Cypress:** Fixing 3DS payment failure in headless mode ([#4807](https://github.com/juspay/hyperswitch/pull/4807)) ([`b335867`](https://github.com/juspay/hyperswitch/commit/b335867eb92b7fe5a1147e7a3dd70d9f2746ba96))
- Implement StrongEq for Vec<u8> ([#4795](https://github.com/juspay/hyperswitch/pull/4795)) ([`b812e59`](https://github.com/juspay/hyperswitch/commit/b812e596a1bef4cc154f5b925753ad158c9022de))

### Refactors

- **connector:** [Klarna] Refactor Authorize call and configs for prod ([#4750](https://github.com/juspay/hyperswitch/pull/4750)) ([`a6570b6`](https://github.com/juspay/hyperswitch/commit/a6570b6a06917be27e543cb35bb210df4fc6391e))
- **core:** Move router data response and request models to hyperswitch domain models crate ([#4789](https://github.com/juspay/hyperswitch/pull/4789)) ([`dd33329`](https://github.com/juspay/hyperswitch/commit/dd333298f8b4e8ff3c15fc79fbc528a61fa1b63f))

**Full Changelog:** [`2024.05.29.0...2024.05.30.0`](https://github.com/juspay/hyperswitch/compare/2024.05.29.0...2024.05.30.0)

- - -

## 2024.05.29.0

### Features

- **connector:**
  - [Iatapay] add upi qr support ([#4728](https://github.com/juspay/hyperswitch/pull/4728)) ([`c9fa94f`](https://github.com/juspay/hyperswitch/commit/c9fa94febe7a1fcd24e8d723d14b78f8a73da0e3))
  - [CRYPTOPAY] Pass network details in payment request ([#4779](https://github.com/juspay/hyperswitch/pull/4779)) ([`84e032e`](https://github.com/juspay/hyperswitch/commit/84e032e6c28afc410c82e73e51deb629b0c4a81a))

### Bug Fixes

- **docker-compose:** Fix docker compose syntax ([#4782](https://github.com/juspay/hyperswitch/pull/4782)) ([`7645edf`](https://github.com/juspay/hyperswitch/commit/7645edfa2e00500da3f8f117cc1a485fe1f41ab5))
- Include client columns in payment attempts response struct ([#4761](https://github.com/juspay/hyperswitch/pull/4761)) ([`d686ec7`](https://github.com/juspay/hyperswitch/commit/d686ec7acda6ce852fac8d7413f9ba903adcee1d))

### Refactors

- **payment_methods:** Add support for passing ttl to locker entries ([#4690](https://github.com/juspay/hyperswitch/pull/4690)) ([`7ca9c6e`](https://github.com/juspay/hyperswitch/commit/7ca9c6e81313199589444a431a73fbcdf712a9ee))
- Retrieve extended card info config during business profile get call ([#4784](https://github.com/juspay/hyperswitch/pull/4784)) ([`c362fd0`](https://github.com/juspay/hyperswitch/commit/c362fd05325743bb3d173e335124734f1c23b9fa))

### Documentation

- **analytics:** Add documentation for setting up data services and enabling data features in control center ([#4741](https://github.com/juspay/hyperswitch/pull/4741)) ([`d15cb31`](https://github.com/juspay/hyperswitch/commit/d15cb31814390bc631f9eb4195ca114e43ab4cd2))

**Full Changelog:** [`2024.05.28.0...2024.05.29.0`](https://github.com/juspay/hyperswitch/compare/2024.05.28.0...2024.05.29.0)

- - -

## 2024.05.28.0

### Features

- **connector:** [AUTHORIZEDOTNET] Implement non-zero mandates ([#4758](https://github.com/juspay/hyperswitch/pull/4758)) ([`ed82af8`](https://github.com/juspay/hyperswitch/commit/ed82af81f9316c266adc7ee8273b0e33e1c83ccf))
- **core:** [Paypal] Add session_token flow for Paypal sdk ([#4697](https://github.com/juspay/hyperswitch/pull/4697)) ([`b3d4d13`](https://github.com/juspay/hyperswitch/commit/b3d4d13db81143cf663142d8bd8fdf95b0882b3f))

**Full Changelog:** [`2024.05.27.0...2024.05.28.0`](https://github.com/juspay/hyperswitch/compare/2024.05.27.0...2024.05.28.0)

- - -

## 2024.05.27.0

### Refactors

- **core:** Inclusion of constraint graph for merchant Payment Method list ([#4626](https://github.com/juspay/hyperswitch/pull/4626)) ([`2cabb0b`](https://github.com/juspay/hyperswitch/commit/2cabb0bedcdf0d1adf568f2533b6ab9ce8d9fc57))

### Miscellaneous Tasks

- Add missing migrations for recently added currencies ([#4760](https://github.com/juspay/hyperswitch/pull/4760)) ([`1026f47`](https://github.com/juspay/hyperswitch/commit/1026f4783000a13b43f22e4db0b36c217d39e541))

**Full Changelog:** [`2024.05.24.1...2024.05.27.0`](https://github.com/juspay/hyperswitch/compare/2024.05.24.1...2024.05.27.0)

- - -

## 2024.05.24.1

### Features

- **payment_charges:** Add support for collecting and refunding charges on payments ([#4628](https://github.com/juspay/hyperswitch/pull/4628)) ([`55ccce6`](https://github.com/juspay/hyperswitch/commit/55ccce61898083992afeab03ba1690954b1b45ef))

### Bug Fixes

- **payment_methods:**
  - Log and ignore the apple pay metadata parsing error while fetching apple pay retry connectors ([#4747](https://github.com/juspay/hyperswitch/pull/4747)) ([`a7fc4c6`](https://github.com/juspay/hyperswitch/commit/a7fc4c6fcd2f031b92e36f40a14be641673b7422))
  - Revert the filter for getting the mcas which are disabled ([#4756](https://github.com/juspay/hyperswitch/pull/4756)) ([`9fb2a83`](https://github.com/juspay/hyperswitch/commit/9fb2a8301453b47e2d1c17e215f740bea8eaa91a))

**Full Changelog:** [`2024.05.24.0...2024.05.24.1`](https://github.com/juspay/hyperswitch/compare/2024.05.24.0...2024.05.24.1)

- - -

## 2024.05.24.0

### Features

- **analytics:** Added client columns in payments analytics ([#4658](https://github.com/juspay/hyperswitch/pull/4658)) ([`0b415dc`](https://github.com/juspay/hyperswitch/commit/0b415dcca67f2994727627990a9cc9db19885b34))
- **router:** Send message_version and directory_server_id in next_action block of three_ds_data for external 3ds flow ([#4715](https://github.com/juspay/hyperswitch/pull/4715)) ([`13f6efc`](https://github.com/juspay/hyperswitch/commit/13f6efc7e8c01b4a377f627b9cfe2319b518204d))
- **users:**
  - Create terminate 2fa API ([#4731](https://github.com/juspay/hyperswitch/pull/4731)) ([`42e5ef1`](https://github.com/juspay/hyperswitch/commit/42e5ef155128f4df717e8fb101da6e6929659a0a))
  - Add support to verify 2FA using recovery code ([#4737](https://github.com/juspay/hyperswitch/pull/4737)) ([`f04c6ac`](https://github.com/juspay/hyperswitch/commit/f04c6ac030485cb28ab09e85a0f2f3c13beb6df3))
- Authentication analytics ([#4684](https://github.com/juspay/hyperswitch/pull/4684)) ([`5e5eb5f`](https://github.com/juspay/hyperswitch/commit/5e5eb5fbae7de2e296899e0372c82906603526d6))

### Bug Fixes

- **kafka:** Fix kafka timestamps sent from application ([#4709](https://github.com/juspay/hyperswitch/pull/4709)) ([`c778af2`](https://github.com/juspay/hyperswitch/commit/c778af26ddb46ff98072e8934a9509ff6e00ddc5))
- **payment_methods:** Mask the email address being logged in the `payment_method_list` response logs ([#4749](https://github.com/juspay/hyperswitch/pull/4749)) ([`23c7395`](https://github.com/juspay/hyperswitch/commit/23c73951bbdd5e049b75ca6d8e3bcccfb629e6eb))

### Refactors

- **bank-redirect:** Dynamic field changes for bankredirect payment method ([#4650](https://github.com/juspay/hyperswitch/pull/4650)) ([`da2dc10`](https://github.com/juspay/hyperswitch/commit/da2dc10f3d7233a0a9eae7d23cb07f7e8fafad78))
- **payment_methods:** Use recurring enabled flag to decide which payment method supports MIT ([#4732](https://github.com/juspay/hyperswitch/pull/4732)) ([`ba624d0`](https://github.com/juspay/hyperswitch/commit/ba624d049840f65fc21a5e578f8d4ba8543e1420))

### Miscellaneous Tasks

- Move RouterData Request types to hyperswitch_domain_models crate ([#4723](https://github.com/juspay/hyperswitch/pull/4723)) ([`ae77373`](https://github.com/juspay/hyperswitch/commit/ae77373b4cac63979673fdac37c55986d954358e))

**Full Changelog:** [`2024.05.23.0...2024.05.24.0`](https://github.com/juspay/hyperswitch/compare/2024.05.23.0...2024.05.24.0)

- - -

## 2024.05.23.0

### Features

- **connector:**
  - Accept connector_transaction_id in 4xx error_response of connector ([#4720](https://github.com/juspay/hyperswitch/pull/4720)) ([`2ad7fc0`](https://github.com/juspay/hyperswitch/commit/2ad7fc0cd6c102bea4d671c98f7fe50fd709d4ec))
  - [AUTHORIZEDOTNET] Implement zero mandates ([#4704](https://github.com/juspay/hyperswitch/pull/4704)) ([`8afeda5`](https://github.com/juspay/hyperswitch/commit/8afeda54fc5e3f3d510c48c81c222387e9cacc0e))
- **payment_methods:** Enable auto-retries for apple pay ([#4721](https://github.com/juspay/hyperswitch/pull/4721)) ([`d942a31`](https://github.com/juspay/hyperswitch/commit/d942a31d60595d366977746be7215620da0ababd))
- **routing:** Use Moka cache for routing with cache invalidation ([#3216](https://github.com/juspay/hyperswitch/pull/3216)) ([`431560b`](https://github.com/juspay/hyperswitch/commit/431560b7fb4401d000c11dbb9c7eb70663591307))
- **users:** Create generate recovery codes API ([#4708](https://github.com/juspay/hyperswitch/pull/4708)) ([`8fa2cd5`](https://github.com/juspay/hyperswitch/commit/8fa2cd556bf898621a1a8722a0af99d174447485))
- **webhook:** Add frm webhook support ([#4662](https://github.com/juspay/hyperswitch/pull/4662)) ([`ae601e8`](https://github.com/juspay/hyperswitch/commit/ae601e8e1be9215488daaae7cb39ad5a030e98d9))

### Bug Fixes

- **core:** Fix failing token based MIT payments ([#4735](https://github.com/juspay/hyperswitch/pull/4735)) ([`1bd4061`](https://github.com/juspay/hyperswitch/commit/1bd406197b5baf1c041f0dffa5bc02dce10f1529))
- Added hget lookup for all updated_by existing cases ([#4716](https://github.com/juspay/hyperswitch/pull/4716)) ([`fabf80c`](https://github.com/juspay/hyperswitch/commit/fabf80c2b18ca690b7fb709c8c12d1ef7f24e5b6))

### Miscellaneous Tasks

- **postman:** Update Postman collection files ([`ec50843`](https://github.com/juspay/hyperswitch/commit/ec508435a19c2942a5d66757a74dd06bed5b1a76))

**Full Changelog:** [`2024.05.22.0...2024.05.23.0`](https://github.com/juspay/hyperswitch/compare/2024.05.22.0...2024.05.23.0)

- - -

## 2024.05.22.0

### Features

- **core:** Add support for connectors having separate version call for pre authentication ([#4603](https://github.com/juspay/hyperswitch/pull/4603)) ([`528d692`](https://github.com/juspay/hyperswitch/commit/528d692a89f5cf9a82d1e5c28e4b3a1ef4bf6c6a))

### Refactors


pub struct ServiceSessionIds {
    pub client_id: Option<String>,
    pub service_id: Option<String>,
    pub correlation_id: Option<String>,
    pub client_reference_id: Option<String>,
    pub merchant_transaction_id: Option<String>,
    pub x_src_flow_id: Option<String>,
}


pub struct SmtpServer {
    /// sender email id
    pub sender: String,
    /// SMTP server specific configs
    pub smtp_config: SmtpServerConfig,
}


pub fn server(state: AppState) -> Scope {
        let mut route = web::scope("/user").app_data(web::Data::new(state.clone()));

        route = route
            .service(web::resource("").route(web::get().to(user::get_user_details)))
            .service(web::resource("/signin").route(web::post().to(user::user_signin)))
            .service(web::resource("/v2/signin").route(web::post().to(user::user_signin)))
            // signin/signup with sso using openidconnect
            .service(web::resource("/oidc").route(web::post().to(user::sso_sign)))
            .service(web::resource("/signout").route(web::post().to(user::signout)))
            .service(web::resource("/rotate_password").route(web::post().to(user::rotate_password)))
            .service(web::resource("/change_password").route(web::post().to(user::change_password)))
            .service(
                web::resource("/internal_signup").route(web::post().to(user::internal_user_signup)),
            )
            .service(
                web::resource("/tenant_signup").route(web::post().to(user::create_tenant_user)),
            )
            .service(web::resource("/create_org").route(web::post().to(user::user_org_create)))
            .service(
                web::resource("/create_merchant")
                    .route(web::post().to(user::user_merchant_account_create)),
            )
            // TODO: To be deprecated
            .service(
                web::resource("/permission_info")
                    .route(web::get().to(user_role::get_authorization_info)),
            )
            // TODO: To be deprecated
            .service(
                web::resource("/module/list").route(web::get().to(user_role::get_role_information)),
            )
            .service(
                web::resource("/parent/list")
                    .route(web::get().to(user_role::get_parent_group_info)),
            )
            .service(
                web::resource("/update").route(web::post().to(user::update_user_account_details)),
            )
            .service(
                web::resource("/data")
                    .route(web::get().to(user::get_multiple_dashboard_metadata))
                    .route(web::post().to(user::set_dashboard_metadata)),
            );

        if state.conf.platform.enabled {
            route = route.service(
                web::resource("/create_platform").route(web::post().to(user::create_platform)),
            )
        }

        route = route
            .service(web::scope("/key").service(
                web::resource("/transfer").route(web::post().to(user::transfer_user_key)),
            ));

        route = route.service(
            web::scope("/list")
                .service(web::resource("/org").route(web::get().to(user::list_orgs_for_user)))
                .service(
                    web::resource("/merchant")
                        .route(web::get().to(user::list_merchants_for_user_in_org)),
                )
                .service(
                    web::resource("/profile")
                        .route(web::get().to(user::list_profiles_for_user_in_org_and_merchant)),
                )
                .service(
                    web::resource("/invitation")
                        .route(web::get().to(user_role::list_invitations_for_user)),
                ),
        );

        route = route.service(
            web::scope("/switch")
                .service(web::resource("/org").route(web::post().to(user::switch_org_for_user)))
                .service(
                    web::resource("/merchant")
                        .route(web::post().to(user::switch_merchant_for_user_in_org)),
                )
                .service(
                    web::resource("/profile")
                        .route(web::post().to(user::switch_profile_for_user_in_org_and_merchant)),
                ),
        );

        // Two factor auth routes
        route = route.service(
            web::scope("/2fa")
                // TODO: to be deprecated
                .service(web::resource("").route(web::get().to(user::check_two_factor_auth_status)))
                .service(
                    web::resource("/v2")
                        .route(web::get().to(user::check_two_factor_auth_status_with_attempts)),
                )
                .service(
                    web::scope("/totp")
                        .service(web::resource("/begin").route(web::get().to(user::totp_begin)))
                        .service(web::resource("/reset").route(web::get().to(user::totp_reset)))
                        .service(
                            web::resource("/verify")
                                .route(web::post().to(user::totp_verify))
                                .route(web::put().to(user::totp_update)),
                        ),
                )
                .service(
                    web::scope("/recovery_code")
                        .service(
                            web::resource("/verify")
                                .route(web::post().to(user::verify_recovery_code)),
                        )
                        .service(
                            web::resource("/generate")
                                .route(web::get().to(user::generate_recovery_codes)),
                        ),
                )
                .service(
                    web::resource("/terminate")
                        .route(web::get().to(user::terminate_two_factor_auth)),
                ),
        );

        route = route.service(
            web::scope("/auth")
                .service(
                    web::resource("")
                        .route(web::post().to(user::create_user_authentication_method))
                        .route(web::put().to(user::update_user_authentication_method)),
                )
                .service(
                    web::resource("/list")
                        .route(web::get().to(user::list_user_authentication_methods)),
                )
                .service(web::resource("/url").route(web::get().to(user::get_sso_auth_url)))
                .service(
                    web::resource("/select").route(web::post().to(user::terminate_auth_select)),
                ),
        );

        #[cfg(feature = "email")]
        {
            route = route
                .service(web::resource("/from_email").route(web::post().to(user::user_from_email)))
                .service(
                    web::resource("/connect_account")
                        .route(web::post().to(user::user_connect_account)),
                )
                .service(
                    web::resource("/forgot_password").route(web::post().to(user::forgot_password)),
                )
                .service(
                    web::resource("/reset_password").route(web::post().to(user::reset_password)),
                )
                .service(
                    web::resource("/signup_with_merchant_id")
                        .route(web::post().to(user::user_signup_with_merchant_id)),
                )
                .service(web::resource("/verify_email").route(web::post().to(user::verify_email)))
                .service(
                    web::resource("/v2/verify_email").route(web::post().to(user::verify_email)),
                )
                .service(
                    web::resource("/verify_email_request")
                        .route(web::post().to(user::verify_email_request)),
                )
                .service(
                    web::resource("/user/resend_invite").route(web::post().to(user::resend_invite)),
                )
                .service(
                    web::resource("/accept_invite_from_email")
                        .route(web::post().to(user::accept_invite_from_email)),
                );
        }
        #[cfg(not(feature = "email"))]
        {
            route = route.service(web::resource("/signup").route(web::post().to(user::user_signup)))
        }

        // User management
        route = route.service(
            web::scope("/user")
                .service(web::resource("").route(web::post().to(user::list_user_roles_details)))
                // TODO: To be deprecated
                .service(web::resource("/v2").route(web::post().to(user::list_user_roles_details)))
                .service(
                    web::resource("/list").route(web::get().to(user_role::list_users_in_lineage)),
                )
                // TODO: To be deprecated
                .service(
                    web::resource("/v2/list")
                        .route(web::get().to(user_role::list_users_in_lineage)),
                )
                .service(
                    web::resource("/invite_multiple")
                        .route(web::post().to(user::invite_multiple_user)),
                )
                .service(
                    web::scope("/invite/accept")
                        .service(
                            web::resource("")
                                .route(web::post().to(user_role::accept_invitations_v2)),
                        )
                        .service(
                            web::resource("/pre_auth")
                                .route(web::post().to(user_role::accept_invitations_pre_auth)),
                        )
                        .service(
                            web::scope("/v2")
                                .service(
                                    web::resource("")
                                        .route(web::post().to(user_role::accept_invitations_v2)),
                                )
                                .service(
                                    web::resource("/pre_auth").route(
                                        web::post().to(user_role::accept_invitations_pre_auth),
                                    ),
                                ),
                        ),
                )
                .service(
                    web::resource("/update_role")
                        .route(web::post().to(user_role::update_user_role)),
                )
                .service(
                    web::resource("/delete").route(web::delete().to(user_role::delete_user_role)),
                ),
        );

        if state.conf().clone_connector_allowlist.is_some() {
            route = route.service(
                web::resource("/clone_connector").route(web::post().to(user::clone_connector)),
            );
        }

        // Role information
        route = route.service(
            web::scope("/role")
                .service(
                    web::resource("")
                        .route(web::get().to(user_role::get_role_from_token))
                        // TODO: To be deprecated
                        .route(web::post().to(user_role::create_role)),
                )
                .service(
                    web::resource("/v2")
                        .route(web::post().to(user_role::create_role_v2))
                        .route(
                            web::get().to(user_role::get_groups_and_resources_for_role_from_token),
                        ),
                )
                // TODO: To be deprecated
                .service(
                    web::resource("/v2/list").route(web::get().to(user_role::list_roles_with_info)),
                )
                .service(
                    web::scope("/list")
                        .service(
                            web::resource("").route(web::get().to(user_role::list_roles_with_info)),
                        )
                        .service(
                            web::resource("/invite").route(
                                web::get().to(user_role::list_invitable_roles_at_entity_level),
                            ),
                        )
                        .service(
                            web::resource("/update").route(
                                web::get().to(user_role::list_updatable_roles_at_entity_level),
                            ),
                        ),
                )
                .service(
                    web::resource("/{role_id}")
                        .route(web::get().to(user_role::get_role))
                        .route(web::put().to(user_role::update_role)),
                )
                .service(
                    web::resource("/{role_id}/v2")
                        .route(web::get().to(user_role::get_parent_info_for_role)),
                ),
        );

        #[cfg(feature = "dummy_connector")]
        {
            route = route.service(
                web::resource("/sample_data")
                    .route(web::post().to(user::generate_sample_data))
                    .route(web::delete().to(user::delete_sample_data)),
            )
        }
        // Admin Theme
        // TODO: To be deprecated
        route = route.service(
            web::scope("/admin/theme")
                .service(
                    web::resource("")
                        .route(web::get().to(user::theme::get_theme_using_lineage))
                        .route(web::post().to(user::theme::create_theme)),
                )
                .service(
                    web::resource("/{theme_id}")
                        .route(web::get().to(user::theme::get_theme_using_theme_id))
                        .route(web::put().to(user::theme::update_theme))
                        .route(web::post().to(user::theme::upload_file_to_theme_storage))
                        .route(web::delete().to(user::theme::delete_theme)),
                ),
        );
        // User Theme
        route = route.service(
            web::scope("/theme")
                .service(
                    web::resource("")
                        .route(web::post().to(user::theme::create_user_theme))
                        .route(web::get().to(user::theme::get_user_theme_using_lineage)),
                )
                .service(
                    web::resource("/list")
                        .route(web::get().to(user::theme::list_all_themes_in_lineage)),
                )
                .service(
                    web::resource("/{theme_id}")
                        .route(web::get().to(user::theme::get_user_theme_using_theme_id))
                        .route(web::put().to(user::theme::update_user_theme))
                        .route(web::post().to(user::theme::upload_file_to_user_theme_storage))
                        .route(web::delete().to(user::theme::delete_user_theme)),
                ),
        );
        route
    }


pub async fn accept_invitations_pre_auth(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<user_role_api::AcceptInvitationsPreAuthRequest>,
) -> HttpResponse {
    let flow = Flow::AcceptInvitationsPreAuth;
    let payload = json_payload.into_inner();
    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        payload,
        |state, user, req_body, _| async move {
            user_role_core::accept_invitations_pre_auth(state, user, req_body).await
        },
        &auth::SinglePurposeJWTAuth(TokenPurpose::AcceptInvite),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


impl Payment for Threedsecureio {}


pub fn get_dispute_dimensions() -> Vec<NameDescription> {
    DisputeDimensions::iter().map(Into::into).collect()
}


pub struct Nuvei {
    pub amount_convertor: &'static (dyn AmountConvertor<Output = StringMajorUnit> + Sync),
}


impl api::RefundSync for Breadpay {}


impl Responder {
    let flow = Flow::ApiKeyCreate;
    let payload = json_payload.into_inner();
    let merchant_id = path.into_inner();

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth_data, payload, _| async {
            api_keys::create_api_key(state, payload, auth_data.key_store).await
        },
        auth::auth_type(
            &auth::PlatformOrgAdminAuthWithMerchantIdFromRoute {
                merchant_id_from_route: merchant_id.clone(),
                is_admin_auth_allowed: true,
            },
            &auth::JWTAuthMerchantFromRoute {
                merchant_id: merchant_id.clone(),
                required_permission: Permission::MerchantApiKeyWrite,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub struct RiskifiedFulfillmentRequest {
    order: OrderFulfillment,
}


OpenAPI Block Path: components.schemas.ThreeDSDecisionRule
{
  "type": "object",
  "description": "Struct representing the output configuration for the 3DS Decision Rule Engine.",
  "required": [
    "decision"
  ],
  "properties": {
    "decision": {
      "$ref": "#/components/schemas/ThreeDSDecision"
    }
  }
}


impl GetAuthType for PublishableKeyAuth {
    fn get_auth_type(&self) -> detached::PayloadType {
        detached::PayloadType::PublishableKey
    }
}

impl GetAuthType for for PublishableKeyAuth


pub struct GenericLinkNew {
    pub link_id: String,
    pub primary_reference: String,
    pub merchant_id: common_utils::id_type::MerchantId,
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub created_at: Option<PrimitiveDateTime>,
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub last_modified_at: Option<PrimitiveDateTime>,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub expiry: PrimitiveDateTime,
    pub link_data: serde_json::Value,
    pub link_status: GenericLinkStatus,
    pub link_type: storage_enums::GenericLinkType,
    pub url: Secret<String>,
    pub return_url: Option<String>,
}


File: crates/hyperswitch_domain_models/src/bulk_tokenization.rs
 Public structs: 4

use api_models::{payment_methods as payment_methods_api, payments as payments_api};
use cards::CardNumber;
use common_enums as enums;
use common_utils::{
    errors,
    ext_traits::OptionExt,
    id_type, pii,
    transformers::{ForeignFrom, ForeignTryFrom},
};
use error_stack::report;

use crate::{
    address::{Address, AddressDetails, PhoneDetails},
    router_request_types::CustomerDetails,
};

#[derive(Debug)]
pub struct CardNetworkTokenizeRequest {
    pub data: TokenizeDataRequest,
    pub customer: CustomerDetails,
    pub billing: Option<Address>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub payment_method_issuer: Option<String>,
}

#[derive(Debug)]
pub enum TokenizeDataRequest {
    Card(TokenizeCardRequest),
    ExistingPaymentMethod(TokenizePaymentMethodRequest),
}

#[derive(Clone, Debug)]
pub struct TokenizeCardRequest {
    pub raw_card_number: CardNumber,
    pub card_expiry_month: masking::Secret<String>,
    pub card_expiry_year: masking::Secret<String>,
    pub card_cvc: Option<masking::Secret<String>>,
    pub card_holder_name: Option<masking::Secret<String>>,
    pub nick_name: Option<masking::Secret<String>>,
    pub card_issuing_country: Option<String>,
    pub card_network: Option<enums::CardNetwork>,
    pub card_issuer: Option<String>,
    pub card_type: Option<payment_methods_api::CardType>,
}

#[derive(Clone, Debug)]
pub struct TokenizePaymentMethodRequest {
    pub payment_method_id: String,
    pub card_cvc: Option<masking::Secret<String>>,
}

#[derive(Default, Debug, serde::Deserialize, serde::Serialize)]
pub struct CardNetworkTokenizeRecord {
    // Card details
    pub raw_card_number: Option<CardNumber>,
    pub card_expiry_month: Option<masking::Secret<String>>,
    pub card_expiry_year: Option<masking::Secret<String>>,
    pub card_cvc: Option<masking::Secret<String>>,
    pub card_holder_name: Option<masking::Secret<String>>,
    pub nick_name: Option<masking::Secret<String>>,
    pub card_issuing_country: Option<String>,
    pub card_network: Option<enums::CardNetwork>,
    pub card_issuer: Option<String>,
    pub card_type: Option<payment_methods_api::CardType>,

    // Payment method details
    pub payment_method_id: Option<String>,
    pub payment_method_type: Option<payment_methods_api::CardType>,
    pub payment_method_issuer: Option<String>,

    // Customer details
    pub customer_id: id_type::CustomerId,
    #[serde(rename = "name")]
    pub customer_name: Option<masking::Secret<String>>,
    #[serde(rename = "email")]
    pub customer_email: Option<pii::Email>,
    #[serde(rename = "phone")]
    pub customer_phone: Option<masking::Secret<String>>,
    #[serde(rename = "phone_country_code")]
    pub customer_phone_country_code: Option<String>,
    #[serde(rename = "tax_registration_id")]
    pub customer_tax_registration_id: Option<masking::Secret<String>>,
    // Billing details
    pub billing_address_city: Option<String>,
    pub billing_address_country: Option<enums::CountryAlpha2>,
    pub billing_address_line1: Option<masking::Secret<String>>,
    pub billing_address_line2: Option<masking::Secret<String>>,
    pub billing_address_line3: Option<masking::Secret<String>>,
    pub billing_address_zip: Option<masking::Secret<String>>,
    pub billing_address_state: Option<masking::Secret<String>>,
    pub billing_address_first_name: Option<masking::Secret<String>>,
    pub billing_address_last_name: Option<masking::Secret<String>>,
    pub billing_phone_number: Option<masking::Secret<String>>,
    pub billing_phone_country_code: Option<String>,
    pub billing_email: Option<pii::Email>,

    // Other details
    pub line_number: Option<u64>,
    pub merchant_id: Option<id_type::MerchantId>,
}

impl ForeignFrom<&CardNetworkTokenizeRecord> for payments_api::CustomerDetails {
    fn foreign_from(record: &CardNetworkTokenizeRecord) -> Self {
        Self {
            id: record.customer_id.clone(),
            name: record.customer_name.clone(),
            email: record.customer_email.clone(),
            phone: record.customer_phone.clone(),
            phone_country_code: record.customer_phone_country_code.clone(),
            tax_registration_id: record.customer_tax_registration_id.clone(),
        }
    }
}

impl ForeignFrom<&CardNetworkTokenizeRecord> for payments_api::Address {
    fn foreign_from(record: &CardNetworkTokenizeRecord) -> Self {
        Self {
            address: Some(payments_api::AddressDetails {
                first_name: record.billing_address_first_name.clone(),
                last_name: record.billing_address_last_name.clone(),
                line1: record.billing_address_line1.clone(),
                line2: record.billing_address_line2.clone(),
                line3: record.billing_address_line3.clone(),
                city: record.billing_address_city.clone(),
                zip: record.billing_address_zip.clone(),
                state: record.billing_address_state.clone(),
                country: record.billing_address_country,
                origin_zip: None,
            }),
            phone: Some(payments_api::PhoneDetails {
                number: record.billing_phone_number.clone(),
                country_code: record.billing_phone_country_code.clone(),
            }),
            email: record.billing_email.clone(),
        }
    }
}

impl ForeignTryFrom<CardNetworkTokenizeRecord> for payment_methods_api::CardNetworkTokenizeRequest {
    type Error = error_stack::Report<errors::ValidationError>;
    fn foreign_try_from(record: CardNetworkTokenizeRecord) -> Result<Self, Self::Error> {
        let billing = Some(payments_api::Address::foreign_from(&record));
        let customer = payments_api::CustomerDetails::foreign_from(&record);
        let merchant_id = record.merchant_id.get_required_value("merchant_id")?;

        match (
            record.raw_card_number,
            record.card_expiry_month,
            record.card_expiry_year,
            record.payment_method_id,
        ) {
            (Some(raw_card_number), Some(card_expiry_month), Some(card_expiry_year), None) => {
                Ok(Self {
                    merchant_id,
                    data: payment_methods_api::TokenizeDataRequest::Card(
                        payment_methods_api::TokenizeCardRequest {
                            raw_card_number,
                            card_expiry_month,
                            card_expiry_year,
                            card_cvc: record.card_cvc,
                            card_holder_name: record.card_holder_name,
                            nick_name: record.nick_name,
                            card_issuing_country: record.card_issuing_country,
                            card_network: record.card_network,
                            card_issuer: record.card_issuer,
                            card_type: record.card_type.clone(),
                        },
                    ),
                    billing,
                    customer,
                    metadata: None,
                    payment_method_issuer: record.payment_method_issuer,
                })
            }
            (None, None, None, Some(payment_method_id)) => Ok(Self {
                merchant_id,
                data: payment_methods_api::TokenizeDataRequest::ExistingPaymentMethod(
                    payment_methods_api::TokenizePaymentMethodRequest {
                        payment_method_id,
                        card_cvc: record.card_cvc,
                    },
                ),
                billing,
                customer,
                metadata: None,
                payment_method_issuer: record.payment_method_issuer,
            }),
            _ => Err(report!(errors::ValidationError::InvalidValue {
                message: "Invalid record in bulk tokenization - expected one of card details or payment method details".to_string()
            })),
        }
    }
}

impl ForeignFrom<&TokenizeCardRequest> for payment_methods_api::MigrateCardDetail {
    fn foreign_from(card: &TokenizeCardRequest) -> Self {
        Self {
            card_number: masking::Secret::new(card.raw_card_number.get_card_no()),
            card_exp_month: card.card_expiry_month.clone(),
            card_exp_year: card.card_expiry_year.clone(),
            card_holder_name: card.card_holder_name.clone(),
            nick_name: card.nick_name.clone(),
            card_issuing_country: card.card_issuing_country.clone(),
            card_network: card.card_network.clone(),
            card_issuer: card.card_issuer.clone(),
            card_type: card
                .card_type
                .as_ref()
                .map(|card_type| card_type.to_string()),
        }
    }
}

impl ForeignTryFrom<CustomerDetails> for payments_api::CustomerDetails {
    type Error = error_stack::Report<errors::ValidationError>;
    fn foreign_try_from(customer: CustomerDetails) -> Result<Self, Self::Error> {
        Ok(Self {
            id: customer.customer_id.get_required_value("customer_id")?,
            name: customer.name,
            email: customer.email,
            phone: customer.phone,
            phone_country_code: customer.phone_country_code,
            tax_registration_id: customer.tax_registration_id,
        })
    }
}

impl ForeignFrom<payment_methods_api::CardNetworkTokenizeRequest> for CardNetworkTokenizeRequest {
    fn foreign_from(req: payment_methods_api::CardNetworkTokenizeRequest) -> Self {
        Self {
            data: TokenizeDataRequest::foreign_from(req.data),
            customer: CustomerDetails::foreign_from(req.customer),
            billing: req.billing.map(ForeignFrom::foreign_from),
            metadata: req.metadata,
            payment_method_issuer: req.payment_method_issuer,
        }
    }
}

impl ForeignFrom<payment_methods_api::TokenizeDataRequest> for TokenizeDataRequest {
    fn foreign_from(req: payment_methods_api::TokenizeDataRequest) -> Self {
        match req {
            payment_methods_api::TokenizeDataRequest::Card(card) => {
                Self::Card(TokenizeCardRequest {
                    raw_card_number: card.raw_card_number,
                    card_expiry_month: card.card_expiry_month,
                    card_expiry_year: card.card_expiry_year,
                    card_cvc: card.card_cvc,
                    card_holder_name: card.card_holder_name,
                    nick_name: card.nick_name,
                    card_issuing_country: card.card_issuing_country,
                    card_network: card.card_network,
                    card_issuer: card.card_issuer,
                    card_type: card.card_type,
                })
            }
            payment_methods_api::TokenizeDataRequest::ExistingPaymentMethod(pm) => {
                Self::ExistingPaymentMethod(TokenizePaymentMethodRequest {
                    payment_method_id: pm.payment_method_id,
                    card_cvc: pm.card_cvc,
                })
            }
        }
    }
}

impl ForeignFrom<payments_api::CustomerDetails> for CustomerDetails {
    fn foreign_from(req: payments_api::CustomerDetails) -> Self {
        Self {
            customer_id: Some(req.id),
            name: req.name,
            email: req.email,
            phone: req.phone,
            phone_country_code: req.phone_country_code,
            tax_registration_id: req.tax_registration_id,
        }
    }
}

impl ForeignFrom<payments_api::Address> for Address {
    fn foreign_from(req: payments_api::Address) -> Self {
        Self {
            address: req.address.map(ForeignFrom::foreign_from),
            phone: req.phone.map(ForeignFrom::foreign_from),
            email: req.email,
        }
    }
}

impl ForeignFrom<payments_api::AddressDetails> for AddressDetails {
    fn foreign_from(req: payments_api::AddressDetails) -> Self {
        Self {
            city: req.city,
            country: req.country,
            line1: req.line1,
            line2: req.line2,
            line3: req.line3,
            zip: req.zip,
            state: req.state,
            first_name: req.first_name,
            last_name: req.last_name,
            origin_zip: req.origin_zip,
        }
    }
}

impl ForeignFrom<payments_api::PhoneDetails> for PhoneDetails {
    fn foreign_from(req: payments_api::PhoneDetails) -> Self {
        Self {
            number: req.number,
            country_code: req.country_code,
        }
    }
}


pub struct AnyPurposeOrLoginTokenAuth;


pub struct VariableDeletePaymentMethodFromVaultInput {
    input: DeletePaymentMethodFromVaultInputData,
}


/// Provides us with all the configured configs of the Merchant in the ascending time configured
/// manner and chooses the first of them
pub async fn get_merchant_default_config(
    db: &dyn StorageInterface,
    // Cannot make this as merchant id domain type because, we are passing profile id also here
    merchant_id: &str,
    transaction_type: &storage::enums::TransactionType,
) -> RouterResult<Vec<routing_types::RoutableConnectorChoice>> {
    let key = get_default_config_key(merchant_id, transaction_type);
    let maybe_config = db.find_config_by_key(&key).await;

    match maybe_config {
        Ok(config) => config
            .config
            .parse_struct("Vec<RoutableConnectors>")
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Merchant default config has invalid structure"),

        Err(e) if e.current_context().is_db_not_found() => {
            let new_config_conns = Vec::<routing_types::RoutableConnectorChoice>::new();
            let serialized = new_config_conns
                .encode_to_string_of_json()
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable(
                    "Error while creating and serializing new merchant default config",
                )?;

            let new_config = configs::ConfigNew {
                key,
                config: serialized,
            };

            db.insert_config(new_config)
                .await
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Error inserting new default routing config into DB")?;

            Ok(new_config_conns)
        }

        Err(e) => Err(e)
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Error fetching default config for merchant"),
    }
}


pub async fn call_surcharge_decision_management(
    state: routes::SessionState,
    merchant_context: &domain::MerchantContext,
    business_profile: &Profile,
    payment_attempt: &storage::PaymentAttempt,
    payment_intent: storage::PaymentIntent,
    billing_address: Option<domain::Address>,
    response_payment_method_types: &mut [ResponsePaymentMethodsEnabled],
) -> errors::RouterResult<api_surcharge_decision_configs::MerchantSurchargeConfigs> {
    #[cfg(feature = "v1")]
    let algorithm_ref: routing_types::RoutingAlgorithmRef = merchant_context
        .get_merchant_account()
        .routing_algorithm
        .clone()
        .map(|val| val.parse_value("routing algorithm"))
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Could not decode the routing algorithm")?
        .unwrap_or_default();

    // TODO: Move to business profile surcharge decision column
    #[cfg(feature = "v2")]
    let algorithm_ref: routing_types::RoutingAlgorithmRef = todo!();

    let (surcharge_results, merchant_sucharge_configs) =
        perform_surcharge_decision_management_for_payment_method_list(
            &state,
            algorithm_ref,
            payment_attempt,
            &payment_intent,
            billing_address.as_ref().map(Into::into),
            response_payment_method_types,
        )
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("error performing surcharge decision operation")?;
    if !surcharge_results.is_empty_result() {
        surcharge_results
            .persist_individual_surcharge_details_in_redis(&state, business_profile)
            .await?;
        let _ = state
            .store
            .update_payment_intent(
                &(&state).into(),
                payment_intent,
                storage::PaymentIntentUpdate::SurchargeApplicableUpdate {
                    surcharge_applicable: true,
                    updated_by: merchant_context
                        .get_merchant_account()
                        .storage_scheme
                        .to_string(),
                },
                merchant_context.get_merchant_key_store(),
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
            .attach_printable("Failed to update surcharge_applicable in Payment Intent");
    }
    Ok(merchant_sucharge_configs)
}


pub async fn organization_retrieve() {}