File: crates/router/src/routes/chat.rs
 Public functions: 1

use actix_web::{web, HttpRequest, HttpResponse};
#[cfg(feature = "olap")]
use api_models::chat as chat_api;
use router_env::{instrument, tracing, Flow};

use super::AppState;
use crate::{
    core::{api_locking, chat as chat_core},
    routes::metrics,
    services::{
        api,
        authentication::{self as auth},
        authorization::permissions::Permission,
    },
};

#[instrument(skip_all)]
pub async fn get_data_from_hyperswitch_ai_workflow(
    state: web::Data<AppState>,
    http_req: HttpRequest,
    payload: web::Json<chat_api::ChatRequest>,
) -> HttpResponse {
    let flow = Flow::GetDataFromHyperswitchAiFlow;
    let session_id = http_req
        .headers()
        .get(common_utils::consts::X_CHAT_SESSION_ID)
        .and_then(|header_value| header_value.to_str().ok());
    Box::pin(api::server_wrap(
        flow.clone(),
        state,
        &http_req,
        payload.into_inner(),
        |state, user: auth::UserFromToken, payload, _| {
            metrics::CHAT_REQUEST_COUNT.add(
                1,
                router_env::metric_attributes!(("merchant_id", user.merchant_id.clone())),
            );
            chat_core::get_data_from_hyperswitch_ai_workflow(state, user, payload, session_id)
        },
        // At present, the AI service retrieves data scoped to the merchant level
        &auth::JWTAuth {
            permission: Permission::MerchantPaymentRead,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


File: crates/router/src/workflows/tokenized_data.rs
 Public structs: 1

use scheduler::consumer::workflows::ProcessTrackerWorkflow;

#[cfg(feature = "v1")]
use crate::core::payment_methods::vault;
use crate::{errors, logger::error, routes::SessionState, types::storage};

pub struct DeleteTokenizeDataWorkflow;

#[async_trait::async_trait]
impl ProcessTrackerWorkflow<SessionState> for DeleteTokenizeDataWorkflow {
    #[cfg(feature = "v1")]
    async fn execute_workflow<'a>(
        &'a self,
        state: &'a SessionState,
        process: storage::ProcessTracker,
    ) -> Result<(), errors::ProcessTrackerError> {
        Ok(vault::start_tokenize_data_workflow(state, &process).await?)
    }

    #[cfg(feature = "v2")]
    async fn execute_workflow<'a>(
        &'a self,
        _state: &'a SessionState,
        _process: storage::ProcessTracker,
    ) -> Result<(), errors::ProcessTrackerError> {
        todo!()
    }

    async fn error_handler<'a>(
        &'a self,
        _state: &'a SessionState,
        process: storage::ProcessTracker,
        _error: errors::ProcessTrackerError,
    ) -> errors::CustomResult<(), errors::ProcessTrackerError> {
        error!(%process.id, "Failed while executing workflow");
        Ok(())
    }
}


pub async fn do_gsm_actions<F, ApiRequest, FData, D>(
    state: &app::SessionState,
    req_state: ReqState,
    payment_data: &mut D,
    mut connector_routing_data: IntoIter<api::ConnectorRoutingData>,
    original_connector_data: &api::ConnectorData,
    mut router_data: types::RouterData<F, FData, types::PaymentsResponseData>,
    merchant_context: &domain::MerchantContext,
    operation: &operations::BoxedOperation<'_, F, ApiRequest, D>,
    customer: &Option<domain::Customer>,
    validate_result: &operations::ValidateResult,
    schedule_time: Option<time::PrimitiveDateTime>,
    frm_suggestion: Option<storage_enums::FrmSuggestion>,
    business_profile: &domain::Profile,
) -> RouterResult<types::RouterData<F, FData, types::PaymentsResponseData>>
where
    F: Clone + Send + Sync,
    FData: Send + Sync + types::Capturable,
    payments::PaymentResponse: operations::Operation<F, FData>,
    D: payments::OperationSessionGetters<F>
        + payments::OperationSessionSetters<F>
        + Send
        + Sync
        + Clone,
    D: ConstructFlowSpecificData<F, FData, types::PaymentsResponseData>,
    types::RouterData<F, FData, types::PaymentsResponseData>: Feature<F, FData>,
    dyn api::Connector: services::api::ConnectorIntegration<F, FData, types::PaymentsResponseData>,
{
    let mut retries = None;

    metrics::AUTO_RETRY_ELIGIBLE_REQUEST_COUNT.add(1, &[]);

    let mut initial_gsm = get_gsm(state, &router_data).await?;

    let step_up_possible = initial_gsm
        .as_ref()
        .and_then(|data| data.feature_data.get_retry_feature_data())
        .map(|data| data.is_step_up_possible())
        .unwrap_or(false);

    #[cfg(feature = "v1")]
    let is_no_three_ds_payment = matches!(
        payment_data.get_payment_attempt().authentication_type,
        Some(storage_enums::AuthenticationType::NoThreeDs)
    );

    #[cfg(feature = "v2")]
    let is_no_three_ds_payment = matches!(
        payment_data.get_payment_attempt().authentication_type,
        storage_enums::AuthenticationType::NoThreeDs
    );

    let should_step_up = if step_up_possible && is_no_three_ds_payment {
        is_step_up_enabled_for_merchant_connector(
            state,
            merchant_context.get_merchant_account().get_id(),
            original_connector_data.connector_name,
        )
        .await
    } else {
        false
    };

    if should_step_up {
        router_data = do_retry(
            &state.clone(),
            req_state.clone(),
            original_connector_data,
            operation,
            customer,
            merchant_context,
            payment_data,
            router_data,
            validate_result,
            schedule_time,
            true,
            frm_suggestion,
            business_profile,
            false, //should_retry_with_pan is not applicable for step-up
            None,
        )
        .await?;
    }
    // Step up is not applicable so proceed with auto retries flow
    else {
        loop {
            // Use initial_gsm for first time alone
            let gsm = match initial_gsm.as_ref() {
                Some(gsm) => Some(gsm.clone()),
                None => get_gsm(state, &router_data).await?,
            };

            match get_gsm_decision(gsm) {
                storage_enums::GsmDecision::Retry => {
                    retries = get_retries(
                        state,
                        retries,
                        merchant_context.get_merchant_account().get_id(),
                        business_profile,
                    )
                    .await;

                    if retries.is_none() || retries == Some(0) {
                        metrics::AUTO_RETRY_EXHAUSTED_COUNT.add(1, &[]);
                        logger::info!("retries exhausted for auto_retry payment");
                        break;
                    }

                    if connector_routing_data.len() == 0 {
                        logger::info!("connectors exhausted for auto_retry payment");
                        metrics::AUTO_RETRY_EXHAUSTED_COUNT.add(1, &[]);
                        break;
                    }

                    let is_network_token = payment_data
                        .get_payment_method_data()
                        .map(|pmd| pmd.is_network_token_payment_method_data())
                        .unwrap_or(false);

                    let clear_pan_possible = initial_gsm
                        .and_then(|data| data.feature_data.get_retry_feature_data())
                        .map(|data| data.is_clear_pan_possible())
                        .unwrap_or(false);

                    let should_retry_with_pan = is_network_token
                        && clear_pan_possible
                        && business_profile.is_clear_pan_retries_enabled;

                    let (connector, routing_decision) = if should_retry_with_pan {
                        // If should_retry_with_pan is true, it indicates that we are retrying with PAN using the same connector.
                        (original_connector_data.clone(), None)
                    } else {
                        let connector_routing_data =
                            super::get_connector_data(&mut connector_routing_data)?;
                        let routing_decision = connector_routing_data.network.map(|card_network| {
                            routing_helpers::RoutingDecisionData::get_debit_routing_decision_data(
                                card_network,
                                None,
                            )
                        });

                        (connector_routing_data.connector_data, routing_decision)
                    };

                    router_data = do_retry(
                        &state.clone(),
                        req_state.clone(),
                        &connector,
                        operation,
                        customer,
                        merchant_context,
                        payment_data,
                        router_data,
                        validate_result,
                        schedule_time,
                        //this is an auto retry payment, but not step-up
                        false,
                        frm_suggestion,
                        business_profile,
                        should_retry_with_pan,
                        routing_decision,
                    )
                    .await?;

                    retries = retries.map(|i| i - 1);
                }
                storage_enums::GsmDecision::DoDefault => break,
            }
            initial_gsm = None;
        }
    }
    Ok(router_data)
}


impl api::ConnectorAccessToken for Payu {}

impl api::ConnectorAccessToken for for Payu


OpenAPI Block Path: components.schemas.SamsungPayWebWalletData
{
  "type": "object",
  "required": [
    "card_brand",
    "card_last4digits",
    "3_d_s"
  ],
  "properties": {
    "method": {
      "type": "string",
      "description": "Specifies authentication method used",
      "nullable": true
    },
    "recurring_payment": {
      "type": "boolean",
      "description": "Value if credential is enabled for recurring payment",
      "nullable": true
    },
    "card_brand": {
      "$ref": "#/components/schemas/SamsungPayCardBrand"
    },
    "card_last4digits": {
      "type": "string",
      "description": "Last 4 digits of the card number"
    },
    "3_d_s": {
      "$ref": "#/components/schemas/SamsungPayTokenData"
    }
  }
}


pub struct ProfileResponse {
    /// The identifier for Merchant Account
    #[schema(max_length = 64, example = "y3oqhf46pyzuxjbcn2giaqnb44", value_type = String)]
    pub merchant_id: id_type::MerchantId,

    /// The identifier for profile. This must be used for creating merchant accounts, payments and payouts
    #[schema(max_length = 64, value_type = String, example = "pro_abcdefghijklmnopqrstuvwxyz")]
    pub id: id_type::ProfileId,

    /// Name of the profile
    #[schema(max_length = 64)]
    pub profile_name: String,

    /// The URL to redirect after the completion of the operation
    #[schema(value_type = Option<String>, max_length = 255, example = "https://www.example.com/success")]
    pub return_url: Option<common_utils::types::Url>,

    /// A boolean value to indicate if payment response hash needs to be enabled
    #[schema(default = true, example = true)]
    pub enable_payment_response_hash: bool,

    /// Refers to the hash key used for calculating the signature for webhooks and redirect response. If the value is not provided, a value is automatically generated.
    pub payment_response_hash_key: Option<String>,

    /// A boolean value to indicate if redirect to merchant with http post needs to be enabled
    #[schema(default = false, example = true)]
    pub redirect_to_merchant_with_http_post: bool,

    /// Webhook related details
    pub webhook_details: Option<WebhookDetails>,

    /// Metadata is useful for storing additional, unstructured information on an object.
    #[schema(value_type = Option<Object>, example = r#"{ "city": "NY", "unit": "245" }"#)]
    pub metadata: Option<pii::SecretSerdeValue>,

    /// Verified Apple Pay domains for a particular profile
    pub applepay_verified_domains: Option<Vec<String>>,

    /// Client Secret Default expiry for all payments created under this profile
    #[schema(example = 900)]
    pub session_expiry: Option<i64>,

    /// Default Payment Link config for all payment links created under this profile
    #[schema(value_type = Option<BusinessPaymentLinkConfig>)]
    pub payment_link_config: Option<BusinessPaymentLinkConfig>,

    /// External 3DS authentication details
    pub authentication_connector_details: Option<AuthenticationConnectorDetails>,

    // Whether to use the billing details passed when creating the intent as payment method billing
    pub use_billing_as_payment_method_billing: Option<bool>,

    /// Merchant's config to support extended card info feature
    pub extended_card_info_config: Option<ExtendedCardInfoConfig>,

    /// A boolean value to indicate if customer shipping details needs to be collected from wallet
    /// connector only if it is required field for connector (Eg. Apple Pay, Google Pay etc)
    #[schema(default = false, example = false)]
    pub collect_shipping_details_from_wallet_connector_if_required: Option<bool>,

    /// A boolean value to indicate if customer billing details needs to be collected from wallet
    /// connector only if it is required field for connector (Eg. Apple Pay, Google Pay etc)
    #[schema(default = false, example = false)]
    pub collect_billing_details_from_wallet_connector_if_required: Option<bool>,

    /// A boolean value to indicate if customer shipping details needs to be collected from wallet
    /// connector irrespective of connector required fields (Eg. Apple pay, Google pay etc)
    #[schema(default = false, example = false)]
    pub always_collect_shipping_details_from_wallet_connector: Option<bool>,

    /// A boolean value to indicate if customer billing details needs to be collected from wallet
    /// connector irrespective of connector required fields (Eg. Apple pay, Google pay etc)
    #[schema(default = false, example = false)]
    pub always_collect_billing_details_from_wallet_connector: Option<bool>,

    /// Indicates if the MIT (merchant initiated transaction) payments can be made connector
    /// agnostic, i.e., MITs may be processed through different connector than CIT (customer
    /// initiated transaction) based on the routing rules.
    /// If set to `false`, MIT will go through the same connector as the CIT.
    pub is_connector_agnostic_mit_enabled: Option<bool>,

    /// Default payout link config
    #[schema(value_type = Option<BusinessPayoutLinkConfig>)]
    pub payout_link_config: Option<BusinessPayoutLinkConfig>,

    /// These key-value pairs are sent as additional custom headers in the outgoing webhook request.
    #[schema(value_type = Option<Object>, example = r#"{ "key1": "value-1", "key2": "value-2" }"#)]
    pub outgoing_webhook_custom_http_headers: Option<MaskedHeaders>,

    /// Will be used to determine the time till which your payment will be active once the payment session starts
    #[schema(value_type = Option<u32>, example = 900)]
    pub order_fulfillment_time: Option<OrderFulfillmentTime>,

    /// Whether the order fulfillment time is calculated from the origin or the time of creating the payment, or confirming the payment
    #[schema(value_type = Option<OrderFulfillmentTimeOrigin>, example = "create")]
    pub order_fulfillment_time_origin: Option<api_enums::OrderFulfillmentTimeOrigin>,

    /// Merchant Connector id to be stored for tax_calculator connector
    #[schema(value_type = Option<String>)]
    pub tax_connector_id: Option<id_type::MerchantConnectorAccountId>,

    /// Indicates if tax_calculator connector is enabled or not.
    /// If set to `true` tax_connector_id will be checked.
    pub is_tax_connector_enabled: bool,

    /// Indicates if network tokenization is enabled or not.
    #[schema(default = false, example = false)]
    pub is_network_tokenization_enabled: bool,

    /// Indicates if CVV should be collected during payment or not.
    #[schema(value_type = Option<bool>)]
    pub should_collect_cvv_during_payment:
        Option<primitive_wrappers::ShouldCollectCvvDuringPayment>,

    /// Indicates if click to pay is enabled or not.
    #[schema(default = false, example = false)]
    pub is_click_to_pay_enabled: bool,

    /// Product authentication ids
    #[schema(value_type = Option<Object>, example = r#"{ "click_to_pay": "mca_ushduqwhdohwd", "netcetera": "mca_kwqhudqwd" }"#)]
    pub authentication_product_ids:
        Option<common_types::payments::AuthenticationConnectorAccountMap>,

    /// Card Testing Guard Configs
    pub card_testing_guard_config: Option<CardTestingGuardConfig>,

    ///Indicates if clear pan retries is enabled or not.
    pub is_clear_pan_retries_enabled: bool,

    /// Indicates if debit routing is enabled or not
    #[schema(value_type = Option<bool>)]
    pub is_debit_routing_enabled: Option<bool>,

    //Merchant country for the profile
    #[schema(value_type = Option<CountryAlpha2>, example = "US")]
    pub merchant_business_country: Option<api_enums::CountryAlpha2>,

    /// Indicates if the redirection has to open in the iframe
    #[schema(example = false)]
    pub is_iframe_redirection_enabled: Option<bool>,

    /// Indicates if external vault is enabled or not.
    pub is_external_vault_enabled: Option<bool>,

    /// External Vault Connector Details
    pub external_vault_connector_details: Option<ExternalVaultConnectorDetails>,

    /// Four-digit code assigned based on business type to determine processing fees and risk level
    #[schema(value_type = Option<MerchantCategoryCode>, example = "5411")]
    pub merchant_category_code: Option<api_enums::MerchantCategoryCode>,

    /// Merchant country code.
    /// This is a 3-digit ISO 3166-1 numeric country code that represents the country in which the merchant is registered or operates.
    /// Merchants typically receive this value based on their business registration information or during onboarding via payment processors or acquiring banks.
    /// It is used in payment processing, fraud detection, and regulatory compliance to determine regional rules and routing behavior.
    #[schema(value_type = Option<MerchantCountryCode>, example = "840")]
    pub merchant_country_code: Option<common_types::payments::MerchantCountryCode>,

    /// Enable split payments, i.e., split the amount between multiple payment methods
    #[schema(value_type = SplitTxnsEnabled, default = "skip")]
    pub split_txns_enabled: common_enums::SplitTxnsEnabled,
}


pub struct Amount {
    total_amount: StringMajorUnit,
    currency: api_models::enums::Currency,
}


pub async fn diesel_make_pg_pool(
    database: &Database,
    _test_transaction: bool,
    schema: &str,
) -> PgPool {
    let database_url = database.get_database_url(schema);
    let manager = async_bb8_diesel::ConnectionManager::<PgConnection>::new(database_url);
    let pool = bb8::Pool::builder()
        .max_size(database.pool_size)
        .connection_timeout(std::time::Duration::from_secs(database.connection_timeout));

    pool.build(manager)
        .await
        .expect("Failed to create PostgreSQL connection pool")
}


impl api::PaymentToken for Mpgs {}


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


pub trait EmailData {
    /// Get the email contents
    async fn get_email_data(&self, base_url: &str) -> CustomResult<EmailContents, EmailError>;
}


pub struct Nomupay {
    #[cfg(feature = "payouts")]
    amount_converter: &'static (dyn AmountConvertor<Output = FloatMajorUnit> + Sync),
}


pub struct Paypal {
    amount_converter: &'static (dyn AmountConvertor<Output = StringMajorUnit> + Sync),
    amount_converter_webhooks: &'static (dyn AmountConvertor<Output = StringMinorUnit> + Sync),
}


pub fn server(state: AppState) -> Scope {
        let mut routes = web::scope("/accounts")
            .service(web::resource("").route(web::post().to(admin::merchant_account_create)))
            .service(web::resource("/list").route(web::get().to(admin::merchant_account_list)))
            .service(
                web::resource("/{id}/kv")
                    .route(web::post().to(admin::merchant_account_toggle_kv))
                    .route(web::get().to(admin::merchant_account_kv_status)),
            )
            .service(
                web::resource("/transfer")
                    .route(web::post().to(admin::merchant_account_transfer_keys)),
            )
            .service(
                web::resource("/kv").route(web::post().to(admin::merchant_account_toggle_all_kv)),
            )
            .service(
                web::resource("/{id}")
                    .route(web::get().to(admin::retrieve_merchant_account))
                    .route(web::post().to(admin::update_merchant_account))
                    .route(web::delete().to(admin::delete_merchant_account)),
            );
        if state.conf.platform.enabled {
            routes = routes.service(
                web::resource("/{id}/platform")
                    .route(web::post().to(admin::merchant_account_enable_platform_account)),
            )
        }
        routes.app_data(web::Data::new(state))
    }


pub struct BankRedirectConfig(pub HashMap<enums::PaymentMethodType, ConnectorBankNames>);


impl api::ConnectorCustomer for Gocardless {}

impl api::ConnectorCustomer for for Gocardless


pub struct PaymentsCancelPostCaptureData {
    pub currency: Option<storage_enums::Currency>,
    pub connector_transaction_id: String,
    pub cancellation_reason: Option<String>,
    pub connector_meta: Option<serde_json::Value>,
    // minor amount data for amount framework
    pub minor_amount: Option<MinorUnit>,
}


pub async fn customers_mandates_list() {}


OpenAPI Block Path: components.schemas.GpaySessionTokenResponse
{
  "oneOf": [
    {
      "$ref": "#/components/schemas/GooglePayThirdPartySdk"
    },
    {
      "$ref": "#/components/schemas/GooglePaySessionResponse"
    }
  ]
}


pub async fn accept_invitations_pre_auth(
    state: SessionState,
    user_token: auth::UserFromSinglePurposeToken,
    req: user_role_api::AcceptInvitationsPreAuthRequest,
) -> UserResponse<user_api::TokenResponse> {
    let lineages = futures::future::try_join_all(req.into_iter().map(|entity| {
        utils::user_role::get_lineage_for_user_id_and_entity_for_accepting_invite(
            &state,
            &user_token.user_id,
            user_token
                .tenant_id
                .as_ref()
                .unwrap_or(&state.tenant.tenant_id),
            entity.entity_id,
            entity.entity_type,
        )
    }))
    .await?
    .into_iter()
    .flatten()
    .collect::<Vec<_>>();

    let update_results = futures::future::join_all(lineages.iter().map(
        |(org_id, merchant_id, profile_id)| async {
            let (update_v1_result, update_v2_result) =
                utils::user_role::update_v1_and_v2_user_roles_in_db(
                    &state,
                    user_token.user_id.as_str(),
                    user_token
                        .tenant_id
                        .as_ref()
                        .unwrap_or(&state.tenant.tenant_id),
                    org_id,
                    merchant_id.as_ref(),
                    profile_id.as_ref(),
                    UserRoleUpdate::UpdateStatus {
                        status: UserStatus::Active,
                        modified_by: user_token.user_id.clone(),
                    },
                )
                .await;

            if update_v1_result.is_err_and(|err| !err.current_context().is_db_not_found())
                || update_v2_result.is_err_and(|err| !err.current_context().is_db_not_found())
            {
                Err(report!(UserErrors::InternalServerError))
            } else {
                Ok(())
            }
        },
    ))
    .await;

    if update_results.is_empty() || update_results.iter().all(Result::is_err) {
        return Err(UserErrors::MerchantIdNotFound.into());
    }

    let user_from_db: domain::UserFromStorage = state
        .global_store
        .find_user_by_id(user_token.user_id.as_str())
        .await
        .change_context(UserErrors::InternalServerError)?
        .into();

    let current_flow =
        domain::CurrentFlow::new(user_token, domain::SPTFlow::MerchantSelect.into())?;
    let next_flow = current_flow.next(user_from_db.clone(), &state).await?;

    let token = next_flow.get_token(&state).await?;

    let response = user_api::TokenResponse {
        token: token.clone(),
        token_type: next_flow.get_flow().into(),
    };
    auth::cookies::set_cookie_response(response, token)
}


File: crates/router/src/types/domain/address.rs
 Public structs: 3

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

use super::{behaviour, types};

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

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

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

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

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

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

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

        Ok(Self {
            address,
            customer_id,
        })
    }

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

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

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

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

        let customer_id = other.customer_id.clone();

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

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

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

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

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

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

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

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

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

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


