File: crates/router/src/routes/configs.rs
 Public functions: 4

use actix_web::{web, HttpRequest, Responder};
use router_env::{instrument, tracing, Flow};

use super::app::AppState;
use crate::{
    core::{api_locking, configs},
    services::{api, authentication as auth},
    types::api as api_types,
};

#[cfg(feature = "v1")]
const ADMIN_API_AUTH: auth::AdminApiAuth = auth::AdminApiAuth;
#[cfg(feature = "v2")]
const ADMIN_API_AUTH: auth::V2AdminApiAuth = auth::V2AdminApiAuth;

#[instrument(skip_all, fields(flow = ?Flow::CreateConfigKey))]
pub async fn config_key_create(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<api_types::Config>,
) -> impl Responder {
    let flow = Flow::CreateConfigKey;
    let payload = json_payload.into_inner();

    api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, _, data, _| configs::set_config(state, data),
        &ADMIN_API_AUTH,
        api_locking::LockAction::NotApplicable,
    )
    .await
}
#[instrument(skip_all, fields(flow = ?Flow::ConfigKeyFetch))]
pub async fn config_key_retrieve(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<String>,
) -> impl Responder {
    let flow = Flow::ConfigKeyFetch;
    let key = path.into_inner();

    api::server_wrap(
        flow,
        state,
        &req,
        &key,
        |state, _, key, _| configs::read_config(state, key),
        &ADMIN_API_AUTH,
        api_locking::LockAction::NotApplicable,
    )
    .await
}
#[instrument(skip_all, fields(flow = ?Flow::ConfigKeyUpdate))]
pub async fn config_key_update(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<String>,
    json_payload: web::Json<api_types::ConfigUpdate>,
) -> impl Responder {
    let flow = Flow::ConfigKeyUpdate;
    let mut payload = json_payload.into_inner();
    let key = path.into_inner();
    payload.key = key;

    api::server_wrap(
        flow,
        state,
        &req,
        &payload,
        |state, _, payload, _| configs::update_config(state, payload),
        &ADMIN_API_AUTH,
        api_locking::LockAction::NotApplicable,
    )
    .await
}

#[instrument(skip_all, fields(flow = ?Flow::ConfigKeyDelete))]
pub async fn config_key_delete(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<String>,
) -> impl Responder {
    let flow = Flow::ConfigKeyDelete;
    let key = path.into_inner();

    api::server_wrap(
        flow,
        state,
        &req,
        key,
        |state, _, key, _| configs::config_delete(state, key),
        &ADMIN_API_AUTH,
        api_locking::LockAction::NotApplicable,
    )
    .await
}


OpenAPI Block Path: components.schemas.PaymentMethodCollectLinkRequest
{
  "allOf": [
    {
      "allOf": [
        {
          "$ref": "#/components/schemas/GenericLinkUiConfig"
        }
      ],
      "nullable": true
    },
    {
      "type": "object",
      "required": [
        "customer_id"
      ],
      "properties": {
        "pm_collect_link_id": {
          "type": "string",
          "description": "The unique identifier for the collect link.",
          "example": "pm_collect_link_2bdacf398vwzq5n422S1",
          "nullable": true
        },
        "customer_id": {
          "type": "string",
          "description": "The unique identifier of the customer.",
          "example": "cus_92dnwed8s32bV9D8Snbiasd8v"
        },
        "session_expiry": {
          "type": "integer",
          "format": "int32",
          "description": "Will be used to expire client secret after certain amount of time to be supplied in seconds\n(900) for 15 mins",
          "example": 900,
          "nullable": true,
          "minimum": 0
        },
        "return_url": {
          "type": "string",
          "description": "Redirect to this URL post completion",
          "example": "https://sandbox.hyperswitch.io/payment_method/collect/pm_collect_link_2bdacf398vwzq5n422S1/status",
          "nullable": true
        },
        "enabled_payment_methods": {
          "type": "array",
          "items": {
            "$ref": "#/components/schemas/EnabledPaymentMethod"
          },
          "description": "List of payment methods shown on collect UI",
          "example": "[{\"payment_method\": \"bank_transfer\", \"payment_method_types\": [\"ach\", \"bacs\"]}]",
          "nullable": true
        }
      }
    }
  ]
}


pub fn extract_payment_link_config(
    pl_config: serde_json::Value,
) -> Result<PaymentLinkConfig, error_stack::Report<errors::ApiErrorResponse>> {
    serde_json::from_value::<PaymentLinkConfig>(pl_config).change_context(
        errors::ApiErrorResponse::InvalidDataValue {
            field_name: "payment_link_config",
        },
    )
}


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

use common_utils::{errors::ValidationError, ext_traits::ValueExt, types::user::ThemeLineage};
use diesel_models::{
    enums as storage_enums, process_tracker::business_status, ApiKeyExpiryTrackingData,
};
use router_env::logger;
use scheduler::{workflows::ProcessTrackerWorkflow, SchedulerSessionState};

use crate::{
    consts, errors,
    logger::error,
    routes::{metrics, SessionState},
    services::email::types::ApiKeyExpiryReminder,
    types::{api, domain::UserEmail, storage},
    utils::{
        user::{self as user_utils, theme as theme_utils},
        OptionExt,
    },
};

pub struct ApiKeyExpiryWorkflow;

#[async_trait::async_trait]
impl ProcessTrackerWorkflow<SessionState> for ApiKeyExpiryWorkflow {
    async fn execute_workflow<'a>(
        &'a self,
        state: &'a SessionState,
        process: storage::ProcessTracker,
    ) -> Result<(), errors::ProcessTrackerError> {
        let db = &*state.store;
        let tracking_data: ApiKeyExpiryTrackingData = process
            .tracking_data
            .clone()
            .parse_value("ApiKeyExpiryTrackingData")?;
        let key_manager_satte = &state.into();
        let key_store = state
            .store
            .get_merchant_key_store_by_merchant_id(
                key_manager_satte,
                &tracking_data.merchant_id,
                &state.store.get_master_key().to_vec().into(),
            )
            .await?;

        let merchant_account = db
            .find_merchant_account_by_merchant_id(
                key_manager_satte,
                &tracking_data.merchant_id,
                &key_store,
            )
            .await?;

        let email_id = merchant_account
            .merchant_details
            .clone()
            .parse_value::<api::MerchantDetails>("MerchantDetails")?
            .primary_email
            .ok_or(errors::ProcessTrackerError::EValidationError(
                ValidationError::MissingRequiredField {
                    field_name: "email".to_string(),
                }
                .into(),
            ))?;

        let task_id = process.id.clone();

        let retry_count = process.retry_count;

        let api_key_name = tracking_data.api_key_name.clone();

        let prefix = tracking_data.prefix.clone();

        let expires_in = tracking_data
            .expiry_reminder_days
            .get(
                usize::try_from(retry_count)
                    .map_err(|_| errors::ProcessTrackerError::TypeConversionError)?,
            )
            .ok_or(errors::ProcessTrackerError::EApiErrorResponse)?;

        let theme = theme_utils::get_most_specific_theme_using_lineage(
            state,
            ThemeLineage::Merchant {
                tenant_id: state.tenant.tenant_id.clone(),
                org_id: merchant_account.get_org_id().clone(),
                merchant_id: merchant_account.get_id().clone(),
            },
        )
        .await
        .map_err(|err| {
            logger::error!(?err, "Failed to get theme");
            errors::ProcessTrackerError::EApiErrorResponse
        })?;

        let email_contents = ApiKeyExpiryReminder {
            recipient_email: UserEmail::from_pii_email(email_id).map_err(|error| {
                logger::error!(
                    ?error,
                    "Failed to convert recipient's email to UserEmail from pii::Email"
                );
                errors::ProcessTrackerError::EApiErrorResponse
            })?,
            subject: consts::EMAIL_SUBJECT_API_KEY_EXPIRY,
            expires_in: *expires_in,
            api_key_name,
            prefix,
            theme_id: theme.as_ref().map(|theme| theme.theme_id.clone()),
            theme_config: theme
                .map(|theme| theme.email_config())
                .unwrap_or(state.conf.theme.email_config.clone()),
        };

        state
            .email_client
            .clone()
            .compose_and_send_email(
                user_utils::get_base_url(state),
                Box::new(email_contents),
                state.conf.proxy.https_url.as_ref(),
            )
            .await
            .map_err(errors::ProcessTrackerError::EEmailError)?;

        // If all the mails have been sent, then retry_count would be equal to length of the expiry_reminder_days vector
        if retry_count
            == i32::try_from(tracking_data.expiry_reminder_days.len() - 1)
                .map_err(|_| errors::ProcessTrackerError::TypeConversionError)?
        {
            state
                .get_db()
                .as_scheduler()
                .finish_process_with_business_status(process, business_status::COMPLETED_BY_PT)
                .await?
        }
        // If tasks are remaining that has to be scheduled
        else {
            let expiry_reminder_day = tracking_data
                .expiry_reminder_days
                .get(
                    usize::try_from(retry_count + 1)
                        .map_err(|_| errors::ProcessTrackerError::TypeConversionError)?,
                )
                .ok_or(errors::ProcessTrackerError::EApiErrorResponse)?;

            let updated_schedule_time = tracking_data.api_key_expiry.map(|api_key_expiry| {
                api_key_expiry.saturating_sub(time::Duration::days(i64::from(*expiry_reminder_day)))
            });
            let updated_process_tracker_data = storage::ProcessTrackerUpdate::Update {
                name: None,
                retry_count: Some(retry_count + 1),
                schedule_time: updated_schedule_time,
                tracking_data: None,
                business_status: None,
                status: Some(storage_enums::ProcessTrackerStatus::New),
                updated_at: Some(common_utils::date_time::now()),
            };
            let task_ids = vec![task_id];
            db.process_tracker_update_process_status_by_ids(task_ids, updated_process_tracker_data)
                .await?;
            // Remaining tasks are re-scheduled, so will be resetting the added count
            metrics::TASKS_RESET_COUNT
                .add(1, router_env::metric_attributes!(("flow", "ApiKeyExpiry")));
        }

        Ok(())
    }

    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 struct RequiredFieldFinal {
    pub mandate: Option<Vec<RequiredFieldInfo>>,
    pub non_mandate: Option<Vec<RequiredFieldInfo>>,
    pub common: Option<Vec<RequiredFieldInfo>>,
}


