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

use actix_web::{web, HttpRequest, HttpResponse};
use api_models::blocklist as api_blocklist;
use router_env::Flow;

use crate::{
    core::{api_locking, blocklist},
    routes::AppState,
    services::{api, authentication as auth, authorization::permissions::Permission},
    types::domain,
};

#[utoipa::path(
    post,
    path = "/blocklist",
    request_body = BlocklistRequest,
    responses(
        (status = 200, description = "Fingerprint Blocked", body = BlocklistResponse),
        (status = 400, description = "Invalid Data")
    ),
    tag = "Blocklist",
    operation_id = "Block a Fingerprint",
    security(("api_key" = []))
)]
pub async fn add_entry_to_blocklist(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<api_blocklist::AddToBlocklistRequest>,
) -> HttpResponse {
    let flow = Flow::AddToBlocklist;
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        json_payload.into_inner(),
        |state, auth: auth::AuthenticationData, body, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            blocklist::add_entry_to_blocklist(state, merchant_context, body)
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuth {
                permission: Permission::MerchantAccountWrite,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[utoipa::path(
    delete,
    path = "/blocklist",
    request_body = BlocklistRequest,
    responses(
        (status = 200, description = "Fingerprint Unblocked", body = BlocklistResponse),
        (status = 400, description = "Invalid Data")
    ),
    tag = "Blocklist",
    operation_id = "Unblock a Fingerprint",
    security(("api_key" = []))
)]
pub async fn remove_entry_from_blocklist(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<api_blocklist::DeleteFromBlocklistRequest>,
) -> HttpResponse {
    let flow = Flow::DeleteFromBlocklist;
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        json_payload.into_inner(),
        |state, auth: auth::AuthenticationData, body, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            blocklist::remove_entry_from_blocklist(state, merchant_context, body)
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuth {
                permission: Permission::MerchantAccountWrite,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[utoipa::path(
    get,
    path = "/blocklist",
    params (
        ("data_kind" = BlocklistDataKind, Query, description = "Kind of the fingerprint list requested"),
    ),
    responses(
        (status = 200, description = "Blocked Fingerprints", body = BlocklistResponse),
        (status = 400, description = "Invalid Data")
    ),
    tag = "Blocklist",
    operation_id = "List Blocked fingerprints of a particular kind",
    security(("api_key" = []))
)]
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
}

#[utoipa::path(
    post,
    path = "/blocklist/toggle",
    params (
        ("status" = bool, Query, description = "Boolean value to enable/disable blocklist"),
    ),
    responses(
        (status = 200, description = "Blocklist guard enabled/disabled", body = ToggleBlocklistResponse),
        (status = 400, description = "Invalid Data")
    ),
    tag = "Blocklist",
    operation_id = "Toggle blocklist guard for a particular merchant",
    security(("api_key" = []))
)]
pub async fn toggle_blocklist_guard(
    state: web::Data<AppState>,
    req: HttpRequest,
    query_payload: web::Query<api_blocklist::ToggleBlocklistQuery>,
) -> 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::toggle_blocklist_guard(state, merchant_context, query)
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuth {
                permission: Permission::MerchantAccountWrite,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


impl Responder {
    let flow = Flow::RecoveryPaymentsCreate;
    let mut payload = json_payload.into_inner();
    Box::pin(api::server_wrap(
        flow,
        state,
        &req.clone(),
        payload,
        |state, auth: auth::AuthenticationData, req_payload, req_state| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            recovery::custom_revenue_recovery_core(
                state.to_owned(),
                req_state,
                merchant_context,
                auth.profile,
                req_payload,
            )
        },
        &auth::V2ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


impl DBOperation {
    pub async fn execute(self, conn: &PgPooledConn) -> crate::StorageResult<DBResult> {
        Ok(match self {
            Self::Insert { insertable } => match *insertable {
                Insertable::PaymentIntent(a) => {
                    DBResult::PaymentIntent(Box::new(a.insert(conn).await?))
                }
                Insertable::PaymentAttempt(a) => {
                    DBResult::PaymentAttempt(Box::new(a.insert(conn).await?))
                }
                Insertable::Refund(a) => DBResult::Refund(Box::new(a.insert(conn).await?)),
                Insertable::Address(addr) => DBResult::Address(Box::new(addr.insert(conn).await?)),
                Insertable::Customer(cust) => {
                    DBResult::Customer(Box::new(cust.insert(conn).await?))
                }
                Insertable::ReverseLookUp(rev) => {
                    DBResult::ReverseLookUp(Box::new(rev.insert(conn).await?))
                }
                Insertable::Payouts(rev) => DBResult::Payouts(Box::new(rev.insert(conn).await?)),
                Insertable::PayoutAttempt(rev) => {
                    DBResult::PayoutAttempt(Box::new(rev.insert(conn).await?))
                }
                Insertable::PaymentMethod(rev) => {
                    DBResult::PaymentMethod(Box::new(rev.insert(conn).await?))
                }
                Insertable::Mandate(m) => DBResult::Mandate(Box::new(m.insert(conn).await?)),
            },
            Self::Update { updatable } => match *updatable {
                #[cfg(feature = "v1")]
                Updateable::PaymentIntentUpdate(a) => {
                    DBResult::PaymentIntent(Box::new(a.orig.update(conn, a.update_data).await?))
                }
                #[cfg(feature = "v2")]
                Updateable::PaymentIntentUpdate(a) => {
                    DBResult::PaymentIntent(Box::new(a.orig.update(conn, a.update_data).await?))
                }
                #[cfg(feature = "v1")]
                Updateable::PaymentAttemptUpdate(a) => DBResult::PaymentAttempt(Box::new(
                    a.orig.update_with_attempt_id(conn, a.update_data).await?,
                )),
                #[cfg(feature = "v2")]
                Updateable::PaymentAttemptUpdate(a) => DBResult::PaymentAttempt(Box::new(
                    a.orig.update_with_attempt_id(conn, a.update_data).await?,
                )),
                #[cfg(feature = "v1")]
                Updateable::RefundUpdate(a) => {
                    DBResult::Refund(Box::new(a.orig.update(conn, a.update_data).await?))
                }
                #[cfg(feature = "v2")]
                Updateable::RefundUpdate(a) => {
                    DBResult::Refund(Box::new(a.orig.update_with_id(conn, a.update_data).await?))
                }
                Updateable::AddressUpdate(a) => {
                    DBResult::Address(Box::new(a.orig.update(conn, a.update_data).await?))
                }
                Updateable::PayoutsUpdate(a) => {
                    DBResult::Payouts(Box::new(a.orig.update(conn, a.update_data).await?))
                }
                Updateable::PayoutAttemptUpdate(a) => DBResult::PayoutAttempt(Box::new(
                    a.orig.update_with_attempt_id(conn, a.update_data).await?,
                )),
                #[cfg(feature = "v1")]
                Updateable::PaymentMethodUpdate(v) => DBResult::PaymentMethod(Box::new(
                    v.orig
                        .update_with_payment_method_id(conn, v.update_data)
                        .await?,
                )),
                #[cfg(feature = "v2")]
                Updateable::PaymentMethodUpdate(v) => DBResult::PaymentMethod(Box::new(
                    v.orig.update_with_id(conn, v.update_data).await?,
                )),
                Updateable::MandateUpdate(m) => DBResult::Mandate(Box::new(
                    Mandate::update_by_merchant_id_mandate_id(
                        conn,
                        &m.orig.merchant_id,
                        &m.orig.mandate_id,
                        m.update_data,
                    )
                    .await?,
                )),
                #[cfg(feature = "v1")]
                Updateable::CustomerUpdate(cust) => DBResult::Customer(Box::new(
                    Customer::update_by_customer_id_merchant_id(
                        conn,
                        cust.orig.customer_id.clone(),
                        cust.orig.merchant_id.clone(),
                        cust.update_data,
                    )
                    .await?,
                )),
                #[cfg(feature = "v2")]
                Updateable::CustomerUpdate(cust) => DBResult::Customer(Box::new(
                    Customer::update_by_id(conn, cust.orig.id, cust.update_data).await?,
                )),
            },
        })
    }
}


pub struct ThreeDSAuthData {
    three_d_s_auth_response: Option<Secret<String>>,
    authentication_value: Option<Secret<String>>,
}


pub struct CheckoutApplePayHeader {
    ephemeral_public_key: Secret<String>,
    public_key_hash: Secret<String>,
    transaction_id: Secret<String>,
}


pub struct DigitalvirgoErrorResponse {
    pub cause: Option<String>,
    pub operation_error: Option<String>,
    pub description: Option<String>,
}


pub struct DebitRoutingOutput {
    pub co_badged_card_networks_info: CoBadgedCardNetworks,
    pub issuer_country: common_enums::CountryAlpha2,
    pub is_regulated: bool,
    pub regulated_name: Option<common_enums::RegulatedName>,
    pub card_type: common_enums::CardType,
}


pub struct WebhookReferences {
    pub merchant_reference: Option<String>,
    pub payment_id: Option<String>,
    pub payment_request_id: Option<String>,
}


impl api::PaymentToken for Itaubank {}


impl ConnectorTransactionId for Helcim {
    #[cfg(feature = "v1")]
    fn connector_transaction_id(
        &self,
        payment_attempt: &PaymentAttempt,
    ) -> Result<Option<String>, ApiErrorResponse> {
        if payment_attempt.get_connector_payment_id().is_none() {
            let metadata =
                Self::connector_transaction_id(self, payment_attempt.connector_metadata.as_ref());
            metadata.map_err(|_| ApiErrorResponse::ResourceIdNotFound)
        } else {
            Ok(payment_attempt
                .get_connector_payment_id()
                .map(ToString::to_string))
        }
    }

    #[cfg(feature = "v2")]
    fn connector_transaction_id(
        &self,
        payment_attempt: &PaymentAttempt,
    ) -> Result<Option<String>, ApiErrorResponse> {
        use hyperswitch_domain_models::errors::api_error_response::ApiErrorResponse;

        if payment_attempt.get_connector_payment_id().is_none() {
            let metadata = Self::connector_transaction_id(
                self,
                payment_attempt
                    .connector_metadata
                    .as_ref()
                    .map(|connector_metadata| connector_metadata.peek()),
            );
            metadata.map_err(|_| ApiErrorResponse::ResourceIdNotFound)
        } else {
            Ok(payment_attempt
                .get_connector_payment_id()
                .map(ToString::to_string))
        }
    }
}

impl ConnectorTransactionId for for Helcim


pub struct Analytics;


impl ThreeDsDecisionRule {
    pub fn server(state: AppState) -> Scope {
        web::scope("/three_ds_decision")
            .app_data(web::Data::new(state))
            .service(
                web::resource("/execute")
                    .route(web::post().to(three_ds_decision_rule::execute_decision_rule)),
            )
    }
}


pub fn make_new_payment_attempt(
    _connector: String,
    _old_payment_attempt: storage::PaymentAttempt,
    _new_attempt_count: i16,
    _is_step_up: bool,
) -> storage::PaymentAttempt {
    todo!()
}


File: crates/api_models/src/disputes.rs
 Public structs: 10

use std::collections::HashMap;

use common_utils::types::{StringMinorUnit, TimeRange};
use masking::{Deserialize, Serialize};
use serde::de::Error;
use time::PrimitiveDateTime;
use utoipa::ToSchema;

use super::enums::{Currency, DisputeStage, DisputeStatus};
use crate::{admin::MerchantConnectorInfo, files};

#[derive(Clone, Debug, Serialize, ToSchema, Eq, PartialEq)]
pub struct DisputeResponse {
    /// The identifier for dispute
    pub dispute_id: String,
    /// The identifier for payment_intent
    #[schema(value_type = String)]
    pub payment_id: common_utils::id_type::PaymentId,
    /// The identifier for payment_attempt
    pub attempt_id: String,
    /// The dispute amount
    pub amount: StringMinorUnit,
    /// The three-letter ISO currency code
    #[schema(value_type = Currency)]
    pub currency: Currency,
    /// Stage of the dispute
    pub dispute_stage: DisputeStage,
    /// Status of the dispute
    pub dispute_status: DisputeStatus,
    /// connector to which dispute is associated with
    pub connector: String,
    /// Status of the dispute sent by connector
    pub connector_status: String,
    /// Dispute id sent by connector
    pub connector_dispute_id: String,
    /// Reason of dispute sent by connector
    pub connector_reason: Option<String>,
    /// Reason code of dispute sent by connector
    pub connector_reason_code: Option<String>,
    /// Evidence deadline of dispute sent by connector
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub challenge_required_by: Option<PrimitiveDateTime>,
    /// Dispute created time sent by connector
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub connector_created_at: Option<PrimitiveDateTime>,
    /// Dispute updated time sent by connector
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub connector_updated_at: Option<PrimitiveDateTime>,
    /// Time at which dispute is received
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created_at: PrimitiveDateTime,
    /// The `profile_id` associated with the dispute
    #[schema(value_type = Option<String>)]
    pub profile_id: Option<common_utils::id_type::ProfileId>,
    /// The `merchant_connector_id` of the connector / processor through which the dispute was processed
    #[schema(value_type = Option<String>)]
    pub merchant_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
}

#[derive(Clone, Debug, Serialize, ToSchema, Eq, PartialEq)]
pub struct DisputeResponsePaymentsRetrieve {
    /// The identifier for dispute
    pub dispute_id: String,
    /// Stage of the dispute
    pub dispute_stage: DisputeStage,
    /// Status of the dispute
    pub dispute_status: DisputeStatus,
    /// Status of the dispute sent by connector
    pub connector_status: String,
    /// Dispute id sent by connector
    pub connector_dispute_id: String,
    /// Reason of dispute sent by connector
    pub connector_reason: Option<String>,
    /// Reason code of dispute sent by connector
    pub connector_reason_code: Option<String>,
    /// Evidence deadline of dispute sent by connector
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub challenge_required_by: Option<PrimitiveDateTime>,
    /// Dispute created time sent by connector
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub connector_created_at: Option<PrimitiveDateTime>,
    /// Dispute updated time sent by connector
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub connector_updated_at: Option<PrimitiveDateTime>,
    /// Time at which dispute is received
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created_at: PrimitiveDateTime,
}

#[derive(Debug, Serialize, Deserialize, strum::Display, Clone)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum EvidenceType {
    CancellationPolicy,
    CustomerCommunication,
    CustomerSignature,
    Receipt,
    RefundPolicy,
    ServiceDocumentation,
    ShippingDocumentation,
    InvoiceShowingDistinctTransactions,
    RecurringTransactionAgreement,
    UncategorizedFile,
}

#[derive(Clone, Debug, Serialize, ToSchema)]
pub struct DisputeEvidenceBlock {
    /// Evidence type
    pub evidence_type: EvidenceType,
    /// File metadata
    pub file_metadata_response: files::FileMetadataResponse,
}

#[derive(Clone, Debug, Deserialize, Serialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct DisputeListGetConstraints {
    /// The identifier for dispute
    pub dispute_id: Option<String>,
    /// The payment_id against which dispute is raised
    pub payment_id: Option<common_utils::id_type::PaymentId>,
    /// Limit on the number of objects to return
    pub limit: Option<u32>,
    /// The starting point within a list of object
    pub offset: Option<u32>,
    /// The identifier for business profile
    #[schema(value_type = Option<String>)]
    pub profile_id: Option<common_utils::id_type::ProfileId>,
    /// The comma separated list of status of the disputes
    #[serde(default, deserialize_with = "parse_comma_separated")]
    pub dispute_status: Option<Vec<DisputeStatus>>,
    /// The comma separated list of stages of the disputes
    #[serde(default, deserialize_with = "parse_comma_separated")]
    pub dispute_stage: Option<Vec<DisputeStage>>,
    /// Reason for the dispute
    pub reason: Option<String>,
    /// The comma separated list of connectors linked to disputes
    #[serde(default, deserialize_with = "parse_comma_separated")]
    pub connector: Option<Vec<String>>,
    /// The comma separated list of currencies of the disputes
    #[serde(default, deserialize_with = "parse_comma_separated")]
    pub currency: Option<Vec<Currency>>,
    /// The merchant connector id to filter the disputes list
    pub merchant_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
    /// 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)]
    pub time_range: Option<TimeRange>,
}

#[derive(Clone, Debug, serde::Serialize, ToSchema)]
pub struct DisputeListFilters {
    /// The map of available connector filters, where the key is the connector name and the value is a list of MerchantConnectorInfo instances
    pub connector: HashMap<String, Vec<MerchantConnectorInfo>>,
    /// The list of available currency filters
    pub currency: Vec<Currency>,
    /// The list of available dispute status filters
    pub dispute_status: Vec<DisputeStatus>,
    /// The list of available dispute stage filters
    pub dispute_stage: Vec<DisputeStage>,
}

#[derive(Default, Clone, Debug, Serialize, Deserialize, ToSchema)]
pub struct SubmitEvidenceRequest {
    ///Dispute Id
    pub dispute_id: String,
    /// Logs showing the usage of service by customer
    pub access_activity_log: Option<String>,
    /// Billing address of the customer
    pub billing_address: Option<String>,
    /// File Id of cancellation policy
    pub cancellation_policy: Option<String>,
    /// Details of showing cancellation policy to customer before purchase
    pub cancellation_policy_disclosure: Option<String>,
    /// Details telling why customer's subscription was not cancelled
    pub cancellation_rebuttal: Option<String>,
    /// File Id of customer communication
    pub customer_communication: Option<String>,
    /// Customer email address
    pub customer_email_address: Option<String>,
    /// Customer name
    pub customer_name: Option<String>,
    /// IP address of the customer
    pub customer_purchase_ip: Option<String>,
    /// Fild Id of customer signature
    pub customer_signature: Option<String>,
    /// Product Description
    pub product_description: Option<String>,
    /// File Id of receipt
    pub receipt: Option<String>,
    /// File Id of refund policy
    pub refund_policy: Option<String>,
    /// Details of showing refund policy to customer before purchase
    pub refund_policy_disclosure: Option<String>,
    /// Details why customer is not entitled to refund
    pub refund_refusal_explanation: Option<String>,
    /// Customer service date
    pub service_date: Option<String>,
    /// File Id service documentation
    pub service_documentation: Option<String>,
    /// Shipping address of the customer
    pub shipping_address: Option<String>,
    /// Delivery service that shipped the product
    pub shipping_carrier: Option<String>,
    /// Shipping date
    pub shipping_date: Option<String>,
    /// File Id shipping documentation
    pub shipping_documentation: Option<String>,
    /// Tracking number of shipped product
    pub shipping_tracking_number: Option<String>,
    /// File Id showing two distinct transactions when customer claims a payment was charged twice
    pub invoice_showing_distinct_transactions: Option<String>,
    /// File Id of recurring transaction agreement
    pub recurring_transaction_agreement: Option<String>,
    /// Any additional supporting file
    pub uncategorized_file: Option<String>,
    /// Any additional evidence statements
    pub uncategorized_text: Option<String>,
}

#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
pub struct DeleteEvidenceRequest {
    /// Id of the dispute
    pub dispute_id: String,
    /// Evidence Type to be deleted
    pub evidence_type: EvidenceType,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct DisputeRetrieveRequest {
    /// The identifier for dispute
    pub dispute_id: String,
    /// Decider to enable or disable the connector call for dispute retrieve request
    pub force_sync: Option<bool>,
}

#[derive(Clone, Debug, serde::Serialize)]
pub struct DisputesAggregateResponse {
    /// Different status of disputes with their count
    pub status_with_count: HashMap<DisputeStatus, i64>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct DisputeRetrieveBody {
    /// Decider to enable or disable the connector call for dispute retrieve request
    pub force_sync: Option<bool>,
}

fn parse_comma_separated<'de, D, T>(v: D) -> Result<Option<Vec<T>>, D::Error>
where
    D: serde::Deserializer<'de>,
    T: std::str::FromStr,
    <T as std::str::FromStr>::Err: std::fmt::Debug + std::fmt::Display + std::error::Error,
{
    let output = Option::<&str>::deserialize(v)?;
    output
        .map(|s| {
            s.split(",")
                .map(|x| x.parse::<T>().map_err(D::Error::custom))
                .collect::<Result<_, _>>()
        })
        .transpose()
}


pub struct DomainInfo {
    pub domain_identifier: DomainIdentifier,
    pub domain_description: String,
}


/// Schedule the task for retry
///
/// Returns bool which indicates whether this was the last retry or not
pub async fn retry_sync_task(
    db: &dyn StorageInterface,
    connector: String,
    merchant_id: common_utils::id_type::MerchantId,
    pt: storage::ProcessTracker,
) -> Result<bool, sch_errors::ProcessTrackerError> {
    let schedule_time: Option<time::PrimitiveDateTime> =
        get_sync_process_schedule_time(db, &connector, &merchant_id, pt.retry_count + 1).await?;

    match schedule_time {
        Some(s_time) => {
            db.as_scheduler().retry_process(pt, s_time).await?;
            Ok(false)
        }
        None => {
            db.as_scheduler()
                .finish_process_with_business_status(pt, business_status::RETRIES_EXCEEDED)
                .await?;
            Ok(true)
        }
    }
}


pub struct CardData {
    card_data: cards::CardNumber,
    expiration_month: Secret<String>,
    expiration_year: Secret<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    security_code: Option<Secret<String>>,
}


pub struct SyncErrorCode {
    ds_errorcode: String,
}


pub struct PaypalNetworkTransactionReference {
    id: String,
}


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


pub struct ItaubankErrorBody {
    pub status: u16,
    pub title: Option<String>,
    pub detail: Option<String>,
    pub violacoes: Option<Vec<Violations>>,
}


pub struct AuthorizedotnetTransactionResponseError {
    _supplemental_data_qualification_indicator: i64,
}


OpenAPI Block Path: components.schemas.ConnectorType
{
  "type": "string",
  "description": "Type of the Connector for the financial use case. Could range from Payments to Accounting to Banking.",
  "enum": [
    "payment_processor",
    "payment_vas",
    "fin_operations",
    "fiz_operations",
    "networks",
    "banking_entities",
    "non_banking_finance",
    "payout_processor",
    "payment_method_auth",
    "authentication_processor",
    "tax_processor",
    "billing_processor",
    "vault_processor"
  ]
}


/// Build UCS webhook transform request from webhook components
pub fn build_webhook_transform_request(
    _webhook_body: &[u8],
    request_details: &hyperswitch_interfaces::webhooks::IncomingWebhookRequestDetails<'_>,
    webhook_secrets: Option<payments_grpc::WebhookSecrets>,
    merchant_id: &str,
    connector_id: &str,
) -> Result<PaymentServiceTransformRequest, error_stack::Report<errors::ApiErrorResponse>> {
    let request_details_grpc = payments_grpc::RequestDetails::foreign_try_from(request_details)
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to transform webhook request details to gRPC format")?;

    Ok(PaymentServiceTransformRequest {
        request_ref_id: Some(Identifier {
            id_type: Some(payments_grpc::identifier::IdType::Id(format!(
                "{}_{}_{}",
                merchant_id,
                connector_id,
                time::OffsetDateTime::now_utc().unix_timestamp()
            ))),
        }),
        request_details: Some(request_details_grpc),
        webhook_secrets,
    })
}


/// Get the default global tenant ID
    pub fn get_default_global_tenant_id() -> Self {
        Self(super::LengthId::new_unchecked(
            super::AlphaNumericId::new_unchecked(DEFAULT_GLOBAL_TENANT_ID.to_string()),
        ))
    }


pub struct ApplePayTotalInfo {
    pub label: String,
    pub amount: StringMajorUnit,
}


impl ConnectorAuthentication for Gpayments {}

impl ConnectorAuthentication for for Gpayments


impl RetryFeatureData {
    /// Checks if step-up retry is possible.
    pub fn is_step_up_possible(&self) -> bool {
        self.step_up_possible
    }

    /// Checks if retry with PAN is possible.
    pub fn is_clear_pan_possible(&self) -> bool {
        self.clear_pan_possible
    }

    /// Checks if retry with alternate network is possible.
    pub fn is_alternate_network_possible(&self) -> bool {
        self.alternate_network_possible
    }

    /// Retrieves the decision to be taken for auto retries flow.
    pub fn get_decision(&self) -> common_enums::GsmDecision {
        self.decision
    }
}


pub struct ProphetpayRefundSyncResponse {
    pub success: bool,
    pub response_text: String,
}


impl PaymentSync for Signifyd {}


pub fn is_internal(&self) -> bool {
        self.is_internal
    }


pub async fn get_tracking_id_from_configs(
    state: &SessionState,
    connector_id: &common_utils::id_type::MerchantConnectorAccountId,
    connector: enums::Connector,
) -> RouterResult<String> {
    let timestamp = state
        .store
        .find_config_by_key_unwrap_or(
            &build_key(connector_id, connector),
            Some(common_utils::date_time::now_unix_timestamp().to_string()),
        )
        .await
        .change_context(ApiErrorResponse::InternalServerError)
        .attach_printable("Error getting data from configs table")?
        .config;

    Ok(format!("{}_{}", connector_id.get_string_repr(), timestamp))
}


impl Entity {
    pub fn get_entity_type(&self) -> EntityType {
        self.entity_type
    }

    pub fn get_entity_id(&self) -> &str {
        &self.entity_id
    }
}


pub struct FraudMarkingInformation {
    reason: Option<String>,
}


pub fn get_dotted_jwe(jwe: encryption::JweBody) -> String {
    let header = jwe.header;
    let encryption_key = jwe.encrypted_key;
    let iv = jwe.iv;
    let encryption_payload = jwe.encrypted_payload;
    let tag = jwe.tag;
    format!("{header}.{encryption_key}.{iv}.{encryption_payload}.{tag}")
}


pub struct ProxyCardDetails {
    /// Tokenized Card Number
    #[schema(value_type = String,example = "tok_sjfowhoejsldj")]
    pub card_number: masking::Secret<String>,

    /// Card Expiry Month
    #[schema(value_type = String,example = "10")]
    pub card_exp_month: masking::Secret<String>,

    /// Card Expiry Year
    #[schema(value_type = String,example = "25")]
    pub card_exp_year: masking::Secret<String>,

    /// First Six Digit of Card Number
    pub bin_number: Option<String>,

    ///Last Four Digit of Card Number
    pub last_four: Option<String>,

    /// Issuer Bank for Card
    pub card_issuer: Option<String>,

    /// Card's Network
    #[schema(value_type = Option<CardNetwork>)]
    pub card_network: Option<common_enums::CardNetwork>,

    /// Card Type
    pub card_type: Option<String>,

    /// Issuing Country of the Card
    pub card_issuing_country: Option<String>,

    /// Card Holder's Nick Name
    #[schema(value_type = Option<String>,example = "John Doe")]
    pub nick_name: Option<masking::Secret<String>>,

    /// Card Holder Name
    #[schema(value_type = String,example = "John Doe")]
    pub card_holder_name: Option<masking::Secret<String>>,

    /// The CVC number for the card
    /// This is optional in case the card needs to be vaulted
    #[schema(value_type = String, example = "242")]
    pub card_cvc: Option<masking::Secret<String>>,
}


pub struct NovalnetPaymentsRequest {
    merchant: NovalnetPaymentsRequestMerchant,
    customer: NovalnetPaymentsRequestCustomer,
    transaction: NovalnetPaymentsRequestTransaction,
    custom: NovalnetCustom,
}


pub fn parse_and_log_keys_in_url_encoded_response<T>(data: &[u8]) {
    match std::str::from_utf8(data) {
        Ok(query_str) => {
            let loggable_keys = [
                "status",
                "orderid",
                "tranID",
                "nbcb",
                "amount",
                "currency",
                "paydate",
                "channel",
                "error_desc",
                "error_code",
                "extraP",
            ];
            let keys: Vec<(Cow<'_, str>, String)> =
                url::form_urlencoded::parse(query_str.as_bytes())
                    .map(|(key, value)| {
                        if loggable_keys.contains(&key.to_string().as_str()) {
                            (key, value.to_string())
                        } else {
                            (key, "SECRET".to_string())
                        }
                    })
                    .collect();
            router_env::logger::info!("Keys in {} response\n{:?}", type_name::<T>(), keys);
        }
        Err(err) => {
            router_env::logger::error!("Failed to convert bytes to string: {:?}", err);
        }
    }
}


impl api::PaymentSync for Bluecode {}


pub struct IntermediateSigningKey {
    signed_key: Secret<String>,
    signatures: Vec<Secret<String>>,
}


pub trait RecoveryDeciderClientInterface: dyn_clone::DynClone + Send + Sync + Debug {
    /// fn to call gRPC service
    async fn decide_on_retry(
        &mut self,
        request_payload: DeciderRequest,
        recovery_headers: super::GrpcRecoveryHeaders,
    ) -> RecoveryDeciderResult<DeciderResponse>;
}


pub async fn get_tokenized_data(
    state: &routes::SessionState,
    lookup_key: &str,
    _should_get_value2: bool,
    encryption_key: &masking::Secret<Vec<u8>>,
) -> RouterResult<api::TokenizePayloadRequest> {
    let redis_key = get_redis_locker_key(lookup_key);
    let func = || async {
        metrics::GET_TOKENIZED_CARD.add(1, &[]);

        let redis_conn = state
            .store
            .get_redis_conn()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to get redis connection")?;

        let response = redis_conn
            .get_key::<bytes::Bytes>(&redis_key.as_str().into())
            .await;

        match response {
            Ok(resp) => {
                let decrypted_payload = GcmAes256
                    .decode_message(
                        encryption_key.peek().as_ref(),
                        masking::Secret::new(resp.into()),
                    )
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed to decode redis temp locker data")?;

                let get_response: api::TokenizePayloadRequest =
                    bytes::Bytes::from(decrypted_payload)
                        .parse_struct("TokenizePayloadRequest")
                        .change_context(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable(
                            "Error getting TokenizePayloadRequest from tokenize response",
                        )?;

                Ok(get_response)
            }
            Err(err) => {
                metrics::TEMP_LOCKER_FAILURES.add(1, &[]);
                Err(err).change_context(errors::ApiErrorResponse::UnprocessableEntity {
                    message: "Token is invalid or expired".into(),
                })
            }
        }
    };

    match func().await {
        Ok(s) => {
            logger::info!(
                "Fetch payload in redis locker successful with lookup key: {:?}",
                redis_key
            );
            Ok(s)
        }
        Err(err) => {
            logger::error!("Redis Temp locker Failed: {:?}", err);
            Err(err)
        }
    }
}


File: crates/router/src/types/api/customers.rs

use api_models::customers;
pub use api_models::customers::{
    CustomerDeleteResponse, CustomerListRequest, CustomerRequest, CustomerUpdateRequest,
    CustomerUpdateRequestInternal,
};
#[cfg(feature = "v2")]
use hyperswitch_domain_models::customer;
use serde::Serialize;

#[cfg(feature = "v1")]
use super::payments;
use crate::{
    newtype,
    types::{domain, ForeignFrom},
};

newtype!(
    pub CustomerResponse = customers::CustomerResponse,
    derives = (Debug, Clone, Serialize)
);

impl common_utils::events::ApiEventMetric for CustomerResponse {
    fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
        self.0.get_api_event_type()
    }
}

#[cfg(feature = "v1")]
impl ForeignFrom<(domain::Customer, Option<payments::AddressDetails>)> for CustomerResponse {
    fn foreign_from((cust, address): (domain::Customer, Option<payments::AddressDetails>)) -> Self {
        customers::CustomerResponse {
            customer_id: cust.customer_id,
            name: cust.name,
            email: cust.email,
            phone: cust.phone,
            phone_country_code: cust.phone_country_code,
            description: cust.description,
            created_at: cust.created_at,
            metadata: cust.metadata,
            address,
            default_payment_method_id: cust.default_payment_method_id,
            tax_registration_id: cust.tax_registration_id,
        }
        .into()
    }
}

#[cfg(feature = "v2")]
impl ForeignFrom<customer::Customer> for CustomerResponse {
    fn foreign_from(cust: domain::Customer) -> Self {
        customers::CustomerResponse {
            id: cust.id,
            merchant_reference_id: cust.merchant_reference_id,
            connector_customer_ids: cust.connector_customer,
            name: cust.name,
            email: cust.email,
            phone: cust.phone,
            phone_country_code: cust.phone_country_code,
            description: cust.description,
            created_at: cust.created_at,
            metadata: cust.metadata,
            default_billing_address: None,
            default_shipping_address: None,
            default_payment_method_id: cust.default_payment_method_id,
            tax_registration_id: cust.tax_registration_id,
        }
        .into()
    }
}


pub async fn retrieve_mandates_list() {}


pub async fn payment_link_retrieve(
    state: web::Data<AppState>,
    req: actix_web::HttpRequest,
    path: web::Path<String>,
    json_payload: web::Query<api_models::payments::RetrievePaymentLinkRequest>,
) -> impl Responder {
    let flow = Flow::PaymentLinkRetrieve;
    let payload = json_payload.into_inner();
    let api_auth = auth::ApiKeyAuth::default();

    let (auth_type, _) =
        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(error_stack::report!(err)),
        };

    api::server_wrap(
        flow,
        state,
        &req,
        payload.clone(),
        |state, _auth, _, _| retrieve_payment_link(state, path.clone()),
        &*auth_type,
        api_locking::LockAction::NotApplicable,
    )
    .await
}


Documentation: api-reference/v1/payments/payments--confirm.mdx
# Type: Doc File

---
openapi: post /payments/{payment_id}/confirm
---


pub async fn trigger_refund_outgoing_webhook(
    state: &SessionState,
    merchant_account: &domain::MerchantAccount,
    refund: &diesel_models::Refund,
    profile_id: id_type::ProfileId,
    key_store: &domain::MerchantKeyStore,
) -> RouterResult<()> {
    todo!()
}


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


File: crates/router/tests/connectors/worldpayvantiv.rs

use hyperswitch_domain_models::payment_method_data::{Card, PaymentMethodData};
use masking::Secret;
use router::types::{self, api, storage::enums};
use test_utils::connector_auth;

use crate::utils::{self, ConnectorActions};

#[derive(Clone, Copy)]
struct WorldpayvantivTest;
impl ConnectorActions for WorldpayvantivTest {}
impl utils::Connector for WorldpayvantivTest {
    fn get_data(&self) -> api::ConnectorData {
        use router::connector::Worldpayxml;
        utils::construct_connector_data_old(
            Box::new(Worldpayxml::new()),
            types::Connector::Plaid,
            api::GetToken::Connector,
            None,
        )
    }

    fn get_auth_token(&self) -> types::ConnectorAuthType {
        utils::to_connector_auth_type(
            connector_auth::ConnectorAuthentication::new()
                .worldpayxml
                .expect("Missing connector authentication configuration")
                .into(),
        )
    }

    fn get_name(&self) -> String {
        "Worldpayxml".to_string()
    }
}

static CONNECTOR: WorldpayvantivTest = WorldpayvantivTest {};

fn get_default_payment_info() -> Option<utils::PaymentInfo> {
    None
}

fn payment_method_details() -> Option<types::PaymentsAuthorizeData> {
    None
}

// Cards Positive Tests
// Creates a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_only_authorize_payment() {
    let response = CONNECTOR
        .authorize_payment(payment_method_details(), get_default_payment_info())
        .await
        .expect("Authorize payment response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized);
}

// Captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(payment_method_details(), None, get_default_payment_info())
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Partially captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(
            payment_method_details(),
            Some(types::PaymentsCaptureData {
                amount_to_capture: 50,
                ..utils::PaymentCaptureType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_authorized_payment() {
    let authorize_response = CONNECTOR
        .authorize_payment(payment_method_details(), get_default_payment_info())
        .await
        .expect("Authorize payment response");
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Authorized,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .expect("PSync response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized,);
}

// Voids a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_void_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_void_payment(
            payment_method_details(),
            Some(types::PaymentsCancelData {
                connector_transaction_id: String::from(""),
                cancellation_reason: Some("requested_by_customer".to_string()),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .expect("Void payment response");
    assert_eq!(response.status, enums::AttemptStatus::Voided);
}

// Refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Synchronizes a refund using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_manually_captured_refund() {
    let refund_response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_make_payment() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_auto_captured_payment() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Charged,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                capture_method: Some(enums::CaptureMethod::Automatic),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(response.status, enums::AttemptStatus::Charged,);
}

// Refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_auto_captured_payment() {
    let response = CONNECTOR
        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_succeeded_payment() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        refund_response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates multiple refunds against a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_succeeded_payment_multiple_times() {
    CONNECTOR
        .make_payment_and_multiple_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await;
}

// Synchronizes a refund using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_refund() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Cards Negative scenarios
// Creates a payment with incorrect CVC.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_cvc() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_cvc: Secret::new("12345".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's security code is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry month.
#[actix_web::test]
async fn should_fail_payment_for_invalid_exp_month() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_exp_month: Secret::new("20".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration month is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry year.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_expiry_year() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_exp_year: Secret::new("2000".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration year is invalid.".to_string(),
    );
}

// Voids a payment using automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_fail_void_payment_for_auto_capture() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let void_response = CONNECTOR
        .void_payment(txn_id.unwrap(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        void_response.response.unwrap_err().message,
        "You cannot cancel this PaymentIntent because it has a status of succeeded."
    );
}

// Captures a payment using invalid connector payment id.
#[actix_web::test]
async fn should_fail_capture_for_invalid_payment() {
    let capture_response = CONNECTOR
        .capture_payment("123456789".to_string(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        capture_response.response.unwrap_err().message,
        String::from("No such payment_intent: '123456789'")
    );
}

// Refunds a payment with refund amount higher than payment amount.
#[actix_web::test]
async fn should_fail_for_refund_amount_higher_than_payment_amount() {
    let response = CONNECTOR
        .make_payment_and_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 150,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Refund amount (₹1.50) is greater than charge amount (₹1.00)",
    );
}

// Connector dependent test cases goes here

// [#478]: add unit tests for non 3DS, wallets & webhooks in connector tests


impl NuveiPaymentsGenericResponse for Capture {}

impl NuveiPaymentsGenericResponse for for Capture


pub struct SantanderRefundRequest {
    #[serde(rename = "valor")]
    pub value: StringMajorUnit,
}


pub struct RevokeMandateResponse {
    data: DeletePaymentMethodFromVault,
}


pub struct Sdk {
    /// Universally unique ID created upon all installations and updates of the 3DS Requestor App on a Customer Device.
    /// This will be newly generated and stored by the 3DS SDK for each installation or update. The field is limited to 36
    /// characters and it shall have a canonical format as defined in IETF RFC 4122. This may utilize any of the specified
    /// versions as long as the output meets specified requirements.
    ///
    /// Starting from EMV 3DS 2.3.1:
    /// In case of Browser-SDK, the SDK App ID value is not reliable, and may change for each transaction.
    #[serde(rename = "sdkAppID")]
    sdk_app_id: Option<String>,

    /// JWE Object as defined Section 6.2.2.1 containing data encrypted by the SDK for the DS to decrypt. This element is
    /// the only field encrypted in this version of the EMV 3-D Secure specification. The field is sent from the SDK and it
    /// is limited to 64.000 characters. The data will be present when sending to DS, but not present from DS to ACS.
    sdk_enc_data: Option<String>,

    /// Public key component of the ephemeral key pair generated by the 3DS SDK and used to establish session keys between
    /// the 3DS SDK and ACS. In AReq, this data element is contained within the ACS Signed Content JWS Object. The field is
    /// limited to maximum 256 characters.
    sdk_ephem_pub_key: Option<HashMap<String, String>>,

    /// Indicates the maximum amount of time (in minutes) for all exchanges. The field shall have value greater or equals
    /// than 05.
    sdk_max_timeout: Option<u8>,

    /// Identifies the vendor and version of the 3DS SDK that is integrated in a 3DS Requestor App, assigned by EMVCo when
    /// the 3DS SDK is approved. The field is limited to 32 characters.
    ///
    /// Starting from EMV 3DS 2.3.1:
    /// Identifies the vendor and version of the 3DS SDK that is utilised for a specific transaction. The value is
    /// assigned by EMVCo when the Letter of Approval of the specific 3DS SDK is issued.
    sdk_reference_number: Option<String>,

    /// Universally unique transaction identifier assigned by the 3DS SDK to identify a single transaction. The field is
    /// limited to 36 characters and it shall be in a canonical format as defined in IETF RFC 4122. This may utilize any of
    /// the specified versions as long as the output meets specific requirements.
    #[serde(rename = "sdkTransID")]
    sdk_trans_id: Option<String>,

    /// Contains the JWS object(represented as a string) created by the Split-SDK Server for the AReq message. A
    /// Split-SDK Server creates a time-stamped signature on certain transaction data that is sent to the DS for
    /// verification. As a prerequisite, the Split-SDK Server has a key pair PbSDK, PvSDK certificate Cert (PbSDK). This
    /// certificate is an X.509 certificate signed by a DS CA whose public key is known to the DS.
    ///
    /// The Split-SDK Server:
    ///    Creates a JSON object of the following data as the JWS payload to be signed:
    ///
    ///    - SDK Reference Number -> Identifies the vendor and version of the 3DS SDK that is utilised for a specific
    ///      transaction. The value is assigned by EMVCo when the Letter of Approval of the
    ///      specific 3DS SDK is issued. The field is limited to 32 characters.
    ///    - SDK Signature Timestamp -> Date and time indicating when the 3DS SDK generated the Split-SDK Server Signed
    ///      Content converted into UTC. The value is limited to 14 characters. Accepted
    ///      format: YYYYMMDDHHMMSS.
    ///    - SDK Transaction ID -> Universally unique transaction identifier assigned by the 3DS SDK to identify a
    ///      single transaction. The field is limited to 36 characters and it shall be in a
    ///      canonical format as defined in IETF RFC 4122. This may utilize any of the specified
    ///      versions as long as the output meets specific requirements.
    ///    - Split-SDK Server ID -> DS assigned Split-SDK Server identifier. Each DS can provide a unique ID to each
    ///      Split-SDK Server on an individual basis. The field is limited to 32 characters.
    ///      Any individual DS may impose specific formatting and character requirements on the
    ///      contents of this field.
    ///
    ///    Generates a digital signature of the full JSON object according to JWS (RFC 7515) using JWS Compact
    ///    Serialization. The parameter values for this version of the specification and to be included in the JWS
    ///    header are:
    ///
    ///    - `alg`: PS2567 or ES256
    ///    - `x5c`: X.5C v3: Cert (PbSDK) and chaining certificates if present
    ///
    ///    All other parameters: optional
    ///
    ///    Includes the resulting JWS in the AReq message as SDK Server Signed Content
    ///
    /// This field is required if sdkType = 02 or 03 and deviceChannel = 01 (APP)
    /// Available for supporting EMV 3DS 2.3.1 and later versions.
    sdk_server_signed_content: Option<String>,

    /// Indicates the type of 3DS SDK.
    /// This data element provides additional information to the DS and ACS to determine the best approach for handling
    /// the transaction. Accepted values are:
    ///
    ///    - 01 -> Default SDK
    ///    - 02 -> Split-SDK
    ///    - 03 -> Limited-SDK
    ///    - 04 -> Browser-SDK
    ///    - 05 -> Shell-SDK
    ///    - 80-99 -> PS-specific value (dependent on the payment scheme type)
    ///
    /// This field is required for requests where deviceChannel = 01 (APP).
    /// Available for supporting EMV 3DS 2.3.1 and later versions.
    sdk_type: Option<SdkType>,

    /// Indicates the characteristics of a Default-SDK.
    ///
    /// This field is required for requests where deviceChannel = 01 (APP) and SDK Type = 01.
    /// Available for supporting EMV 3DS 2.3.1 and later versions.
    default_sdk_type: Option<DefaultSdkType>,

    /// Indicates the characteristics of a Split-SDK.
    ///
    /// This field is required for requests where deviceChannel = 01 (APP) and SDK Type = 02.
    /// Available for supporting EMV 3DS 2.3.1 and later versions.
    split_sdk_type: Option<SplitSdkType>,
}


impl RelayUpdate {
    pub fn from(
        response: Result<router_response_types::RefundsResponseData, ErrorResponse>,
    ) -> Self {
        match response {
            Err(error) => Self::ErrorUpdate {
                error_code: error.code,
                error_message: error.reason.unwrap_or(error.message),
                status: common_enums::RelayStatus::Failure,
            },
            Ok(response) => Self::StatusUpdate {
                connector_reference_id: Some(response.connector_refund_id),
                status: common_enums::RelayStatus::from(response.refund_status),
            },
        }
    }
}


impl api::RefundExecute for Stripebilling {}

impl api::RefundExecute for for Stripebilling


impl PaymentIntentInterface for KafkaStore {
    type Error = errors::StorageError;
    async fn update_payment_intent(
        &self,
        state: &KeyManagerState,
        this: storage::PaymentIntent,
        payment_intent: storage::PaymentIntentUpdate,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<storage::PaymentIntent, errors::StorageError> {
        let intent = self
            .diesel_store
            .update_payment_intent(
                state,
                this.clone(),
                payment_intent.clone(),
                key_store,
                storage_scheme,
            )
            .await?;

        if let Err(er) = self
            .kafka_producer
            .log_payment_intent(
                &intent,
                Some(this),
                self.tenant_id.clone(),
                state.add_confirm_value_in_infra_values(payment_intent.is_confirm_operation()),
            )
            .await
        {
            logger::error!(message="Failed to add analytics entry for Payment Intent {intent:?}", error_message=?er);
        };

        Ok(intent)
    }

    async fn insert_payment_intent(
        &self,
        state: &KeyManagerState,
        new: storage::PaymentIntent,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<storage::PaymentIntent, errors::StorageError> {
        logger::debug!("Inserting PaymentIntent Via KafkaStore");
        let intent = self
            .diesel_store
            .insert_payment_intent(state, new, key_store, storage_scheme)
            .await?;

        if let Err(er) = self
            .kafka_producer
            .log_payment_intent(
                &intent,
                None,
                self.tenant_id.clone(),
                state.infra_values.clone(),
            )
            .await
        {
            logger::error!(message="Failed to add analytics entry for Payment Intent {intent:?}", error_message=?er);
        };

        Ok(intent)
    }

    #[cfg(feature = "v1")]
    async fn find_payment_intent_by_payment_id_merchant_id(
        &self,
        state: &KeyManagerState,
        payment_id: &id_type::PaymentId,
        merchant_id: &id_type::MerchantId,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<storage::PaymentIntent, errors::StorageError> {
        self.diesel_store
            .find_payment_intent_by_payment_id_merchant_id(
                state,
                payment_id,
                merchant_id,
                key_store,
                storage_scheme,
            )
            .await
    }

    #[cfg(feature = "v2")]
    async fn find_payment_intent_by_id(
        &self,
        state: &KeyManagerState,
        payment_id: &id_type::GlobalPaymentId,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<storage::PaymentIntent, errors::StorageError> {
        self.diesel_store
            .find_payment_intent_by_id(state, payment_id, key_store, storage_scheme)
            .await
    }

    #[cfg(all(feature = "olap", feature = "v1"))]
    async fn filter_payment_intent_by_constraints(
        &self,
        state: &KeyManagerState,
        merchant_id: &id_type::MerchantId,
        filters: &hyperswitch_domain_models::payments::payment_intent::PaymentIntentFetchConstraints,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<storage::PaymentIntent>, errors::StorageError> {
        self.diesel_store
            .filter_payment_intent_by_constraints(
                state,
                merchant_id,
                filters,
                key_store,
                storage_scheme,
            )
            .await
    }

    #[cfg(all(feature = "olap", feature = "v1"))]
    async fn filter_payment_intents_by_time_range_constraints(
        &self,
        state: &KeyManagerState,
        merchant_id: &id_type::MerchantId,
        time_range: &common_utils::types::TimeRange,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<storage::PaymentIntent>, errors::StorageError> {
        self.diesel_store
            .filter_payment_intents_by_time_range_constraints(
                state,
                merchant_id,
                time_range,
                key_store,
                storage_scheme,
            )
            .await
    }
    #[cfg(feature = "olap")]
    async fn get_intent_status_with_count(
        &self,
        merchant_id: &id_type::MerchantId,
        profile_id_list: Option<Vec<id_type::ProfileId>>,
        time_range: &common_utils::types::TimeRange,
    ) -> error_stack::Result<Vec<(common_enums::IntentStatus, i64)>, errors::StorageError> {
        self.diesel_store
            .get_intent_status_with_count(merchant_id, profile_id_list, time_range)
            .await
    }

    #[cfg(all(feature = "olap", feature = "v1"))]
    async fn get_filtered_payment_intents_attempt(
        &self,
        state: &KeyManagerState,
        merchant_id: &id_type::MerchantId,
        constraints: &hyperswitch_domain_models::payments::payment_intent::PaymentIntentFetchConstraints,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<
        Vec<(
            hyperswitch_domain_models::payments::PaymentIntent,
            hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt,
        )>,
        errors::StorageError,
    > {
        self.diesel_store
            .get_filtered_payment_intents_attempt(
                state,
                merchant_id,
                constraints,
                key_store,
                storage_scheme,
            )
            .await
    }

    #[cfg(all(feature = "olap", feature = "v2"))]
    async fn get_filtered_payment_intents_attempt(
        &self,
        state: &KeyManagerState,
        merchant_id: &id_type::MerchantId,
        constraints: &hyperswitch_domain_models::payments::payment_intent::PaymentIntentFetchConstraints,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<
        Vec<(
            hyperswitch_domain_models::payments::PaymentIntent,
            Option<hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt>,
        )>,
        errors::StorageError,
    > {
        self.diesel_store
            .get_filtered_payment_intents_attempt(
                state,
                merchant_id,
                constraints,
                key_store,
                storage_scheme,
            )
            .await
    }

    #[cfg(all(feature = "olap", feature = "v1"))]
    async fn get_filtered_active_attempt_ids_for_total_count(
        &self,
        merchant_id: &id_type::MerchantId,
        constraints: &hyperswitch_domain_models::payments::payment_intent::PaymentIntentFetchConstraints,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<String>, errors::StorageError> {
        self.diesel_store
            .get_filtered_active_attempt_ids_for_total_count(
                merchant_id,
                constraints,
                storage_scheme,
            )
            .await
    }

    #[cfg(feature = "v2")]
    async fn find_payment_intent_by_merchant_reference_id_profile_id(
        &self,
        state: &KeyManagerState,
        merchant_reference_id: &id_type::PaymentReferenceId,
        profile_id: &id_type::ProfileId,
        merchant_key_store: &domain::MerchantKeyStore,
        storage_scheme: &MerchantStorageScheme,
    ) -> error_stack::Result<hyperswitch_domain_models::payments::PaymentIntent, errors::StorageError>
    {
        self.diesel_store
            .find_payment_intent_by_merchant_reference_id_profile_id(
                state,
                merchant_reference_id,
                profile_id,
                merchant_key_store,
                storage_scheme,
            )
            .await
    }
    #[cfg(all(feature = "olap", feature = "v2"))]
    async fn get_filtered_active_attempt_ids_for_total_count(
        &self,
        merchant_id: &id_type::MerchantId,
        constraints: &hyperswitch_domain_models::payments::payment_intent::PaymentIntentFetchConstraints,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<Option<String>>, errors::StorageError> {
        self.diesel_store
            .get_filtered_active_attempt_ids_for_total_count(
                merchant_id,
                constraints,
                storage_scheme,
            )
            .await
    }
}

impl PaymentIntentInterface for for KafkaStore


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

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

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

impl ConnectorSpecifications for for Billwerk


pub struct ProcessorConnected {
    pub processor_id: id_type::MerchantConnectorAccountId,
    pub processor_name: String,
}


pub struct DomainIdentifier(String);


OpenAPI Block Path: components.schemas.SamsungPayWalletData
{
  "type": "object",
  "required": [
    "payment_credential"
  ],
  "properties": {
    "payment_credential": {
      "$ref": "#/components/schemas/SamsungPayWalletCredentials"
    }
  }
}


pub fn get_debit_routing_decision_data(
        network: common_enums::enums::CardNetwork,
        debit_routing_result: Option<open_router::DebitRoutingOutput>,
    ) -> Self {
        Self::DebitRouting(DebitRoutingDecisionData {
            card_network: network,
            debit_routing_result,
        })
    }


pub fn analyze_program(js_program: JsValue) -> JsResult {
    let program: ast::Program<ConnectorSelection> = serde_wasm_bindgen::from_value(js_program)?;
    analyzer::analyze(program, SEED_DATA.get().map(|sd| &sd.cgraph)).err_to_js()?;
    Ok(JsValue::NULL)
}


pub struct Status {
    pub code: String,
    pub description: String,
    pub severity: String,
}


impl PaymentToken for Plaid {}


OpenAPI Block Path: paths."/relay/{relay_id}"
{
  "get": {
    "tags": [
      "Relay"
    ],
    "summary": "Relay - Retrieve",
    "description": "Retrieves a relay details.",
    "operationId": "Retrieve a Relay details",
    "parameters": [
      {
        "name": "relay_id",
        "in": "path",
        "description": "The unique identifier for the Relay",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      {
        "name": "X-Profile-Id",
        "in": "header",
        "description": "Profile ID for authentication",
        "required": true,
        "schema": {
          "type": "string"
        }
      }
    ],
    "responses": {
      "200": {
        "description": "Relay Retrieved",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/RelayResponse"
            }
          }
        }
      },
      "404": {
        "description": "Relay details was not found"
      }
    },
    "security": [
      {
        "api_key": []
      },
      {
        "ephemeral_key": []
      }
    ]
  }
}


 macro_rules! platform {
//     (
//     ) => {
//         concat!(
//             env!("VERGEN_SYSINFO_OS_VERSION"),
//             " - ",
//             env!("VERGEN_SYSINFO_CPU_BRAND"),
//         )
//     };
// }


impl RevenueRecoveryPaymentsAttemptStatus {
    pub(crate) async fn update_pt_status_based_on_attempt_status_for_execute_payment(
        &self,
        db: &dyn StorageInterface,
        execute_task_process: &storage::ProcessTracker,
    ) -> Result<(), errors::ProcessTrackerError> {
        logger::info!("Entering update_pt_status_based_on_attempt_status_for_execute_payment");
        match &self {
            Self::Succeeded | Self::Failed | Self::Processing => {
                // finish the current execute task
                db.finish_process_with_business_status(
                    execute_task_process.clone(),
                    business_status::EXECUTE_WORKFLOW_COMPLETE_FOR_PSYNC,
                )
                .await?;
            }

            Self::InvalidStatus(action) => {
                logger::debug!(
                    "Invalid Attempt Status for the Recovery Payment : {}",
                    action
                );
                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.update_process(execute_task_process.clone(), pt_update)
                    .await?;
            }
        };
        Ok(())
    }

    #[allow(clippy::too_many_arguments)]
    pub(crate) async fn update_pt_status_based_on_attempt_status_for_payments_sync(
        &self,
        state: &SessionState,
        payment_intent: &PaymentIntent,
        process_tracker: storage::ProcessTracker,
        profile: &domain::Profile,
        merchant_context: domain::MerchantContext,
        revenue_recovery_payment_data: &storage::revenue_recovery::RevenueRecoveryPaymentData,
        payment_attempt: PaymentAttempt,
        revenue_recovery_metadata: &mut PaymentRevenueRecoveryMetadata,
    ) -> Result<(), errors::ProcessTrackerError> {
        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 db = &*state.store;

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

        let recovery_payment_attempt =
            hyperswitch_domain_models::revenue_recovery::RecoveryPaymentAttempt::from(
                &payment_attempt,
            );

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

        let used_token = get_payment_processor_token_id_from_payment_attempt(&payment_attempt);

        let retry_count = process_tracker.retry_count;

        match self {
            Self::Succeeded => {
                // finish psync task as the payment was a success
                db.as_scheduler()
                    .finish_process_with_business_status(
                        process_tracker,
                        business_status::PSYNC_WORKFLOW_COMPLETE,
                    )
                    .await?;
                // publish events to kafka
                if let Err(e) = recovery_incoming_flow::RecoveryPaymentTuple::publish_revenue_recovery_event_to_kafka(
                    state,
                    &recovery_payment_tuple,
                    Some(retry_count+1)
                )
                .await{
                    router_env::logger::error!(
                        "Failed to publish revenue recovery event to kafka: {:?}",
                        e
                    );
                };

                // 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,
                    // Since this is succeeded payment attempt, 'is_hard_decine' will be false.
                    &Some(false),
                    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;

                // 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")?;
            }
            Self::Failed => {
                // finish psync task
                db.as_scheduler()
                    .finish_process_with_business_status(
                        process_tracker.clone(),
                        business_status::PSYNC_WORKFLOW_COMPLETE,
                    )
                    .await?;
                // publish events to kafka
                if let Err(e) = recovery_incoming_flow::RecoveryPaymentTuple::publish_revenue_recovery_event_to_kafka(
                    state,
                    &recovery_payment_tuple,
                    Some(retry_count+1)
                )
                .await{
                    router_env::logger::error!(
                        "Failed to publish revenue recovery event to kafka : {:?}", e
                    );
                };

                let error_code = recovery_payment_attempt.error_code;

                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,
                    &error_code,
                    &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;

                // Reopen calculate workflow on payment failure
                reopen_calculate_workflow_on_payment_failure(
                    state,
                    &process_tracker,
                    profile,
                    merchant_context,
                    payment_intent,
                    revenue_recovery_payment_data,
                )
                .await?;
            }
            Self::Processing => {
                // do a psync payment
                let action = Box::pin(Action::payment_sync_call(
                    state,
                    revenue_recovery_payment_data,
                    payment_intent,
                    &process_tracker,
                    profile,
                    merchant_context,
                    payment_attempt,
                ))
                .await?;

                //handle the response
                Box::pin(action.psync_response_handler(
                    state,
                    payment_intent,
                    &process_tracker,
                    revenue_recovery_metadata,
                    revenue_recovery_payment_data,
                ))
                .await?;
            }
            Self::InvalidStatus(status) => logger::debug!(
                "Invalid Attempt Status for the Recovery Payment : {}",
                status
            ),
        }
        Ok(())
    }
}


pub fn get_transaction_type(&self) -> api_enums::TransactionType {
        match self.connector_type {
            #[cfg(feature = "payouts")]
            api_enums::ConnectorType::PayoutProcessor => api_enums::TransactionType::Payout,
            _ => api_enums::TransactionType::Payment,
        }
    }


pub fn get_html_body(email_body: EmailBody) -> String {
        match email_body {
            EmailBody::Verify {
                link,
                entity_name,
                entity_logo_url,
                primary_color,
                background_color,
                foreground_color,
            } => {
                format!(
                    include_str!("assets/verify.html"),
                    link = link,
                    entity_name = entity_name,
                    entity_logo_url = entity_logo_url,
                    primary_color = primary_color,
                    background_color = background_color,
                    foreground_color = foreground_color
                )
            }
            EmailBody::Reset {
                link,
                user_name,
                entity_name,
                entity_logo_url,
                primary_color,
                background_color,
                foreground_color,
            } => {
                format!(
                    include_str!("assets/reset.html"),
                    link = link,
                    username = user_name,
                    entity_name = entity_name,
                    entity_logo_url = entity_logo_url,
                    primary_color = primary_color,
                    background_color = background_color,
                    foreground_color = foreground_color
                )
            }
            EmailBody::MagicLink {
                link,
                user_name,
                entity_name,
                entity_logo_url,
                primary_color,
                background_color,
                foreground_color,
            } => {
                format!(
                    include_str!("assets/magic_link.html"),
                    username = user_name,
                    link = link,
                    entity_name = entity_name,
                    entity_logo_url = entity_logo_url,
                    primary_color = primary_color,
                    background_color = background_color,
                    foreground_color = foreground_color
                )
            }

            EmailBody::InviteUser {
                link,
                user_name,
                entity_name,
                entity_logo_url,
                primary_color,
                background_color,
                foreground_color,
            } => {
                format!(
                    include_str!("assets/invite.html"),
                    username = user_name,
                    link = link,
                    entity_name = entity_name,
                    entity_logo_url = entity_logo_url,
                    primary_color = primary_color,
                    background_color = background_color,
                    foreground_color = foreground_color
                )
            }
            // TODO: Change the linked html for accept invite from email
            EmailBody::AcceptInviteFromEmail {
                link,
                user_name,
                entity_name,
                entity_logo_url,
                primary_color,
                background_color,
                foreground_color,
            } => {
                format!(
                    include_str!("assets/invite.html"),
                    username = user_name,
                    link = link,
                    entity_name = entity_name,
                    entity_logo_url = entity_logo_url,
                    primary_color = primary_color,
                    background_color = background_color,
                    foreground_color = foreground_color
                )
            }
            EmailBody::ReconActivation { user_name } => {
                format!(
                    include_str!("assets/recon_activation.html"),
                    username = user_name,
                )
            }
            EmailBody::BizEmailProd {
                user_name,
                poc_email,
                legal_business_name,
                business_location,
                business_website,
                product_type,
            } => {
                format!(
                    include_str!("assets/bizemailprod.html"),
                    poc_email = poc_email,
                    legal_business_name = legal_business_name,
                    business_location = business_location,
                    business_website = business_website,
                    username = user_name,
                    product_type = product_type
                )
            }
            EmailBody::ProFeatureRequest {
                feature_name,
                merchant_id,
                user_name,
                user_email,
            } => format!(
                "Dear Hyperswitch Support Team,

Dashboard Pro Feature Request,
Feature name  : {feature_name}
Merchant ID   : {}
Merchant Name : {user_name}
Email         : {user_email}

(note: This is an auto generated email. Use merchant email for any further communications)",
                merchant_id.get_string_repr()
            ),
            EmailBody::ApiKeyExpiryReminder {
                expires_in,
                api_key_name,
                prefix,
            } => format!(
                include_str!("assets/api_key_expiry_reminder.html"),
                api_key_name = api_key_name,
                prefix = prefix,
                expires_in = expires_in,
            ),
            EmailBody::WelcomeToCommunity => {
                include_str!("assets/welcome_to_community.html").to_string()
            }
        }
    }


impl db::payment_method_session::PaymentMethodsSessionInterface for KafkaStore {
    async fn insert_payment_methods_session(
        &self,
        state: &KeyManagerState,
        key_store: &hyperswitch_domain_models::merchant_key_store::MerchantKeyStore,
        payment_methods_session: hyperswitch_domain_models::payment_methods::PaymentMethodSession,
        validity: i64,
    ) -> CustomResult<(), errors::StorageError> {
        self.diesel_store
            .insert_payment_methods_session(state, key_store, payment_methods_session, validity)
            .await
    }

    async fn get_payment_methods_session(
        &self,
        state: &KeyManagerState,
        key_store: &hyperswitch_domain_models::merchant_key_store::MerchantKeyStore,
        id: &id_type::GlobalPaymentMethodSessionId,
    ) -> CustomResult<
        hyperswitch_domain_models::payment_methods::PaymentMethodSession,
        errors::StorageError,
    > {
        self.diesel_store
            .get_payment_methods_session(state, key_store, id)
            .await
    }

    async fn update_payment_method_session(
        &self,
        state: &KeyManagerState,
        key_store: &hyperswitch_domain_models::merchant_key_store::MerchantKeyStore,
        id: &id_type::GlobalPaymentMethodSessionId,
        payment_methods_session: hyperswitch_domain_models::payment_methods::PaymentMethodsSessionUpdateEnum,
        current_session: hyperswitch_domain_models::payment_methods::PaymentMethodSession,
    ) -> CustomResult<
        hyperswitch_domain_models::payment_methods::PaymentMethodSession,
        errors::StorageError,
    > {
        self.diesel_store
            .update_payment_method_session(
                state,
                key_store,
                id,
                payment_methods_session,
                current_session,
            )
            .await
    }
}

impl db::payment_method_session::PaymentMethodsSessionInterface for for KafkaStore


File: crates/diesel_models/src/locker_mock_up.rs
 Public structs: 2

use diesel::{Identifiable, Insertable, Queryable, Selectable};

use crate::schema::locker_mock_up;

#[derive(Clone, Debug, Eq, Identifiable, Queryable, Selectable, PartialEq)]
#[diesel(table_name = locker_mock_up, primary_key(card_id), check_for_backend(diesel::pg::Pg))]
pub struct LockerMockUp {
    pub card_id: String,
    pub external_id: String,
    pub card_fingerprint: String,
    pub card_global_fingerprint: String,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub card_number: String,
    pub card_exp_year: String,
    pub card_exp_month: String,
    pub name_on_card: Option<String>,
    pub nickname: Option<String>,
    pub customer_id: Option<common_utils::id_type::CustomerId>,
    pub duplicate: Option<bool>,
    pub card_cvc: Option<String>,
    pub payment_method_id: Option<String>,
    pub enc_card_data: Option<String>,
}

#[derive(Clone, Debug, Default, Insertable, router_derive::DebugAsDisplay)]
#[diesel(table_name = locker_mock_up)]
pub struct LockerMockUpNew {
    pub card_id: String,
    pub external_id: String,
    pub card_fingerprint: String,
    pub card_global_fingerprint: String,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub card_number: String,
    pub card_exp_year: String,
    pub card_exp_month: String,
    pub name_on_card: Option<String>,
    pub card_cvc: Option<String>,
    pub payment_method_id: Option<String>,
    pub customer_id: Option<common_utils::id_type::CustomerId>,
    pub nickname: Option<String>,
    pub enc_card_data: Option<String>,
}


pub struct PaystackRouterData<T> {
    pub amount: MinorUnit,
    pub router_data: T,
}


impl api::Refund for Bambora {}


/// Generate a response from the given Data. This should be implemented on a payment data object
pub trait GenerateResponse<Response>
where
    Self: Sized,
{
    #[cfg(feature = "v2")]
    #[allow(clippy::too_many_arguments)]
    fn generate_response(
        self,
        state: &SessionState,
        connector_http_status_code: Option<u16>,
        external_latency: Option<u128>,
        is_latency_header_enabled: Option<bool>,
        merchant_context: &domain::MerchantContext,
        profile: &domain::Profile,
        connector_response_data: Option<common_types::domain::ConnectorResponseData>,
    ) -> RouterResponse<Response>;
}


OpenAPI Block Path: components.schemas.VoucherData
{
  "oneOf": [
    {
      "type": "object",
      "required": [
        "boleto"
      ],
      "properties": {
        "boleto": {
          "$ref": "#/components/schemas/BoletoVoucherData"
        }
      }
    },
    {
      "type": "string",
      "enum": [
        "efecty"
      ]
    },
    {
      "type": "string",
      "enum": [
        "pago_efectivo"
      ]
    },
    {
      "type": "string",
      "enum": [
        "red_compra"
      ]
    },
    {
      "type": "string",
      "enum": [
        "red_pagos"
      ]
    },
    {
      "type": "object",
      "required": [
        "alfamart"
      ],
      "properties": {
        "alfamart": {
          "$ref": "#/components/schemas/AlfamartVoucherData"
        }
      }
    },
    {
      "type": "object",
      "required": [
        "indomaret"
      ],
      "properties": {
        "indomaret": {
          "$ref": "#/components/schemas/IndomaretVoucherData"
        }
      }
    },
    {
      "type": "string",
      "enum": [
        "oxxo"
      ]
    },
    {
      "type": "object",
      "required": [
        "seven_eleven"
      ],
      "properties": {
        "seven_eleven": {
          "$ref": "#/components/schemas/JCSVoucherData"
        }
      }
    },
    {
      "type": "object",
      "required": [
        "lawson"
      ],
      "properties": {
        "lawson": {
          "$ref": "#/components/schemas/JCSVoucherData"
        }
      }
    },
    {
      "type": "object",
      "required": [
        "mini_stop"
      ],
      "properties": {
        "mini_stop": {
          "$ref": "#/components/schemas/JCSVoucherData"
        }
      }
    },
    {
      "type": "object",
      "required": [
        "family_mart"
      ],
      "properties": {
        "family_mart": {
          "$ref": "#/components/schemas/JCSVoucherData"
        }
      }
    },
    {
      "type": "object",
      "required": [
        "seicomart"
      ],
      "properties": {
        "seicomart": {
          "$ref": "#/components/schemas/JCSVoucherData"
        }
      }
    },
    {
      "type": "object",
      "required": [
        "pay_easy"
      ],
      "properties": {
        "pay_easy": {
          "$ref": "#/components/schemas/JCSVoucherData"
        }
      }
    }
  ]
}


pub fn get_pending_captures(&self) -> Vec<&storage::Capture> {
        self.all_captures
            .iter()
            .filter(|capture| capture.1.status == storage_enums::CaptureStatus::Pending)
            .map(|key_value| key_value.1)
            .collect()
    }


impl NuveiPaymentsGenericResponse for PSync {}

impl NuveiPaymentsGenericResponse for for PSync