pub struct PaymentAttemptBatchNew {
//     pub payment_id: common_utils::id_type::PaymentId,
//     pub merchant_id: common_utils::id_type::MerchantId,
//     pub status: AttemptStatus,
//     pub error_message: Option<String>,
//     pub surcharge_amount: Option<i64>,
//     pub tax_on_surcharge: Option<i64>,
//     pub payment_method_id: Option<String>,
//     pub authentication_type: Option<AuthenticationType>,
//     #[serde(with = "common_utils::custom_serde::iso8601")]
//     pub created_at: PrimitiveDateTime,
//     #[serde(with = "common_utils::custom_serde::iso8601")]
//     pub modified_at: PrimitiveDateTime,
//     #[serde(default, with = "common_utils::custom_serde::iso8601::option")]
//     pub last_synced: Option<PrimitiveDateTime>,
//     pub cancellation_reason: Option<String>,
//     pub browser_info: Option<serde_json::Value>,
//     pub payment_token: Option<String>,
//     pub error_code: Option<String>,
//     pub connector_metadata: Option<serde_json::Value>,
//     pub payment_experience: Option<PaymentExperience>,
//     pub payment_method_data: Option<serde_json::Value>,
//     pub preprocessing_step_id: Option<String>,
//     pub error_reason: Option<String>,
//     pub connector_response_reference_id: Option<String>,
//     pub multiple_capture_count: Option<i16>,
//     pub amount_capturable: i64,
//     pub updated_by: String,
//     pub merchant_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
//     pub authentication_data: Option<serde_json::Value>,
//     pub encoded_data: Option<String>,
//     pub unified_code: Option<String>,
//     pub unified_message: Option<String>,
//     pub net_amount: Option<i64>,
//     pub external_three_ds_authentication_attempted: Option<bool>,
//     pub authentication_connector: Option<String>,
//     pub authentication_id: Option<String>,
//     pub fingerprint_id: Option<String>,
//     pub charge_id: Option<String>,
//     pub client_source: Option<String>,
//     pub client_version: Option<String>,
//     pub customer_acceptance: Option<common_utils::pii::SecretSerdeValue>,
//     pub profile_id: common_utils::id_type::ProfileId,
//     pub organization_id: common_utils::id_type::OrganizationId,
// }


/// Validates Hubspot configuration
    pub(super) fn validate(&self) -> Result<(), InvalidCrmConfig> {
        use common_utils::fp_utils::when;

        when(self.request_url.is_default_or_empty(), || {
            Err(InvalidCrmConfig("request url must not be empty"))
        })?;

        when(self.form_id.is_default_or_empty(), || {
            Err(InvalidCrmConfig("form_id must not be empty"))
        })
    }


pub async fn get_merchant_fingerprint_secret(
    state: &SessionState,
    merchant_id: &common_utils::id_type::MerchantId,
) -> RouterResult<String> {
    let key = merchant_id.get_merchant_fingerprint_secret_key();
    let config_fetch_result = state.store.find_config_by_key(&key).await;

    match config_fetch_result {
        Ok(config) => Ok(config.config),

        Err(e) if e.current_context().is_db_not_found() => {
            let new_fingerprint_secret =
                utils::generate_id(consts::FINGERPRINT_SECRET_LENGTH, "fs");
            let new_config = storage::ConfigNew {
                key,
                config: new_fingerprint_secret.clone(),
            };

            state
                .store
                .insert_config(new_config)
                .await
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("unable to create new fingerprint secret for merchant")?;

            Ok(new_fingerprint_secret)
        }

        Err(e) => Err(e)
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("error fetching merchant fingerprint secret"),
    }
}


pub fn set_validate_result(
        self,
        customer: &'a api::CustomerDetails,
    ) -> NetworkTokenizationBuilder<'a, PmValidated> {
        NetworkTokenizationBuilder {
            state: std::marker::PhantomData,
            customer: Some(customer),
            card: self.card,
            card_cvc: self.card_cvc,
            network_token: self.network_token,
            stored_card: self.stored_card,
            stored_token: self.stored_token,
            payment_method_response: self.payment_method_response,
            card_tokenized: self.card_tokenized,
            error_code: self.error_code,
            error_message: self.error_message,
        }
    }