pub async fn payments_complete_authorize(
    state: web::Data<app::AppState>,
    req: actix_web::HttpRequest,
    json_payload: web::Json<payment_types::PaymentsCompleteAuthorizeRequest>,
    path: web::Path<common_utils::id_type::PaymentId>,
) -> impl Responder {
    let flow = Flow::PaymentsCompleteAuthorize;
    let mut payload = json_payload.into_inner();

    let payment_id = path.into_inner();
    payload.payment_id.clone_from(&payment_id);

    tracing::Span::current().record("payment_id", payment_id.get_string_repr());

    let payment_confirm_req = payment_types::PaymentsRequest {
        payment_id: Some(payment_types::PaymentIdType::PaymentIntentId(
            payment_id.clone(),
        )),
        shipping: payload.shipping.clone(),
        client_secret: Some(payload.client_secret.peek().clone()),
        threeds_method_comp_ind: payload.threeds_method_comp_ind.clone(),
        ..Default::default()
    };

    let api_auth = auth::ApiKeyAuth {
        is_connected_allowed: false,
        is_platform_allowed: true,
    };

    let (auth_type, auth_flow) =
        match auth::check_client_secret_and_get_auth(req.headers(), &payment_confirm_req, api_auth)
        {
            Ok(auth) => auth,
            Err(err) => return api::log_and_return_error_response(report!(err)),
        };

    let locking_action = payload.get_locking_input(flow.clone());
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth: auth::AuthenticationData, _req, req_state| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payments::payments_core::<
                api_types::CompleteAuthorize,
                payment_types::PaymentsResponse,
                _,
                _,
                _,
                payments::PaymentData<api_types::CompleteAuthorize>,
            >(
                state.clone(),
                req_state,
                merchant_context,
                auth.profile_id,
                payments::operations::payment_complete_authorize::CompleteAuthorize,
                payment_confirm_req.clone(),
                auth_flow,
                payments::CallConnectorAction::Trigger,
                None,
                HeaderPayload::default(),
            )
        },
        &*auth_type,
        locking_action,
    ))
    .await
}


pub struct DestinationChargeRefund {
    pub revert_platform_fee: bool,
    pub revert_transfer: bool,
}


pub struct CheckbookPaymentsResponse {
    pub status: CheckbookPaymentStatus,
    pub id: String,
    pub amount: Option<FloatMajorUnit>,
    pub description: Option<String>,
    pub name: Option<String>,
    pub recipient: Option<String>,
}


impl Responder {
    let flow = Flow::DecisionManagerUpsertConfig;
    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        json_payload.into_inner(),
        |state, auth: auth::AuthenticationData, update_decision, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            conditional_config::upsert_conditional_config(state, merchant_context, update_decision)
        },
        #[cfg(not(feature = "release"))]
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuth {
                permission: Permission::MerchantThreeDsDecisionManagerWrite,
            },
            req.headers(),
        ),
        #[cfg(feature = "release")]
        &auth::JWTAuth {
            permission: Permission::MerchantThreeDsDecisionManagerWrite,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


impl HubspotProxyConfig {
    /// 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 struct RoutingRule {
    pub rule_id: Option<String>,
    pub name: String,
    pub description: Option<String>,
    pub metadata: Option<RoutingMetadata>,
    pub created_by: String,
    #[serde(default)]
    pub algorithm_for: AlgorithmType,
    pub algorithm: StaticRoutingAlgorithm,
}


pub struct PayloadEventDetails {
    #[serde(rename = "id")]
    pub transaction_id: Option<String>,
    pub object: String,
    pub value: Option<serde_json::Value>, // Changed to handle any value type including null
}


File: crates/router/src/core/payments/operations/payment_response.rs
 Public structs: 2

use std::collections::HashMap;

use api_models::payments::{ConnectorMandateReferenceId, MandateReferenceId};
#[cfg(feature = "dynamic_routing")]
use api_models::routing::RoutableConnectorChoice;
use async_trait::async_trait;
use common_enums::AuthorizationStatus;
#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
use common_utils::ext_traits::ValueExt;
use common_utils::{
    ext_traits::{AsyncExt, Encode},
    types::{keymanager::KeyManagerState, ConnectorTransactionId, MinorUnit},
};
use error_stack::{report, ResultExt};
use futures::FutureExt;
use hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt;
#[cfg(feature = "v2")]
use hyperswitch_domain_models::payments::{
    PaymentConfirmData, PaymentIntentData, PaymentStatusData,
};
use router_derive;
use router_env::{instrument, logger, tracing};
use storage_impl::DataModelExt;
use tracing_futures::Instrument;

use super::{Operation, OperationSessionSetters, PostUpdateTracker};
#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
use crate::core::routing::helpers as routing_helpers;
#[cfg(feature = "v2")]
use crate::utils::OptionExt;
use crate::{
    connector::utils::PaymentResponseRouterData,
    consts,
    core::{
        card_testing_guard::utils as card_testing_guard_utils,
        errors::{self, CustomResult, RouterResult, StorageErrorExt},
        mandate,
        payment_methods::{self, cards::create_encrypted_data},
        payments::{
            helpers::{
                self as payments_helpers,
                update_additional_payment_data_with_connector_response_pm_data,
            },
            tokenization,
            types::MultipleCaptureData,
            PaymentData, PaymentMethodChecker,
        },
        utils as core_utils,
    },
    routes::{metrics, SessionState},
    types::{
        self, domain,
        storage::{self, enums},
        transformers::{ForeignFrom, ForeignTryFrom},
        CaptureSyncResponse, ErrorResponse,
    },
    utils,
};

#[cfg(feature = "v1")]
#[derive(Debug, Clone, Copy, router_derive::PaymentOperation)]
#[operation(
    operations = "post_update_tracker",
    flow = "sync_data, cancel_data, authorize_data, capture_data, complete_authorize_data, approve_data, reject_data, setup_mandate_data, session_data,incremental_authorization_data, sdk_session_update_data, post_session_tokens_data, update_metadata_data, cancel_post_capture_data"
)]
pub struct PaymentResponse;

#[cfg(feature = "v2")]
#[derive(Debug, Clone, Copy)]
pub struct PaymentResponse;

