pub async fn list_blocked_payment_methods(
    state: web::Data<AppState>,
    req: HttpRequest,
    query_payload: web::Query<api_blocklist::ListBlocklistQuery>,
) -> HttpResponse {
    let flow = Flow::ListBlocklist;
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        query_payload.into_inner(),
        |state, auth: auth::AuthenticationData, query, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            blocklist::list_blocklist_entries(state, merchant_context, query)
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuth {
                permission: Permission::MerchantAccountRead,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


impl api::MandateSetup for HyperswitchVault {}

impl api::MandateSetup for for HyperswitchVault


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


impl api::PaymentAuthorize for Iatapay {}

impl api::PaymentAuthorize for for Iatapay


impl Action {
    #[allow(clippy::too_many_arguments)]
    pub async fn execute_payment(
        state: &SessionState,
        _merchant_id: &id_type::MerchantId,
        payment_intent: &PaymentIntent,
        process: &storage::ProcessTracker,
        profile: &domain::Profile,
        merchant_context: domain::MerchantContext,
        revenue_recovery_payment_data: &storage::revenue_recovery::RevenueRecoveryPaymentData,
        revenue_recovery_metadata: &PaymentRevenueRecoveryMetadata,
    ) -> RecoveryResult<Self> {
        let connector_customer_id = payment_intent
            .extract_connector_customer_id_from_payment_intent()
            .change_context(errors::RecoveryError::ValueNotFound)
            .attach_printable("Failed to extract customer ID from payment intent")?;

        let tracking_data: pcr::RevenueRecoveryWorkflowTrackingData =
            serde_json::from_value(process.tracking_data.clone())
                .change_context(errors::RecoveryError::ValueNotFound)
                .attach_printable("Failed to deserialize the tracking data from process tracker")?;

        let last_token_used = payment_intent
            .feature_metadata
            .as_ref()
            .and_then(|fm| fm.payment_revenue_recovery_metadata.as_ref())
            .map(|rr| {
                rr.billing_connector_payment_details
                    .payment_processor_token
                    .clone()
            });

        let recovery_algorithm = tracking_data.revenue_recovery_retry;

        let scheduled_token = match storage::revenue_recovery_redis_operation::RedisTokenManager::get_token_based_on_retry_type(
            state,
            &connector_customer_id,
            recovery_algorithm,
            last_token_used.as_deref(),
        )
        .await {
            Ok(scheduled_token_opt) => scheduled_token_opt,
            Err(e) => {
                logger::error!(
                    error = ?e,
                    connector_customer_id = %connector_customer_id,
                    "Failed to get PSP token status"
                );
                None
            }
        };

        match scheduled_token {
            Some(scheduled_token) => {
                let response = revenue_recovery_core::api::call_proxy_api(
                    state,
                    payment_intent,
                    revenue_recovery_payment_data,
                    revenue_recovery_metadata,
                    &scheduled_token
                        .payment_processor_token_details
                        .payment_processor_token,
                )
                .await;

                let recovery_payment_intent =
                    hyperswitch_domain_models::revenue_recovery::RecoveryPaymentIntent::from(
                        payment_intent,
                    );

                // handle proxy api's response
                match response {
                    Ok(payment_data) => match payment_data.payment_attempt.status.foreign_into() {
                        RevenueRecoveryPaymentsAttemptStatus::Succeeded => {
                            let recovery_payment_attempt =
                                hyperswitch_domain_models::revenue_recovery::RecoveryPaymentAttempt::from(
                                    &payment_data.payment_attempt,
                                );

                            let recovery_payment_tuple =
                                recovery_incoming_flow::RecoveryPaymentTuple::new(
                                    &recovery_payment_intent,
                                    &recovery_payment_attempt,
                                );

                            // publish events to kafka
                            if let Err(e) = recovery_incoming_flow::RecoveryPaymentTuple::publish_revenue_recovery_event_to_kafka(
                            state,
                            &recovery_payment_tuple,
                            Some(process.retry_count+1)
                        )
                        .await{
                            router_env::logger::error!(
                                "Failed to publish revenue recovery event to kafka: {:?}",
                                e
                            );
                        };

                            let is_hard_decline = revenue_recovery::check_hard_decline(
                                state,
                                &payment_data.payment_attempt,
                            )
                            .await
                            .ok();

                            // update the status of token in redis
                            let _update_error_code = storage::revenue_recovery_redis_operation::RedisTokenManager::update_payment_processor_token_error_code_from_process_tracker(
                                state,
                                &connector_customer_id,
                                &None,
                                &is_hard_decline,
                                Some(&scheduled_token.payment_processor_token_details.payment_processor_token),
                            )
                            .await;

                            // unlocking the token
                            let _unlock_the_connector_customer_id = storage::revenue_recovery_redis_operation::RedisTokenManager::unlock_connector_customer_status(
                    state,
                    &connector_customer_id,
                )
                .await;

                            Ok(Self::SuccessfulPayment(
                                payment_data.payment_attempt.clone(),
                            ))
                        }
                        RevenueRecoveryPaymentsAttemptStatus::Failed => {
                            let recovery_payment_attempt =
                                hyperswitch_domain_models::revenue_recovery::RecoveryPaymentAttempt::from(
                                    &payment_data.payment_attempt,
                                );

                            let recovery_payment_tuple =
                                recovery_incoming_flow::RecoveryPaymentTuple::new(
                                    &recovery_payment_intent,
                                    &recovery_payment_attempt,
                                );

                            // publish events to kafka
                            if let Err(e) = recovery_incoming_flow::RecoveryPaymentTuple::publish_revenue_recovery_event_to_kafka(
                                state,
                                &recovery_payment_tuple,
                                Some(process.retry_count+1)
                            )
                            .await{
                                router_env::logger::error!(
                                    "Failed to publish revenue recovery event to kafka: {:?}",
                                    e
                                );
                            };

                            let error_code = payment_data
                                .payment_attempt
                                .clone()
                                .error
                                .map(|error| error.code);

                            let is_hard_decline = revenue_recovery::check_hard_decline(
                                state,
                                &payment_data.payment_attempt,
                            )
                            .await
                            .ok();

                            let _update_connector_customer_id = storage::revenue_recovery_redis_operation::RedisTokenManager::update_payment_processor_token_error_code_from_process_tracker(
                                state,
                                &connector_customer_id,
                                &error_code,
                                &is_hard_decline,
                                Some(&scheduled_token
                                    .payment_processor_token_details
                                    .payment_processor_token)
                                    ,
                            )
                            .await;

                            // unlocking the token
                            let _unlock_connector_customer_id = storage::revenue_recovery_redis_operation::RedisTokenManager::unlock_connector_customer_status(
                                state,
                                &connector_customer_id,
                            )
                            .await;

                            // Reopen calculate workflow on payment failure
                            reopen_calculate_workflow_on_payment_failure(
                                state,
                                process,
                                profile,
                                merchant_context,
                                payment_intent,
                                revenue_recovery_payment_data,
                            )
                            .await?;

                            // Return terminal failure to finish the current execute workflow
                            Ok(Self::TerminalFailure(payment_data.payment_attempt.clone()))
                        }

                        RevenueRecoveryPaymentsAttemptStatus::Processing => {
                            Ok(Self::SyncPayment(payment_data.payment_attempt.clone()))
                        }
                        RevenueRecoveryPaymentsAttemptStatus::InvalidStatus(action) => {
                            logger::info!(?action, "Invalid Payment Status For PCR Payment");
                            Ok(Self::ManualReviewAction)
                        }
                    },
                    Err(err) =>
                    // check for an active attempt being constructed or not
                    {
                        logger::error!(execute_payment_res=?err);
                        Ok(Self::ReviewPayment)
                    }
                }
            }
            None => {
                let response = revenue_recovery_core::api::call_psync_api(
                    state,
                    payment_intent.get_id(),
                    revenue_recovery_payment_data,
                )
                .await;

                let payment_status_data = response
                    .change_context(errors::RecoveryError::PaymentCallFailed)
                    .attach_printable("Error while executing the Psync call")?;

                let payment_attempt = payment_status_data.payment_attempt;

                logger::info!(
                    process_id = %process.id,
                    connector_customer_id = %connector_customer_id,
                    "No token available, finishing CALCULATE_WORKFLOW"
                );

                state
                    .store
                    .as_scheduler()
                    .finish_process_with_business_status(
                        process.clone(),
                        business_status::CALCULATE_WORKFLOW_FINISH,
                    )
                    .await
                    .change_context(errors::RecoveryError::ProcessTrackerFailure)
                    .attach_printable("Failed to finish CALCULATE_WORKFLOW")?;

                logger::info!(
                    process_id = %process.id,
                    connector_customer_id = %connector_customer_id,
                    "CALCULATE_WORKFLOW finished successfully"
                );
                Ok(Self::TerminalFailure(payment_attempt.clone()))
            }
        }
    }

    pub async fn execute_payment_task_response_handler(
        &self,
        state: &SessionState,
        payment_intent: &PaymentIntent,
        execute_task_process: &storage::ProcessTracker,
        revenue_recovery_payment_data: &storage::revenue_recovery::RevenueRecoveryPaymentData,
        revenue_recovery_metadata: &mut PaymentRevenueRecoveryMetadata,
    ) -> Result<(), errors::ProcessTrackerError> {
        logger::info!("Entering execute_payment_task_response_handler");

        let db = &*state.store;
        match self {
            Self::SyncPayment(payment_attempt) => {
                revenue_recovery_core::insert_psync_pcr_task_to_pt(
                    revenue_recovery_payment_data.billing_mca.get_id().clone(),
                    db,
                    revenue_recovery_payment_data
                        .merchant_account
                        .get_id()
                        .to_owned(),
                    payment_intent.id.clone(),
                    revenue_recovery_payment_data.profile.get_id().to_owned(),
                    payment_attempt.id.clone(),
                    storage::ProcessTrackerRunner::PassiveRecoveryWorkflow,
                    revenue_recovery_payment_data.retry_algorithm,
                )
                .await
                .change_context(errors::RecoveryError::ProcessTrackerFailure)
                .attach_printable("Failed to create a psync workflow in the process tracker")?;

                db.as_scheduler()
                    .finish_process_with_business_status(
                        execute_task_process.clone(),
                        business_status::EXECUTE_WORKFLOW_COMPLETE_FOR_PSYNC,
                    )
                    .await
                    .change_context(errors::RecoveryError::ProcessTrackerFailure)
                    .attach_printable("Failed to update the process tracker")?;
                Ok(())
            }

            Self::RetryPayment(schedule_time) => {
                db.as_scheduler()
                    .retry_process(execute_task_process.clone(), *schedule_time)
                    .await?;

                // update the connector payment transmission field to Unsuccessful and unset active attempt id
                revenue_recovery_metadata.set_payment_transmission_field_for_api_request(
                    enums::PaymentConnectorTransmission::ConnectorCallUnsuccessful,
                );

                let payment_update_req =
                PaymentsUpdateIntentRequest::update_feature_metadata_and_active_attempt_with_api(
                    payment_intent
                        .feature_metadata
                        .clone()
                        .unwrap_or_default()
                        .convert_back()
                        .set_payment_revenue_recovery_metadata_using_api(
                            revenue_recovery_metadata.clone(),
                        ),
                    api_enums::UpdateActiveAttempt::Unset,
                );
                logger::info!(
                    "Call made to payments update intent api , with the request body {:?}",
                    payment_update_req
                );
                revenue_recovery_core::api::update_payment_intent_api(
                    state,
                    payment_intent.id.clone(),
                    revenue_recovery_payment_data,
                    payment_update_req,
                )
                .await
                .change_context(errors::RecoveryError::PaymentCallFailed)?;
                Ok(())
            }
            Self::TerminalFailure(payment_attempt) => {
                // update the connector payment transmission field to Unsuccessful and unset active attempt id
                revenue_recovery_metadata.set_payment_transmission_field_for_api_request(
                    enums::PaymentConnectorTransmission::ConnectorCallUnsuccessful,
                );

                let payment_update_req =
                PaymentsUpdateIntentRequest::update_feature_metadata_and_active_attempt_with_api(
                    payment_intent
                        .feature_metadata
                        .clone()
                        .unwrap_or_default()
                        .convert_back()
                        .set_payment_revenue_recovery_metadata_using_api(
                            revenue_recovery_metadata.clone(),
                        ),
                    api_enums::UpdateActiveAttempt::Unset,
                );
                logger::info!(
                    "Call made to payments update intent api , with the request body {:?}",
                    payment_update_req
                );
                revenue_recovery_core::api::update_payment_intent_api(
                    state,
                    payment_intent.id.clone(),
                    revenue_recovery_payment_data,
                    payment_update_req,
                )
                .await
                .change_context(errors::RecoveryError::PaymentCallFailed)?;

                db.as_scheduler()
                    .finish_process_with_business_status(
                        execute_task_process.clone(),
                        business_status::EXECUTE_WORKFLOW_FAILURE,
                    )
                    .await
                    .change_context(errors::RecoveryError::ProcessTrackerFailure)
                    .attach_printable("Failed to update the process tracker")?;
                // TODO: Add support for retrying failed outgoing recordback webhooks
                Ok(())
            }
            Self::SuccessfulPayment(payment_attempt) => {
                db.as_scheduler()
                    .finish_process_with_business_status(
                        execute_task_process.clone(),
                        business_status::EXECUTE_WORKFLOW_COMPLETE,
                    )
                    .await
                    .change_context(errors::RecoveryError::ProcessTrackerFailure)
                    .attach_printable("Failed to update the process tracker")?;
                // Record back to billing connector for terminal status
                // TODO: Add support for retrying failed outgoing recordback webhooks
                record_back_to_billing_connector(
                    state,
                    payment_attempt,
                    payment_intent,
                    &revenue_recovery_payment_data.billing_mca,
                )
                .await
                .change_context(errors::RecoveryError::RecordBackToBillingConnectorFailed)
                .attach_printable("Failed to update the process tracker")?;
                Ok(())
            }
            Self::ReviewPayment => {
                // requeue the process tracker in case of error response
                let pt_update = storage::ProcessTrackerUpdate::StatusUpdate {
                    status: enums::ProcessTrackerStatus::Pending,
                    business_status: Some(String::from(business_status::EXECUTE_WORKFLOW_REQUEUE)),
                };
                db.as_scheduler()
                    .update_process(execute_task_process.clone(), pt_update)
                    .await?;
                Ok(())
            }
            Self::ManualReviewAction => {
                logger::debug!("Invalid Payment Status For PCR Payment");
                let pt_update = storage::ProcessTrackerUpdate::StatusUpdate {
                    status: enums::ProcessTrackerStatus::Review,
                    business_status: Some(String::from(business_status::EXECUTE_WORKFLOW_COMPLETE)),
                };
                // update the process tracker status as Review
                db.as_scheduler()
                    .update_process(execute_task_process.clone(), pt_update)
                    .await?;
                Ok(())
            }
        }
    }

    pub async fn payment_sync_call(
        state: &SessionState,
        revenue_recovery_payment_data: &storage::revenue_recovery::RevenueRecoveryPaymentData,
        payment_intent: &PaymentIntent,
        process: &storage::ProcessTracker,
        profile: &domain::Profile,
        merchant_context: domain::MerchantContext,
        payment_attempt: PaymentAttempt,
    ) -> RecoveryResult<Self> {
        logger::info!("Entering payment_sync_call");

        let response = revenue_recovery_core::api::call_psync_api(
            state,
            payment_intent.get_id(),
            revenue_recovery_payment_data,
        )
        .await;
        let used_token = get_payment_processor_token_id_from_payment_attempt(&payment_attempt);

        match response {
            Ok(_payment_data) => match payment_attempt.status.foreign_into() {
                RevenueRecoveryPaymentsAttemptStatus::Succeeded => {
                    let connector_customer_id = payment_intent
                        .extract_connector_customer_id_from_payment_intent()
                        .change_context(errors::RecoveryError::ValueNotFound)
                        .attach_printable("Failed to extract customer ID from payment intent")?;

                    let is_hard_decline =
                        revenue_recovery::check_hard_decline(state, &payment_attempt)
                            .await
                            .ok();

                    // update the status of token in redis
                    let _update_error_code = storage::revenue_recovery_redis_operation::RedisTokenManager::update_payment_processor_token_error_code_from_process_tracker(
                    state,
                    &connector_customer_id,
                    &None,
                    &is_hard_decline,
                    used_token.as_deref(),
                )
                .await;

                    // unlocking the token
                    let _unlock_the_connector_customer_id = storage::revenue_recovery_redis_operation::RedisTokenManager::unlock_connector_customer_status(
                    state,
                    &connector_customer_id,
                )
                .await;

                    Ok(Self::SuccessfulPayment(payment_attempt))
                }
                RevenueRecoveryPaymentsAttemptStatus::Failed => {
                    let connector_customer_id = payment_intent
                        .extract_connector_customer_id_from_payment_intent()
                        .change_context(errors::RecoveryError::ValueNotFound)
                        .attach_printable("Failed to extract customer ID from payment intent")?;

                    let error_code = payment_attempt.clone().error.map(|error| error.code);

                    let is_hard_decline =
                        revenue_recovery::check_hard_decline(state, &payment_attempt)
                            .await
                            .ok();

                    let _update_error_code = storage::revenue_recovery_redis_operation::RedisTokenManager::update_payment_processor_token_error_code_from_process_tracker(
                            state,
                            &connector_customer_id,
                            &error_code,
                            &is_hard_decline,
                            used_token.as_deref(),
                        )
                        .await;

                    // unlocking the token
                    let _unlock_connector_customer_id = storage::revenue_recovery_redis_operation::RedisTokenManager::unlock_connector_customer_status(
                        state,
                        &connector_customer_id,
                    )
                    .await;

                    // Reopen calculate workflow on payment failure
                    reopen_calculate_workflow_on_payment_failure(
                        state,
                        process,
                        profile,
                        merchant_context,
                        payment_intent,
                        revenue_recovery_payment_data,
                    )
                    .await?;

                    Ok(Self::TerminalFailure(payment_attempt.clone()))
                }

                RevenueRecoveryPaymentsAttemptStatus::Processing => {
                    Ok(Self::SyncPayment(payment_attempt))
                }
                RevenueRecoveryPaymentsAttemptStatus::InvalidStatus(action) => {
                    logger::info!(?action, "Invalid Payment Status For PCR PSync Payment");
                    Ok(Self::ManualReviewAction)
                }
            },
            Err(err) =>
            // if there is an error while psync we create a new Review Task
            {
                logger::error!(sync_payment_response=?err);
                Ok(Self::ReviewPayment)
            }
        }
    }
    pub async fn psync_response_handler(
        &self,
        state: &SessionState,
        payment_intent: &PaymentIntent,
        psync_task_process: &storage::ProcessTracker,
        revenue_recovery_metadata: &mut PaymentRevenueRecoveryMetadata,
        revenue_recovery_payment_data: &storage::revenue_recovery::RevenueRecoveryPaymentData,
    ) -> Result<(), errors::ProcessTrackerError> {
        logger::info!("Entering psync_response_handler");

        let db = &*state.store;
        match self {
            Self::SyncPayment(payment_attempt) => {
                //  get a schedule time for psync
                // and retry the process if there is a schedule time
                // if None mark the pt status as Retries Exceeded and finish the task
                payment_sync::retry_sync_task(
                    db,
                    revenue_recovery_metadata.connector.to_string(),
                    revenue_recovery_payment_data
                        .merchant_account
                        .get_id()
                        .clone(),
                    psync_task_process.clone(),
                )
                .await?;
                Ok(())
            }

            Self::RetryPayment(schedule_time) => {
                // finish the psync task
                db.as_scheduler()
                    .finish_process_with_business_status(
                        psync_task_process.clone(),
                        business_status::PSYNC_WORKFLOW_COMPLETE,
                    )
                    .await
                    .change_context(errors::RecoveryError::ProcessTrackerFailure)
                    .attach_printable("Failed to update the process tracker")?;

                // update the connector payment transmission field to Unsuccessful and unset active attempt id
                revenue_recovery_metadata.set_payment_transmission_field_for_api_request(
                    enums::PaymentConnectorTransmission::ConnectorCallUnsuccessful,
                );

                let payment_update_req =
                PaymentsUpdateIntentRequest::update_feature_metadata_and_active_attempt_with_api(
                    payment_intent
                        .feature_metadata
                        .clone()
                        .unwrap_or_default()
                        .convert_back()
                        .set_payment_revenue_recovery_metadata_using_api(
                            revenue_recovery_metadata.clone(),
                        ),
                    api_enums::UpdateActiveAttempt::Unset,
                );
                logger::info!(
                    "Call made to payments update intent api , with the request body {:?}",
                    payment_update_req
                );

                revenue_recovery_core::api::update_payment_intent_api(
                    state,
                    payment_intent.id.clone(),
                    revenue_recovery_payment_data,
                    payment_update_req,
                )
                .await
                .change_context(errors::RecoveryError::PaymentCallFailed)?;

                // fetch the execute task
                let task = revenue_recovery_core::EXECUTE_WORKFLOW;
                let runner = storage::ProcessTrackerRunner::PassiveRecoveryWorkflow;
                let process_tracker_id = payment_intent
                    .get_id()
                    .get_execute_revenue_recovery_id(task, runner);
                let execute_task_process = db
                    .as_scheduler()
                    .find_process_by_id(&process_tracker_id)
                    .await
                    .change_context(errors::RecoveryError::ProcessTrackerFailure)?
                    .get_required_value("Process Tracker")?;
                // retry the execute tasks
                db.as_scheduler()
                    .retry_process(execute_task_process, *schedule_time)
                    .await
                    .change_context(errors::RecoveryError::ProcessTrackerFailure)
                    .attach_printable("Failed to update the process tracker")?;
                Ok(())
            }

            Self::TerminalFailure(payment_attempt) => {
                // update the connector payment transmission field to Unsuccessful and unset active attempt id
                revenue_recovery_metadata.set_payment_transmission_field_for_api_request(
                    enums::PaymentConnectorTransmission::ConnectorCallUnsuccessful,
                );

                let payment_update_req =
                PaymentsUpdateIntentRequest::update_feature_metadata_and_active_attempt_with_api(
                    payment_intent
                        .feature_metadata
                        .clone()
                        .unwrap_or_default()
                        .convert_back()
                        .set_payment_revenue_recovery_metadata_using_api(
                            revenue_recovery_metadata.clone(),
                        ),
                    api_enums::UpdateActiveAttempt::Unset,
                );
                logger::info!(
                    "Call made to payments update intent api , with the request body {:?}",
                    payment_update_req
                );

                revenue_recovery_core::api::update_payment_intent_api(
                    state,
                    payment_intent.id.clone(),
                    revenue_recovery_payment_data,
                    payment_update_req,
                )
                .await
                .change_context(errors::RecoveryError::PaymentCallFailed)?;

                // TODO: Add support for retrying failed outgoing recordback webhooks
                // finish the current psync task
                db.as_scheduler()
                    .finish_process_with_business_status(
                        psync_task_process.clone(),
                        business_status::PSYNC_WORKFLOW_COMPLETE,
                    )
                    .await
                    .change_context(errors::RecoveryError::ProcessTrackerFailure)
                    .attach_printable("Failed to update the process tracker")?;
                Ok(())
            }
            Self::SuccessfulPayment(payment_attempt) => {
                // finish the current psync task
                db.as_scheduler()
                    .finish_process_with_business_status(
                        psync_task_process.clone(),
                        business_status::PSYNC_WORKFLOW_COMPLETE,
                    )
                    .await
                    .change_context(errors::RecoveryError::ProcessTrackerFailure)
                    .attach_printable("Failed to update the process tracker")?;

                // Record a successful transaction back to Billing Connector
                // TODO: Add support for retrying failed outgoing recordback webhooks
                record_back_to_billing_connector(
                    state,
                    payment_attempt,
                    payment_intent,
                    &revenue_recovery_payment_data.billing_mca,
                )
                .await
                .change_context(errors::RecoveryError::RecordBackToBillingConnectorFailed)
                .attach_printable("Failed to update the process tracker")?;
                Ok(())
            }
            Self::ReviewPayment => {
                // requeue the process tracker task in case of psync api error
                let pt_update = storage::ProcessTrackerUpdate::StatusUpdate {
                    status: enums::ProcessTrackerStatus::Pending,
                    business_status: Some(String::from(business_status::PSYNC_WORKFLOW_REQUEUE)),
                };
                db.as_scheduler()
                    .update_process(psync_task_process.clone(), pt_update)
                    .await?;
                Ok(())
            }
            Self::ManualReviewAction => {
                logger::debug!("Invalid Payment Status For PCR Payment");
                let pt_update = storage::ProcessTrackerUpdate::StatusUpdate {
                    status: enums::ProcessTrackerStatus::Review,
                    business_status: Some(String::from(business_status::PSYNC_WORKFLOW_COMPLETE)),
                };
                // update the process tracker status as Review
                db.as_scheduler()
                    .update_process(psync_task_process.clone(), pt_update)
                    .await
                    .change_context(errors::RecoveryError::ProcessTrackerFailure)
                    .attach_printable("Failed to update the process tracker")?;

                Ok(())
            }
        }
    }

    pub(crate) async fn decide_retry_failure_action(
        state: &SessionState,
        merchant_id: &id_type::MerchantId,
        pt: storage::ProcessTracker,
        revenue_recovery_payment_data: &storage::revenue_recovery::RevenueRecoveryPaymentData,
        payment_attempt: &PaymentAttempt,
        payment_intent: &PaymentIntent,
    ) -> RecoveryResult<Self> {
        let db = &*state.store;
        let next_retry_count = pt.retry_count + 1;
        let error_message = payment_attempt
            .error
            .as_ref()
            .map(|details| details.message.clone());
        let error_code = payment_attempt
            .error
            .as_ref()
            .map(|details| details.code.clone());
        let connector_name = payment_attempt
            .connector
            .clone()
            .ok_or(errors::RecoveryError::ValueNotFound)
            .attach_printable("unable to derive payment connector from payment attempt")?;
        let gsm_record = helpers::get_gsm_record(
            state,
            error_code,
            error_message,
            connector_name,
            REVENUE_RECOVERY.to_string(),
        )
        .await;
        let is_hard_decline = gsm_record
            .and_then(|gsm_record| gsm_record.error_category)
            .map(|gsm_error_category| {
                gsm_error_category == common_enums::ErrorCategory::HardDecline
            })
            .unwrap_or(false);
        let schedule_time = revenue_recovery_payment_data
            .get_schedule_time_based_on_retry_type(
                state,
                merchant_id,
                next_retry_count,
                payment_attempt,
                payment_intent,
                is_hard_decline,
            )
            .await;

        match schedule_time {
            Some(schedule_time) => Ok(Self::RetryPayment(schedule_time)),

            None => Ok(Self::TerminalFailure(payment_attempt.clone())),
        }
    }
}


- **cypress:** Execute cypress tests in parallel ([#6225](https://github.com/juspay/hyperswitch/pull/6225)) ([`f247978`](https://github.com/juspay/hyperswitch/commit/f24797834553794f341bd4f3be3afe5fcba693ed))

### Refactors

- **connector:** [WorldPay] propagate refusal codes as error code and messages ([#6392](https://github.com/juspay/hyperswitch/pull/6392)) ([`3d1a3cd`](https://github.com/juspay/hyperswitch/commit/3d1a3cdc8f942a3dca2e6a200bf9200366bd62f1))
- **permissions:** Remove permissions field from permission info API response ([#6376](https://github.com/juspay/hyperswitch/pull/6376)) ([`e5710fa`](https://github.com/juspay/hyperswitch/commit/e5710fa084ed5b0a4969a63b14a7f8e3433a3c64))

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

- - -

## 2024.10.22.0

### Features

- **connector:** Add 3DS flow for Worldpay ([#6374](https://github.com/juspay/hyperswitch/pull/6374)) ([`b93c849`](https://github.com/juspay/hyperswitch/commit/b93c849623c46ad00fe8dfe5bed85a43c700b3c8))

### Bug Fixes

- **mandates:** Allow connector_mandate_detail updation in case of 'Authorized' Payments ([#6379](https://github.com/juspay/hyperswitch/pull/6379)) ([`d09a805`](https://github.com/juspay/hyperswitch/commit/d09a805c0ab4e1224a94ef64b0d75a77355bc3f3))

### Refactors

- **connector:** [WorldPay] migrate from modular to standard payment APIs ([#6317](https://github.com/juspay/hyperswitch/pull/6317)) ([`58296ff`](https://github.com/juspay/hyperswitch/commit/58296ffae6ff6f2f2c8f7b23dd28e92b374b9be3))
- **router:** Introduce ApiKeyId id type ([#6324](https://github.com/juspay/hyperswitch/pull/6324)) ([`b3ce373`](https://github.com/juspay/hyperswitch/commit/b3ce373f8ecdce362296c9a4b3c3e3543e1baa6f))

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

- - -

## 2024.10.21.0

### Features

- **opensearch:** Add additional global search filters and create sessionizer indexes for local ([#6352](https://github.com/juspay/hyperswitch/pull/6352)) ([`2e6cd6d`](https://github.com/juspay/hyperswitch/commit/2e6cd6d31e4e3168b97427de936724de94df6415))

### Bug Fixes

- **router:** Make `x_merchant_domain` as required value only for session call done on web ([#6362](https://github.com/juspay/hyperswitch/pull/6362)) ([`ba6f7a8`](https://github.com/juspay/hyperswitch/commit/ba6f7a817ba3eeb8b3d6304ddd5b2baaf55733e8))

### Refactors

- **connector:**
  - Added amount conversion framework for Mollie ([#6280](https://github.com/juspay/hyperswitch/pull/6280)) ([`451376e`](https://github.com/juspay/hyperswitch/commit/451376e7993839f5c93624c12833af7d47aa4e34))
  - [Billwerk] Move connector Billwerk form Router to HyperswitchConnector Crate ([#6266](https://github.com/juspay/hyperswitch/pull/6266)) ([`3cf6210`](https://github.com/juspay/hyperswitch/commit/3cf6210176b2ecc4537b7537a28ea4c87a553794))
  - Add amount conversion framework to opayo ([#6342](https://github.com/juspay/hyperswitch/pull/6342)) ([`91146de`](https://github.com/juspay/hyperswitch/commit/91146de2a2bc684998023535e56dee1af92fda76))
- **core:** Populate shipping_cost in payment response ([#6351](https://github.com/juspay/hyperswitch/pull/6351)) ([`368e6b5`](https://github.com/juspay/hyperswitch/commit/368e6b53109890ca44bc352dd07ee542791e50df))
- **users:** Update Database connection for Read only functions ([#6167](https://github.com/juspay/hyperswitch/pull/6167)) ([`fba4a02`](https://github.com/juspay/hyperswitch/commit/fba4a027dfe1c514867c54dba32079dff63609a9))

### Documentation

- Upload new logos ([#6368](https://github.com/juspay/hyperswitch/pull/6368)) ([`0bda934`](https://github.com/juspay/hyperswitch/commit/0bda934aca6bc53b21ab3c2be2af27219ef4f68a))

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

- - -

## 2024.10.18.0

### Features

- **router:** Add payments create-intent flow for v2 ([#6193](https://github.com/juspay/hyperswitch/pull/6193)) ([`afa803e`](https://github.com/juspay/hyperswitch/commit/afa803e0f9711f83b31ce53a59e867517a885963))
- **worldpay:** Migrate to v7 ([#6109](https://github.com/juspay/hyperswitch/pull/6109)) ([`962afbd`](https://github.com/juspay/hyperswitch/commit/962afbd084458e9afb11a0278a8210edd9226a3d))

### Bug Fixes

- **mandates:** Handle the connector_mandate creation once and only if the payment is charged ([#6327](https://github.com/juspay/hyperswitch/pull/6327)) ([`e14a0fe`](https://github.com/juspay/hyperswitch/commit/e14a0fe8f290a697126756ba2facc58234e5d135))
- **payments_list:** Skip count query if no filters and add logging ([#6331](https://github.com/juspay/hyperswitch/pull/6331)) ([`df2501c`](https://github.com/juspay/hyperswitch/commit/df2501ceafab6180e867953f7c298a541fcea757))
- **router:** Set the eligible connector in the payment attempt for nti based mit flow ([#6347](https://github.com/juspay/hyperswitch/pull/6347)) ([`1a3d0a6`](https://github.com/juspay/hyperswitch/commit/1a3d0a60f4e3b07786460621c14c5aa37510b53a))
- **users:** Add max wrong attempts for two-fa ([#6247](https://github.com/juspay/hyperswitch/pull/6247)) ([`2798f57`](https://github.com/juspay/hyperswitch/commit/2798f575605cc4439166344e57ff19b612f1304a))
- Set headers as optional in ob flows ([#6305](https://github.com/juspay/hyperswitch/pull/6305)) ([`9576ee3`](https://github.com/juspay/hyperswitch/commit/9576ee37a6468d79afc4be280749a2176a95e63b))

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

- - -

## 2024.10.17.0

### Features

- **connector:** [fiuu] Add support for payment and refund webhooks ([#6315](https://github.com/juspay/hyperswitch/pull/6315)) ([`d04a87b`](https://github.com/juspay/hyperswitch/commit/d04a87be9e763034c070686cf1c2c73045650d4a))
- **sample_data:** Extend the batch sample data interface trait for disputes ([#6293](https://github.com/juspay/hyperswitch/pull/6293)) ([`1b31c57`](https://github.com/juspay/hyperswitch/commit/1b31c57fd961d6cec5d8ef1403bf501d1dd74b52))
- **user_role:** Add limit to `generic_user_roles_list_for_org_and_extra` ([#6191](https://github.com/juspay/hyperswitch/pull/6191)) ([`6aa6b7b`](https://github.com/juspay/hyperswitch/commit/6aa6b7bdc64a367ffaec97fa3826da6e2431ff9d))

### Refactors

- **cypress:** Reuse config update command ([#6197](https://github.com/juspay/hyperswitch/pull/6197)) ([`da194f3`](https://github.com/juspay/hyperswitch/commit/da194f34c6860af04d83ef69041f9e79249454ae))
- **users:** Move hardcoded email subjects to constants ([#6110](https://github.com/juspay/hyperswitch/pull/6110)) ([`899ec23`](https://github.com/juspay/hyperswitch/commit/899ec23565f99daaad821c1ec1482b4c0cc408c5))

### Documentation

- Simplify README ([#6306](https://github.com/juspay/hyperswitch/pull/6306)) ([`b377227`](https://github.com/juspay/hyperswitch/commit/b3772272678dd9e93b7afc7958b3344cbfe64708))

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

- - -

## 2024.10.16.0

### Features

- **core:** Add payments post_session_tokens flow ([#6202](https://github.com/juspay/hyperswitch/pull/6202)) ([`53e82c3`](https://github.com/juspay/hyperswitch/commit/53e82c3faef3ee629a38180e3882a2920332a9a8))
- **router:** Implement post_update_tracker for SessionUpdate Flow and add support for session_update_flow for Paypal ([#6299](https://github.com/juspay/hyperswitch/pull/6299)) ([`7e90031`](https://github.com/juspay/hyperswitch/commit/7e90031c68c7b93db996ee03e11c56b56a87402b))

### Documentation

- **README:** Remove FAQs section ([#6297](https://github.com/juspay/hyperswitch/pull/6297)) ([`d06d19f`](https://github.com/juspay/hyperswitch/commit/d06d19fc96e1a74d20e2fe3613f86d541947e0ae))
- **error_codes:** Add unified error codes ([#6319](https://github.com/juspay/hyperswitch/pull/6319)) ([`342529e`](https://github.com/juspay/hyperswitch/commit/342529e0565baaa02f33266c3be620a9561048c8))

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

- - -

## 2024.10.15.0

### Features

- **analytics:** Add metrics, filters and APIs for Analytics v2 Dashboard - Payments Page ([#5870](https://github.com/juspay/hyperswitch/pull/5870)) ([`f123df9`](https://github.com/juspay/hyperswitch/commit/f123df9aa31c45b417224af73c2a98325984b3dd))
- **connector:** [CYBERSOURCE] Add paze dashboard configs ([#6304](https://github.com/juspay/hyperswitch/pull/6304)) ([`df280f2`](https://github.com/juspay/hyperswitch/commit/df280f2574ac701a5e32b9bcae90c87cab7bc5aa))
- **payment_methods_v2:** Delete payment method api ([#6211](https://github.com/juspay/hyperswitch/pull/6211)) ([`8e538cd`](https://github.com/juspay/hyperswitch/commit/8e538cd6b3da4a155c55ce153982bff3c59ef575))
- **payments:** Support for card_network filter in payments list ([#5994](https://github.com/juspay/hyperswitch/pull/5994)) ([`1ac8c92`](https://github.com/juspay/hyperswitch/commit/1ac8c92c4bd2259cdd8bf755210bcb3c0eb31472))
- **router:** Add support for Samsung pay app tokens flow ([#6257](https://github.com/juspay/hyperswitch/pull/6257)) ([`f6b0b98`](https://github.com/juspay/hyperswitch/commit/f6b0b98e0a6c07308b481715f7c9ad063a5f0de9))

### Bug Fixes

- **router:**
  - Update nick_name only if card_token.card_holder_name is non empty and populate additional card_details from payment_attempt if not present in the locker ([#6308](https://github.com/juspay/hyperswitch/pull/6308)) ([`9da9c5e`](https://github.com/juspay/hyperswitch/commit/9da9c5e0ffe219a0bf6e08281b87c77eeb5c4575))
  - Replace underscore by hyphen in Samsung pay session call ([#6311](https://github.com/juspay/hyperswitch/pull/6311)) ([`7f1bbbf`](https://github.com/juspay/hyperswitch/commit/7f1bbbfffecb74555756b0003d6a0ae940e581db))

### Refactors

- **connector:** [Adyen platform] api contract change for webhook ([#6281](https://github.com/juspay/hyperswitch/pull/6281)) ([`5b4a1d5`](https://github.com/juspay/hyperswitch/commit/5b4a1d5f6d7b4143116c5f1faf6cb325e4368e6d))
- Add user agent header in outgoing webhooks ([#6289](https://github.com/juspay/hyperswitch/pull/6289)) ([`fe62b1f`](https://github.com/juspay/hyperswitch/commit/fe62b1fe2137de456a6a0e8e315fd0592c29577d))

### Documentation

- **v2:** Added 'X-Merchant-Id' to headers in Profile API docs ([#6291](https://github.com/juspay/hyperswitch/pull/6291)) ([`ca086d0`](https://github.com/juspay/hyperswitch/commit/ca086d0b25ee12419ebcb7250b4a6678cc33a8a6))

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

- - -

## 2024.10.11.0

### Features

- **router:** Add network transaction id support for mit payments ([#6245](https://github.com/juspay/hyperswitch/pull/6245)) ([`ba75a3f`](https://github.com/juspay/hyperswitch/commit/ba75a3f5a936ec981422bbe3c4fbdd9f12928615))

### Refactors

- Refactor(router): modify `net_amount` to be a struct in the domain model of payment_attempt and handle amount changes across all flows ([#6252](https://github.com/juspay/hyperswitch/pull/6252)) ([`5930089`](https://github.com/juspay/hyperswitch/commit/5930089682f89e1cc3e14720fcfa31de43353686))

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

- - -

## 2024.10.09.0

### Features

- **connector:**
  - [Novalnet] add webhooks for card ([#6033](https://github.com/juspay/hyperswitch/pull/6033)) ([`d61ebef`](https://github.com/juspay/hyperswitch/commit/d61ebef14908473458ae5962a63b035ddd0b3d94))
  - Integrate PAZE Wallet ([#6030](https://github.com/juspay/hyperswitch/pull/6030)) ([`535f2f1`](https://github.com/juspay/hyperswitch/commit/535f2f12f825be384a17fba8628d8517027bb6c6))

### Bug Fixes

- **connector:**
  - [deutsche bank] add support for sepa one-off payments ([#6246](https://github.com/juspay/hyperswitch/pull/6246)) ([`4e07fe9`](https://github.com/juspay/hyperswitch/commit/4e07fe9e8a8ccc19d9e247f4da787c5bf04411ca))
  - [Stripe] fix cashapp webhooks response deserialization failure ([#5690](https://github.com/juspay/hyperswitch/pull/5690)) ([`2ccce01`](https://github.com/juspay/hyperswitch/commit/2ccce01bf4c65559fd085dbb3ab32ef646998c17))
  - Remove placeholder from novalnet webhooks secret ([#6268](https://github.com/juspay/hyperswitch/pull/6268)) ([`86a43b9`](https://github.com/juspay/hyperswitch/commit/86a43b9bc41a358fe133c9fdea8dde09d4965c98))
- **euclid_wasm:** Update dependency for wasm in validate.rs ([#6262](https://github.com/juspay/hyperswitch/pull/6262)) ([`cc7c17f`](https://github.com/juspay/hyperswitch/commit/cc7c17f873efbe2818bcc472c0e2add3c836e71d))
- **users:** Allow accepting invites for `org_admin`s ([#6253](https://github.com/juspay/hyperswitch/pull/6253)) ([`2bc21cf`](https://github.com/juspay/hyperswitch/commit/2bc21cfc5e3e6d8403bec82fde14cfd01536f406))

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

- - -

## 2024.10.08.0

### Bug Fixes

- **user_role:** Restrict updating user role to the same `EntityType` ([#6224](https://github.com/juspay/hyperswitch/pull/6224)) ([`b499287`](https://github.com/juspay/hyperswitch/commit/b499287f2347837bc885387bb5eb99b3fd841f63))
- **users:** Trustpay refund url update ([#6251](https://github.com/juspay/hyperswitch/pull/6251)) ([`f4830eb`](https://github.com/juspay/hyperswitch/commit/f4830ebaae5dcc8407e420dfeb1ca981c08bc8fb))

### Refactors

- **dynamic_fields:** Rename sepa in dynamic fields ([#6234](https://github.com/juspay/hyperswitch/pull/6234)) ([`e44eb13`](https://github.com/juspay/hyperswitch/commit/e44eb13c6188df4863dc6f960e35b2ab6e96c064))

### Documentation

- Fix broken links to Running Additional Services ([#6243](https://github.com/juspay/hyperswitch/pull/6243)) ([`da6c0ff`](https://github.com/juspay/hyperswitch/commit/da6c0ff60bf059e73383ac37671c6df5c26d332c))

### Miscellaneous Tasks

- V2 api changes for session token endpoint ([#6032](https://github.com/juspay/hyperswitch/pull/6032)) ([`6e355f3`](https://github.com/juspay/hyperswitch/commit/6e355f34a8cef41cb9d9047f7c8792d4b46c10d8))

### Build System / Dependencies

- **docker-compose-development:** Address build failure of `hyperswitch-server` service ([#6217](https://github.com/juspay/hyperswitch/pull/6217)) ([`b79f75a`](https://github.com/juspay/hyperswitch/commit/b79f75a7ab9ed63a75defa2b3c5f9c170fca493e))

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

- - -

## 2024.10.07.0

### Features

- **opensearch:** Restrict search view access based on user roles and permissions ([#5932](https://github.com/juspay/hyperswitch/pull/5932)) ([`caa0693`](https://github.com/juspay/hyperswitch/commit/caa0693148764175201f7b1e2029fe29941cc7eb))

### Bug Fixes

- Add `reference` in `sepa_bank_instructions` ([#6215](https://github.com/juspay/hyperswitch/pull/6215)) ([`036a2d5`](https://github.com/juspay/hyperswitch/commit/036a2d5056134c067ec76dfd2afce4855303f5d7))
- Batch encrypt/decrypt on merchant connector account ([#6206](https://github.com/juspay/hyperswitch/pull/6206)) ([`b713948`](https://github.com/juspay/hyperswitch/commit/b7139483bb4735b7dfaf7e659ab33a16a90af1db))

### Refactors

- **user_role:** Remove V1 insertion for `user_roles` and allow Invites for `org_admins` ([#6185](https://github.com/juspay/hyperswitch/pull/6185)) ([`c07ee28`](https://github.com/juspay/hyperswitch/commit/c07ee28c0a0b388ee8064a247e70484a3c4fec33))
- **users:** Deprecate unused user APIs and stabilize v1 APIs ([#6114](https://github.com/juspay/hyperswitch/pull/6114)) ([`b2eb56e`](https://github.com/juspay/hyperswitch/commit/b2eb56e8d8589d1ae1a841a2c9e914c9d93e7993))

### Documentation

- Change organization_id to id in organization endpoints ([#6218](https://github.com/juspay/hyperswitch/pull/6218)) ([`939483c`](https://github.com/juspay/hyperswitch/commit/939483cebe91d16266521827e9fbd654fb060ca6))

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

- - -

## 2024.10.04.1

### Features

- **connector:** Add dynamic duitnow qr code, google pay and applpe pay for fiuu ([#6204](https://github.com/juspay/hyperswitch/pull/6204)) ([`2e54186`](https://github.com/juspay/hyperswitch/commit/2e54186a809e1322683a9379923ce418d05d3619))

### Bug Fixes

- **router:** Persist card_network if present for non co-badged cards ([#6212](https://github.com/juspay/hyperswitch/pull/6212)) ([`7564826`](https://github.com/juspay/hyperswitch/commit/75648262e7f741351c1149cd01083065d17bde7f))

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

- - -

## 2024.10.04.0

### Features

- **connector:** [Digital Virgo] template for integration ([#6145](https://github.com/juspay/hyperswitch/pull/6145)) ([`be3cf2c`](https://github.com/juspay/hyperswitch/commit/be3cf2c8693f4725e8c8ebd59412385dd4dcb7a1))
- **router:** Add profile level auto retries config support ([#6200](https://github.com/juspay/hyperswitch/pull/6200)) ([`5648977`](https://github.com/juspay/hyperswitch/commit/56489771e403864602adff5f954d1f59c65764c3))

### Bug Fixes

- **bug:** [IATAPAY] Fix PCM value for UPI_COLLECT ([#6207](https://github.com/juspay/hyperswitch/pull/6207)) ([`81e3d9d`](https://github.com/juspay/hyperswitch/commit/81e3d9df901d1b874dcbd5cd01f0b5532ae981a1))
- **payment_intent:** Batch encrypt and decrypt payment intent ([#6164](https://github.com/juspay/hyperswitch/pull/6164)) ([`369939a`](https://github.com/juspay/hyperswitch/commit/369939a37385fe85fd3430d9be0b7b0698962625))


File: crates/external_services/src/managers/secrets_management.rs
 Public functions: 2

//! Secrets management util module

use common_utils::errors::CustomResult;
#[cfg(feature = "hashicorp-vault")]
use error_stack::ResultExt;
use hyperswitch_interfaces::secrets_interface::{
    SecretManagementInterface, SecretsManagementError,
};

#[cfg(feature = "aws_kms")]
use crate::aws_kms;
#[cfg(feature = "hashicorp-vault")]
use crate::hashicorp_vault;
use crate::no_encryption::core::NoEncryption;

/// Enum representing configuration options for secrets management.
#[derive(Debug, Clone, Default, serde::Deserialize)]
#[serde(tag = "secrets_manager")]
#[serde(rename_all = "snake_case")]
pub enum SecretsManagementConfig {
    /// AWS KMS configuration
    #[cfg(feature = "aws_kms")]
    AwsKms {
        /// AWS KMS config
        aws_kms: aws_kms::core::AwsKmsConfig,
    },

    /// HashiCorp-Vault configuration
    #[cfg(feature = "hashicorp-vault")]
    HashiCorpVault {
        /// HC-Vault config
        hc_vault: hashicorp_vault::core::HashiCorpVaultConfig,
    },

    /// Variant representing no encryption
    #[default]
    NoEncryption,
}

impl SecretsManagementConfig {
    /// Verifies that the client configuration is usable
    pub fn validate(&self) -> Result<(), &'static str> {
        match self {
            #[cfg(feature = "aws_kms")]
            Self::AwsKms { aws_kms } => aws_kms.validate(),
            #[cfg(feature = "hashicorp-vault")]
            Self::HashiCorpVault { hc_vault } => hc_vault.validate(),
            Self::NoEncryption => Ok(()),
        }
    }

    /// Retrieves the appropriate secret management client based on the configuration.
    pub async fn get_secret_management_client(
        &self,
    ) -> CustomResult<Box<dyn SecretManagementInterface>, SecretsManagementError> {
        match self {
            #[cfg(feature = "aws_kms")]
            Self::AwsKms { aws_kms } => {
                Ok(Box::new(aws_kms::core::AwsKmsClient::new(aws_kms).await))
            }
            #[cfg(feature = "hashicorp-vault")]
            Self::HashiCorpVault { hc_vault } => {
                hashicorp_vault::core::HashiCorpVault::new(hc_vault)
                    .change_context(SecretsManagementError::ClientCreationFailed)
                    .map(|inner| -> Box<dyn SecretManagementInterface> { Box::new(inner) })
            }
            Self::NoEncryption => Ok(Box::new(NoEncryption)),
        }
    }
}


impl PaymentTokenData {
    #[cfg(feature = "v1")]
    pub fn permanent_card(
        payment_method_id: Option<String>,
        locker_id: Option<String>,
        token: String,
        network_token_locker_id: Option<String>,
    ) -> Self {
        Self::PermanentCard(CardTokenData {
            payment_method_id,
            locker_id,
            token,
            network_token_locker_id,
        })
    }

    #[cfg(feature = "v2")]
    pub fn permanent_card(
        payment_method_id: common_utils::id_type::GlobalPaymentMethodId,
        locker_id: Option<String>,
        token: String,
    ) -> Self {
        Self::PermanentCard(CardTokenData {
            payment_method_id,
            locker_id,
            token,
        })
    }

    pub fn temporary_generic(token: String) -> Self {
        Self::TemporaryGeneric(GenericTokenData { token })
    }

    #[cfg(feature = "v1")]
    pub fn wallet_token(payment_method_id: String) -> Self {
        Self::WalletToken(WalletTokenData { payment_method_id })
    }

    #[cfg(feature = "v1")]
    pub fn is_permanent_card(&self) -> bool {
        matches!(self, Self::PermanentCard(_) | Self::Permanent(_))
    }

    #[cfg(feature = "v2")]
    pub fn is_permanent_card(&self) -> bool {
        matches!(self, Self::PermanentCard(_))
    }
}


pub async fn setup_intents_confirm(
    state: web::Data<routes::AppState>,
    qs_config: web::Data<serde_qs::Config>,
    req: HttpRequest,
    form_payload: web::Bytes,
    path: web::Path<common_utils::id_type::PaymentId>,
) -> HttpResponse {
    let setup_id = path.into_inner();
    let stripe_payload: types::StripeSetupIntentRequest = match qs_config
        .deserialize_bytes(&form_payload)
    {
        Ok(p) => p,
        Err(err) => {
            return api::log_and_return_error_response(report!(errors::StripeErrorCode::from(err)))
        }
    };

    let mut payload: payment_types::PaymentsRequest =
        match payment_types::PaymentsRequest::try_from(stripe_payload) {
            Ok(req) => req,
            Err(err) => return api::log_and_return_error_response(err),
        };
    payload.payment_id = Some(api_types::PaymentIdType::PaymentIntentId(setup_id));
    payload.confirm = Some(true);

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

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

    let flow = Flow::PaymentsConfirm;

    Box::pin(wrap::compatibility_api_wrap::<
        _,
        _,
        _,
        _,
        _,
        types::StripeSetupIntentResponse,
        errors::StripeErrorCode,
        _,
    >(
        flow,
        state.into_inner(),
        &req,
        payload,
        |state, auth, req, req_state| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payments::payments_core::<
                api_types::SetupMandate,
                api_types::PaymentsResponse,
                _,
                _,
                _,
                payments::PaymentData<api_types::SetupMandate>,
            >(
                state,
                req_state,
                merchant_context,
                None,
                payments::PaymentConfirm,
                req,
                auth_flow,
                payments::CallConnectorAction::Trigger,
                None,
                hyperswitch_domain_models::payments::HeaderPayload::default(),
            )
        },
        &*auth_type,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub struct AdyenParamsWithThreeBaseUrls {
    /// base url
    pub base_url: String,
    /// secondary base url
    #[cfg(feature = "payouts")]
    pub payout_base_url: String,
    /// third base url
    pub dispute_base_url: String,
}


pub async fn retrieve_disputes_list_profile() {}


pub struct PaymentMethodsEnabled {
    /// Type of payment method.
    #[schema(value_type = PaymentMethod,example = "card")]
    pub payment_method_type: common_enums::PaymentMethod,

    /// Payment method configuration, this includes all the filters associated with the payment method
    pub payment_method_subtypes: Option<Vec<RequestPaymentMethodTypes>>,
}


pub struct PostAuthentication;


pub struct SubmitSinglePaymentResult {
    response: PaymentResponse,
}


pub async fn api_key_update(
    state: web::Data<AppState>,
    req: HttpRequest,
    key_id: web::Path<common_utils::id_type::ApiKeyId>,
    json_payload: web::Json<api_types::UpdateApiKeyRequest>,
) -> impl Responder {
    let flow = Flow::ApiKeyUpdate;
    let api_key_id = key_id.into_inner();
    let mut payload = json_payload.into_inner();
    payload.key_id = api_key_id;

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state,
         auth::AuthenticationDataWithoutProfile {
             merchant_account, ..
         },
         mut payload,
         _| {
            payload.merchant_id = merchant_account.get_id().to_owned();
            api_keys::update_api_key(state, payload)
        },
        auth::auth_type(
            &auth::AdminApiAuthWithMerchantIdFromHeader,
            &auth::JWTAuthMerchantFromHeader {
                required_permission: Permission::MerchantApiKeyRead,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub struct ExchangeToken;


impl api::RefundExecute for Rapyd {}


pub struct PayoutListConstraints {
    /// The identifier for customer
    #[schema(value_type = Option<String>, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
    pub customer_id: Option<id_type::CustomerId>,

    /// A cursor for use in pagination, fetch the next list after some object
    #[schema(example = "payout_fafa124123", value_type = Option<String>,)]
    pub starting_after: Option<id_type::PayoutId>,

    /// A cursor for use in pagination, fetch the previous list before some object
    #[schema(example = "payout_fafa124123", value_type = Option<String>,)]
    pub ending_before: Option<id_type::PayoutId>,

    /// limit on the number of objects to return
    #[schema(default = 10, maximum = 100)]
    #[serde(default = "default_payouts_list_limit")]
    pub limit: u32,

    /// The time at which payout is created
    #[schema(example = "2022-09-10T10:11:12Z")]
    #[serde(default, with = "common_utils::custom_serde::iso8601::option")]
    pub created: Option<PrimitiveDateTime>,

    /// The time range for which objects are needed. TimeRange has two fields start_time and end_time from which objects can be filtered as per required scenarios (created_at, time less than, greater than etc).
    #[serde(flatten)]
    #[schema(value_type = Option<TimeRange>)]
    pub time_range: Option<common_utils::types::TimeRange>,
}


impl api::RefundSync for Redsys {}


pub struct SkrillData {}


pub async fn get_payment_method_from_hs_locker<'a>(
    state: &'a routes::SessionState,
    key_store: &domain::MerchantKeyStore,
    customer_id: &id_type::CustomerId,
    merchant_id: &id_type::MerchantId,
    payment_method_reference: &'a str,
    locker_choice: Option<api_enums::LockerChoice>,
) -> errors::CustomResult<Secret<String>, errors::VaultError> {
    let locker = &state.conf.locker;
    let jwekey = state.conf.jwekey.get_inner();

    let payment_method_data = if !locker.mock_locker {
        let request = payment_methods::mk_get_card_request_hs(
            jwekey,
            locker,
            customer_id,
            merchant_id,
            payment_method_reference,
            locker_choice,
            state.tenant.tenant_id.clone(),
            state.request_id,
        )
        .await
        .change_context(errors::VaultError::FetchPaymentMethodFailed)
        .attach_printable("Making get payment method request failed")?;

        let get_card_resp = call_locker_api::<payment_methods::RetrieveCardResp>(
            state,
            request,
            "get_pm_from_locker",
            locker_choice,
        )
        .await
        .change_context(errors::VaultError::FetchPaymentMethodFailed)?;

        let retrieve_card_resp = get_card_resp
            .payload
            .get_required_value("RetrieveCardRespPayload")
            .change_context(errors::VaultError::FetchPaymentMethodFailed)
            .attach_printable("Failed to retrieve field - payload from RetrieveCardResp")?;
        let enc_card_data = retrieve_card_resp
            .enc_card_data
            .get_required_value("enc_card_data")
            .change_context(errors::VaultError::FetchPaymentMethodFailed)
            .attach_printable(
                "Failed to retrieve field - enc_card_data from RetrieveCardRespPayload",
            )?;
        decode_and_decrypt_locker_data(state, key_store, enc_card_data.peek().to_string()).await?
    } else {
        mock_get_payment_method(state, key_store, payment_method_reference)
            .await?
            .payment_method
            .payment_method_data
    };
    Ok(payment_method_data)
}


pub fn get_product_type(&self) -> Option<common_enums::MerchantProductType> {
        self.product_type
    }


File: crates/router/src/services.rs
 Public functions: 3

pub mod api;
pub mod authentication;
pub mod authorization;
pub mod connector_integration_interface;
#[cfg(feature = "email")]
pub mod email;
pub mod encryption;
#[cfg(feature = "olap")]
pub mod jwt;
pub mod kafka;
pub mod logger;
pub mod pm_auth;

pub mod card_testing_guard;
#[cfg(feature = "olap")]
pub mod openidconnect;

use std::sync::Arc;

use error_stack::ResultExt;
pub use hyperswitch_interfaces::connector_integration_v2::{
    BoxedConnectorIntegrationV2, ConnectorIntegrationAnyV2, ConnectorIntegrationV2,
};
use masking::{ExposeInterface, StrongSecret};
#[cfg(feature = "kv_store")]
use storage_impl::kv_router_store::KVRouterStore;
use storage_impl::{config::TenantConfig, errors::StorageResult, redis::RedisStore, RouterStore};
use tokio::sync::oneshot;

pub use self::{api::*, encryption::*};
use crate::{configs::Settings, core::errors};

#[cfg(not(feature = "olap"))]
pub type StoreType = storage_impl::database::store::Store;
#[cfg(feature = "olap")]
pub type StoreType = storage_impl::database::store::ReplicaStore;

#[cfg(not(feature = "kv_store"))]
pub type Store = RouterStore<StoreType>;
#[cfg(feature = "kv_store")]
pub type Store = KVRouterStore<StoreType>;

/// # Panics
///
/// Will panic if hex decode of master key fails
#[allow(clippy::expect_used)]
pub async fn get_store(
    config: &Settings,
    tenant: &dyn TenantConfig,
    cache_store: Arc<RedisStore>,
    test_transaction: bool,
) -> StorageResult<Store> {
    let master_config = config.master_database.clone().into_inner();

    #[cfg(feature = "olap")]
    let replica_config = config.replica_database.clone().into_inner();

    #[allow(clippy::expect_used)]
    let master_enc_key = hex::decode(config.secrets.get_inner().master_enc_key.clone().expose())
        .map(StrongSecret::new)
        .expect("Failed to decode master key from hex");

    #[cfg(not(feature = "olap"))]
    let conf = master_config.into();
    #[cfg(feature = "olap")]
    // this would get abstracted, for all cases
    #[allow(clippy::useless_conversion)]
    let conf = (master_config.into(), replica_config.into());

    let store: RouterStore<StoreType> = if test_transaction {
        RouterStore::test_store(conf, tenant, &config.redis, master_enc_key).await?
    } else {
        RouterStore::from_config(
            conf,
            tenant,
            master_enc_key,
            cache_store,
            storage_impl::redis::cache::IMC_INVALIDATION_CHANNEL,
        )
        .await?
    };

    #[cfg(feature = "kv_store")]
    let store = KVRouterStore::from_store(
        store,
        config.drainer.stream_name.clone(),
        config.drainer.num_partitions,
        config.kv_config.ttl,
        config.kv_config.soft_kill,
    );

    Ok(store)
}

#[allow(clippy::expect_used)]
pub async fn get_cache_store(
    config: &Settings,
    shut_down_signal: oneshot::Sender<()>,
    _test_transaction: bool,
) -> StorageResult<Arc<RedisStore>> {
    RouterStore::<StoreType>::cache_store(&config.redis, shut_down_signal).await
}

#[inline]
pub fn generate_aes256_key() -> errors::CustomResult<[u8; 32], common_utils::errors::CryptoError> {
    use ring::rand::SecureRandom;

    let rng = ring::rand::SystemRandom::new();
    let mut key: [u8; 256 / 8] = [0_u8; 256 / 8];
    rng.fill(&mut key)
        .change_context(common_utils::errors::CryptoError::EncodingFailed)?;
    Ok(key)
}


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

# Cards

Types to handle card masking and validation.


pub async fn update_window_for_elimination_routing(
    state: &SessionState,
    payment_attempt: &storage::PaymentAttempt,
    profile_id: &id_type::ProfileId,
    dynamic_algo_ref: routing_types::DynamicRoutingAlgorithmRef,
    elimination_routing_configs_params_interpolator: DynamicRoutingConfigParamsInterpolator,
    gsm_error_category: common_enums::ErrorCategory,
) -> RouterResult<()> {
    if let Some(elimination_algo_ref) = dynamic_algo_ref.elimination_routing_algorithm {
        if elimination_algo_ref.enabled_feature != routing_types::DynamicRoutingFeatures::None {
            let client = &state
                .grpc_client
                .dynamic_routing
                .as_ref()
                .ok_or(errors::ApiErrorResponse::GenericNotFoundError {
                    message: "dynamic routing gRPC client not found".to_string(),
                })?
                .elimination_based_client;

            let elimination_routing_config = fetch_dynamic_routing_configs::<
                routing_types::EliminationRoutingConfig,
            >(
                state,
                profile_id,
                elimination_algo_ref
                    .algorithm_id_with_timestamp
                    .algorithm_id
                    .ok_or(errors::ApiErrorResponse::GenericNotFoundError {
                        message: "elimination routing algorithm_id not found".to_string(),
                    })
                    .attach_printable(
                        "elimination_routing_algorithm_id not found in business_profile",
                    )?,
            )
            .await
            .change_context(errors::ApiErrorResponse::GenericNotFoundError {
                message: "elimination based dynamic routing configs not found".to_string(),
            })
            .attach_printable("unable to retrieve success_rate based dynamic routing configs")?;

            let payment_connector = &payment_attempt.connector.clone().ok_or(
                errors::ApiErrorResponse::GenericNotFoundError {
                    message: "unable to derive payment connector from payment attempt".to_string(),
                },
            )?;

            let elimination_routing_config_params = elimination_routing_configs_params_interpolator
                .get_string_val(
                    elimination_routing_config
                        .params
                        .as_ref()
                        .ok_or(errors::RoutingError::EliminationBasedRoutingParamsNotFoundError)
                        .change_context(errors::ApiErrorResponse::InternalServerError)?,
                );

            let labels_with_bucket_name =
                vec![routing_types::RoutableConnectorChoiceWithBucketName::new(
                    routing_types::RoutableConnectorChoice {
                        choice_kind: api_models::routing::RoutableChoiceKind::FullStruct,
                        connector: common_enums::RoutableConnectors::from_str(
                            payment_connector.as_str(),
                        )
                        .change_context(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable("unable to infer routable_connector from connector")?,
                        merchant_connector_id: payment_attempt.merchant_connector_id.clone(),
                    },
                    gsm_error_category.to_string(),
                )];

            let event_request = routing_utils::UpdateEliminationBucketEventRequest {
                id: profile_id.get_string_repr().to_string(),
                params: elimination_routing_config_params.clone(),
                labels_with_bucket_name: labels_with_bucket_name
                    .iter()
                    .map(|conn_choice| {
                        routing_utils::LabelWithBucketNameEventRequest::from(conn_choice)
                    })
                    .collect(),
                config: elimination_routing_config
                    .elimination_analyser_config
                    .as_ref()
                    .map(routing_utils::EliminationRoutingEventBucketConfig::from),
            };

            let routing_events_wrapper = routing_utils::RoutingEventsWrapper::new(
                state.tenant.tenant_id.clone(),
                state.request_id,
                payment_attempt.payment_id.get_string_repr().to_string(),
                profile_id.to_owned(),
                payment_attempt.merchant_id.to_owned(),
                "IntelligentRouter: UpdateEliminationBucket".to_string(),
                Some(event_request.clone()),
                true,
                false,
            );

            let closure = || async {
                let update_response_result = client
                .update_elimination_bucket_config(
                    profile_id.get_string_repr().to_string(),
                    elimination_routing_config_params,
                    labels_with_bucket_name,
                    elimination_routing_config.elimination_analyser_config,
                    state.get_grpc_headers(),
                )
                .await
                .change_context(errors::RoutingError::EliminationRoutingCalculationError)
                .attach_printable(
                    "unable to update elimination based routing buckets in dynamic routing service",
                );

                match update_response_result {
                    Ok(resp) => {
                        let updated_resp =
                            routing_utils::UpdateEliminationBucketEventResponse::try_from(&resp)
                            .change_context(errors::RoutingError::RoutingEventsError { message: "Unable to convert to UpdateEliminationBucketEventResponse from UpdateEliminationBucketResponse".to_string(), status_code: 500 })?;

                        Ok(Some(updated_resp))
                    }
                    Err(err) => {
                        logger::error!(
                            "unable to update elimination  score in dynamic routing service: {:?}",
                            err.current_context()
                        );

                        Err(err)
                    }
                }
            };

            let events_response = routing_events_wrapper.construct_event_builder( "EliminationAnalyser.UpdateEliminationBucket".to_string(),
            routing_events::RoutingEngine::IntelligentRouter,
            routing_events::ApiMethod::Grpc)
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Elimination-Intelligent-Router: Failed to update elimination bucket in Intelligent-Router")?
            .trigger_event(state, closure)
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Elimination-Intelligent-Router: Failed to update elimination bucket in Intelligent-Router")?;

            let _response: routing_utils::UpdateEliminationBucketEventResponse = events_response
                .response
                .ok_or(errors::ApiErrorResponse::InternalServerError)
                .attach_printable(
                    "UpdateEliminationBucketEventResponse not found in RoutingEventResponse",
                )?;

            let mut routing_event = events_response
                .event
                .ok_or(errors::RoutingError::RoutingEventsError {
                    message:
                        "Elimination-Intelligent-Router: RoutingEvent not found in RoutingEventsResponse"
                            .to_string(),
                    status_code: 500,
                })
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Elimination-Intelligent-Router: RoutingEvent not found in RoutingEventsResponse")?;

            routing_event.set_status_code(200);
            routing_event.set_payment_connector(routing_types::RoutableConnectorChoice {
                choice_kind: api_models::routing::RoutableChoiceKind::FullStruct,
                connector: common_enums::RoutableConnectors::from_str(payment_connector.as_str())
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("unable to infer routable_connector from connector")?,
                merchant_connector_id: payment_attempt.merchant_connector_id.clone(),
            });
            state.event_handler().log_event(&routing_event);
            Ok(())
        } else {
            Ok(())
        }
    } else {
        Ok(())
    }
}


File: crates/payment_methods/src/controller.rs
 Public functions: 1
 Public structs: 1

use std::fmt::Debug;

#[cfg(feature = "payouts")]
use api_models::payouts;
use api_models::{enums as api_enums, payment_methods as api};
#[cfg(feature = "v1")]
use common_enums::enums as common_enums;
#[cfg(feature = "v2")]
use common_utils::encryption;
use common_utils::{crypto, ext_traits, id_type, type_name, types::keymanager};
use error_stack::ResultExt;
use hyperswitch_domain_models::{merchant_key_store, payment_methods, type_encryption};
use masking::{PeekInterface, Secret};
#[cfg(feature = "v1")]
use scheduler::errors as sch_errors;
use serde::{Deserialize, Serialize};
use storage_impl::{errors as storage_errors, payment_method};

use crate::core::errors;

#[derive(Debug, Deserialize, Serialize)]
pub struct DeleteCardResp {
    pub status: String,
    pub error_message: Option<String>,
    pub error_code: Option<String>,
}

#[derive(Debug, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum DataDuplicationCheck {
    Duplicated,
    MetaDataChanged,
}

#[async_trait::async_trait]
pub trait PaymentMethodsController {
    #[cfg(feature = "v1")]
    #[allow(clippy::too_many_arguments)]
    async fn create_payment_method(
        &self,
        req: &api::PaymentMethodCreate,
        customer_id: &id_type::CustomerId,
        payment_method_id: &str,
        locker_id: Option<String>,
        merchant_id: &id_type::MerchantId,
        pm_metadata: Option<serde_json::Value>,
        customer_acceptance: Option<serde_json::Value>,
        payment_method_data: crypto::OptionalEncryptableValue,
        connector_mandate_details: Option<serde_json::Value>,
        status: Option<common_enums::PaymentMethodStatus>,
        network_transaction_id: Option<String>,
        payment_method_billing_address: crypto::OptionalEncryptableValue,
        card_scheme: Option<String>,
        network_token_requestor_reference_id: Option<String>,
        network_token_locker_id: Option<String>,
        network_token_payment_method_data: crypto::OptionalEncryptableValue,
    ) -> errors::PmResult<payment_methods::PaymentMethod>;

    #[cfg(feature = "v1")]
    #[allow(clippy::too_many_arguments)]
    async fn insert_payment_method(
        &self,
        resp: &api::PaymentMethodResponse,
        req: &api::PaymentMethodCreate,
        key_store: &merchant_key_store::MerchantKeyStore,
        merchant_id: &id_type::MerchantId,
        customer_id: &id_type::CustomerId,
        pm_metadata: Option<serde_json::Value>,
        customer_acceptance: Option<serde_json::Value>,
        locker_id: Option<String>,
        connector_mandate_details: Option<serde_json::Value>,
        network_transaction_id: Option<String>,
        payment_method_billing_address: crypto::OptionalEncryptableValue,
        network_token_requestor_reference_id: Option<String>,
        network_token_locker_id: Option<String>,
        network_token_payment_method_data: crypto::OptionalEncryptableValue,
    ) -> errors::PmResult<payment_methods::PaymentMethod>;

    #[cfg(feature = "v2")]
    #[allow(clippy::too_many_arguments)]
    async fn insert_payment_method(
        &self,
        resp: &api::PaymentMethodResponse,
        req: &api::PaymentMethodCreate,
        key_store: &merchant_key_store::MerchantKeyStore,
        merchant_id: &id_type::MerchantId,
        customer_id: &id_type::CustomerId,
        pm_metadata: Option<serde_json::Value>,
        customer_acceptance: Option<serde_json::Value>,
        locker_id: Option<String>,
        connector_mandate_details: Option<serde_json::Value>,
        network_transaction_id: Option<String>,
        payment_method_billing_address: Option<encryption::Encryption>,
    ) -> errors::PmResult<payment_methods::PaymentMethod>;

    #[cfg(feature = "v1")]
    async fn add_payment_method(
        &self,
        req: &api::PaymentMethodCreate,
    ) -> errors::PmResponse<api::PaymentMethodResponse>;

    #[cfg(feature = "v1")]
    async fn retrieve_payment_method(
        &self,
        pm: api::PaymentMethodId,
    ) -> errors::PmResponse<api::PaymentMethodResponse>;

    #[cfg(feature = "v1")]
    async fn delete_payment_method(
        &self,
        pm_id: api::PaymentMethodId,
    ) -> errors::PmResponse<api::PaymentMethodDeleteResponse>;

    async fn add_card_hs(
        &self,
        req: api::PaymentMethodCreate,
        card: &api::CardDetail,
        customer_id: &id_type::CustomerId,
        locker_choice: api_enums::LockerChoice,
        card_reference: Option<&str>,
    ) -> errors::VaultResult<(api::PaymentMethodResponse, Option<DataDuplicationCheck>)>;

    /// The response will be the tuple of PaymentMethodResponse and the duplication check of payment_method
    async fn add_card_to_locker(
        &self,
        req: api::PaymentMethodCreate,
        card: &api::CardDetail,
        customer_id: &id_type::CustomerId,
        card_reference: Option<&str>,
    ) -> errors::VaultResult<(api::PaymentMethodResponse, Option<DataDuplicationCheck>)>;

    #[cfg(feature = "payouts")]
    async fn add_bank_to_locker(
        &self,
        req: api::PaymentMethodCreate,
        key_store: &merchant_key_store::MerchantKeyStore,
        bank: &payouts::Bank,
        customer_id: &id_type::CustomerId,
    ) -> errors::VaultResult<(api::PaymentMethodResponse, Option<DataDuplicationCheck>)>;

    #[cfg(feature = "v1")]
    async fn get_or_insert_payment_method(
        &self,
        req: api::PaymentMethodCreate,
        resp: &mut api::PaymentMethodResponse,
        customer_id: &id_type::CustomerId,
        key_store: &merchant_key_store::MerchantKeyStore,
    ) -> errors::PmResult<payment_methods::PaymentMethod>;

    #[cfg(feature = "v2")]
    async fn get_or_insert_payment_method(
        &self,
        _req: api::PaymentMethodCreate,
        _resp: &mut api::PaymentMethodResponse,
        _customer_id: &id_type::CustomerId,
        _key_store: &merchant_key_store::MerchantKeyStore,
    ) -> errors::PmResult<payment_methods::PaymentMethod> {
        todo!()
    }

    #[cfg(feature = "v1")]
    async fn get_card_details_with_locker_fallback(
        &self,
        pm: &payment_methods::PaymentMethod,
    ) -> errors::PmResult<Option<api::CardDetailFromLocker>>;

    #[cfg(feature = "v1")]
    async fn get_card_details_without_locker_fallback(
        &self,
        pm: &payment_methods::PaymentMethod,
    ) -> errors::PmResult<api::CardDetailFromLocker>;

    async fn delete_card_from_locker(
        &self,
        customer_id: &id_type::CustomerId,
        merchant_id: &id_type::MerchantId,
        card_reference: &str,
    ) -> errors::PmResult<DeleteCardResp>;

    #[cfg(feature = "v1")]
    fn store_default_payment_method(
        &self,
        req: &api::PaymentMethodCreate,
        customer_id: &id_type::CustomerId,
        merchant_id: &id_type::MerchantId,
    ) -> (api::PaymentMethodResponse, Option<DataDuplicationCheck>);

    #[cfg(feature = "v2")]
    fn store_default_payment_method(
        &self,
        req: &api::PaymentMethodCreate,
        customer_id: &id_type::CustomerId,
        merchant_id: &id_type::MerchantId,
    ) -> (api::PaymentMethodResponse, Option<DataDuplicationCheck>);

    #[cfg(feature = "v1")]
    #[allow(clippy::too_many_arguments)]
    async fn save_network_token_and_update_payment_method(
        &self,
        req: &api::PaymentMethodMigrate,
        key_store: &merchant_key_store::MerchantKeyStore,
        network_token_data: &api_models::payment_methods::MigrateNetworkTokenData,
        network_token_requestor_ref_id: String,
        pm_id: String,
    ) -> errors::PmResult<bool>;

    #[cfg(feature = "v1")]
    async fn set_default_payment_method(
        &self,
        merchant_id: &id_type::MerchantId,
        customer_id: &id_type::CustomerId,
        payment_method_id: String,
    ) -> errors::PmResponse<api_models::payment_methods::CustomerDefaultPaymentMethodResponse>;

    #[cfg(feature = "v1")]
    async fn add_payment_method_status_update_task(
        &self,
        payment_method: &payment_methods::PaymentMethod,
        prev_status: common_enums::PaymentMethodStatus,
        curr_status: common_enums::PaymentMethodStatus,
        merchant_id: &id_type::MerchantId,
    ) -> Result<(), sch_errors::ProcessTrackerError>;

    #[cfg(feature = "v1")]
    async fn validate_merchant_connector_ids_in_connector_mandate_details(
        &self,
        key_store: &merchant_key_store::MerchantKeyStore,
        connector_mandate_details: &api_models::payment_methods::CommonMandateReference,
        merchant_id: &id_type::MerchantId,
        card_network: Option<common_enums::CardNetwork>,
    ) -> errors::PmResult<()>;

    #[cfg(feature = "v1")]
    async fn get_card_details_from_locker(
        &self,
        pm: &payment_methods::PaymentMethod,
    ) -> errors::PmResult<api::CardDetailFromLocker>;
}

pub async fn create_encrypted_data<T>(
    key_manager_state: &keymanager::KeyManagerState,
    key_store: &merchant_key_store::MerchantKeyStore,
    data: T,
) -> Result<
    crypto::Encryptable<Secret<serde_json::Value>>,
    error_stack::Report<storage_errors::StorageError>,
>
where
    T: Debug + Serialize,
{
    let key = key_store.key.get_inner().peek();
    let identifier = keymanager::Identifier::Merchant(key_store.merchant_id.clone());

    let encoded_data = ext_traits::Encode::encode_to_value(&data)
        .change_context(storage_errors::StorageError::SerializationFailed)
        .attach_printable("Unable to encode data")?;

    let secret_data = Secret::<_, masking::WithType>::new(encoded_data);

    let encrypted_data = type_encryption::crypto_operation(
        key_manager_state,
        type_name!(payment_method::PaymentMethod),
        type_encryption::CryptoOperation::Encrypt(secret_data),
        identifier.clone(),
        key,
    )
    .await
    .and_then(|val| val.try_into_operation())
    .change_context(storage_errors::StorageError::EncryptionError)
    .attach_printable("Unable to encrypt data")?;

    Ok(encrypted_data)
}