pub struct RoutingEventsRequest {
    pub payment_id: common_utils::id_type::PaymentId,
    pub refund_id: Option<String>,
    pub dispute_id: Option<String>,
}


pub struct AuthenticationDetails {
    pub authn_flow_type: super::authentication::AuthNFlowType,
    pub authentication_value: Option<Secret<String>>,
    pub trans_status: common_enums::TransactionStatus,
    pub connector_metadata: Option<serde_json::Value>,
    pub ds_trans_id: Option<String>,
    pub eci: Option<String>,
    pub challenge_code: Option<String>,
    pub challenge_cancel: Option<String>,
    pub challenge_code_reason: Option<String>,
    pub message_extension: Option<common_utils::pii::SecretSerdeValue>,
}


pub struct ProcessorResponse {
    name: Option<String>,
}


pub struct ExpiryDate {
    pub month: Secret<i8>,
    pub year: Secret<i32>,
}


pub struct SuccessBasedRoutingConfig {
    pub params: Option<Vec<DynamicRoutingConfigParams>>,
    pub config: Option<SuccessBasedRoutingConfigBody>,
    #[schema(value_type = DecisionEngineSuccessRateData)]
    pub decision_engine_configs: Option<open_router::DecisionEngineSuccessRateData>,
}


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


impl webhooks::IncomingWebhook for Custombilling {
    fn get_webhook_object_reference_id(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_event_type(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_resource_object(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }
}

impl webhooks::IncomingWebhook for for Custombilling


impl ConnectorSpecifications for Mollie {}

impl ConnectorSpecifications for for Mollie


pub struct DwollaErrorDetails {
    pub errors: Vec<DwollaErrorDetail>,
}


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


pub async fn find_by_org_id(
        conn: &PgPooledConn,
        org_id: id_type::OrganizationId,
    ) -> StorageResult<Self> {
        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl_identifier.eq(org_id),
        )
        .await
    }


File: crates/common_utils/src/metrics/utils.rs
 Public functions: 2

//! metric utility functions

use std::time;

use router_env::opentelemetry;

/// Record the time taken by the future to execute
#[inline]
pub async fn time_future<F, R>(future: F) -> (R, time::Duration)
where
    F: futures::Future<Output = R>,
{
    let start = time::Instant::now();
    let result = future.await;
    let time_spent = start.elapsed();
    (result, time_spent)
}

/// Record the time taken (in seconds) by the operation for the given context
#[inline]
pub async fn record_operation_time<F, R>(
    future: F,
    metric: &opentelemetry::metrics::Histogram<f64>,
    key_value: &[opentelemetry::KeyValue],
) -> R
where
    F: futures::Future<Output = R>,
{
    let (result, time) = time_future(future).await;
    metric.record(time.as_secs_f64(), key_value);
    result
}


File: crates/router/src/db/address.rs

use common_utils::{id_type, types::keymanager::KeyManagerState};
use diesel_models::{address::AddressUpdateInternal, enums::MerchantStorageScheme};
use error_stack::ResultExt;

use super::MockDb;
use crate::{
    core::errors::{self, CustomResult},
    types::{
        domain::{
            self,
            behaviour::{Conversion, ReverseConversion},
        },
        storage as storage_types,
    },
};

#[async_trait::async_trait]
pub trait AddressInterface
where
    domain::Address:
        Conversion<DstType = storage_types::Address, NewDstType = storage_types::AddressNew>,
{
    async fn update_address(
        &self,
        state: &KeyManagerState,
        address_id: String,
        address: storage_types::AddressUpdate,
        key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::Address, errors::StorageError>;

    async fn update_address_for_payments(
        &self,
        state: &KeyManagerState,
        this: domain::PaymentAddress,
        address: domain::AddressUpdate,
        payment_id: id_type::PaymentId,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<domain::PaymentAddress, errors::StorageError>;

    async fn find_address_by_address_id(
        &self,
        state: &KeyManagerState,
        address_id: &str,
        key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::Address, errors::StorageError>;

    async fn insert_address_for_payments(
        &self,
        state: &KeyManagerState,
        payment_id: &id_type::PaymentId,
        address: domain::PaymentAddress,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<domain::PaymentAddress, errors::StorageError>;

    async fn insert_address_for_customers(
        &self,
        state: &KeyManagerState,
        address: domain::CustomerAddress,
        key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::Address, errors::StorageError>;

    async fn find_address_by_merchant_id_payment_id_address_id(
        &self,
        state: &KeyManagerState,
        merchant_id: &id_type::MerchantId,
        payment_id: &id_type::PaymentId,
        address_id: &str,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<domain::PaymentAddress, errors::StorageError>;

    async fn update_address_by_merchant_id_customer_id(
        &self,
        state: &KeyManagerState,
        customer_id: &id_type::CustomerId,
        merchant_id: &id_type::MerchantId,
        address: storage_types::AddressUpdate,
        key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<Vec<domain::Address>, errors::StorageError>;
}

#[cfg(not(feature = "kv_store"))]
mod storage {
    use common_utils::{ext_traits::AsyncExt, id_type, types::keymanager::KeyManagerState};
    use error_stack::{report, ResultExt};
    use router_env::{instrument, tracing};

    use super::AddressInterface;
    use crate::{
        connection,
        core::errors::{self, CustomResult},
        services::Store,
        types::{
            domain::{
                self,
                behaviour::{Conversion, ReverseConversion},
            },
            storage::{self as storage_types, enums::MerchantStorageScheme},
        },
    };
    #[async_trait::async_trait]
    impl AddressInterface for Store {
        #[instrument(skip_all)]
        async fn find_address_by_address_id(
            &self,
            state: &KeyManagerState,
            address_id: &str,
            key_store: &domain::MerchantKeyStore,
        ) -> CustomResult<domain::Address, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            storage_types::Address::find_by_address_id(&conn, address_id)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
                .async_and_then(|address| async {
                    address
                        .convert(
                            state,
                            key_store.key.get_inner(),
                            key_store.merchant_id.clone().into(),
                        )
                        .await
                        .change_context(errors::StorageError::DecryptionError)
                })
                .await
        }

        #[instrument(skip_all)]
        async fn find_address_by_merchant_id_payment_id_address_id(
            &self,
            state: &KeyManagerState,
            merchant_id: &id_type::MerchantId,
            payment_id: &id_type::PaymentId,
            address_id: &str,
            key_store: &domain::MerchantKeyStore,
            _storage_scheme: MerchantStorageScheme,
        ) -> CustomResult<domain::PaymentAddress, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            storage_types::Address::find_by_merchant_id_payment_id_address_id(
                &conn,
                merchant_id,
                payment_id,
                address_id,
            )
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
            .async_and_then(|address| async {
                address
                    .convert(state, key_store.key.get_inner(), merchant_id.clone().into())
                    .await
                    .change_context(errors::StorageError::DecryptionError)
            })
            .await
        }

        #[instrument(skip_all)]
        async fn update_address(
            &self,
            state: &KeyManagerState,
            address_id: String,
            address: storage_types::AddressUpdate,
            key_store: &domain::MerchantKeyStore,
        ) -> CustomResult<domain::Address, errors::StorageError> {
            let conn = connection::pg_connection_write(self).await?;
            storage_types::Address::update_by_address_id(&conn, address_id, address.into())
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
                .async_and_then(|address| async {
                    address
                        .convert(
                            state,
                            key_store.key.get_inner(),
                            key_store.merchant_id.clone().into(),
                        )
                        .await
                        .change_context(errors::StorageError::DecryptionError)
                })
                .await
        }

        #[instrument(skip_all)]
        async fn update_address_for_payments(
            &self,
            state: &KeyManagerState,
            this: domain::PaymentAddress,
            address_update: domain::AddressUpdate,
            _payment_id: id_type::PaymentId,
            key_store: &domain::MerchantKeyStore,
            _storage_scheme: MerchantStorageScheme,
        ) -> CustomResult<domain::PaymentAddress, errors::StorageError> {
            let conn = connection::pg_connection_write(self).await?;
            let address = Conversion::convert(this)
                .await
                .change_context(errors::StorageError::EncryptionError)?;
            address
                .update(&conn, address_update.into())
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
                .async_and_then(|address| async {
                    address
                        .convert(
                            state,
                            key_store.key.get_inner(),
                            key_store.merchant_id.clone().into(),
                        )
                        .await
                        .change_context(errors::StorageError::DecryptionError)
                })
                .await
        }

        #[instrument(skip_all)]
        async fn insert_address_for_payments(
            &self,
            state: &KeyManagerState,
            _payment_id: &id_type::PaymentId,
            address: domain::PaymentAddress,
            key_store: &domain::MerchantKeyStore,
            _storage_scheme: MerchantStorageScheme,
        ) -> CustomResult<domain::PaymentAddress, errors::StorageError> {
            let conn = connection::pg_connection_write(self).await?;
            address
                .construct_new()
                .await
                .change_context(errors::StorageError::EncryptionError)?
                .insert(&conn)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
                .async_and_then(|address| async {
                    address
                        .convert(
                            state,
                            key_store.key.get_inner(),
                            key_store.merchant_id.clone().into(),
                        )
                        .await
                        .change_context(errors::StorageError::DecryptionError)
                })
                .await
        }

        #[instrument(skip_all)]
        async fn insert_address_for_customers(
            &self,
            state: &KeyManagerState,
            address: domain::CustomerAddress,
            key_store: &domain::MerchantKeyStore,
        ) -> CustomResult<domain::Address, errors::StorageError> {
            let conn = connection::pg_connection_write(self).await?;
            address
                .construct_new()
                .await
                .change_context(errors::StorageError::EncryptionError)?
                .insert(&conn)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
                .async_and_then(|address| async {
                    address
                        .convert(
                            state,
                            key_store.key.get_inner(),
                            key_store.merchant_id.clone().into(),
                        )
                        .await
                        .change_context(errors::StorageError::DecryptionError)
                })
                .await
        }

        #[instrument(skip_all)]
        async fn update_address_by_merchant_id_customer_id(
            &self,
            state: &KeyManagerState,
            customer_id: &id_type::CustomerId,
            merchant_id: &id_type::MerchantId,
            address: storage_types::AddressUpdate,
            key_store: &domain::MerchantKeyStore,
        ) -> CustomResult<Vec<domain::Address>, errors::StorageError> {
            let conn = connection::pg_connection_write(self).await?;
            storage_types::Address::update_by_merchant_id_customer_id(
                &conn,
                customer_id,
                merchant_id,
                address.into(),
            )
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
            .async_and_then(|addresses| async {
                let mut output = Vec::with_capacity(addresses.len());
                for address in addresses.into_iter() {
                    output.push(
                        address
                            .convert(state, key_store.key.get_inner(), merchant_id.clone().into())
                            .await
                            .change_context(errors::StorageError::DecryptionError)?,
                    )
                }
                Ok(output)
            })
            .await
        }
    }
}

#[cfg(feature = "kv_store")]
mod storage {
    use common_utils::{ext_traits::AsyncExt, id_type, types::keymanager::KeyManagerState};
    use diesel_models::{enums::MerchantStorageScheme, AddressUpdateInternal};
    use error_stack::{report, ResultExt};
    use redis_interface::HsetnxReply;
    use router_env::{instrument, tracing};
    use storage_impl::redis::kv_store::{
        decide_storage_scheme, kv_wrapper, KvOperation, Op, PartitionKey,
    };

    use super::AddressInterface;
    use crate::{
        connection,
        core::errors::{self, CustomResult},
        services::Store,
        types::{
            domain::{
                self,
                behaviour::{Conversion, ReverseConversion},
            },
            storage::{self as storage_types, kv},
        },
        utils::db_utils,
    };
    #[async_trait::async_trait]
    impl AddressInterface for Store {
        #[instrument(skip_all)]
        async fn find_address_by_address_id(
            &self,
            state: &KeyManagerState,
            address_id: &str,
            key_store: &domain::MerchantKeyStore,
        ) -> CustomResult<domain::Address, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            storage_types::Address::find_by_address_id(&conn, address_id)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
                .async_and_then(|address| async {
                    address
                        .convert(
                            state,
                            key_store.key.get_inner(),
                            key_store.merchant_id.clone().into(),
                        )
                        .await
                        .change_context(errors::StorageError::DecryptionError)
                })
                .await
        }

        #[instrument(skip_all)]
        async fn find_address_by_merchant_id_payment_id_address_id(
            &self,
            state: &KeyManagerState,
            merchant_id: &id_type::MerchantId,
            payment_id: &id_type::PaymentId,
            address_id: &str,
            key_store: &domain::MerchantKeyStore,
            storage_scheme: MerchantStorageScheme,
        ) -> CustomResult<domain::PaymentAddress, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            let database_call = || async {
                storage_types::Address::find_by_merchant_id_payment_id_address_id(
                    &conn,
                    merchant_id,
                    payment_id,
                    address_id,
                )
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
            };
            let storage_scheme = Box::pin(decide_storage_scheme::<_, storage_types::Address>(
                self,
                storage_scheme,
                Op::Find,
            ))
            .await;
            let address = match storage_scheme {
                MerchantStorageScheme::PostgresOnly => database_call().await,
                MerchantStorageScheme::RedisKv => {
                    let key = PartitionKey::MerchantIdPaymentId {
                        merchant_id,
                        payment_id,
                    };
                    let field = format!("add_{address_id}");
                    Box::pin(db_utils::try_redis_get_else_try_database_get(
                        async {
                            Box::pin(kv_wrapper(
                                self,
                                KvOperation::<diesel_models::Address>::HGet(&field),
                                key,
                            ))
                            .await?
                            .try_into_hget()
                        },
                        database_call,
                    ))
                    .await
                }
            }?;
            address
                .convert(
                    state,
                    key_store.key.get_inner(),
                    common_utils::types::keymanager::Identifier::Merchant(
                        key_store.merchant_id.clone(),
                    ),
                )
                .await
                .change_context(errors::StorageError::DecryptionError)
        }

        #[instrument(skip_all)]
        async fn update_address(
            &self,
            state: &KeyManagerState,
            address_id: String,
            address: storage_types::AddressUpdate,
            key_store: &domain::MerchantKeyStore,
        ) -> CustomResult<domain::Address, errors::StorageError> {
            let conn = connection::pg_connection_write(self).await?;
            storage_types::Address::update_by_address_id(&conn, address_id, address.into())
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
                .async_and_then(|address| async {
                    address
                        .convert(
                            state,
                            key_store.key.get_inner(),
                            key_store.merchant_id.clone().into(),
                        )
                        .await
                        .change_context(errors::StorageError::DecryptionError)
                })
                .await
        }

        #[instrument(skip_all)]
        async fn update_address_for_payments(
            &self,
            state: &KeyManagerState,
            this: domain::PaymentAddress,
            address_update: domain::AddressUpdate,
            payment_id: id_type::PaymentId,
            key_store: &domain::MerchantKeyStore,
            storage_scheme: MerchantStorageScheme,
        ) -> CustomResult<domain::PaymentAddress, errors::StorageError> {
            let conn = connection::pg_connection_write(self).await?;
            let address = Conversion::convert(this)
                .await
                .change_context(errors::StorageError::EncryptionError)?;
            let merchant_id = address.merchant_id.clone();
            let key = PartitionKey::MerchantIdPaymentId {
                merchant_id: &merchant_id,
                payment_id: &payment_id,
            };
            let field = format!("add_{}", address.address_id);
            let storage_scheme = Box::pin(decide_storage_scheme::<_, storage_types::Address>(
                self,
                storage_scheme,
                Op::Update(key.clone(), &field, Some(address.updated_by.as_str())),
            ))
            .await;
            match storage_scheme {
                MerchantStorageScheme::PostgresOnly => {
                    address
                        .update(&conn, address_update.into())
                        .await
                        .map_err(|error| report!(errors::StorageError::from(error)))
                        .async_and_then(|address| async {
                            address
                                .convert(
                                    state,
                                    key_store.key.get_inner(),
                                    key_store.merchant_id.clone().into(),
                                )
                                .await
                                .change_context(errors::StorageError::DecryptionError)
                        })
                        .await
                }
                MerchantStorageScheme::RedisKv => {
                    let updated_address = AddressUpdateInternal::from(address_update.clone())
                        .create_address(address.clone());
                    let redis_value = serde_json::to_string(&updated_address)
                        .change_context(errors::StorageError::KVError)?;

                    let redis_entry = kv::TypedSql {
                        op: kv::DBOperation::Update {
                            updatable: Box::new(kv::Updateable::AddressUpdate(Box::new(
                                kv::AddressUpdateMems {
                                    orig: address,
                                    update_data: address_update.into(),
                                },
                            ))),
                        },
                    };

                    Box::pin(kv_wrapper::<(), _, _>(
                        self,
                        KvOperation::Hset::<storage_types::Address>(
                            (&field, redis_value),
                            redis_entry,
                        ),
                        key,
                    ))
                    .await
                    .change_context(errors::StorageError::KVError)?
                    .try_into_hset()
                    .change_context(errors::StorageError::KVError)?;

                    updated_address
                        .convert(
                            state,
                            key_store.key.get_inner(),
                            key_store.merchant_id.clone().into(),
                        )
                        .await
                        .change_context(errors::StorageError::DecryptionError)
                }
            }
        }

        #[instrument(skip_all)]
        async fn insert_address_for_payments(
            &self,
            state: &KeyManagerState,
            payment_id: &id_type::PaymentId,
            address: domain::PaymentAddress,
            key_store: &domain::MerchantKeyStore,
            storage_scheme: MerchantStorageScheme,
        ) -> CustomResult<domain::PaymentAddress, errors::StorageError> {
            let address_new = address
                .clone()
                .construct_new()
                .await
                .change_context(errors::StorageError::EncryptionError)?;
            let merchant_id = address_new.merchant_id.clone();
            let storage_scheme = Box::pin(decide_storage_scheme::<_, storage_types::Address>(
                self,
                storage_scheme,
                Op::Insert,
            ))
            .await;
            match storage_scheme {
                MerchantStorageScheme::PostgresOnly => {
                    let conn = connection::pg_connection_write(self).await?;
                    address_new
                        .insert(&conn)
                        .await
                        .map_err(|error| report!(errors::StorageError::from(error)))
                        .async_and_then(|address| async {
                            address
                                .convert(
                                    state,
                                    key_store.key.get_inner(),
                                    key_store.merchant_id.clone().into(),
                                )
                                .await
                                .change_context(errors::StorageError::DecryptionError)
                        })
                        .await
                }
                MerchantStorageScheme::RedisKv => {
                    let key = PartitionKey::MerchantIdPaymentId {
                        merchant_id: &merchant_id,
                        payment_id,
                    };
                    let field = format!("add_{}", &address_new.address_id);
                    let created_address = diesel_models::Address {
                        address_id: address_new.address_id.clone(),
                        city: address_new.city.clone(),
                        country: address_new.country,
                        line1: address_new.line1.clone(),
                        line2: address_new.line2.clone(),
                        line3: address_new.line3.clone(),
                        state: address_new.state.clone(),
                        zip: address_new.zip.clone(),
                        first_name: address_new.first_name.clone(),
                        last_name: address_new.last_name.clone(),
                        phone_number: address_new.phone_number.clone(),
                        country_code: address_new.country_code.clone(),
                        created_at: address_new.created_at,
                        modified_at: address_new.modified_at,
                        customer_id: address_new.customer_id.clone(),
                        merchant_id: address_new.merchant_id.clone(),
                        payment_id: address_new.payment_id.clone(),
                        updated_by: storage_scheme.to_string(),
                        email: address_new.email.clone(),
                        origin_zip: address_new.origin_zip.clone(),
                    };

                    let redis_entry = kv::TypedSql {
                        op: kv::DBOperation::Insert {
                            insertable: Box::new(kv::Insertable::Address(Box::new(address_new))),
                        },
                    };

                    match Box::pin(kv_wrapper::<diesel_models::Address, _, _>(
                        self,
                        KvOperation::HSetNx::<diesel_models::Address>(
                            &field,
                            &created_address,
                            redis_entry,
                        ),
                        key,
                    ))
                    .await
                    .change_context(errors::StorageError::KVError)?
                    .try_into_hsetnx()
                    {
                        Ok(HsetnxReply::KeyNotSet) => Err(errors::StorageError::DuplicateValue {
                            entity: "address",
                            key: Some(created_address.address_id),
                        }
                        .into()),
                        Ok(HsetnxReply::KeySet) => Ok(created_address
                            .convert(
                                state,
                                key_store.key.get_inner(),
                                key_store.merchant_id.clone().into(),
                            )
                            .await
                            .change_context(errors::StorageError::DecryptionError)?),
                        Err(er) => Err(er).change_context(errors::StorageError::KVError),
                    }
                }
            }
        }

        #[instrument(skip_all)]
        async fn insert_address_for_customers(
            &self,
            state: &KeyManagerState,
            address: domain::CustomerAddress,
            key_store: &domain::MerchantKeyStore,
        ) -> CustomResult<domain::Address, errors::StorageError> {
            let conn = connection::pg_connection_write(self).await?;
            address
                .construct_new()
                .await
                .change_context(errors::StorageError::EncryptionError)?
                .insert(&conn)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
                .async_and_then(|address| async {
                    address
                        .convert(
                            state,
                            key_store.key.get_inner(),
                            key_store.merchant_id.clone().into(),
                        )
                        .await
                        .change_context(errors::StorageError::DecryptionError)
                })
                .await
        }

        #[instrument(skip_all)]
        async fn update_address_by_merchant_id_customer_id(
            &self,
            state: &KeyManagerState,
            customer_id: &id_type::CustomerId,
            merchant_id: &id_type::MerchantId,
            address: storage_types::AddressUpdate,
            key_store: &domain::MerchantKeyStore,
        ) -> CustomResult<Vec<domain::Address>, errors::StorageError> {
            let conn = connection::pg_connection_write(self).await?;
            storage_types::Address::update_by_merchant_id_customer_id(
                &conn,
                customer_id,
                merchant_id,
                address.into(),
            )
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
            .async_and_then(|addresses| async {
                let mut output = Vec::with_capacity(addresses.len());
                for address in addresses.into_iter() {
                    output.push(
                        address
                            .convert(
                                state,
                                key_store.key.get_inner(),
                                key_store.merchant_id.clone().into(),
                            )
                            .await
                            .change_context(errors::StorageError::DecryptionError)?,
                    )
                }
                Ok(output)
            })
            .await
        }
    }
}

#[async_trait::async_trait]
impl AddressInterface for MockDb {
    async fn find_address_by_address_id(
        &self,
        state: &KeyManagerState,
        address_id: &str,
        key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::Address, errors::StorageError> {
        match self
            .addresses
            .lock()
            .await
            .iter()
            .find(|address| address.address_id == address_id)
        {
            Some(address) => address
                .clone()
                .convert(
                    state,
                    key_store.key.get_inner(),
                    key_store.merchant_id.clone().into(),
                )
                .await
                .change_context(errors::StorageError::DecryptionError),
            None => {
                return Err(
                    errors::StorageError::ValueNotFound("address not found".to_string()).into(),
                )
            }
        }
    }

    async fn find_address_by_merchant_id_payment_id_address_id(
        &self,
        state: &KeyManagerState,
        _merchant_id: &id_type::MerchantId,
        _payment_id: &id_type::PaymentId,
        address_id: &str,
        key_store: &domain::MerchantKeyStore,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<domain::PaymentAddress, errors::StorageError> {
        match self
            .addresses
            .lock()
            .await
            .iter()
            .find(|address| address.address_id == address_id)
        {
            Some(address) => address
                .clone()
                .convert(
                    state,
                    key_store.key.get_inner(),
                    key_store.merchant_id.clone().into(),
                )
                .await
                .change_context(errors::StorageError::DecryptionError),
            None => {
                return Err(
                    errors::StorageError::ValueNotFound("address not found".to_string()).into(),
                )
            }
        }
    }

    async fn update_address(
        &self,
        state: &KeyManagerState,
        address_id: String,
        address_update: storage_types::AddressUpdate,
        key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::Address, errors::StorageError> {
        let updated_addr = self
            .addresses
            .lock()
            .await
            .iter_mut()
            .find(|address| address.address_id == address_id)
            .map(|a| {
                let address_updated =
                    AddressUpdateInternal::from(address_update).create_address(a.clone());
                *a = address_updated.clone();
                address_updated
            });
        match updated_addr {
            Some(address_updated) => address_updated
                .convert(
                    state,
                    key_store.key.get_inner(),
                    key_store.merchant_id.clone().into(),
                )
                .await
                .change_context(errors::StorageError::DecryptionError),
            None => Err(errors::StorageError::ValueNotFound(
                "cannot find address to update".to_string(),
            )
            .into()),
        }
    }

    async fn update_address_for_payments(
        &self,
        state: &KeyManagerState,
        this: domain::PaymentAddress,
        address_update: domain::AddressUpdate,
        _payment_id: id_type::PaymentId,
        key_store: &domain::MerchantKeyStore,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<domain::PaymentAddress, errors::StorageError> {
        let updated_addr = self
            .addresses
            .lock()
            .await
            .iter_mut()
            .find(|address| address.address_id == this.address.address_id)
            .map(|a| {
                let address_updated =
                    AddressUpdateInternal::from(address_update).create_address(a.clone());
                *a = address_updated.clone();
                address_updated
            });
        match updated_addr {
            Some(address_updated) => address_updated
                .convert(
                    state,
                    key_store.key.get_inner(),
                    key_store.merchant_id.clone().into(),
                )
                .await
                .change_context(errors::StorageError::DecryptionError),
            None => Err(errors::StorageError::ValueNotFound(
                "cannot find address to update".to_string(),
            )
            .into()),
        }
    }

    async fn insert_address_for_payments(
        &self,
        state: &KeyManagerState,
        _payment_id: &id_type::PaymentId,
        address_new: domain::PaymentAddress,
        key_store: &domain::MerchantKeyStore,
        _storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<domain::PaymentAddress, errors::StorageError> {
        let mut addresses = self.addresses.lock().await;

        let address = Conversion::convert(address_new)
            .await
            .change_context(errors::StorageError::EncryptionError)?;

        addresses.push(address.clone());

        address
            .convert(
                state,
                key_store.key.get_inner(),
                key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(errors::StorageError::DecryptionError)
    }

    async fn insert_address_for_customers(
        &self,
        state: &KeyManagerState,
        address_new: domain::CustomerAddress,
        key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::Address, errors::StorageError> {
        let mut addresses = self.addresses.lock().await;

        let address = Conversion::convert(address_new)
            .await
            .change_context(errors::StorageError::EncryptionError)?;

        addresses.push(address.clone());

        address
            .convert(
                state,
                key_store.key.get_inner(),
                key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(errors::StorageError::DecryptionError)
    }

    async fn update_address_by_merchant_id_customer_id(
        &self,
        state: &KeyManagerState,
        customer_id: &id_type::CustomerId,
        merchant_id: &id_type::MerchantId,
        address_update: storage_types::AddressUpdate,
        key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<Vec<domain::Address>, errors::StorageError> {
        let updated_addr = self
            .addresses
            .lock()
            .await
            .iter_mut()
            .find(|address| {
                address.customer_id.as_ref() == Some(customer_id)
                    && address.merchant_id == *merchant_id
            })
            .map(|a| {
                let address_updated =
                    AddressUpdateInternal::from(address_update).create_address(a.clone());
                *a = address_updated.clone();
                address_updated
            });
        match updated_addr {
            Some(address) => {
                let address: domain::Address = address
                    .convert(
                        state,
                        key_store.key.get_inner(),
                        key_store.merchant_id.clone().into(),
                    )
                    .await
                    .change_context(errors::StorageError::DecryptionError)?;
                Ok(vec![address])
            }
            None => {
                Err(errors::StorageError::ValueNotFound("address not found".to_string()).into())
            }
        }
    }
}


impl api::PaymentsCompleteAuthorize for Payme {}

impl api::PaymentsCompleteAuthorize for for Payme


Documentation: crates/router_derive/README.md
# Type: Doc File

# `router_derive`

Utility macros for the `router` crate.


pub async fn merchant_account_create() {}


pub async fn resolve_billing_address_for_payout(
    state: &SessionState,
    req_billing: Option<&api_models::payments::Address>,
    existing_address_id: Option<&String>,
    payment_method: Option<&hyperswitch_domain_models::payment_methods::PaymentMethod>,
    merchant_context: &domain::MerchantContext,
    customer_id: Option<&id_type::CustomerId>,
    payout_id: &id_type::PayoutId,
) -> RouterResult<(
    Option<hyperswitch_domain_models::address::Address>,
    Option<String>,
)> {
    let payout_id_as_payment_id = id_type::PaymentId::try_from(std::borrow::Cow::Owned(
        payout_id.get_string_repr().to_string(),
    ))
    .change_context(errors::ApiErrorResponse::InvalidRequestData {
        message: "payout_id contains invalid data for PaymentId conversion".to_string(),
    })
    .attach_printable("Error converting payout_id to PaymentId type")?;

    match (req_billing, existing_address_id, payment_method) {
        // Address in request
        (Some(_), _, _) => {
            let billing_address = payment_helpers::create_or_find_address_for_payment_by_request(
                state,
                req_billing,
                None,
                merchant_context.get_merchant_account().get_id(),
                customer_id,
                merchant_context.get_merchant_key_store(),
                &payout_id_as_payment_id,
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await?;
            let address_id = billing_address.as_ref().map(|a| a.address_id.clone());
            let hyperswitch_address = billing_address
                .map(|addr| hyperswitch_domain_models::address::Address::from(&addr));
            Ok((hyperswitch_address, address_id))
        }

        // Existing address using address_id
        (None, Some(address_id), _) => {
            let billing_address = payment_helpers::create_or_find_address_for_payment_by_request(
                state,
                None,
                Some(address_id),
                merchant_context.get_merchant_account().get_id(),
                customer_id,
                merchant_context.get_merchant_key_store(),
                &payout_id_as_payment_id,
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await?;
            let hyperswitch_address = billing_address
                .map(|addr| hyperswitch_domain_models::address::Address::from(&addr));
            Ok((hyperswitch_address, Some(address_id.clone())))
        }

        // Existing address in stored payment method
        (None, None, Some(pm)) => {
            pm.payment_method_billing_address.as_ref().map_or_else(
                || {
                    logger::info!("No billing address found in payment method");
                    Ok((None, None))
                },
                |encrypted_billing_address| {
                    logger::info!("Found encrypted billing address data in payment method");

                    #[cfg(feature = "v1")]
                    {
                        encrypted_billing_address
                            .clone()
                            .into_inner()
                            .expose()
                            .parse_value::<hyperswitch_domain_models::address::Address>(
                                "payment_method_billing_address",
                            )
                            .map(|domain_address| {
                                logger::info!("Successfully parsed as hyperswitch_domain_models::address::Address");
                                (Some(domain_address), None)
                            })
                            .map_err(|e| {
                                logger::error!("Failed to parse billing address into (hyperswitch_domain_models::address::Address): {:?}", e);
                                errors::ApiErrorResponse::InternalServerError
                            })
                            .attach_printable("Failed to parse stored billing address")
                    }

                    #[cfg(feature = "v2")]
                    {
                        // TODO: Implement v2 logic when needed
                        logger::warn!("v2 billing address resolution not yet implemented");
                        Ok((None, None))
                    }
                },
            )
        }

        (None, None, None) => Ok((None, None)),
    }
}


pub async fn read_string(field: &mut Field) -> Option<String> {
    let bytes = field.try_next().await;
    if let Ok(Some(bytes)) = bytes {
        String::from_utf8(bytes.to_vec()).ok()
    } else {
        None
    }
}


impl DashboardMetadata {
    pub async fn update(
        conn: &PgPooledConn,
        user_id: Option<String>,
        merchant_id: id_type::MerchantId,
        org_id: id_type::OrganizationId,
        data_key: enums::DashboardMetadata,
        dashboard_metadata_update: DashboardMetadataUpdate,
    ) -> StorageResult<Self> {
        let predicate = dsl::merchant_id
            .eq(merchant_id.to_owned())
            .and(dsl::org_id.eq(org_id.to_owned()))
            .and(dsl::data_key.eq(data_key.to_owned()));

        if let Some(uid) = user_id {
            generics::generic_update_with_unique_predicate_get_result::<
                <Self as HasTable>::Table,
                _,
                _,
                _,
            >(
                conn,
                predicate.and(dsl::user_id.eq(uid)),
                DashboardMetadataUpdateInternal::from(dashboard_metadata_update),
            )
            .await
        } else {
            generics::generic_update_with_unique_predicate_get_result::<
                <Self as HasTable>::Table,
                _,
                _,
                _,
            >(
                conn,
                predicate.and(dsl::user_id.is_null()),
                DashboardMetadataUpdateInternal::from(dashboard_metadata_update),
            )
            .await
        }
    }

    pub async fn find_user_scoped_dashboard_metadata(
        conn: &PgPooledConn,
        user_id: String,
        merchant_id: id_type::MerchantId,
        org_id: id_type::OrganizationId,
        data_types: Vec<enums::DashboardMetadata>,
    ) -> StorageResult<Vec<Self>> {
        let predicate = dsl::user_id
            .eq(user_id)
            .and(dsl::merchant_id.eq(merchant_id))
            .and(dsl::org_id.eq(org_id))
            .and(dsl::data_key.eq_any(data_types));

        generics::generic_filter::<<Self as HasTable>::Table, _, _, _>(
            conn,
            predicate,
            None,
            None,
            Some(dsl::last_modified_at.asc()),
        )
        .await
    }

    pub async fn find_merchant_scoped_dashboard_metadata(
        conn: &PgPooledConn,
        merchant_id: id_type::MerchantId,
        org_id: id_type::OrganizationId,
        data_types: Vec<enums::DashboardMetadata>,
    ) -> StorageResult<Vec<Self>> {
        let predicate = dsl::merchant_id
            .eq(merchant_id)
            .and(dsl::org_id.eq(org_id))
            .and(dsl::data_key.eq_any(data_types));

        generics::generic_filter::<<Self as HasTable>::Table, _, _, _>(
            conn,
            predicate,
            None,
            None,
            Some(dsl::last_modified_at.asc()),
        )
        .await
    }

    pub async fn delete_all_user_scoped_dashboard_metadata_by_merchant_id(
        conn: &PgPooledConn,
        user_id: String,
        merchant_id: id_type::MerchantId,
    ) -> StorageResult<bool> {
        generics::generic_delete::<<Self as HasTable>::Table, _>(
            conn,
            dsl::user_id
                .eq(user_id)
                .and(dsl::merchant_id.eq(merchant_id)),
        )
        .await
    }

    pub async fn delete_user_scoped_dashboard_metadata_by_merchant_id_data_key(
        conn: &PgPooledConn,
        user_id: String,
        merchant_id: id_type::MerchantId,
        data_key: enums::DashboardMetadata,
    ) -> StorageResult<Self> {
        generics::generic_delete_one_with_result::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::user_id
                .eq(user_id)
                .and(dsl::merchant_id.eq(merchant_id))
                .and(dsl::data_key.eq(data_key)),
        )
        .await
    }
}


impl api::Payment for Wellsfargopayout {}

impl api::Payment for for Wellsfargopayout


File: crates/router/src/types/storage/events.rs

pub use diesel_models::events::{Event, EventMetadata, EventNew};


pub struct WebhookAmount {
    pub amount: FloatMajorUnit,
    pub currency: enums::Currency,
}


pub fn validate(&self) -> Result<(), ApplicationError> {
        use common_utils::fp_utils::when;

        #[cfg(feature = "keymanager_mtls")]
        when(
            self.enabled && (self.ca.is_default_or_empty() || self.cert.is_default_or_empty()),
            || {
                Err(ApplicationError::InvalidConfigurationValueError(
                    "Invalid CA or Certificate for Keymanager.".into(),
                ))
            },
        )?;

        when(self.enabled && self.url.is_default_or_empty(), || {
            Err(ApplicationError::InvalidConfigurationValueError(
                "Invalid URL for Keymanager".into(),
            ))
        })
    }


File: crates/scheduler/src/consumer/types.rs

pub mod batch;
pub mod process_data;

pub use self::batch::ProcessTrackerBatch;