feat(core): support for gpay session token creation (#152)

This commit is contained in:
Narayan Bhat
2022-12-19 13:38:03 +05:30
committed by GitHub
parent 5a43da6a1a
commit 50706bde77
15 changed files with 262 additions and 62 deletions

View File

@ -691,11 +691,65 @@ pub struct PaymentsSessionRequest {
pub client_secret: String, pub client_secret: String,
} }
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct GpayAllowedMethodsParameters {
pub allowed_auth_methods: Vec<String>,
pub allowed_card_networks: Vec<String>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct GpayTokenParameters {
pub gateway: String,
pub gateway_merchant_id: String,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct GpayTokenizationSpecification {
#[serde(rename = "type")]
pub token_specification_type: String,
pub parameters: GpayTokenParameters,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct GpayAllowedPaymentMethods {
#[serde(rename = "type")]
pub payment_method_type: String,
pub parameters: GpayAllowedMethodsParameters,
pub tokenization_specification: GpayTokenizationSpecification,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct GpayTransactionInfo {
pub country_code: String,
pub currency_code: String,
pub total_price_status: String,
pub total_price: i64,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct GpayMerchantInfo {
pub merchant_name: String,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct GpayMetadata {
pub merchant_info: GpayMerchantInfo,
pub allowed_payment_methods: Vec<GpayAllowedPaymentMethods>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct GpaySessionTokenData {
pub gpay: GpayMetadata,
}
#[derive(Debug, Clone, serde::Serialize)] #[derive(Debug, Clone, serde::Serialize)]
#[serde(tag = "connector_name")] #[serde(tag = "connector_name")]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
pub enum SessionToken { pub enum SessionToken {
Gpay {}, Gpay {
allowed_payment_methods: Vec<GpayAllowedPaymentMethods>,
transaction_info: GpayTransactionInfo,
},
Klarna { Klarna {
session_token: String, session_token: String,
session_id: String, session_id: String,

View File

@ -111,7 +111,7 @@ impl
.build(), .build(),
); );
logger::debug!(session_request=?request); logger::debug!(braintree_session_request=?request);
Ok(request) Ok(request)
} }
@ -132,9 +132,14 @@ impl
fn get_request_body( fn get_request_body(
&self, &self,
_req: &types::PaymentsSessionRouterData, req: &types::PaymentsSessionRouterData,
) -> CustomResult<Option<String>, errors::ConnectorError> { ) -> CustomResult<Option<String>, errors::ConnectorError> {
Ok(None) let braintree_session_request =
utils::Encode::<braintree::BraintreeSessionRequest>::convert_and_encode(req)
.change_context(errors::ConnectorError::RequestEncodingFailed)?;
logger::debug!(?braintree_session_request);
Ok(Some(braintree_session_request))
} }
fn handle_response( fn handle_response(

View File

@ -19,6 +19,27 @@ pub struct BraintreePaymentsRequest {
transaction: TransactionBody, transaction: TransactionBody,
} }
#[derive(Default, Debug, Serialize, Eq, PartialEq)]
pub struct BraintreeApiVersion {
version: String,
}
#[derive(Default, Debug, Serialize, Eq, PartialEq)]
pub struct BraintreeSessionRequest {
client_token: BraintreeApiVersion,
}
impl TryFrom<&types::PaymentsSessionRouterData> for BraintreeSessionRequest {
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(_item: &types::PaymentsSessionRouterData) -> Result<Self, Self::Error> {
Ok(Self {
client_token: BraintreeApiVersion {
version: "2".to_string(),
},
})
}
}
#[derive(Default, Debug, Serialize, Eq, PartialEq)] #[derive(Default, Debug, Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct TransactionBody { pub struct TransactionBody {
@ -178,7 +199,7 @@ impl<F, T>
Ok(types::RouterData { Ok(types::RouterData {
response: Ok(types::PaymentsResponseData::SessionResponse { response: Ok(types::PaymentsResponseData::SessionResponse {
session_token: types::api::SessionToken::Paypal { session_token: types::api::SessionToken::Paypal {
session_token: item.response.client_token.value.authorization_fingerprint, session_token: item.response.client_token.value,
}, },
}), }),
..item.data ..item.data
@ -192,16 +213,10 @@ pub struct BraintreePaymentsResponse {
transaction: TransactionResponse, transaction: TransactionResponse,
} }
#[derive(Default, Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AuthorizationFingerprint {
authorization_fingerprint: String,
}
#[derive(Default, Debug, Clone, Deserialize)] #[derive(Default, Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct ClientToken { pub struct ClientToken {
#[serde(with = "common_utils::custom_serde::json_string")] pub value: String,
pub value: AuthorizationFingerprint,
} }
#[derive(Default, Debug, Clone, Deserialize)] #[derive(Default, Debug, Clone, Deserialize)]

View File

@ -169,7 +169,6 @@ where
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
#[instrument(skip_all)]
pub async fn payments_core<F, Res, Req, Op, FData>( pub async fn payments_core<F, Res, Req, Op, FData>(
state: &AppState, state: &AppState,
merchant_account: storage::MerchantAccount, merchant_account: storage::MerchantAccount,
@ -236,8 +235,11 @@ where
}, },
)?; )?;
let connector_data = let connector_data = api::ConnectorData::get_connector_by_name(
api::ConnectorData::get_connector_by_name(&state.conf.connectors, &connector)?; &state.conf.connectors,
&connector,
api::GetToken::Connector,
)?;
let flow_type = connector_data let flow_type = connector_data
.connector .connector
@ -402,17 +404,16 @@ where
for (connector_res, connector) in result.into_iter().zip(connectors) { for (connector_res, connector) in result.into_iter().zip(connectors) {
let connector_name = connector.connector_name.to_string(); let connector_name = connector.connector_name.to_string();
match connector_res?.response { match connector_res {
Ok(connector_response) => { Ok(connector_response) => {
if let types::PaymentsResponseData::SessionResponse { session_token } = if let Ok(types::PaymentsResponseData::SessionResponse { session_token }) =
connector_response connector_response.response
{ {
payment_data.sessions_token.push(session_token); payment_data.sessions_token.push(session_token);
} }
} }
Err(connector_error) => { Err(connector_error) => {
logger::debug!( logger::error!(
"sessions_connector_error {} {:?}", "sessions_connector_error {} {:?}",
connector_name, connector_name,
connector_error connector_error

View File

@ -1,9 +1,11 @@
use api_models::payments as payment_types;
use async_trait::async_trait; use async_trait::async_trait;
use error_stack::ResultExt;
use super::{ConstructFlowSpecificData, Feature}; use super::{ConstructFlowSpecificData, Feature};
use crate::{ use crate::{
core::{ core::{
errors::{ConnectorErrorExt, RouterResult}, errors::{self, ConnectorErrorExt, RouterResult},
payments::{self, transformers, PaymentData}, payments::{self, transformers, PaymentData},
}, },
routes, services, routes, services,
@ -11,6 +13,7 @@ use crate::{
self, api, self, api,
storage::{self, enums}, storage::{self, enums},
}, },
utils::OptionExt,
}; };
#[async_trait] #[async_trait]
@ -55,6 +58,45 @@ impl Feature<api::Session, types::PaymentsSessionData> for types::PaymentsSessio
} }
} }
fn create_gpay_session_token(
router_data: &types::PaymentsSessionRouterData,
) -> RouterResult<types::PaymentsSessionRouterData> {
let connector_metadata = router_data.connector_meta_data.clone();
let gpay_data = connector_metadata
.clone()
.parse_value::<payment_types::GpaySessionTokenData>("GpaySessionTokenData")
.change_context(errors::ConnectorError::NoConnectorMetaData)
.attach_printable(format!(
"cannnot parse gpay metadata from the given value {:?}",
connector_metadata
))
.change_context(errors::ApiErrorResponse::InvalidDataFormat {
field_name: "connector_metadata".to_string(),
expected_format: "gpay_metadata_format".to_string(),
})?;
let session_data = router_data.request.clone();
let transaction_info = payment_types::GpayTransactionInfo {
country_code: session_data.country.unwrap_or_else(|| "US".to_string()),
currency_code: router_data.request.currency.to_string(),
total_price_status: "Final".to_string(),
total_price: router_data.request.amount,
};
let response_router_data = types::PaymentsSessionRouterData {
response: Ok(types::PaymentsResponseData::SessionResponse {
session_token: payment_types::SessionToken::Gpay {
allowed_payment_methods: gpay_data.gpay.allowed_payment_methods,
transaction_info,
},
}),
..router_data.clone()
};
Ok(response_router_data)
}
impl types::PaymentsSessionRouterData { impl types::PaymentsSessionRouterData {
pub async fn decide_flow<'a, 'b>( pub async fn decide_flow<'a, 'b>(
&'b self, &'b self,
@ -64,20 +106,25 @@ impl types::PaymentsSessionRouterData {
_confirm: Option<bool>, _confirm: Option<bool>,
call_connector_action: payments::CallConnectorAction, call_connector_action: payments::CallConnectorAction,
) -> RouterResult<types::PaymentsSessionRouterData> { ) -> RouterResult<types::PaymentsSessionRouterData> {
let connector_integration: services::BoxedConnectorIntegration< match connector.get_token {
api::Session, api::GetToken::Metadata => create_gpay_session_token(self),
types::PaymentsSessionData, api::GetToken::Connector => {
types::PaymentsResponseData, let connector_integration: services::BoxedConnectorIntegration<
> = connector.connector.get_connector_integration(); api::Session,
let resp = services::execute_connector_processing_step( types::PaymentsSessionData,
state, types::PaymentsResponseData,
connector_integration, > = connector.connector.get_connector_integration();
self, let resp = services::execute_connector_processing_step(
call_connector_action, state,
) connector_integration,
.await self,
.map_err(|error| error.to_payment_failed_response())?; call_connector_action,
)
.await
.map_err(|error| error.to_payment_failed_response())?;
Ok(resp) Ok(resp)
}
}
} }
} }

View File

@ -650,7 +650,11 @@ pub async fn get_connector_default(
.change_context(errors::ApiErrorResponse::InternalServerError)? .change_context(errors::ApiErrorResponse::InternalServerError)?
.as_str(); .as_str();
let connector_data = api::ConnectorData::get_connector_by_name(connectors, connector_name)?; let connector_data = api::ConnectorData::get_connector_by_name(
connectors,
connector_name,
api::GetToken::Connector,
)?;
Ok(api::ConnectorCallType::Single(connector_data)) Ok(api::ConnectorCallType::Single(connector_data))
} }

View File

@ -1,6 +1,7 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use async_trait::async_trait; use async_trait::async_trait;
use common_utils::ext_traits::ValueExt;
use error_stack::ResultExt; use error_stack::ResultExt;
use router_derive::PaymentOperation; use router_derive::PaymentOperation;
use router_env::{instrument, tracing}; use router_env::{instrument, tracing};
@ -197,6 +198,11 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsSessionRequest> for Paymen
} }
} }
#[derive(serde::Deserialize, Default)]
pub struct PaymentMethodEnabled {
payment_method: String,
}
#[async_trait] #[async_trait]
impl<F: Clone + Send, Op: Send + Sync + Operation<F, api::PaymentsSessionRequest>> impl<F: Clone + Send, Op: Send + Sync + Operation<F, api::PaymentsSessionRequest>>
Domain<F, api::PaymentsSessionRequest> for Op Domain<F, api::PaymentsSessionRequest> for Op
@ -257,12 +263,13 @@ where
let supported_connectors: &Vec<String> = state.conf.connectors.supported.wallets.as_ref(); let supported_connectors: &Vec<String> = state.conf.connectors.supported.wallets.as_ref();
//FIXME: Check if merchant has enabled wallet through the connector let connector_accounts = db
let connector_names = db
.find_merchant_connector_account_by_merchant_id_list(&merchant_account.merchant_id) .find_merchant_connector_account_by_merchant_id_list(&merchant_account.merchant_id)
.await .await
.change_context(errors::ApiErrorResponse::InternalServerError) .change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Database error when querying for merchant accounts")? .attach_printable("Database error when querying for merchant connector accounts")?;
let normal_connector_names = connector_accounts
.iter() .iter()
.filter(|connector_account| { .filter(|connector_account| {
supported_connectors.contains(&connector_account.connector_name) supported_connectors.contains(&connector_account.connector_name)
@ -270,11 +277,48 @@ where
.map(|filtered_connector| filtered_connector.connector_name.clone()) .map(|filtered_connector| filtered_connector.connector_name.clone())
.collect::<Vec<String>>(); .collect::<Vec<String>>();
let mut connectors_data = Vec::with_capacity(connector_names.len()); // Parse the payment methods enabled to check if the merchant has enabled gpay ( wallet )
// through that connector this parsing from Value to payment method is costly and has to be done for every connector
// for sure looks like an area of optimization
let session_token_from_metadata_connectors = connector_accounts
.iter()
.filter(|connector_account| {
connector_account
.payment_methods_enabled
.clone()
.unwrap_or_default()
.iter()
.any(|payment_method| {
let parsed_payment_method: PaymentMethodEnabled = payment_method
.clone()
.parse_value("payment_method")
.unwrap_or_default();
for connector_name in connector_names { parsed_payment_method.payment_method == "wallet"
let connector_data = })
api::ConnectorData::get_connector_by_name(connectors, &connector_name)?; })
.map(|filtered_connector| filtered_connector.connector_name.clone())
.collect::<Vec<String>>();
let mut connectors_data = Vec::with_capacity(
normal_connector_names.len() + session_token_from_metadata_connectors.len(),
);
for connector_name in normal_connector_names {
let connector_data = api::ConnectorData::get_connector_by_name(
connectors,
&connector_name,
api::GetToken::Connector,
)?;
connectors_data.push(connector_data);
}
for connector_name in session_token_from_metadata_connectors {
let connector_data = api::ConnectorData::get_connector_by_name(
connectors,
&connector_name,
api::GetToken::Metadata,
)?;
connectors_data.push(connector_data); connectors_data.push(connector_data);
} }

View File

@ -468,6 +468,11 @@ impl<F: Clone> TryFrom<PaymentData<F>> for types::PaymentsSessionData {
Ok(Self { Ok(Self {
amount: payment_data.amount.into(), amount: payment_data.amount.into(),
currency: payment_data.currency, currency: payment_data.currency,
country: payment_data
.address
.billing
.and_then(|billing_address| billing_address.address.map(|address| address.country))
.flatten(),
}) })
} }
} }

View File

@ -97,10 +97,13 @@ pub async fn trigger_refund_to_gateway(
.clone() .clone()
.ok_or(errors::ApiErrorResponse::InternalServerError)?; .ok_or(errors::ApiErrorResponse::InternalServerError)?;
let connector_id = connector.to_string(); let connector_id = connector.to_string();
let connector: api::ConnectorData = let connector: api::ConnectorData = api::ConnectorData::get_connector_by_name(
api::ConnectorData::get_connector_by_name(&state.conf.connectors, &connector_id) &state.conf.connectors,
.change_context(errors::ApiErrorResponse::InternalServerError) &connector_id,
.attach_printable("Failed to get the connector")?; api::GetToken::Connector,
)
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to get the connector")?;
let currency = payment_attempt.currency.ok_or_else(|| { let currency = payment_attempt.currency.ok_or_else(|| {
report!(errors::ApiErrorResponse::MissingRequiredField { report!(errors::ApiErrorResponse::MissingRequiredField {
@ -241,10 +244,13 @@ pub async fn sync_refund_with_gateway(
refund: &storage::Refund, refund: &storage::Refund,
) -> RouterResult<storage::Refund> { ) -> RouterResult<storage::Refund> {
let connector_id = refund.connector.to_string(); let connector_id = refund.connector.to_string();
let connector: api::ConnectorData = let connector: api::ConnectorData = api::ConnectorData::get_connector_by_name(
api::ConnectorData::get_connector_by_name(&state.conf.connectors, &connector_id) &state.conf.connectors,
.change_context(errors::ApiErrorResponse::InternalServerError) &connector_id,
.attach_printable("Failed to get the connector")?; api::GetToken::Connector,
)
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to get the connector")?;
let currency = payment_attempt.currency.get_required_value("currency")?; let currency = payment_attempt.currency.get_required_value("currency")?;

View File

@ -197,10 +197,13 @@ pub async fn webhooks_core(
connector_name: &str, connector_name: &str,
body: actix_web::web::Bytes, body: actix_web::web::Bytes,
) -> RouterResponse<serde_json::Value> { ) -> RouterResponse<serde_json::Value> {
let connector = let connector = api::ConnectorData::get_connector_by_name(
api::ConnectorData::get_connector_by_name(&state.conf.connectors, connector_name) &state.conf.connectors,
.change_context(errors::ApiErrorResponse::InternalServerError) connector_name,
.attach_printable("Failed construction of ConnectorData")?; api::GetToken::Connector,
)
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed construction of ConnectorData")?;
let connector = connector.connector; let connector = connector.connector;

View File

@ -124,9 +124,9 @@ pub struct PaymentsCancelData {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct PaymentsSessionData { pub struct PaymentsSessionData {
//TODO: Add the fields here as required
pub amount: i64, pub amount: i64,
pub currency: storage_enums::Currency, pub currency: storage_enums::Currency,
pub country: Option<String>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -147,12 +147,6 @@ pub struct PaymentsTransactionResponse {
pub redirect: bool, pub redirect: bool,
} }
#[derive(Debug, Clone)]
pub struct PaymentsSessionResponse {
pub session_id: Option<String>,
pub session_token: String,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum PaymentsResponseData { pub enum PaymentsResponseData {
TransactionResponse { TransactionResponse {

View File

@ -64,9 +64,17 @@ impl<T: Refund + Payment + Debug + ConnectorRedirectResponse + Send + IncomingWe
type BoxedConnector = Box<&'static (dyn Connector + marker::Sync)>; type BoxedConnector = Box<&'static (dyn Connector + marker::Sync)>;
// Normal flow will call the connector and follow the flow specific operations (capture, authorize)
// SessionTokenFromMetadata will avoid calling the connector instead create the session token ( for sdk )
pub enum GetToken {
Metadata,
Connector,
}
pub struct ConnectorData { pub struct ConnectorData {
pub connector: BoxedConnector, pub connector: BoxedConnector,
pub connector_name: types::Connector, pub connector_name: types::Connector,
pub get_token: GetToken,
} }
pub enum ConnectorCallType { pub enum ConnectorCallType {
@ -78,6 +86,7 @@ impl ConnectorData {
pub fn get_connector_by_name( pub fn get_connector_by_name(
connectors: &Connectors, connectors: &Connectors,
name: &str, name: &str,
connector_type: GetToken,
) -> CustomResult<ConnectorData, errors::ApiErrorResponse> { ) -> CustomResult<ConnectorData, errors::ApiErrorResponse> {
let connector = Self::convert_connector(connectors, name)?; let connector = Self::convert_connector(connectors, name)?;
let connector_name = types::Connector::from_str(name) let connector_name = types::Connector::from_str(name)
@ -88,6 +97,7 @@ impl ConnectorData {
Ok(ConnectorData { Ok(ConnectorData {
connector, connector,
connector_name, connector_name,
get_token: connector_type,
}) })
} }

View File

@ -104,6 +104,7 @@ async fn payments_create_success() {
let connector = types::api::ConnectorData { let connector = types::api::ConnectorData {
connector: Box::new(&CV), connector: Box::new(&CV),
connector_name: types::Connector::Aci, connector_name: types::Connector::Aci,
get_token: types::api::GetToken::Connector,
}; };
let connector_integration: services::BoxedConnectorIntegration< let connector_integration: services::BoxedConnectorIntegration<
types::api::Authorize, types::api::Authorize,
@ -135,6 +136,7 @@ async fn payments_create_failure() {
let connector = types::api::ConnectorData { let connector = types::api::ConnectorData {
connector: Box::new(&CV), connector: Box::new(&CV),
connector_name: types::Connector::Aci, connector_name: types::Connector::Aci,
get_token: types::api::GetToken::Connector,
}; };
let connector_integration: services::BoxedConnectorIntegration< let connector_integration: services::BoxedConnectorIntegration<
types::api::Authorize, types::api::Authorize,
@ -171,6 +173,7 @@ async fn refund_for_successful_payments() {
let connector = types::api::ConnectorData { let connector = types::api::ConnectorData {
connector: Box::new(&CV), connector: Box::new(&CV),
connector_name: types::Connector::Aci, connector_name: types::Connector::Aci,
get_token: types::api::GetToken::Connector,
}; };
let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await; let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await;
let connector_integration: services::BoxedConnectorIntegration< let connector_integration: services::BoxedConnectorIntegration<
@ -226,6 +229,7 @@ async fn refunds_create_failure() {
let connector = types::api::ConnectorData { let connector = types::api::ConnectorData {
connector: Box::new(&CV), connector: Box::new(&CV),
connector_name: types::Connector::Aci, connector_name: types::Connector::Aci,
get_token: types::api::GetToken::Connector,
}; };
let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await; let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await;
let connector_integration: services::BoxedConnectorIntegration< let connector_integration: services::BoxedConnectorIntegration<

View File

@ -102,6 +102,7 @@ async fn payments_create_success() {
let connector = types::api::ConnectorData { let connector = types::api::ConnectorData {
connector: Box::new(&CV), connector: Box::new(&CV),
connector_name: types::Connector::Authorizedotnet, connector_name: types::Connector::Authorizedotnet,
get_token: types::api::GetToken::Connector,
}; };
let connector_integration: services::BoxedConnectorIntegration< let connector_integration: services::BoxedConnectorIntegration<
types::api::Authorize, types::api::Authorize,
@ -136,6 +137,7 @@ async fn payments_create_failure() {
let connector = types::api::ConnectorData { let connector = types::api::ConnectorData {
connector: Box::new(&CV), connector: Box::new(&CV),
connector_name: types::Connector::Authorizedotnet, connector_name: types::Connector::Authorizedotnet,
get_token: types::api::GetToken::Connector,
}; };
let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await; let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await;
let connector_integration: services::BoxedConnectorIntegration< let connector_integration: services::BoxedConnectorIntegration<
@ -179,6 +181,7 @@ async fn refunds_create_success() {
let connector = types::api::ConnectorData { let connector = types::api::ConnectorData {
connector: Box::new(&CV), connector: Box::new(&CV),
connector_name: types::Connector::Authorizedotnet, connector_name: types::Connector::Authorizedotnet,
get_token: types::api::GetToken::Connector,
}; };
let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await; let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await;
let connector_integration: services::BoxedConnectorIntegration< let connector_integration: services::BoxedConnectorIntegration<
@ -214,6 +217,7 @@ async fn refunds_create_failure() {
let connector = types::api::ConnectorData { let connector = types::api::ConnectorData {
connector: Box::new(&CV), connector: Box::new(&CV),
connector_name: types::Connector::Authorizedotnet, connector_name: types::Connector::Authorizedotnet,
get_token: types::api::GetToken::Connector,
}; };
let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await; let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await;
let connector_integration: services::BoxedConnectorIntegration< let connector_integration: services::BoxedConnectorIntegration<

View File

@ -100,6 +100,7 @@ async fn test_checkout_payment_success() {
let connector = types::api::ConnectorData { let connector = types::api::ConnectorData {
connector: Box::new(&CV), connector: Box::new(&CV),
connector_name: types::Connector::Checkout, connector_name: types::Connector::Checkout,
get_token: types::api::GetToken::Connector,
}; };
let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await; let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await;
let connector_integration: services::BoxedConnectorIntegration< let connector_integration: services::BoxedConnectorIntegration<
@ -138,6 +139,7 @@ async fn test_checkout_refund_success() {
let connector = types::api::ConnectorData { let connector = types::api::ConnectorData {
connector: Box::new(&CV), connector: Box::new(&CV),
connector_name: types::Connector::Checkout, connector_name: types::Connector::Checkout,
get_token: types::api::GetToken::Connector,
}; };
let connector_integration: services::BoxedConnectorIntegration< let connector_integration: services::BoxedConnectorIntegration<
types::api::Authorize, types::api::Authorize,
@ -203,6 +205,7 @@ async fn test_checkout_payment_failure() {
let connector = types::api::ConnectorData { let connector = types::api::ConnectorData {
connector: Box::new(&CV), connector: Box::new(&CV),
connector_name: types::Connector::Checkout, connector_name: types::Connector::Checkout,
get_token: types::api::GetToken::Connector,
}; };
let connector_integration: services::BoxedConnectorIntegration< let connector_integration: services::BoxedConnectorIntegration<
types::api::Authorize, types::api::Authorize,
@ -234,6 +237,7 @@ async fn test_checkout_refund_failure() {
let connector = types::api::ConnectorData { let connector = types::api::ConnectorData {
connector: Box::new(&CV), connector: Box::new(&CV),
connector_name: types::Connector::Checkout, connector_name: types::Connector::Checkout,
get_token: types::api::GetToken::Connector,
}; };
let connector_integration: services::BoxedConnectorIntegration< let connector_integration: services::BoxedConnectorIntegration<
types::api::Authorize, types::api::Authorize,