mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 20:23:43 +08:00
feat(core): support for gpay session token creation (#152)
This commit is contained in:
@ -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,
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
@ -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)]
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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")?;
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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<
|
||||||
|
|||||||
@ -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<
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user