#[cfg(feature = "v1")]
#[async_trait]
impl<F: Send + Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsAuthorizeData>
    for PaymentResponse
{
    async fn update_tracker<'b>(
        &'b self,
        db: &'b SessionState,
        mut payment_data: PaymentData<F>,
        router_data: types::RouterData<
            F,
            types::PaymentsAuthorizeData,
            types::PaymentsResponseData,
        >,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: enums::MerchantStorageScheme,
        locale: &Option<String>,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))] routable_connector: Vec<
            RoutableConnectorChoice,
        >,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))] business_profile: &domain::Profile,
    ) -> RouterResult<PaymentData<F>>
    where
        F: 'b,
    {
        payment_data.mandate_id = payment_data
            .mandate_id
            .or_else(|| router_data.request.mandate_id.clone());

        // update setup_future_usage incase it is downgraded to on-session
        payment_data.payment_attempt.setup_future_usage_applied =
            router_data.request.setup_future_usage;

        payment_data = Box::pin(payment_response_update_tracker(
            db,
            payment_data,
            router_data,
            key_store,
            storage_scheme,
            locale,
            #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
            routable_connector,
            #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
            business_profile,
        ))
        .await?;

        Ok(payment_data)
    }

    #[cfg(feature = "v2")]
    async fn save_pm_and_mandate<'b>(
        &self,
        state: &SessionState,
        resp: &types::RouterData<F, types::PaymentsAuthorizeData, types::PaymentsResponseData>,
        merchant_context: &domain::MerchantContext,
        payment_data: &mut PaymentData<F>,
        business_profile: &domain::Profile,
    ) -> CustomResult<(), errors::ApiErrorResponse>
    where
        F: 'b + Clone + Send + Sync,
    {
        todo!()
    }

    #[cfg(feature = "v1")]
    async fn save_pm_and_mandate<'b>(
        &self,
        state: &SessionState,
        resp: &types::RouterData<F, types::PaymentsAuthorizeData, types::PaymentsResponseData>,
        merchant_context: &domain::MerchantContext,
        payment_data: &mut PaymentData<F>,
        business_profile: &domain::Profile,
    ) -> CustomResult<(), errors::ApiErrorResponse>
    where
        F: 'b + Clone + Send + Sync,
    {
        let customer_id = payment_data.payment_intent.customer_id.clone();
        let save_payment_data = tokenization::SavePaymentMethodData::from(resp);
        let payment_method_billing_address = payment_data.address.get_payment_method_billing();

        let connector_name = payment_data
            .payment_attempt
            .connector
            .clone()
            .ok_or_else(|| {
                logger::error!("Missing required Param connector_name");
                errors::ApiErrorResponse::MissingRequiredField {
                    field_name: "connector_name",
                }
            })?;
        let merchant_connector_id = payment_data.payment_attempt.merchant_connector_id.clone();
        let billing_name = resp
            .address
            .get_payment_method_billing()
            .and_then(|billing_details| billing_details.address.as_ref())
            .and_then(|address| address.get_optional_full_name());
        let mut should_avoid_saving = false;
        let vault_operation = payment_data.vault_operation.clone();
        let payment_method_info = payment_data.payment_method_info.clone();

        if let Some(payment_method_info) = &payment_data.payment_method_info {
            if payment_data.payment_intent.off_session.is_none() && resp.response.is_ok() {
                should_avoid_saving = resp.request.payment_method_type
                    == Some(enums::PaymentMethodType::ApplePay)
                    || resp.request.payment_method_type
                        == Some(enums::PaymentMethodType::GooglePay);
                payment_methods::cards::update_last_used_at(
                    payment_method_info,
                    state,
                    merchant_context.get_merchant_account().storage_scheme,
                    merchant_context.get_merchant_key_store(),
                )
                .await
                .map_err(|e| {
                    logger::error!("Failed to update last used at: {:?}", e);
                })
                .ok();
            }
        };
        let connector_mandate_reference_id = payment_data
            .payment_attempt
            .connector_mandate_detail
            .as_ref()
            .map(|detail| ConnectorMandateReferenceId::foreign_from(detail.clone()));
        let save_payment_call_future = Box::pin(tokenization::save_payment_method(
            state,
            connector_name.clone(),
            save_payment_data,
            customer_id.clone(),
            merchant_context,
            resp.request.payment_method_type,
            billing_name.clone(),
            payment_method_billing_address,
            business_profile,
            connector_mandate_reference_id.clone(),
            merchant_connector_id.clone(),
            vault_operation.clone(),
            payment_method_info.clone(),
        ));

        let is_connector_mandate = resp.request.customer_acceptance.is_some()
            && matches!(
                resp.request.setup_future_usage,
                Some(enums::FutureUsage::OffSession)
            );

        let is_legacy_mandate = resp.request.setup_mandate_details.is_some()
            && matches!(
                resp.request.setup_future_usage,
                Some(enums::FutureUsage::OffSession)
            );
        let storage_scheme = merchant_context.get_merchant_account().storage_scheme;
        if is_legacy_mandate {
            // Mandate is created on the application side and at the connector.
            let tokenization::SavePaymentMethodDataResponse {
                payment_method_id, ..
            } = save_payment_call_future.await?;

            let mandate_id = mandate::mandate_procedure(
                state,
                resp,
                &customer_id.clone(),
                payment_method_id.clone(),
                merchant_connector_id.clone(),
                merchant_context.get_merchant_account().storage_scheme,
                payment_data.payment_intent.get_id(),
            )
            .await?;
            payment_data.payment_attempt.payment_method_id = payment_method_id;
            payment_data.payment_attempt.mandate_id = mandate_id;

            Ok(())
        } else if is_connector_mandate {
            // The mandate is created on connector's end.
            let tokenization::SavePaymentMethodDataResponse {
                payment_method_id,
                connector_mandate_reference_id,
                ..
            } = save_payment_call_future.await?;
            payment_data.payment_method_info = if let Some(payment_method_id) = &payment_method_id {
                match state
                    .store
                    .find_payment_method(
                        &(state.into()),
                        merchant_context.get_merchant_key_store(),
                        payment_method_id,
                        storage_scheme,
                    )
                    .await
                {
                    Ok(payment_method) => Some(payment_method),
                    Err(error) => {
                        if error.current_context().is_db_not_found() {
                            logger::info!("Payment Method not found in db {:?}", error);
                            None
                        } else {
                            Err(error)
                                .change_context(errors::ApiErrorResponse::InternalServerError)
                                .attach_printable("Error retrieving payment method from db")
                                .map_err(|err| logger::error!(payment_method_retrieve=?err))
                                .ok()
                        }
                    }
                }
            } else {
                None
            };
            payment_data.payment_attempt.payment_method_id = payment_method_id;
            payment_data.payment_attempt.connector_mandate_detail = connector_mandate_reference_id
                .clone()
                .map(ForeignFrom::foreign_from);
            payment_data.set_mandate_id(api_models::payments::MandateIds {
                mandate_id: None,
                mandate_reference_id: connector_mandate_reference_id.map(|connector_mandate_id| {
                    MandateReferenceId::ConnectorMandateId(connector_mandate_id)
                }),
            });
            Ok(())
        } else if should_avoid_saving {
            if let Some(pm_info) = &payment_data.payment_method_info {
                payment_data.payment_attempt.payment_method_id = Some(pm_info.get_id().clone());
            };
            Ok(())
        } else {
            // Save card flow
            let save_payment_data = tokenization::SavePaymentMethodData::from(resp);
            let state = state.clone();
            let customer_id = payment_data.payment_intent.customer_id.clone();
            let payment_attempt = payment_data.payment_attempt.clone();

            let business_profile = business_profile.clone();
            let payment_method_type = resp.request.payment_method_type;
            let payment_method_billing_address = payment_method_billing_address.cloned();

            let cloned_merchant_context = merchant_context.clone();
            logger::info!("Call to save_payment_method in locker");
            let _task_handle = tokio::spawn(
                async move {
                    logger::info!("Starting async call to save_payment_method in locker");

                    let result = Box::pin(tokenization::save_payment_method(
                        &state,
                        connector_name,
                        save_payment_data,
                        customer_id,
                        &cloned_merchant_context,
                        payment_method_type,
                        billing_name,
                        payment_method_billing_address.as_ref(),
                        &business_profile,
                        connector_mandate_reference_id,
                        merchant_connector_id.clone(),
                        vault_operation.clone(),
                        payment_method_info.clone(),
                    ))
                    .await;

                    if let Err(err) = result {
                        logger::error!("Asynchronously saving card in locker failed : {:?}", err);
                    } else if let Ok(tokenization::SavePaymentMethodDataResponse {
                        payment_method_id,
                        ..
                    }) = result
                    {
                        let payment_attempt_update =
                            storage::PaymentAttemptUpdate::PaymentMethodDetailsUpdate {
                                payment_method_id,
                                updated_by: storage_scheme.clone().to_string(),
                            };

                        #[cfg(feature = "v1")]
                        let respond = state
                            .store
                            .update_payment_attempt_with_attempt_id(
                                payment_attempt,
                                payment_attempt_update,
                                storage_scheme,
                            )
                            .await;

                        #[cfg(feature = "v2")]
                        let respond = state
                            .store
                            .update_payment_attempt_with_attempt_id(
                                &(&state).into(),
                                &key_store,
                                payment_attempt,
                                payment_attempt_update,
                                storage_scheme,
                            )
                            .await;

                        if let Err(err) = respond {
                            logger::error!("Error updating payment attempt: {:?}", err);
                        };
                    }
                }
                .in_current_span(),
            );
            Ok(())
        }
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsIncrementalAuthorizationData>
    for PaymentResponse
{
    async fn update_tracker<'b>(
        &'b self,
        state: &'b SessionState,
        mut payment_data: PaymentData<F>,
        router_data: types::RouterData<
            F,
            types::PaymentsIncrementalAuthorizationData,
            types::PaymentsResponseData,
        >,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: enums::MerchantStorageScheme,
        _locale: &Option<String>,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))] _routable_connector: Vec<
            RoutableConnectorChoice,
        >,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
        _business_profile: &domain::Profile,
    ) -> RouterResult<PaymentData<F>>
    where
        F: 'b + Send,
    {
        let incremental_authorization_details = payment_data
            .incremental_authorization_details
            .clone()
            .ok_or_else(|| {
                report!(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("missing incremental_authorization_details in payment_data")
            })?;
        // Update payment_intent and payment_attempt 'amount' if incremental_authorization is successful
        let (option_payment_attempt_update, option_payment_intent_update) = match router_data
            .response
            .clone()
        {
            Err(_) => (None, None),
            Ok(types::PaymentsResponseData::IncrementalAuthorizationResponse {
                status, ..
            }) => {
                if status == AuthorizationStatus::Success {
                    (
                        Some(
                            storage::PaymentAttemptUpdate::IncrementalAuthorizationAmountUpdate {
                                net_amount: hyperswitch_domain_models::payments::payment_attempt::NetAmount::new(
                                    // Internally, `NetAmount` is computed as (order_amount + additional_amount), so we subtract here to avoid double-counting.
                                    incremental_authorization_details.total_amount - payment_data.payment_attempt.net_amount.get_additional_amount(),
                                    None,
                                    None,
                                    None,
                                    None,
                                ),
                                amount_capturable: incremental_authorization_details.total_amount,
                            },
                        ),
                        Some(
                            storage::PaymentIntentUpdate::IncrementalAuthorizationAmountUpdate {
                                amount: incremental_authorization_details.total_amount - payment_data.payment_attempt.net_amount.get_additional_amount(),
                            },
                        ),
                    )
                } else {
                    (None, None)
                }
            }
            _ => Err(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("unexpected response in incremental_authorization flow")?,
        };
        //payment_attempt update
        if let Some(payment_attempt_update) = option_payment_attempt_update {
            #[cfg(feature = "v1")]
            {
                payment_data.payment_attempt = state
                    .store
                    .update_payment_attempt_with_attempt_id(
                        payment_data.payment_attempt.clone(),
                        payment_attempt_update,
                        storage_scheme,
                    )
                    .await
                    .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
            }

            #[cfg(feature = "v2")]
            {
                payment_data.payment_attempt = state
                    .store
                    .update_payment_attempt_with_attempt_id(
                        &state.into(),
                        key_store,
                        payment_data.payment_attempt.clone(),
                        payment_attempt_update,
                        storage_scheme,
                    )
                    .await
                    .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
            }
        }
        // payment_intent update
        if let Some(payment_intent_update) = option_payment_intent_update {
            payment_data.payment_intent = state
                .store
                .update_payment_intent(
                    &state.into(),
                    payment_data.payment_intent.clone(),
                    payment_intent_update,
                    key_store,
                    storage_scheme,
                )
                .await
                .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
        }
        // Update the status of authorization record
        let authorization_update = match &router_data.response {
            Err(res) => Ok(storage::AuthorizationUpdate::StatusUpdate {
                status: AuthorizationStatus::Failure,
                error_code: Some(res.code.clone()),
                error_message: Some(res.message.clone()),
                connector_authorization_id: None,
            }),
            Ok(types::PaymentsResponseData::IncrementalAuthorizationResponse {
                status,
                error_code,
                error_message,
                connector_authorization_id,
            }) => Ok(storage::AuthorizationUpdate::StatusUpdate {
                status: status.clone(),
                error_code: error_code.clone(),
                error_message: error_message.clone(),
                connector_authorization_id: connector_authorization_id.clone(),
            }),
            Ok(_) => Err(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("unexpected response in incremental_authorization flow"),
        }?;
        let authorization_id = incremental_authorization_details
            .authorization_id
            .clone()
            .ok_or(
                report!(errors::ApiErrorResponse::InternalServerError).attach_printable(
                    "missing authorization_id in incremental_authorization_details in payment_data",
                ),
            )?;
        state
            .store
            .update_authorization_by_merchant_id_authorization_id(
                router_data.merchant_id.clone(),
                authorization_id,
                authorization_update,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("failed while updating authorization")?;
        //Fetch all the authorizations of the payment and send in incremental authorization response
        let authorizations = state
            .store
            .find_all_authorizations_by_merchant_id_payment_id(
                &router_data.merchant_id,
                payment_data.payment_intent.get_id(),
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("failed while retrieving authorizations")?;
        payment_data.authorizations = authorizations;
        Ok(payment_data)
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsSyncData> for PaymentResponse {
    async fn update_tracker<'b>(
        &'b self,
        db: &'b SessionState,
        payment_data: PaymentData<F>,
        router_data: types::RouterData<F, types::PaymentsSyncData, types::PaymentsResponseData>,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: enums::MerchantStorageScheme,
        locale: &Option<String>,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))] routable_connector: Vec<
            RoutableConnectorChoice,
        >,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))] business_profile: &domain::Profile,
    ) -> RouterResult<PaymentData<F>>
    where
        F: 'b + Send,
    {
        Box::pin(payment_response_update_tracker(
            db,
            payment_data,
            router_data,
            key_store,
            storage_scheme,
            locale,
            #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
            routable_connector,
            #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
            business_profile,
        ))
        .await
    }

    async fn save_pm_and_mandate<'b>(
        &self,
        state: &SessionState,
        resp: &types::RouterData<F, types::PaymentsSyncData, types::PaymentsResponseData>,
        merchant_context: &domain::MerchantContext,
        payment_data: &mut PaymentData<F>,
        _business_profile: &domain::Profile,
    ) -> CustomResult<(), errors::ApiErrorResponse>
    where
        F: 'b + Clone + Send + Sync,
    {
        let (connector_mandate_id, mandate_metadata, connector_mandate_request_reference_id) = resp
            .response
            .clone()
            .ok()
            .and_then(|resp| {
                if let types::PaymentsResponseData::TransactionResponse {
                    mandate_reference, ..
                } = resp
                {
                    mandate_reference.map(|mandate_ref| {
                        (
                            mandate_ref.connector_mandate_id.clone(),
                            mandate_ref.mandate_metadata.clone(),
                            mandate_ref.connector_mandate_request_reference_id.clone(),
                        )
                    })
                } else {
                    None
                }
            })
            .unwrap_or((None, None, None));

        update_connector_mandate_details_for_the_flow(
            connector_mandate_id,
            mandate_metadata,
            connector_mandate_request_reference_id,
            payment_data,
        )?;

        update_payment_method_status_and_ntid(
            state,
            merchant_context.get_merchant_key_store(),
            payment_data,
            resp.status,
            resp.response.clone(),
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await?;
        Ok(())
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsSessionData>
    for PaymentResponse
{
    async fn update_tracker<'b>(
        &'b self,
        db: &'b SessionState,
        mut payment_data: PaymentData<F>,
        router_data: types::RouterData<F, types::PaymentsSessionData, types::PaymentsResponseData>,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: enums::MerchantStorageScheme,
        locale: &Option<String>,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))] routable_connector: Vec<
            RoutableConnectorChoice,
        >,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))] business_profile: &domain::Profile,
    ) -> RouterResult<PaymentData<F>>
    where
        F: 'b + Send,
    {
        payment_data = Box::pin(payment_response_update_tracker(
            db,
            payment_data,
            router_data,
            key_store,
            storage_scheme,
            locale,
            #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
            routable_connector,
            #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
            business_profile,
        ))
        .await?;

        Ok(payment_data)
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::SdkPaymentsSessionUpdateData>
    for PaymentResponse
{
    async fn update_tracker<'b>(
        &'b self,
        db: &'b SessionState,
        mut payment_data: PaymentData<F>,
        router_data: types::RouterData<
            F,
            types::SdkPaymentsSessionUpdateData,
            types::PaymentsResponseData,
        >,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: enums::MerchantStorageScheme,
        _locale: &Option<String>,
        #[cfg(feature = "dynamic_routing")] _routable_connector: Vec<RoutableConnectorChoice>,
        #[cfg(feature = "dynamic_routing")] _business_profile: &domain::Profile,
    ) -> RouterResult<PaymentData<F>>
    where
        F: 'b + Send,
    {
        let connector = payment_data
            .payment_attempt
            .connector
            .clone()
            .ok_or(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("connector not found")?;

        let key_manager_state = db.into();

        // For PayPal, if we call TaxJar for tax calculation, we need to call the connector again to update the order amount so that we can confirm the updated amount and order details. Therefore, we will store the required changes in the database during the post_update_tracker call.
        if payment_data.should_update_in_post_update_tracker() {
            match router_data.response.clone() {
                Ok(types::PaymentsResponseData::PaymentResourceUpdateResponse { status }) => {
                    if status.is_success() {
                        let shipping_address = payment_data
                            .tax_data
                            .clone()
                            .map(|tax_data| tax_data.shipping_details);

                        let shipping_details = shipping_address
                            .clone()
                            .async_map(|shipping_details| {
                                create_encrypted_data(
                                    &key_manager_state,
                                    key_store,
                                    shipping_details,
                                )
                            })
                            .await
                            .transpose()
                            .change_context(errors::ApiErrorResponse::InternalServerError)
                            .attach_printable("Unable to encrypt shipping details")?;

                        let shipping_address =
                            payments_helpers::create_or_update_address_for_payment_by_request(
                                db,
                                shipping_address.map(From::from).as_ref(),
                                payment_data.payment_intent.shipping_address_id.as_deref(),
                                &payment_data.payment_intent.merchant_id,
                                payment_data.payment_intent.customer_id.as_ref(),
                                key_store,
                                &payment_data.payment_intent.payment_id,
                                storage_scheme,
                            )
                            .await?;

                        let payment_intent_update = hyperswitch_domain_models::payments::payment_intent::PaymentIntentUpdate::SessionResponseUpdate {
                    tax_details: payment_data.payment_intent.tax_details.clone().ok_or(errors::ApiErrorResponse::InternalServerError).attach_printable("payment_intent.tax_details not found")?,
                    shipping_address_id: shipping_address.map(|address| address.address_id),
                    updated_by: payment_data.payment_intent.updated_by.clone(),
                    shipping_details,
        };

                        let m_db = db.clone().store;
                        let payment_intent = payment_data.payment_intent.clone();
                        let key_manager_state: KeyManagerState = db.into();

                        let updated_payment_intent = m_db
                            .update_payment_intent(
                                &key_manager_state,
                                payment_intent,
                                payment_intent_update,
                                key_store,
                                storage_scheme,
                            )
                            .await
                            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

                        payment_data.payment_intent = updated_payment_intent;
                    } else {
                        router_data.response.map_err(|err| {
                            errors::ApiErrorResponse::ExternalConnectorError {
                                code: err.code,
                                message: err.message,
                                connector,
                                status_code: err.status_code,
                                reason: err.reason,
                            }
                        })?;
                    }
                }
                Err(err) => {
                    Err(errors::ApiErrorResponse::ExternalConnectorError {
                        code: err.code,
                        message: err.message,
                        connector,
                        status_code: err.status_code,
                        reason: err.reason,
                    })?;
                }
                _ => {
                    Err(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable("Unexpected response in session_update flow")?;
                }
            }
        }

        Ok(payment_data)
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsPostSessionTokensData>
    for PaymentResponse
{
    async fn update_tracker<'b>(
        &'b self,
        db: &'b SessionState,
        mut payment_data: PaymentData<F>,
        router_data: types::RouterData<
            F,
            types::PaymentsPostSessionTokensData,
            types::PaymentsResponseData,
        >,
        _key_store: &domain::MerchantKeyStore,
        storage_scheme: enums::MerchantStorageScheme,
        _locale: &Option<String>,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))] _routable_connector: Vec<
            RoutableConnectorChoice,
        >,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
        _business_profile: &domain::Profile,
    ) -> RouterResult<PaymentData<F>>
    where
        F: 'b + Send,
    {
        match router_data.response.clone() {
            Ok(types::PaymentsResponseData::TransactionResponse {
                connector_metadata, ..
            }) => {
                let m_db = db.clone().store;
                let payment_attempt_update =
                    storage::PaymentAttemptUpdate::PostSessionTokensUpdate {
                        updated_by: storage_scheme.clone().to_string(),
                        connector_metadata,
                    };
                let updated_payment_attempt = m_db
                    .update_payment_attempt_with_attempt_id(
                        payment_data.payment_attempt.clone(),
                        payment_attempt_update,
                        storage_scheme,
                    )
                    .await
                    .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
                payment_data.payment_attempt = updated_payment_attempt;
            }
            Err(err) => {
                logger::error!("Invalid request sent to connector: {:?}", err);
                Err(errors::ApiErrorResponse::InvalidRequestData {
                    message: "Invalid request sent to connector".to_string(),
                })?;
            }
            _ => {
                Err(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Unexpected response in PostSessionTokens flow")?;
            }
        }
        Ok(payment_data)
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsUpdateMetadataData>
    for PaymentResponse
{
    async fn update_tracker<'b>(
        &'b self,
        db: &'b SessionState,
        mut payment_data: PaymentData<F>,
        router_data: types::RouterData<
            F,
            types::PaymentsUpdateMetadataData,
            types::PaymentsResponseData,
        >,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: enums::MerchantStorageScheme,
        _locale: &Option<String>,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))] _routable_connector: Vec<
            RoutableConnectorChoice,
        >,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
        _business_profile: &domain::Profile,
    ) -> RouterResult<PaymentData<F>>
    where
        F: 'b + Send,
    {
        let connector = payment_data
            .payment_attempt
            .connector
            .clone()
            .ok_or(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("connector not found in payment_attempt")?;

        match router_data.response.clone() {
            Ok(types::PaymentsResponseData::PaymentResourceUpdateResponse { status, .. }) => {
                if status.is_success() {
                    let m_db = db.clone().store;
                    let payment_intent = payment_data.payment_intent.clone();
                    let key_manager_state: KeyManagerState = db.into();

                    let payment_intent_update =
                        hyperswitch_domain_models::payments::payment_intent::PaymentIntentUpdate::MetadataUpdate {
                            metadata: payment_data
                                .payment_intent
                                .metadata
                                .clone()
                                .ok_or(errors::ApiErrorResponse::InternalServerError)
                                .attach_printable("payment_intent.metadata not found")?,
                            updated_by: payment_data.payment_intent.updated_by.clone(),
                        };

                    let updated_payment_intent = m_db
                        .update_payment_intent(
                            &key_manager_state,
                            payment_intent,
                            payment_intent_update,
                            key_store,
                            storage_scheme,
                        )
                        .await
                        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

                    payment_data.payment_intent = updated_payment_intent;
                } else {
                    router_data.response.map_err(|err| {
                        errors::ApiErrorResponse::ExternalConnectorError {
                            code: err.code,
                            message: err.message,
                            connector,
                            status_code: err.status_code,
                            reason: err.reason,
                        }
                    })?;
                }
            }
            Err(err) => {
                Err(errors::ApiErrorResponse::ExternalConnectorError {
                    code: err.code,
                    message: err.message,
                    connector,
                    status_code: err.status_code,
                    reason: err.reason,
                })?;
            }
            _ => {
                Err(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Unexpected response in Update Metadata flow")?;
            }
        }

        Ok(payment_data)
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsCaptureData>
    for PaymentResponse
{
    async fn update_tracker<'b>(
        &'b self,
        db: &'b SessionState,
        mut payment_data: PaymentData<F>,
        router_data: types::RouterData<F, types::PaymentsCaptureData, types::PaymentsResponseData>,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: enums::MerchantStorageScheme,
        locale: &Option<String>,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))] routable_connector: Vec<
            RoutableConnectorChoice,
        >,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))] business_profile: &domain::Profile,
    ) -> RouterResult<PaymentData<F>>
    where
        F: 'b + Send,
    {
        payment_data = Box::pin(payment_response_update_tracker(
            db,
            payment_data,
            router_data,
            key_store,
            storage_scheme,
            locale,
            #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
            routable_connector,
            #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
            business_profile,
        ))
        .await?;

        Ok(payment_data)
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsCancelData> for PaymentResponse {
    async fn update_tracker<'b>(
        &'b self,
        db: &'b SessionState,
        mut payment_data: PaymentData<F>,
        router_data: types::RouterData<F, types::PaymentsCancelData, types::PaymentsResponseData>,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: enums::MerchantStorageScheme,
        locale: &Option<String>,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))] routable_connector: Vec<
            RoutableConnectorChoice,
        >,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))] business_profile: &domain::Profile,
    ) -> RouterResult<PaymentData<F>>
    where
        F: 'b + Send,
    {
        payment_data = Box::pin(payment_response_update_tracker(
            db,
            payment_data,
            router_data,
            key_store,
            storage_scheme,
            locale,
            #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
            routable_connector,
            #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
            business_profile,
        ))
        .await?;

        Ok(payment_data)
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsCancelPostCaptureData>
    for PaymentResponse
{
    async fn update_tracker<'b>(
        &'b self,
        db: &'b SessionState,
        mut payment_data: PaymentData<F>,
        router_data: types::RouterData<
            F,
            types::PaymentsCancelPostCaptureData,
            types::PaymentsResponseData,
        >,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: enums::MerchantStorageScheme,
        locale: &Option<String>,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))] routable_connector: Vec<
            RoutableConnectorChoice,
        >,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))] business_profile: &domain::Profile,
    ) -> RouterResult<PaymentData<F>>
    where
        F: 'b + Send,
    {
        payment_data = Box::pin(payment_response_update_tracker(
            db,
            payment_data,
            router_data,
            key_store,
            storage_scheme,
            locale,
            #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
            routable_connector,
            #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
            business_profile,
        ))
        .await?;

        Ok(payment_data)
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsApproveData>
    for PaymentResponse
{
    async fn update_tracker<'b>(
        &'b self,
        db: &'b SessionState,
        mut payment_data: PaymentData<F>,
        router_data: types::RouterData<F, types::PaymentsApproveData, types::PaymentsResponseData>,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: enums::MerchantStorageScheme,
        locale: &Option<String>,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))] routable_connector: Vec<
            RoutableConnectorChoice,
        >,
        #[cfg(all(feature = "v1", feature = "dynamic_routing"))] business_profile: &domain::Profile,
    ) -> RouterResult<PaymentData<F>>
    where
        F: 'b + Send,
    {
        payment_data = Box::pin(payment_response_update_tracker(
            db,
            payment_data,
            router_data,
            key_store,
            storage_scheme,
            locale,
            #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
            routable_connector,
            #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
            business_profile,
        ))
        .await?;

        Ok(payment_data)
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsRejectData> for PaymentResponse {
    async fn update_tracker<'b>(
        &'b self,
        db: &'b SessionState,
        mut payment_data: PaymentData<F>,
        router_data: types::RouterData<F, types::PaymentsRejectData, types::PaymentsResponseData>,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: enums::MerchantStorageScheme,
        locale: &Option<String>,


File: crates/external_services/src/no_encryption.rs

//! No encryption functionalities

pub mod core;

pub mod implementers;


impl api::TaxCalculation for Taxjar {}


pub struct BluesnapCardHolderInfo {
    first_name: Secret<String>,
    last_name: Secret<String>,
    email: Email,
}


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


pub fn insert_locales_in_context_for_payout_link_status(context: &mut Context, locale: &str) {
    let language = get_language(locale);
    let locale = language.as_str();
    let i18n_payout_link_status_title = t!("payout_link.status.title", locale = locale);
    let i18n_success_text = t!("payout_link.status.text.success", locale = locale);
    let i18n_success_message = t!("payout_link.status.message.success", locale = locale);
    let i18n_pending_text = t!("payout_link.status.text.processing", locale = locale);
    let i18n_pending_message = t!("payout_link.status.message.processing", locale = locale);
    let i18n_failed_text = t!("payout_link.status.text.failed", locale = locale);
    let i18n_failed_message = t!("payout_link.status.message.failed", locale = locale);
    let i18n_ref_id_text = t!("payout_link.status.info.ref_id", locale = locale);
    let i18n_error_code_text = t!("payout_link.status.info.error_code", locale = locale);
    let i18n_error_message = t!("payout_link.status.info.error_message", locale = locale);
    let i18n_redirecting_text = t!(
        "payout_link.status.redirection_text.redirecting",
        locale = locale
    );
    let i18n_redirecting_in_text = t!(
        "payout_link.status.redirection_text.redirecting_in",
        locale = locale
    );
    let i18n_seconds_text = t!(
        "payout_link.status.redirection_text.seconds",
        locale = locale
    );

    context.insert(
        "i18n_payout_link_status_title",
        &i18n_payout_link_status_title,
    );
    context.insert("i18n_success_text", &i18n_success_text);
    context.insert("i18n_success_message", &i18n_success_message);
    context.insert("i18n_pending_text", &i18n_pending_text);
    context.insert("i18n_pending_message", &i18n_pending_message);
    context.insert("i18n_failed_text", &i18n_failed_text);
    context.insert("i18n_failed_message", &i18n_failed_message);
    context.insert("i18n_ref_id_text", &i18n_ref_id_text);
    context.insert("i18n_error_code_text", &i18n_error_code_text);
    context.insert("i18n_error_message", &i18n_error_message);
    context.insert("i18n_redirecting_text", &i18n_redirecting_text);
    context.insert("i18n_redirecting_in_text", &i18n_redirecting_in_text);
    context.insert("i18n_seconds_text", &i18n_seconds_text);
}


impl ConnectorRedirectResponse for Paybox {
    fn get_flow_type(
        &self,
        _query_params: &str,
        _json_payload: Option<serde_json::Value>,
        action: PaymentAction,
    ) -> CustomResult<CallConnectorAction, errors::ConnectorError> {
        match action {
            PaymentAction::PSync
            | PaymentAction::CompleteAuthorize
            | PaymentAction::PaymentAuthenticateCompleteAuthorize => {
                Ok(CallConnectorAction::Trigger)
            }
        }
    }
}

impl ConnectorRedirectResponse for for Paybox


pub fn update_storage_scheme(&mut self, storage_scheme: common_enums::MerchantStorageScheme) {
        self.updated_by = Some(storage_scheme.to_string());
    }


impl FutureUsage {
    /// Indicates whether the payment method should be saved for future use or not
    pub fn is_off_session(self) -> bool {
        match self {
            Self::OffSession => true,
            Self::OnSession => false,
        }
    }
}


impl SuccessBasedAlgorithm {
    pub fn new(
        algorithm_id_with_timestamp: DynamicAlgorithmWithTimestamp<
            common_utils::id_type::RoutingId,
        >,
    ) -> Self {
        Self {
            algorithm_id_with_timestamp,
            enabled_feature: DynamicRoutingFeatures::None,
        }
    }
}


impl GetPaymentMethodType for PayLaterData {
    fn get_payment_method_type(&self) -> api_enums::PaymentMethodType {
        match self {
            Self::KlarnaRedirect { .. } => api_enums::PaymentMethodType::Klarna,
            Self::KlarnaSdk { .. } => api_enums::PaymentMethodType::Klarna,
            Self::FlexitiRedirect { .. } => api_enums::PaymentMethodType::Flexiti,
            Self::AffirmRedirect {} => api_enums::PaymentMethodType::Affirm,
            Self::AfterpayClearpayRedirect { .. } => api_enums::PaymentMethodType::AfterpayClearpay,
            Self::PayBrightRedirect {} => api_enums::PaymentMethodType::PayBright,
            Self::WalleyRedirect {} => api_enums::PaymentMethodType::Walley,
            Self::AlmaRedirect {} => api_enums::PaymentMethodType::Alma,
            Self::AtomeRedirect {} => api_enums::PaymentMethodType::Atome,
            Self::BreadpayRedirect {} => api_enums::PaymentMethodType::Breadpay,
        }
    }
}

impl GetPaymentMethodType for for PayLaterData


impl ApiEventMetric for GetFrmFilterRequest {}

impl ApiEventMetric for for GetFrmFilterRequest


pub fn get_refund_id_as_string(&self) -> String {
        self.refund_id.clone()
    }


impl ConnectorValidation for Celero {
    fn validate_connector_against_payment_request(
        &self,
        capture_method: Option<enums::CaptureMethod>,
        _payment_method: enums::PaymentMethod,
        _pmt: Option<enums::PaymentMethodType>,
    ) -> CustomResult<(), errors::ConnectorError> {
        let capture_method = capture_method.unwrap_or_default();

        // CeleroCommerce supports both automatic (sale) and manual (authorize + capture) flows
        let is_capture_method_supported = matches!(
            capture_method,
            enums::CaptureMethod::Automatic
                | enums::CaptureMethod::Manual
                | enums::CaptureMethod::SequentialAutomatic
        );

        if is_capture_method_supported {
            Ok(())
        } else {
            Err(errors::ConnectorError::NotSupported {
                message: capture_method.to_string(),
                connector: self.id(),
            }
            .into())
        }
    }
}


pub async fn mk_add_locker_request_hs(
    jwekey: &settings::Jwekey,
    locker: &settings::Locker,
    payload: &StoreLockerReq,
    locker_choice: api_enums::LockerChoice,
    tenant_id: id_type::TenantId,
    request_id: Option<RequestId>,
) -> CustomResult<services::Request, errors::VaultError> {
    let payload = payload
        .encode_to_vec()
        .change_context(errors::VaultError::RequestEncodingFailed)?;

    let private_key = jwekey.vault_private_key.peek().as_bytes();

    let jws = encryption::jws_sign_payload(&payload, &locker.locker_signing_key_id, private_key)
        .await
        .change_context(errors::VaultError::RequestEncodingFailed)?;

    let jwe_payload = mk_basilisk_req(jwekey, &jws, locker_choice).await?;
    let mut url = match locker_choice {
        api_enums::LockerChoice::HyperswitchCardVault => locker.host.to_owned(),
    };
    url.push_str("/cards/add");
    let mut request = services::Request::new(services::Method::Post, &url);
    request.add_header(headers::CONTENT_TYPE, "application/json".into());
    request.add_header(
        headers::X_TENANT_ID,
        tenant_id.get_string_repr().to_owned().into(),
    );
    if let Some(req_id) = request_id {
        request.add_header(
            headers::X_REQUEST_ID,
            req_id.as_hyphenated().to_string().into(),
        );
    }
    request.set_body(RequestContent::Json(Box::new(jwe_payload)));
    Ok(request)
}


pub struct ToggleDynamicRoutingPath {
    #[schema(value_type = String)]
    pub profile_id: common_utils::id_type::ProfileId,
}


impl api::MandateSetup for Nomupay {}


pub struct DomainTokenData {
        /// The specific token data retrieved from the vault, containing sensitive PII
        pub specific_token_data: SecretSerdeValue,
        /// The type of vault connector being used for token retrieval
        pub vault_connector: VaultConnectors,
    }


pub struct ProcessingInformationResponse {
    payment_solution: Option<String>,
    commerce_indicator: Option<String>,
    commerce_indicator_label: Option<String>,
    authorization_options: Option<AuthorizationOptions>,
    ecommerce_indicator: Option<String>,
}


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

use api_models::payments::AmountFilter;
use async_bb8_diesel::AsyncRunQueryDsl;
use common_utils::errors::CustomResult;
use diesel::{associations::HasTable, BoolExpressionMethods, ExpressionMethods, QueryDsl};
#[cfg(feature = "v1")]
use diesel_models::schema::refund::dsl;
#[cfg(feature = "v2")]
use diesel_models::schema_v2::refund::dsl;
use diesel_models::{
    enums::{Currency, RefundStatus},
    errors,
    query::generics::db_metrics,
    refund::Refund,
};
use error_stack::ResultExt;
use hyperswitch_domain_models::refunds;

use crate::{connection::PgPooledConn, logger};

#[async_trait::async_trait]
pub trait RefundDbExt: Sized {
    #[cfg(feature = "v1")]
    async fn filter_by_constraints(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: &refunds::RefundListConstraints,
        limit: i64,
        offset: i64,
    ) -> CustomResult<Vec<Self>, errors::DatabaseError>;

    #[cfg(feature = "v2")]
    async fn filter_by_constraints(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: refunds::RefundListConstraints,
        limit: i64,
        offset: i64,
    ) -> CustomResult<Vec<Self>, errors::DatabaseError>;

    #[cfg(feature = "v1")]
    async fn filter_by_meta_constraints(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: &common_utils::types::TimeRange,
    ) -> CustomResult<api_models::refunds::RefundListMetaData, errors::DatabaseError>;

    #[cfg(feature = "v1")]
    async fn get_refunds_count(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: &refunds::RefundListConstraints,
    ) -> CustomResult<i64, errors::DatabaseError>;

    #[cfg(feature = "v1")]
    async fn get_refund_status_with_count(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        profile_id_list: Option<Vec<common_utils::id_type::ProfileId>>,
        time_range: &common_utils::types::TimeRange,
    ) -> CustomResult<Vec<(RefundStatus, i64)>, errors::DatabaseError>;

    #[cfg(feature = "v2")]
    async fn get_refunds_count(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: refunds::RefundListConstraints,
    ) -> CustomResult<i64, errors::DatabaseError>;
}

#[async_trait::async_trait]
impl RefundDbExt for Refund {
    #[cfg(feature = "v1")]
    async fn filter_by_constraints(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: &refunds::RefundListConstraints,
        limit: i64,
        offset: i64,
    ) -> CustomResult<Vec<Self>, errors::DatabaseError> {
        let mut filter = <Self as HasTable>::table()
            .filter(dsl::merchant_id.eq(merchant_id.to_owned()))
            .order(dsl::modified_at.desc())
            .into_boxed();
        let mut search_by_pay_or_ref_id = false;

        if let (Some(pid), Some(ref_id)) = (
            &refund_list_details.payment_id,
            &refund_list_details.refund_id,
        ) {
            search_by_pay_or_ref_id = true;
            filter = filter
                .filter(
                    dsl::payment_id
                        .eq(pid.to_owned())
                        .or(dsl::refund_id.eq(ref_id.to_owned())),
                )
                .limit(limit)
                .offset(offset);
        };

        if !search_by_pay_or_ref_id {
            match &refund_list_details.payment_id {
                Some(pid) => {
                    filter = filter.filter(dsl::payment_id.eq(pid.to_owned()));
                }
                None => {
                    filter = filter.limit(limit).offset(offset);
                }
            };
        }
        if !search_by_pay_or_ref_id {
            match &refund_list_details.refund_id {
                Some(ref_id) => {
                    filter = filter.filter(dsl::refund_id.eq(ref_id.to_owned()));
                }
                None => {
                    filter = filter.limit(limit).offset(offset);
                }
            };
        }
        match &refund_list_details.profile_id {
            Some(profile_id) => {
                filter = filter
                    .filter(dsl::profile_id.eq_any(profile_id.to_owned()))
                    .limit(limit)
                    .offset(offset);
            }
            None => {
                filter = filter.limit(limit).offset(offset);
            }
        };

        if let Some(time_range) = refund_list_details.time_range {
            filter = filter.filter(dsl::created_at.ge(time_range.start_time));

            if let Some(end_time) = time_range.end_time {
                filter = filter.filter(dsl::created_at.le(end_time));
            }
        }

        filter = match refund_list_details.amount_filter {
            Some(AmountFilter {
                start_amount: Some(start),
                end_amount: Some(end),
            }) => filter.filter(dsl::refund_amount.between(start, end)),
            Some(AmountFilter {
                start_amount: Some(start),
                end_amount: None,
            }) => filter.filter(dsl::refund_amount.ge(start)),
            Some(AmountFilter {
                start_amount: None,
                end_amount: Some(end),
            }) => filter.filter(dsl::refund_amount.le(end)),
            _ => filter,
        };

        if let Some(connector) = refund_list_details.connector.clone() {
            filter = filter.filter(dsl::connector.eq_any(connector));
        }

        if let Some(merchant_connector_id) = refund_list_details.merchant_connector_id.clone() {
            filter = filter.filter(dsl::merchant_connector_id.eq_any(merchant_connector_id));
        }

        if let Some(filter_currency) = &refund_list_details.currency {
            filter = filter.filter(dsl::currency.eq_any(filter_currency.clone()));
        }

        if let Some(filter_refund_status) = &refund_list_details.refund_status {
            filter = filter.filter(dsl::refund_status.eq_any(filter_refund_status.clone()));
        }

        logger::debug!(query = %diesel::debug_query::<diesel::pg::Pg, _>(&filter).to_string());

        db_metrics::track_database_call::<<Self as HasTable>::Table, _, _>(
            filter.get_results_async(conn),
            db_metrics::DatabaseOperation::Filter,
        )
        .await
        .change_context(errors::DatabaseError::NotFound)
        .attach_printable_lazy(|| "Error filtering records by predicate")
    }

    #[cfg(feature = "v2")]
    async fn filter_by_constraints(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: refunds::RefundListConstraints,
        limit: i64,
        offset: i64,
    ) -> CustomResult<Vec<Self>, errors::DatabaseError> {
        let mut filter = <Self as HasTable>::table()
            .filter(dsl::merchant_id.eq(merchant_id.to_owned()))
            .order(dsl::modified_at.desc())
            .into_boxed();

        if let Some(payment_id) = &refund_list_details.payment_id {
            filter = filter.filter(dsl::payment_id.eq(payment_id.to_owned()));
        }

        if let Some(refund_id) = &refund_list_details.refund_id {
            filter = filter.filter(dsl::id.eq(refund_id.to_owned()));
        }

        if let Some(time_range) = &refund_list_details.time_range {
            filter = filter.filter(dsl::created_at.ge(time_range.start_time));

            if let Some(end_time) = time_range.end_time {
                filter = filter.filter(dsl::created_at.le(end_time));
            }
        }

        filter = match refund_list_details.amount_filter {
            Some(AmountFilter {
                start_amount: Some(start),
                end_amount: Some(end),
            }) => filter.filter(dsl::refund_amount.between(start, end)),
            Some(AmountFilter {
                start_amount: Some(start),
                end_amount: None,
            }) => filter.filter(dsl::refund_amount.ge(start)),
            Some(AmountFilter {
                start_amount: None,
                end_amount: Some(end),
            }) => filter.filter(dsl::refund_amount.le(end)),
            _ => filter,
        };

        if let Some(connector) = refund_list_details.connector {
            filter = filter.filter(dsl::connector.eq_any(connector));
        }

        if let Some(connector_id_list) = refund_list_details.connector_id_list {
            filter = filter.filter(dsl::connector_id.eq_any(connector_id_list));
        }

        if let Some(filter_currency) = refund_list_details.currency {
            filter = filter.filter(dsl::currency.eq_any(filter_currency));
        }

        if let Some(filter_refund_status) = refund_list_details.refund_status {
            filter = filter.filter(dsl::refund_status.eq_any(filter_refund_status));
        }

        filter = filter.limit(limit).offset(offset);

        logger::debug!(query = %diesel::debug_query::<diesel::pg::Pg, _>(&filter).to_string());

        db_metrics::track_database_call::<<Self as HasTable>::Table, _, _>(
            filter.get_results_async(conn),
            db_metrics::DatabaseOperation::Filter,
        )
        .await
        .change_context(errors::DatabaseError::NotFound)
        .attach_printable_lazy(|| "Error filtering records by predicate")

        // todo!()
    }

    #[cfg(feature = "v1")]
    async fn filter_by_meta_constraints(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: &common_utils::types::TimeRange,
    ) -> CustomResult<api_models::refunds::RefundListMetaData, errors::DatabaseError> {
        let start_time = refund_list_details.start_time;

        let end_time = refund_list_details
            .end_time
            .unwrap_or_else(common_utils::date_time::now);

        let filter = <Self as HasTable>::table()
            .filter(dsl::merchant_id.eq(merchant_id.to_owned()))
            .order(dsl::modified_at.desc())
            .filter(dsl::created_at.ge(start_time))
            .filter(dsl::created_at.le(end_time));

        let filter_connector: Vec<String> = filter
            .clone()
            .select(dsl::connector)
            .distinct()
            .order_by(dsl::connector.asc())
            .get_results_async(conn)
            .await
            .change_context(errors::DatabaseError::Others)
            .attach_printable("Error filtering records by connector")?;

        let filter_currency: Vec<Currency> = filter
            .clone()
            .select(dsl::currency)
            .distinct()
            .order_by(dsl::currency.asc())
            .get_results_async(conn)
            .await
            .change_context(errors::DatabaseError::Others)
            .attach_printable("Error filtering records by currency")?;

        let filter_status: Vec<RefundStatus> = filter
            .select(dsl::refund_status)
            .distinct()
            .order_by(dsl::refund_status.asc())
            .get_results_async(conn)
            .await
            .change_context(errors::DatabaseError::Others)
            .attach_printable("Error filtering records by refund status")?;

        let meta = api_models::refunds::RefundListMetaData {
            connector: filter_connector,
            currency: filter_currency,
            refund_status: filter_status,
        };

        Ok(meta)
    }

    #[cfg(feature = "v1")]
    async fn get_refunds_count(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: &refunds::RefundListConstraints,
    ) -> CustomResult<i64, errors::DatabaseError> {
        let mut filter = <Self as HasTable>::table()
            .count()
            .filter(dsl::merchant_id.eq(merchant_id.to_owned()))
            .into_boxed();

        let mut search_by_pay_or_ref_id = false;

        if let (Some(pid), Some(ref_id)) = (
            &refund_list_details.payment_id,
            &refund_list_details.refund_id,
        ) {
            search_by_pay_or_ref_id = true;
            filter = filter.filter(
                dsl::payment_id
                    .eq(pid.to_owned())
                    .or(dsl::refund_id.eq(ref_id.to_owned())),
            );
        };

        if !search_by_pay_or_ref_id {
            if let Some(pay_id) = &refund_list_details.payment_id {
                filter = filter.filter(dsl::payment_id.eq(pay_id.to_owned()));
            }
        }

        if !search_by_pay_or_ref_id {
            if let Some(ref_id) = &refund_list_details.refund_id {
                filter = filter.filter(dsl::refund_id.eq(ref_id.to_owned()));
            }
        }
        if let Some(profile_id) = &refund_list_details.profile_id {
            filter = filter.filter(dsl::profile_id.eq_any(profile_id.to_owned()));
        }

        if let Some(time_range) = refund_list_details.time_range {
            filter = filter.filter(dsl::created_at.ge(time_range.start_time));

            if let Some(end_time) = time_range.end_time {
                filter = filter.filter(dsl::created_at.le(end_time));
            }
        }

        filter = match refund_list_details.amount_filter {
            Some(AmountFilter {
                start_amount: Some(start),
                end_amount: Some(end),
            }) => filter.filter(dsl::refund_amount.between(start, end)),
            Some(AmountFilter {
                start_amount: Some(start),
                end_amount: None,
            }) => filter.filter(dsl::refund_amount.ge(start)),
            Some(AmountFilter {
                start_amount: None,
                end_amount: Some(end),
            }) => filter.filter(dsl::refund_amount.le(end)),
            _ => filter,
        };

        if let Some(connector) = refund_list_details.connector.clone() {
            filter = filter.filter(dsl::connector.eq_any(connector));
        }

        if let Some(merchant_connector_id) = refund_list_details.merchant_connector_id.clone() {
            filter = filter.filter(dsl::merchant_connector_id.eq_any(merchant_connector_id))
        }

        if let Some(filter_currency) = &refund_list_details.currency {
            filter = filter.filter(dsl::currency.eq_any(filter_currency.clone()));
        }

        if let Some(filter_refund_status) = &refund_list_details.refund_status {
            filter = filter.filter(dsl::refund_status.eq_any(filter_refund_status.clone()));
        }

        logger::debug!(query = %diesel::debug_query::<diesel::pg::Pg, _>(&filter).to_string());

        filter
            .get_result_async::<i64>(conn)
            .await
            .change_context(errors::DatabaseError::NotFound)
            .attach_printable_lazy(|| "Error filtering count of refunds")
    }

    #[cfg(feature = "v2")]
    async fn get_refunds_count(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: refunds::RefundListConstraints,
    ) -> CustomResult<i64, errors::DatabaseError> {
        let mut filter = <Self as HasTable>::table()
            .count()
            .filter(dsl::merchant_id.eq(merchant_id.to_owned()))
            .into_boxed();

        if let Some(payment_id) = &refund_list_details.payment_id {
            filter = filter.filter(dsl::payment_id.eq(payment_id.to_owned()));
        }

        if let Some(refund_id) = &refund_list_details.refund_id {
            filter = filter.filter(dsl::id.eq(refund_id.to_owned()));
        }

        if let Some(time_range) = refund_list_details.time_range {
            filter = filter.filter(dsl::created_at.ge(time_range.start_time));

            if let Some(end_time) = time_range.end_time {
                filter = filter.filter(dsl::created_at.le(end_time));
            }
        }

        filter = match refund_list_details.amount_filter {
            Some(AmountFilter {
                start_amount: Some(start),
                end_amount: Some(end),
            }) => filter.filter(dsl::refund_amount.between(start, end)),
            Some(AmountFilter {
                start_amount: Some(start),
                end_amount: None,
            }) => filter.filter(dsl::refund_amount.ge(start)),
            Some(AmountFilter {
                start_amount: None,
                end_amount: Some(end),
            }) => filter.filter(dsl::refund_amount.le(end)),
            _ => filter,
        };

        if let Some(connector) = refund_list_details.connector {
            filter = filter.filter(dsl::connector.eq_any(connector));
        }

        if let Some(connector_id_list) = refund_list_details.connector_id_list {
            filter = filter.filter(dsl::connector_id.eq_any(connector_id_list));
        }

        if let Some(filter_currency) = refund_list_details.currency {
            filter = filter.filter(dsl::currency.eq_any(filter_currency));
        }

        if let Some(filter_refund_status) = refund_list_details.refund_status {
            filter = filter.filter(dsl::refund_status.eq_any(filter_refund_status));
        }

        logger::debug!(query = %diesel::debug_query::<diesel::pg::Pg, _>(&filter).to_string());

        filter
            .get_result_async::<i64>(conn)
            .await
            .change_context(errors::DatabaseError::NotFound)
            .attach_printable_lazy(|| "Error filtering count of refunds")
    }

    #[cfg(feature = "v1")]
    async fn get_refund_status_with_count(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        profile_id_list: Option<Vec<common_utils::id_type::ProfileId>>,
        time_range: &common_utils::types::TimeRange,
    ) -> CustomResult<Vec<(RefundStatus, i64)>, errors::DatabaseError> {
        let mut query = <Self as HasTable>::table()
            .group_by(dsl::refund_status)
            .select((dsl::refund_status, diesel::dsl::count_star()))
            .filter(dsl::merchant_id.eq(merchant_id.to_owned()))
            .into_boxed();

        if let Some(profile_id) = profile_id_list {
            query = query.filter(dsl::profile_id.eq_any(profile_id));
        }

        query = query.filter(dsl::created_at.ge(time_range.start_time));

        query = match time_range.end_time {
            Some(ending_at) => query.filter(dsl::created_at.le(ending_at)),
            None => query,
        };

        logger::debug!(filter = %diesel::debug_query::<diesel::pg::Pg,_>(&query).to_string());

        db_metrics::track_database_call::<<Self as HasTable>::Table, _, _>(
            query.get_results_async::<(RefundStatus, i64)>(conn),
            db_metrics::DatabaseOperation::Count,
        )
        .await
        .change_context(errors::DatabaseError::NotFound)
        .attach_printable_lazy(|| "Error filtering status count of refunds")
    }
}


pub struct OpayoCard {
    name: Secret<String>,
    number: cards::CardNumber,
    expiry_month: Secret<String>,
    expiry_year: Secret<String>,
    cvc: Secret<String>,
    complete: bool,
}


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


impl Default for Filter {
    fn default() -> Self {
        Self::NestedFilter(FilterCombinator::default(), Vec::new())
    }
}


/// Create a new event context.
    pub fn new(message_sink: A) -> Self {
        Self {
            message_sink: Arc::new(message_sink),
            metadata: HashMap::new(),
        }
    }


pub fn postgres_url(&self) -> String {
        format!(
            "postgres://{}:{}@{}:{}/{}",
            self.username, self.password, self.host, self.port, self.dbname
        )
    }


pub struct LogFile {
    /// Whether you want to store log in log files.
    pub enabled: bool,
    /// Where to store log files.
    pub path: String,
    /// Name of log file without suffix.
    pub file_name: String,
    /// What gets into log files.
    pub level: Level,
    /// Directive which sets the log level for one or more crates/modules.
    pub filtering_directive: Option<String>,
    // pub do_async: bool, // is not used
    // pub rotation: u16,
}


pub struct DlocalPaymentsSyncRequest {
    pub authz_id: String,
}


impl api::Refund for Opennode {}


pub struct NoonPayPal {
    return_url: String,
}


Documentation: api-reference/v1/merchant-connector-account/merchant-connector--retrieve.mdx
# Type: Doc File

---
openapi: get /accounts/{account_id}/connectors/{connector_id}
---


pub struct ProFeatureRequest {
    pub recipient_email: domain::UserEmail,
    pub feature_name: String,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub user_name: domain::UserName,
    pub user_email: domain::UserEmail,
    pub subject: String,
    pub theme_id: Option<String>,
    pub theme_config: EmailThemeConfig,
}


pub fn number_array_value(input: &str) -> ParseResult<&str, ast::ValueType> {
    fn num_minor_unit(input: &str) -> ParseResult<&str, MinorUnit> {
        combinator::map(num_i64, MinorUnit::new)(input)
    }
    let many_with_comma = multi::many0(sequence::preceded(
        skip_ws(complete::tag(",")),
        skip_ws(num_minor_unit),
    ));

    let full_sequence = sequence::pair(skip_ws(num_minor_unit), many_with_comma);

    error::context(
        "number_array_value",
        combinator::map(
            sequence::delimited(
                skip_ws(complete::tag("(")),
                full_sequence,
                skip_ws(complete::tag(")")),
            ),
            |tup: (MinorUnit, Vec<MinorUnit>)| {
                let mut rest = tup.1;
                rest.insert(0, tup.0);
                ast::ValueType::NumberArray(rest)
            },
        ),
    )(input)
}


pub async fn generic_insert<T, V, R>(conn: &PgPooledConn, values: V) -> StorageResult<R>
where
    T: HasTable<Table = T> + Table + 'static + Debug,
    V: Debug + Insertable<T>,
    <T as QuerySource>::FromClause: QueryFragment<Pg> + Debug,
    <V as Insertable<T>>::Values: CanInsertInSingleQuery<Pg> + QueryFragment<Pg> + 'static,
    InsertStatement<T, <V as Insertable<T>>::Values>:
        AsQuery + LoadQuery<'static, PgConnection, R> + Send,
    R: Send + 'static,
{
    let debug_values = format!("{values:?}");

    let query = diesel::insert_into(<T as HasTable>::table()).values(values);
    logger::debug!(query = %debug_query::<Pg, _>(&query).to_string());

    match track_database_call::<T, _, _>(query.get_result_async(conn), DatabaseOperation::Insert)
        .await
    {
        Ok(value) => Ok(value),
        Err(err) => match err {
            DieselError::DatabaseError(diesel::result::DatabaseErrorKind::UniqueViolation, _) => {
                Err(report!(err)).change_context(errors::DatabaseError::UniqueViolation)
            }
            _ => Err(report!(err)).change_context(errors::DatabaseError::Others),
        },
    }
    .attach_printable_lazy(|| format!("Error while inserting {debug_values}"))
}


impl api::PaymentSync for Paysafe {}


pub struct SinglePurposeOrLoginTokenAuth(pub TokenPurpose);


pub fn new(
        tenant_id: common_utils::id_type::TenantId,
        merchant_id: common_utils::id_type::MerchantId,
        event_id: String,
        event_type: OutgoingWebhookEventType,
        content: Option<OutgoingWebhookEventContent>,
        error: Option<Value>,
        initial_attempt_id: Option<String>,
        status_code: Option<u16>,
        delivery_attempt: Option<WebhookDeliveryAttempt>,
    ) -> Self {
        Self {
            tenant_id,
            merchant_id,
            event_id,
            event_type,
            content,
            is_error: error.is_some(),
            error,
            created_at_timestamp: OffsetDateTime::now_utc().unix_timestamp_nanos() / 1_000_000,
            initial_attempt_id,
            status_code,
            delivery_attempt,
        }
    }


impl AuthorizationUpdateInternal {
    pub fn create_authorization(self, source: Authorization) -> Authorization {
        Authorization {
            status: self.status.unwrap_or(source.status),
            error_code: self.error_code.or(source.error_code),
            error_message: self.error_message.or(source.error_message),
            modified_at: self.modified_at.unwrap_or(common_utils::date_time::now()),
            connector_authorization_id: self
                .connector_authorization_id
                .or(source.connector_authorization_id),
            ..source
        }
    }
}


pub fn from_storage(intent: &'a PaymentIntent, infra_values: Option<Value>) -> Self {
        let PaymentIntent {
            id,
            merchant_id,
            status,
            amount_details,
            amount_captured,
            customer_id,
            description,
            return_url,
            metadata,
            statement_descriptor,
            created_at,
            modified_at,
            last_synced,
            setup_future_usage,
            active_attempt_id,
            order_details,
            allowed_payment_method_types,
            connector_metadata,
            feature_metadata,
            attempt_count,
            profile_id,
            payment_link_id,
            frm_merchant_decision,
            updated_by,
            request_incremental_authorization,
            split_txns_enabled,
            authorization_count,
            session_expiry,
            request_external_three_ds_authentication,
            frm_metadata,
            customer_details,
            merchant_reference_id,
            billing_address,
            shipping_address,
            capture_method,
            authentication_type,
            prerouting_algorithm,
            organization_id,
            enable_payment_link,
            apply_mit_exemption,
            customer_present,
            payment_link_config,
            routing_algorithm_id,
            split_payments,
            force_3ds_challenge,
            force_3ds_challenge_trigger,
            processor_merchant_id,
            created_by,
            is_iframe_redirection_enabled,
            is_payment_id_from_merchant,
        } = intent;

        Self {
            payment_id: id,
            merchant_id,
            status: *status,
            amount: amount_details.order_amount,
            currency: amount_details.currency,
            amount_captured: *amount_captured,
            customer_id: customer_id.as_ref(),
            description: description.as_ref(),
            return_url: return_url.as_ref(),
            metadata: metadata.as_ref(),
            statement_descriptor: statement_descriptor.as_ref(),
            created_at: created_at.assume_utc(),
            modified_at: modified_at.assume_utc(),
            last_synced: last_synced.map(|t| t.assume_utc()),
            setup_future_usage: *setup_future_usage,
            off_session: setup_future_usage.is_off_session(),
            active_attempt_id: active_attempt_id.as_ref(),
            attempt_count: *attempt_count,
            profile_id,
            customer_email: None,
            feature_metadata: feature_metadata.as_ref(),
            organization_id,
            order_details: order_details.as_ref(),
            allowed_payment_method_types: allowed_payment_method_types.as_ref(),
            connector_metadata: connector_metadata.as_ref(),
            payment_link_id: payment_link_id.as_ref(),
            updated_by,
            surcharge_applicable: None,
            request_incremental_authorization: *request_incremental_authorization,
            split_txns_enabled: *split_txns_enabled,
            authorization_count: *authorization_count,
            session_expiry: session_expiry.assume_utc(),
            request_external_three_ds_authentication: *request_external_three_ds_authentication,
            frm_metadata: frm_metadata
                .as_ref()
                .map(|frm_metadata| frm_metadata.as_ref()),
            customer_details: customer_details
                .as_ref()
                .map(|customer_details| customer_details.get_inner().as_ref()),
            shipping_cost: amount_details.shipping_cost,
            tax_details: amount_details.tax_details.clone(),
            skip_external_tax_calculation: amount_details.get_external_tax_action_as_bool(),
            request_extended_authorization: None,
            psd2_sca_exemption_type: None,
            split_payments: split_payments.as_ref(),
            platform_merchant_id: None,
            force_3ds_challenge: *force_3ds_challenge,
            force_3ds_challenge_trigger: *force_3ds_challenge_trigger,
            processor_merchant_id,
            created_by: created_by.as_ref(),
            is_iframe_redirection_enabled: *is_iframe_redirection_enabled,
            merchant_reference_id: merchant_reference_id.as_ref(),
            billing_address: billing_address
                .as_ref()
                .map(|billing_address| Secret::new(billing_address.get_inner())),
            shipping_address: shipping_address
                .as_ref()
                .map(|shipping_address| Secret::new(shipping_address.get_inner())),
            capture_method: *capture_method,
            authentication_type: *authentication_type,
            prerouting_algorithm: prerouting_algorithm.as_ref(),
            surcharge_amount: amount_details.surcharge_amount,
            tax_on_surcharge: amount_details.tax_on_surcharge,
            frm_merchant_decision: *frm_merchant_decision,
            enable_payment_link: *enable_payment_link,
            apply_mit_exemption: *apply_mit_exemption,
            customer_present: *customer_present,
            routing_algorithm_id: routing_algorithm_id.as_ref(),
            payment_link_config: payment_link_config.as_ref(),
            infra_values,
        }
    }