feat: add routing support for v2 sdk session flow (#6763)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Hrithikesh
2025-03-26 13:47:52 +05:30
committed by GitHub
parent d58685071b
commit c3e8c67bfa
65 changed files with 3470 additions and 3993 deletions

View File

@ -1,5 +1,9 @@
//! API interface
/// authentication module
pub mod authentication;
/// authentication_v2 module
pub mod authentication_v2;
pub mod disputes;
pub mod disputes_v2;
pub mod files;
@ -19,6 +23,8 @@ pub mod refunds_v2;
pub mod revenue_recovery;
pub mod revenue_recovery_v2;
use std::fmt::Debug;
use common_enums::{
enums::{CallConnectorAction, CaptureMethod, EventClass, PaymentAction, PaymentMethodType},
PaymentMethod,
@ -29,6 +35,8 @@ use common_utils::{
};
use error_stack::ResultExt;
use hyperswitch_domain_models::{
configs::Connectors,
errors::api_error_response::ApiErrorResponse,
payment_method_data::PaymentMethodData,
router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
router_data_v2::{
@ -55,14 +63,67 @@ use hyperswitch_domain_models::{
use masking::Maskable;
use serde_json::json;
#[cfg(feature = "frm")]
pub use self::fraud_check::*;
#[cfg(feature = "frm")]
pub use self::fraud_check_v2::*;
#[cfg(feature = "payouts")]
pub use self::payouts::*;
#[cfg(feature = "payouts")]
pub use self::payouts_v2::*;
pub use self::{payments::*, refunds::*};
use crate::{
configs::Connectors, connector_integration_v2::ConnectorIntegrationV2, consts, errors,
events::connector_api_logs::ConnectorEvent, metrics, types,
api::revenue_recovery::RevenueRecovery, connector_integration_v2::ConnectorIntegrationV2,
consts, errors, events::connector_api_logs::ConnectorEvent, metrics, types, webhooks,
};
/// Connector trait
pub trait Connector:
Send
+ Refund
+ Payment
+ ConnectorRedirectResponse
+ webhooks::IncomingWebhook
+ ConnectorAccessToken
+ disputes::Dispute
+ files::FileUpload
+ ConnectorTransactionId
+ Payouts
+ ConnectorVerifyWebhookSource
+ FraudCheck
+ ConnectorMandateRevoke
+ authentication::ExternalAuthentication
+ TaxCalculation
+ UnifiedAuthenticationService
+ RevenueRecovery
{
}
impl<
T: Refund
+ Payment
+ ConnectorRedirectResponse
+ Send
+ webhooks::IncomingWebhook
+ ConnectorAccessToken
+ disputes::Dispute
+ files::FileUpload
+ ConnectorTransactionId
+ Payouts
+ ConnectorVerifyWebhookSource
+ FraudCheck
+ ConnectorMandateRevoke
+ authentication::ExternalAuthentication
+ TaxCalculation
+ UnifiedAuthenticationService
+ RevenueRecovery,
> Connector for T
{
}
/// Alias for Box<&'static (dyn Connector + Sync)>
pub type BoxedConnector = Box<&'static (dyn Connector + Sync)>;
/// type BoxedConnectorIntegration
pub type BoxedConnectorIntegration<'a, T, Req, Resp> =
Box<&'a (dyn ConnectorIntegration<T, Req, Resp> + Send + Sync)>;
@ -582,6 +643,16 @@ pub trait ConnectorRedirectResponse {
/// Empty trait for when payouts feature is disabled
#[cfg(not(feature = "payouts"))]
pub trait Payouts {}
/// Empty trait for when payouts feature is disabled
#[cfg(not(feature = "payouts"))]
pub trait PayoutsV2 {}
/// Empty trait for when frm feature is disabled
#[cfg(not(feature = "frm"))]
pub trait FraudCheck {}
/// Empty trait for when frm feature is disabled
#[cfg(not(feature = "frm"))]
pub trait FraudCheckV2 {}
fn get_connector_payment_method_type_info(
supported_payment_method: &SupportedPaymentMethods,
@ -609,3 +680,16 @@ fn get_connector_payment_method_type_info(
})
.transpose()
}
/// ConnectorTransactionId trait
pub trait ConnectorTransactionId: ConnectorCommon + Sync {
/// fn connector_transaction_id
fn connector_transaction_id(
&self,
payment_attempt: hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt,
) -> Result<Option<String>, ApiErrorResponse> {
Ok(payment_attempt
.get_connector_payment_id()
.map(ToString::to_string))
}
}

View File

@ -0,0 +1,50 @@
use hyperswitch_domain_models::{
router_flow_types::authentication::{
Authentication, PostAuthentication, PreAuthentication, PreAuthenticationVersionCall,
},
router_request_types::authentication::{
ConnectorAuthenticationRequestData, ConnectorPostAuthenticationRequestData,
PreAuthNRequestData,
},
router_response_types::AuthenticationResponseData,
};
use crate::api::ConnectorIntegration;
/// trait ConnectorAuthentication
pub trait ConnectorAuthentication:
ConnectorIntegration<Authentication, ConnectorAuthenticationRequestData, AuthenticationResponseData>
{
}
/// trait ConnectorPreAuthentication
pub trait ConnectorPreAuthentication:
ConnectorIntegration<PreAuthentication, PreAuthNRequestData, AuthenticationResponseData>
{
}
/// trait ConnectorPreAuthenticationVersionCall
pub trait ConnectorPreAuthenticationVersionCall:
ConnectorIntegration<PreAuthenticationVersionCall, PreAuthNRequestData, AuthenticationResponseData>
{
}
/// trait ConnectorPostAuthentication
pub trait ConnectorPostAuthentication:
ConnectorIntegration<
PostAuthentication,
ConnectorPostAuthenticationRequestData,
AuthenticationResponseData,
>
{
}
/// trait ExternalAuthentication
pub trait ExternalAuthentication:
super::ConnectorCommon
+ ConnectorAuthentication
+ ConnectorPreAuthentication
+ ConnectorPreAuthenticationVersionCall
+ ConnectorPostAuthentication
{
}

View File

@ -0,0 +1,67 @@
use hyperswitch_domain_models::{
router_data_v2::ExternalAuthenticationFlowData,
router_flow_types::authentication::{
Authentication, PostAuthentication, PreAuthentication, PreAuthenticationVersionCall,
},
router_request_types::authentication::{
ConnectorAuthenticationRequestData, ConnectorPostAuthenticationRequestData,
PreAuthNRequestData,
},
router_response_types::AuthenticationResponseData,
};
use crate::api::ConnectorIntegrationV2;
/// trait ConnectorAuthenticationV2
pub trait ConnectorAuthenticationV2:
ConnectorIntegrationV2<
Authentication,
ExternalAuthenticationFlowData,
ConnectorAuthenticationRequestData,
AuthenticationResponseData,
>
{
}
/// trait ConnectorPreAuthenticationV2
pub trait ConnectorPreAuthenticationV2:
ConnectorIntegrationV2<
PreAuthentication,
ExternalAuthenticationFlowData,
PreAuthNRequestData,
AuthenticationResponseData,
>
{
}
/// trait ConnectorPreAuthenticationVersionCallV2
pub trait ConnectorPreAuthenticationVersionCallV2:
ConnectorIntegrationV2<
PreAuthenticationVersionCall,
ExternalAuthenticationFlowData,
PreAuthNRequestData,
AuthenticationResponseData,
>
{
}
/// trait ConnectorPostAuthenticationV2
pub trait ConnectorPostAuthenticationV2:
ConnectorIntegrationV2<
PostAuthentication,
ExternalAuthenticationFlowData,
ConnectorPostAuthenticationRequestData,
AuthenticationResponseData,
>
{
}
/// trait ExternalAuthenticationV2
pub trait ExternalAuthenticationV2:
super::ConnectorCommon
+ ConnectorAuthenticationV2
+ ConnectorPreAuthenticationV2
+ ConnectorPreAuthenticationVersionCallV2
+ ConnectorPostAuthenticationV2
{
}

View File

@ -39,3 +39,14 @@ pub trait FraudCheckRecordReturn:
ConnectorIntegration<RecordReturn, FraudCheckRecordReturnData, FraudCheckResponseData>
{
}
/// trait FraudCheck
pub trait FraudCheck:
super::ConnectorCommon
+ FraudCheckSale
+ FraudCheckTransaction
+ FraudCheckCheckout
+ FraudCheckFulfillment
+ FraudCheckRecordReturn
{
}

View File

@ -45,3 +45,14 @@ pub trait FraudCheckRecordReturnV2:
>
{
}
/// trait FraudCheckV2
pub trait FraudCheckV2:
super::ConnectorCommon
+ FraudCheckSaleV2
+ FraudCheckTransactionV2
+ FraudCheckCheckoutV2
+ FraudCheckFulfillmentV2
+ FraudCheckRecordReturnV2
{
}

View File

@ -1,208 +1 @@
//! Configs interface
use common_enums::ApplicationError;
use masking::Secret;
use router_derive;
use serde::Deserialize;
// struct Connectors
#[allow(missing_docs, missing_debug_implementations)]
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
#[serde(default)]
pub struct Connectors {
pub aci: ConnectorParams,
pub adyen: AdyenParamsWithThreeBaseUrls,
pub adyenplatform: ConnectorParams,
pub airwallex: ConnectorParams,
pub amazonpay: ConnectorParams,
pub applepay: ConnectorParams,
pub authorizedotnet: ConnectorParams,
pub bambora: ConnectorParams,
pub bamboraapac: ConnectorParams,
pub bankofamerica: ConnectorParams,
pub billwerk: ConnectorParams,
pub bitpay: ConnectorParams,
pub bluesnap: ConnectorParamsWithSecondaryBaseUrl,
pub boku: ConnectorParams,
pub braintree: ConnectorParams,
pub cashtocode: ConnectorParams,
pub chargebee: ConnectorParams,
pub checkout: ConnectorParams,
pub coinbase: ConnectorParams,
pub coingate: ConnectorParams,
pub cryptopay: ConnectorParams,
pub ctp_mastercard: NoParams,
pub cybersource: ConnectorParams,
pub datatrans: ConnectorParamsWithSecondaryBaseUrl,
pub deutschebank: ConnectorParams,
pub digitalvirgo: ConnectorParams,
pub dlocal: ConnectorParams,
#[cfg(feature = "dummy_connector")]
pub dummyconnector: ConnectorParams,
pub ebanx: ConnectorParams,
pub elavon: ConnectorParams,
pub fiserv: ConnectorParams,
pub fiservemea: ConnectorParams,
pub fiuu: ConnectorParamsWithThreeUrls,
pub forte: ConnectorParams,
pub getnet: ConnectorParams,
pub globalpay: ConnectorParams,
pub globepay: ConnectorParams,
pub gocardless: ConnectorParams,
pub gpayments: ConnectorParams,
pub helcim: ConnectorParams,
pub hipay: ConnectorParamsWithThreeUrls,
pub iatapay: ConnectorParams,
pub inespay: ConnectorParams,
pub itaubank: ConnectorParams,
pub jpmorgan: ConnectorParams,
pub juspaythreedsserver: ConnectorParams,
pub klarna: ConnectorParams,
pub mifinity: ConnectorParams,
pub mollie: ConnectorParams,
pub moneris: ConnectorParams,
pub multisafepay: ConnectorParams,
pub netcetera: ConnectorParams,
pub nexinets: ConnectorParams,
pub nexixpay: ConnectorParams,
pub nmi: ConnectorParams,
pub nomupay: ConnectorParams,
pub noon: ConnectorParamsWithModeType,
pub novalnet: ConnectorParams,
pub nuvei: ConnectorParams,
pub opayo: ConnectorParams,
pub opennode: ConnectorParams,
pub paybox: ConnectorParamsWithSecondaryBaseUrl,
pub payeezy: ConnectorParams,
pub payme: ConnectorParams,
pub payone: ConnectorParams,
pub paypal: ConnectorParams,
pub paystack: ConnectorParams,
pub payu: ConnectorParams,
pub placetopay: ConnectorParams,
pub plaid: ConnectorParams,
pub powertranz: ConnectorParams,
pub prophetpay: ConnectorParams,
pub rapyd: ConnectorParams,
pub razorpay: ConnectorParamsWithKeys,
pub recurly: ConnectorParams,
pub redsys: ConnectorParams,
pub riskified: ConnectorParams,
pub shift4: ConnectorParams,
pub signifyd: ConnectorParams,
pub square: ConnectorParams,
pub stax: ConnectorParams,
pub stripe: ConnectorParamsWithFileUploadUrl,
pub stripebilling: ConnectorParams,
pub taxjar: ConnectorParams,
pub threedsecureio: ConnectorParams,
pub thunes: ConnectorParams,
pub trustpay: ConnectorParamsWithMoreUrls,
pub tsys: ConnectorParams,
pub unified_authentication_service: ConnectorParams,
pub volt: ConnectorParams,
pub wellsfargo: ConnectorParams,
pub wellsfargopayout: ConnectorParams,
pub wise: ConnectorParams,
pub worldline: ConnectorParams,
pub worldpay: ConnectorParams,
pub xendit: ConnectorParams,
pub zen: ConnectorParams,
pub zsl: ConnectorParams,
}
/// struct ConnectorParams
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
#[serde(default)]
pub struct ConnectorParams {
/// base url
pub base_url: String,
/// secondary base url
pub secondary_base_url: Option<String>,
}
///struct No Param for connectors with no params
#[derive(Debug, Deserialize, Clone, Default)]
pub struct NoParams;
impl NoParams {
/// function to satisfy connector param validation macro
pub fn validate(&self, _parent_field: &str) -> Result<(), ApplicationError> {
Ok(())
}
}
/// struct ConnectorParamsWithKeys
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
#[serde(default)]
pub struct ConnectorParamsWithKeys {
/// base url
pub base_url: String,
/// api key
pub api_key: Secret<String>,
/// merchant ID
pub merchant_id: Secret<String>,
}
/// struct ConnectorParamsWithModeType
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
#[serde(default)]
pub struct ConnectorParamsWithModeType {
/// base url
pub base_url: String,
/// secondary base url
pub secondary_base_url: Option<String>,
/// Can take values like Test or Live for Noon
pub key_mode: String,
}
/// struct ConnectorParamsWithMoreUrls
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
#[serde(default)]
pub struct ConnectorParamsWithMoreUrls {
/// base url
pub base_url: String,
/// base url for bank redirects
pub base_url_bank_redirects: String,
}
/// struct ConnectorParamsWithFileUploadUrl
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
#[serde(default)]
pub struct ConnectorParamsWithFileUploadUrl {
/// base url
pub base_url: String,
/// base url for file upload
pub base_url_file_upload: String,
}
/// struct ConnectorParamsWithThreeBaseUrls
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
#[serde(default)]
pub struct AdyenParamsWithThreeBaseUrls {
/// base url
pub base_url: String,
/// secondary base url
#[cfg(feature = "payouts")]
pub payout_base_url: String,
/// third base url
pub dispute_base_url: String,
}
/// struct ConnectorParamsWithSecondaryBaseUrl
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
#[serde(default)]
pub struct ConnectorParamsWithSecondaryBaseUrl {
/// base url
pub base_url: String,
/// secondary base url
pub secondary_base_url: String,
}
/// struct ConnectorParamsWithThreeUrls
#[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)]
#[serde(default)]
pub struct ConnectorParamsWithThreeUrls {
/// base url
pub base_url: String,
/// secondary base url
pub secondary_base_url: String,
/// third base url
pub third_base_url: String,
}
pub use hyperswitch_domain_models::configs::Connectors;

View File

@ -0,0 +1,737 @@
use api_models::webhooks::{IncomingWebhookEvent, ObjectReferenceId};
use common_enums::PaymentAction;
use common_utils::{crypto, errors::CustomResult, request::Request};
use hyperswitch_domain_models::{
api::ApplicationResponse,
configs::Connectors,
errors::api_error_response::ApiErrorResponse,
payment_method_data::PaymentMethodData,
router_data::{ConnectorAuthType, ErrorResponse, RouterData},
router_data_v2::RouterDataV2,
router_response_types::{ConnectorInfo, SupportedPaymentMethods},
};
use crate::{
api,
api::{
BoxedConnectorIntegration, CaptureSyncMethod, Connector, ConnectorCommon,
ConnectorIntegration, ConnectorRedirectResponse, ConnectorSpecifications,
ConnectorValidation, CurrencyUnit,
},
authentication::ExternalAuthenticationPayload,
connector_integration_v2::{BoxedConnectorIntegrationV2, ConnectorIntegrationV2, ConnectorV2},
disputes, errors,
events::connector_api_logs::ConnectorEvent,
types,
webhooks::{IncomingWebhook, IncomingWebhookFlowError, IncomingWebhookRequestDetails},
};
/// RouterDataConversion trait
///
/// This trait must be implemented for conversion between Router data and RouterDataV2
pub trait RouterDataConversion<T, Req: Clone, Resp: Clone> {
/// Convert RouterData to RouterDataV2
///
/// # Arguments
///
/// * `old_router_data` - A reference to the old RouterData
///
/// # Returns
///
/// A `CustomResult` containing the new RouterDataV2 or a ConnectorError
fn from_old_router_data(
old_router_data: &RouterData<T, Req, Resp>,
) -> CustomResult<RouterDataV2<T, Self, Req, Resp>, errors::ConnectorError>
where
Self: Sized;
/// Convert RouterDataV2 back to RouterData
///
/// # Arguments
///
/// * `new_router_data` - The new RouterDataV2
///
/// # Returns
///
/// A `CustomResult` containing the old RouterData or a ConnectorError
fn to_old_router_data(
new_router_data: RouterDataV2<T, Self, Req, Resp>,
) -> CustomResult<RouterData<T, Req, Resp>, errors::ConnectorError>
where
Self: Sized;
}
/// Alias for Box<&'static (dyn Connector + Sync)>
pub type BoxedConnector = Box<&'static (dyn Connector + Sync)>;
/// Alias for Box<&'static (dyn ConnectorV2 + Sync)>
pub type BoxedConnectorV2 = Box<&'static (dyn ConnectorV2 + Sync)>;
/// Enum representing the Connector
#[derive(Clone)]
pub enum ConnectorEnum {
/// Old connector type
Old(BoxedConnector),
/// New connector type
New(BoxedConnectorV2),
}
impl std::fmt::Debug for ConnectorEnum {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Old(_) => f
.debug_tuple("Old")
.field(&std::any::type_name::<BoxedConnector>().to_string())
.finish(),
Self::New(_) => f
.debug_tuple("New")
.field(&std::any::type_name::<BoxedConnectorV2>().to_string())
.finish(),
}
}
}
#[allow(missing_debug_implementations)]
/// Enum representing the Connector Integration
#[derive(Clone)]
pub enum ConnectorIntegrationEnum<'a, F, ResourceCommonData, Req, Resp> {
/// Old connector integration type
Old(BoxedConnectorIntegration<'a, F, Req, Resp>),
/// New connector integration type
New(BoxedConnectorIntegrationV2<'a, F, ResourceCommonData, Req, Resp>),
}
/// Alias for Box<dyn ConnectorIntegrationInterface>
pub type BoxedConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp> =
Box<dyn ConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp> + Send + Sync>;
impl ConnectorEnum {
/// Get the connector integration
///
/// # Returns
///
/// A `BoxedConnectorIntegrationInterface` containing the connector integration
pub fn get_connector_integration<F, ResourceCommonData, Req, Resp>(
&self,
) -> BoxedConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp>
where
dyn Connector + Sync: ConnectorIntegration<F, Req, Resp>,
dyn ConnectorV2 + Sync: ConnectorIntegrationV2<F, ResourceCommonData, Req, Resp>,
ResourceCommonData: RouterDataConversion<F, Req, Resp> + Clone + 'static,
F: Clone + 'static,
Req: Clone + 'static,
Resp: Clone + 'static,
{
match self {
Self::Old(old_integration) => Box::new(ConnectorIntegrationEnum::Old(
old_integration.get_connector_integration(),
)),
Self::New(new_integration) => Box::new(ConnectorIntegrationEnum::New(
new_integration.get_connector_integration_v2(),
)),
}
}
/// validates the file upload
pub fn validate_file_upload(
&self,
purpose: api::files::FilePurpose,
file_size: i32,
file_type: mime::Mime,
) -> CustomResult<(), errors::ConnectorError> {
match self {
Self::Old(connector) => connector.validate_file_upload(purpose, file_size, file_type),
Self::New(connector) => {
connector.validate_file_upload_v2(purpose, file_size, file_type)
}
}
}
}
#[async_trait::async_trait]
impl IncomingWebhook for ConnectorEnum {
fn get_webhook_body_decoding_algorithm(
&self,
request: &IncomingWebhookRequestDetails<'_>,
) -> CustomResult<Box<dyn crypto::DecodeMessage + Send>, errors::ConnectorError> {
match self {
Self::Old(connector) => connector.get_webhook_body_decoding_algorithm(request),
Self::New(connector) => connector.get_webhook_body_decoding_algorithm(request),
}
}
fn get_webhook_body_decoding_message(
&self,
request: &IncomingWebhookRequestDetails<'_>,
) -> CustomResult<Vec<u8>, errors::ConnectorError> {
match self {
Self::Old(connector) => connector.get_webhook_body_decoding_message(request),
Self::New(connector) => connector.get_webhook_body_decoding_message(request),
}
}
async fn decode_webhook_body(
&self,
request: &IncomingWebhookRequestDetails<'_>,
merchant_id: &common_utils::id_type::MerchantId,
connector_webhook_details: Option<common_utils::pii::SecretSerdeValue>,
connector_name: &str,
) -> CustomResult<Vec<u8>, errors::ConnectorError> {
match self {
Self::Old(connector) => {
connector
.decode_webhook_body(
request,
merchant_id,
connector_webhook_details,
connector_name,
)
.await
}
Self::New(connector) => {
connector
.decode_webhook_body(
request,
merchant_id,
connector_webhook_details,
connector_name,
)
.await
}
}
}
fn get_webhook_source_verification_algorithm(
&self,
request: &IncomingWebhookRequestDetails<'_>,
) -> CustomResult<Box<dyn crypto::VerifySignature + Send>, errors::ConnectorError> {
match self {
Self::Old(connector) => connector.get_webhook_source_verification_algorithm(request),
Self::New(connector) => connector.get_webhook_source_verification_algorithm(request),
}
}
async fn get_webhook_source_verification_merchant_secret(
&self,
merchant_id: &common_utils::id_type::MerchantId,
connector_name: &str,
connector_webhook_details: Option<common_utils::pii::SecretSerdeValue>,
) -> CustomResult<api_models::webhooks::ConnectorWebhookSecrets, errors::ConnectorError> {
match self {
Self::Old(connector) => {
connector
.get_webhook_source_verification_merchant_secret(
merchant_id,
connector_name,
connector_webhook_details,
)
.await
}
Self::New(connector) => {
connector
.get_webhook_source_verification_merchant_secret(
merchant_id,
connector_name,
connector_webhook_details,
)
.await
}
}
}
fn get_webhook_source_verification_signature(
&self,
request: &IncomingWebhookRequestDetails<'_>,
connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
) -> CustomResult<Vec<u8>, errors::ConnectorError> {
match self {
Self::Old(connector) => connector
.get_webhook_source_verification_signature(request, connector_webhook_secrets),
Self::New(connector) => connector
.get_webhook_source_verification_signature(request, connector_webhook_secrets),
}
}
fn get_webhook_source_verification_message(
&self,
request: &IncomingWebhookRequestDetails<'_>,
merchant_id: &common_utils::id_type::MerchantId,
connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
) -> CustomResult<Vec<u8>, errors::ConnectorError> {
match self {
Self::Old(connector) => connector.get_webhook_source_verification_message(
request,
merchant_id,
connector_webhook_secrets,
),
Self::New(connector) => connector.get_webhook_source_verification_message(
request,
merchant_id,
connector_webhook_secrets,
),
}
}
async fn verify_webhook_source(
&self,
request: &IncomingWebhookRequestDetails<'_>,
merchant_id: &common_utils::id_type::MerchantId,
connector_webhook_details: Option<common_utils::pii::SecretSerdeValue>,
connector_account_details: crypto::Encryptable<masking::Secret<serde_json::Value>>,
connector_name: &str,
) -> CustomResult<bool, errors::ConnectorError> {
match self {
Self::Old(connector) => {
connector
.verify_webhook_source(
request,
merchant_id,
connector_webhook_details,
connector_account_details,
connector_name,
)
.await
}
Self::New(connector) => {
connector
.verify_webhook_source(
request,
merchant_id,
connector_webhook_details,
connector_account_details,
connector_name,
)
.await
}
}
}
fn get_webhook_object_reference_id(
&self,
request: &IncomingWebhookRequestDetails<'_>,
) -> CustomResult<ObjectReferenceId, errors::ConnectorError> {
match self {
Self::Old(connector) => connector.get_webhook_object_reference_id(request),
Self::New(connector) => connector.get_webhook_object_reference_id(request),
}
}
fn get_webhook_event_type(
&self,
request: &IncomingWebhookRequestDetails<'_>,
) -> CustomResult<IncomingWebhookEvent, errors::ConnectorError> {
match self {
Self::Old(connector) => connector.get_webhook_event_type(request),
Self::New(connector) => connector.get_webhook_event_type(request),
}
}
fn get_webhook_resource_object(
&self,
request: &IncomingWebhookRequestDetails<'_>,
) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
match self {
Self::Old(connector) => connector.get_webhook_resource_object(request),
Self::New(connector) => connector.get_webhook_resource_object(request),
}
}
fn get_webhook_api_response(
&self,
request: &IncomingWebhookRequestDetails<'_>,
error_kind: Option<IncomingWebhookFlowError>,
) -> CustomResult<ApplicationResponse<serde_json::Value>, errors::ConnectorError> {
match self {
Self::Old(connector) => connector.get_webhook_api_response(request, error_kind),
Self::New(connector) => connector.get_webhook_api_response(request, error_kind),
}
}
fn get_dispute_details(
&self,
request: &IncomingWebhookRequestDetails<'_>,
) -> CustomResult<disputes::DisputePayload, errors::ConnectorError> {
match self {
Self::Old(connector) => connector.get_dispute_details(request),
Self::New(connector) => connector.get_dispute_details(request),
}
}
fn get_external_authentication_details(
&self,
request: &IncomingWebhookRequestDetails<'_>,
) -> CustomResult<ExternalAuthenticationPayload, errors::ConnectorError> {
match self {
Self::Old(connector) => connector.get_external_authentication_details(request),
Self::New(connector) => connector.get_external_authentication_details(request),
}
}
fn get_mandate_details(
&self,
request: &IncomingWebhookRequestDetails<'_>,
) -> CustomResult<
Option<hyperswitch_domain_models::router_flow_types::ConnectorMandateDetails>,
errors::ConnectorError,
> {
match self {
Self::Old(connector) => connector.get_mandate_details(request),
Self::New(connector) => connector.get_mandate_details(request),
}
}
fn get_network_txn_id(
&self,
request: &IncomingWebhookRequestDetails<'_>,
) -> CustomResult<
Option<hyperswitch_domain_models::router_flow_types::ConnectorNetworkTxnId>,
errors::ConnectorError,
> {
match self {
Self::Old(connector) => connector.get_network_txn_id(request),
Self::New(connector) => connector.get_network_txn_id(request),
}
}
}
impl ConnectorRedirectResponse for ConnectorEnum {
fn get_flow_type(
&self,
query_params: &str,
json_payload: Option<serde_json::Value>,
action: PaymentAction,
) -> CustomResult<common_enums::CallConnectorAction, errors::ConnectorError> {
match self {
Self::Old(connector) => connector.get_flow_type(query_params, json_payload, action),
Self::New(connector) => connector.get_flow_type(query_params, json_payload, action),
}
}
}
impl ConnectorValidation for ConnectorEnum {
fn validate_connector_against_payment_request(
&self,
capture_method: Option<common_enums::CaptureMethod>,
payment_method: common_enums::PaymentMethod,
pmt: Option<common_enums::PaymentMethodType>,
) -> CustomResult<(), errors::ConnectorError> {
match self {
Self::Old(connector) => connector.validate_connector_against_payment_request(
capture_method,
payment_method,
pmt,
),
Self::New(connector) => connector.validate_connector_against_payment_request(
capture_method,
payment_method,
pmt,
),
}
}
fn validate_mandate_payment(
&self,
pm_type: Option<common_enums::PaymentMethodType>,
pm_data: PaymentMethodData,
) -> CustomResult<(), errors::ConnectorError> {
match self {
Self::Old(connector) => connector.validate_mandate_payment(pm_type, pm_data),
Self::New(connector) => connector.validate_mandate_payment(pm_type, pm_data),
}
}
fn validate_psync_reference_id(
&self,
data: &hyperswitch_domain_models::router_request_types::PaymentsSyncData,
is_three_ds: bool,
status: common_enums::enums::AttemptStatus,
connector_meta_data: Option<common_utils::pii::SecretSerdeValue>,
) -> CustomResult<(), errors::ConnectorError> {
match self {
Self::Old(connector) => connector.validate_psync_reference_id(
data,
is_three_ds,
status,
connector_meta_data,
),
Self::New(connector) => connector.validate_psync_reference_id(
data,
is_three_ds,
status,
connector_meta_data,
),
}
}
fn is_webhook_source_verification_mandatory(&self) -> bool {
match self {
Self::Old(connector) => connector.is_webhook_source_verification_mandatory(),
Self::New(connector) => connector.is_webhook_source_verification_mandatory(),
}
}
}
impl ConnectorSpecifications for ConnectorEnum {
fn get_supported_payment_methods(&self) -> Option<&'static SupportedPaymentMethods> {
match self {
Self::Old(connector) => connector.get_supported_payment_methods(),
Self::New(connector) => connector.get_supported_payment_methods(),
}
}
/// Supported webhooks flows
fn get_supported_webhook_flows(&self) -> Option<&'static [common_enums::EventClass]> {
match self {
Self::Old(connector) => connector.get_supported_webhook_flows(),
Self::New(connector) => connector.get_supported_webhook_flows(),
}
}
/// Details related to connector
fn get_connector_about(&self) -> Option<&'static ConnectorInfo> {
match self {
Self::Old(connector) => connector.get_connector_about(),
Self::New(connector) => connector.get_connector_about(),
}
}
}
impl ConnectorCommon for ConnectorEnum {
fn id(&self) -> &'static str {
match self {
Self::Old(connector) => connector.id(),
Self::New(connector) => connector.id(),
}
}
fn get_currency_unit(&self) -> CurrencyUnit {
match self {
Self::Old(connector) => connector.get_currency_unit(),
Self::New(connector) => connector.get_currency_unit(),
}
}
fn get_auth_header(
&self,
auth_type: &ConnectorAuthType,
) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
match self {
Self::Old(connector) => connector.get_auth_header(auth_type),
Self::New(connector) => connector.get_auth_header(auth_type),
}
}
fn common_get_content_type(&self) -> &'static str {
match self {
Self::Old(connector) => connector.common_get_content_type(),
Self::New(connector) => connector.common_get_content_type(),
}
}
fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str {
match self {
Self::Old(connector) => connector.base_url(connectors),
Self::New(connector) => connector.base_url(connectors),
}
}
fn build_error_response(
&self,
res: types::Response,
event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
match self {
Self::Old(connector) => connector.build_error_response(res, event_builder),
Self::New(connector) => connector.build_error_response(res, event_builder),
}
}
}
/// Trait representing the connector integration interface
///
/// This trait defines the methods required for a connector integration interface.
pub trait ConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp>: Send + Sync {
/// Clone the connector integration interface
///
/// # Returns
///
/// A `Box` containing the cloned connector integration interface
fn clone_box(
&self,
) -> Box<dyn ConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp> + Send + Sync>;
/// Get the multiple capture sync method
///
/// # Returns
///
/// A `CustomResult` containing the `CaptureSyncMethod` or a `ConnectorError`
fn get_multiple_capture_sync_method(
&self,
) -> CustomResult<CaptureSyncMethod, errors::ConnectorError>;
/// Build a request for the connector integration
///
/// # Arguments
///
/// * `req` - A reference to the RouterData
/// # Returns
///
/// A `CustomResult` containing an optional Request or a ConnectorError
fn build_request(
&self,
req: &RouterData<F, Req, Resp>,
_connectors: &Connectors,
) -> CustomResult<Option<Request>, errors::ConnectorError>;
/// handles response from the connector
fn handle_response(
&self,
data: &RouterData<F, Req, Resp>,
event_builder: Option<&mut ConnectorEvent>,
_res: types::Response,
) -> CustomResult<RouterData<F, Req, Resp>, errors::ConnectorError>
where
F: Clone,
Req: Clone,
Resp: Clone;
/// Get the error response
///
/// # Arguments
///
/// * `res` - The response
/// * `event_builder` - An optional event builder
///
/// # Returns
///
/// A `CustomResult` containing the `ErrorResponse` or a `ConnectorError`
fn get_error_response(
&self,
res: types::Response,
event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError>;
/// Get the 5xx error response
///
/// # Arguments
///
/// * `res` - The response
/// * `event_builder` - An optional event builder
///
/// # Returns
///
/// A `CustomResult` containing the `ErrorResponse` or a `ConnectorError`
fn get_5xx_error_response(
&self,
res: types::Response,
event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError>;
}
impl<T: 'static, ResourceCommonData: 'static, Req: 'static, Resp: 'static>
ConnectorIntegrationInterface<T, ResourceCommonData, Req, Resp>
for ConnectorIntegrationEnum<'static, T, ResourceCommonData, Req, Resp>
where
ResourceCommonData: RouterDataConversion<T, Req, Resp> + Clone,
T: Clone,
Req: Clone,
Resp: Clone,
{
fn get_multiple_capture_sync_method(
&self,
) -> CustomResult<CaptureSyncMethod, errors::ConnectorError> {
match self {
ConnectorIntegrationEnum::Old(old_integration) => {
old_integration.get_multiple_capture_sync_method()
}
ConnectorIntegrationEnum::New(new_integration) => {
new_integration.get_multiple_capture_sync_method()
}
}
}
fn build_request(
&self,
req: &RouterData<T, Req, Resp>,
connectors: &Connectors,
) -> CustomResult<Option<Request>, errors::ConnectorError> {
match self {
ConnectorIntegrationEnum::Old(old_integration) => {
old_integration.build_request(req, connectors)
}
ConnectorIntegrationEnum::New(new_integration) => {
let new_router_data = ResourceCommonData::from_old_router_data(req)?;
new_integration.build_request_v2(&new_router_data)
}
}
}
fn handle_response(
&self,
data: &RouterData<T, Req, Resp>,
event_builder: Option<&mut ConnectorEvent>,
res: types::Response,
) -> CustomResult<RouterData<T, Req, Resp>, errors::ConnectorError>
where
T: Clone,
Req: Clone,
Resp: Clone,
{
match self {
ConnectorIntegrationEnum::Old(old_integration) => {
old_integration.handle_response(data, event_builder, res)
}
ConnectorIntegrationEnum::New(new_integration) => {
let new_router_data = ResourceCommonData::from_old_router_data(data)?;
new_integration
.handle_response_v2(&new_router_data, event_builder, res)
.map(ResourceCommonData::to_old_router_data)?
}
}
}
fn get_error_response(
&self,
res: types::Response,
event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
match self {
ConnectorIntegrationEnum::Old(old_integration) => {
old_integration.get_error_response(res, event_builder)
}
ConnectorIntegrationEnum::New(new_integration) => {
new_integration.get_error_response_v2(res, event_builder)
}
}
}
fn get_5xx_error_response(
&self,
res: types::Response,
event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
match self {
ConnectorIntegrationEnum::Old(old_integration) => {
old_integration.get_5xx_error_response(res, event_builder)
}
ConnectorIntegrationEnum::New(new_integration) => {
new_integration.get_5xx_error_response(res, event_builder)
}
}
}
fn clone_box(
&self,
) -> Box<dyn ConnectorIntegrationInterface<T, ResourceCommonData, Req, Resp> + Send + Sync>
{
Box::new(self.clone())
}
}
impl api::ConnectorTransactionId for ConnectorEnum {
/// Get the connector transaction ID
///
/// # Arguments
///
/// * `payment_attempt` - The payment attempt
///
/// # Returns
///
/// A `Result` containing an optional transaction ID or an ApiErrorResponse
fn connector_transaction_id(
&self,
payment_attempt: hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt,
) -> Result<Option<String>, ApiErrorResponse> {
match self {
Self::Old(connector) => connector.connector_transaction_id(payment_attempt),
Self::New(connector) => connector.connector_transaction_id(payment_attempt),
}
}
}

View File

@ -1,4 +1,5 @@
//! definition of the new connector integration trait
use common_utils::{
errors::CustomResult,
request::{Method, Request, RequestBuilder, RequestContent},
@ -8,9 +9,54 @@ use masking::Maskable;
use serde_json::json;
use crate::{
api::CaptureSyncMethod, errors, events::connector_api_logs::ConnectorEvent, metrics, types,
api::{self, CaptureSyncMethod},
errors,
events::connector_api_logs::ConnectorEvent,
metrics, types, webhooks,
};
/// ConnectorV2 trait
pub trait ConnectorV2:
Send
+ api::refunds_v2::RefundV2
+ api::payments_v2::PaymentV2
+ api::ConnectorRedirectResponse
+ webhooks::IncomingWebhook
+ api::ConnectorAccessTokenV2
+ api::disputes_v2::DisputeV2
+ api::files_v2::FileUploadV2
+ api::ConnectorTransactionId
+ api::PayoutsV2
+ api::ConnectorVerifyWebhookSourceV2
+ api::FraudCheckV2
+ api::ConnectorMandateRevokeV2
+ api::authentication_v2::ExternalAuthenticationV2
+ api::UnifiedAuthenticationServiceV2
{
}
impl<
T: api::refunds_v2::RefundV2
+ api::payments_v2::PaymentV2
+ api::ConnectorRedirectResponse
+ Send
+ webhooks::IncomingWebhook
+ api::ConnectorAccessTokenV2
+ api::disputes_v2::DisputeV2
+ api::files_v2::FileUploadV2
+ api::ConnectorTransactionId
+ api::PayoutsV2
+ api::ConnectorVerifyWebhookSourceV2
+ api::FraudCheckV2
+ api::ConnectorMandateRevokeV2
+ api::authentication_v2::ExternalAuthenticationV2
+ api::UnifiedAuthenticationServiceV2,
> ConnectorV2 for T
{
}
/// Alias for Box<&'static (dyn ConnectorV2 + Sync)>
pub type BoxedConnectorV2 = Box<&'static (dyn ConnectorV2 + Sync)>;
/// alias for Box of a type that implements trait ConnectorIntegrationV2
pub type BoxedConnectorIntegrationV2<'a, Flow, ResourceCommonData, Req, Resp> =
Box<&'a (dyn ConnectorIntegrationV2<Flow, ResourceCommonData, Req, Resp> + Send + Sync)>;
@ -39,7 +85,7 @@ where
/// The new connector integration trait with an additional ResourceCommonData generic parameter
pub trait ConnectorIntegrationV2<Flow, ResourceCommonData, Req, Resp>:
ConnectorIntegrationAnyV2<Flow, ResourceCommonData, Req, Resp> + Sync + super::api::ConnectorCommon
ConnectorIntegrationAnyV2<Flow, ResourceCommonData, Req, Resp> + Sync + api::ConnectorCommon
{
/// returns a vec of tuple of header key and value
fn get_headers(

View File

@ -0,0 +1,800 @@
use common_utils::{errors::CustomResult, id_type};
use error_stack::ResultExt;
#[cfg(feature = "frm")]
use hyperswitch_domain_models::router_data_v2::flow_common_types::FrmFlowData;
#[cfg(feature = "payouts")]
use hyperswitch_domain_models::router_data_v2::flow_common_types::PayoutFlowData;
use hyperswitch_domain_models::{
payment_address::PaymentAddress,
router_data::{self, RouterData},
router_data_v2::{
flow_common_types::{
AccessTokenFlowData, DisputesFlowData, ExternalAuthenticationFlowData, FilesFlowData,
MandateRevokeFlowData, PaymentFlowData, RefundFlowData, RevenueRecoveryRecordBackData,
UasFlowData, WebhookSourceVerifyData,
},
RouterDataV2,
},
};
use crate::{connector_integration_interface::RouterDataConversion, errors::ConnectorError};
fn get_irrelevant_id_string(id_name: &str, flow_name: &str) -> String {
format!("irrelevant {id_name} in {flow_name} flow")
}
fn get_default_router_data<F, Req, Resp>(
tenant_id: id_type::TenantId,
flow_name: &str,
request: Req,
response: Result<Resp, router_data::ErrorResponse>,
) -> RouterData<F, Req, Resp> {
RouterData {
tenant_id,
flow: std::marker::PhantomData,
merchant_id: id_type::MerchantId::get_irrelevant_merchant_id(),
customer_id: None,
connector_customer: None,
connector: get_irrelevant_id_string("connector", flow_name),
payment_id: id_type::PaymentId::get_irrelevant_id(flow_name)
.get_string_repr()
.to_owned(),
attempt_id: get_irrelevant_id_string("attempt_id", flow_name),
status: common_enums::AttemptStatus::default(),
payment_method: common_enums::PaymentMethod::default(),
connector_auth_type: router_data::ConnectorAuthType::default(),
description: None,
address: PaymentAddress::default(),
auth_type: common_enums::AuthenticationType::default(),
connector_meta_data: None,
connector_wallets_details: None,
amount_captured: None,
access_token: None,
session_token: None,
reference_id: None,
payment_method_token: None,
recurring_mandate_payment_data: None,
preprocessing_id: None,
payment_method_balance: None,
connector_api_version: None,
request,
response,
connector_request_reference_id: get_irrelevant_id_string(
"connector_request_reference_id",
flow_name,
),
#[cfg(feature = "payouts")]
payout_method_data: None,
#[cfg(feature = "payouts")]
quote_id: None,
test_mode: None,
connector_http_status_code: None,
external_latency: None,
apple_pay_flow: None,
frm_metadata: None,
dispute_id: None,
refund_id: None,
connector_response: None,
payment_method_status: None,
minor_amount_captured: None,
integrity_check: Ok(()),
additional_merchant_data: None,
header_payload: None,
connector_mandate_request_reference_id: None,
authentication_id: None,
psd2_sca_exemption_type: None,
}
}
impl<T, Req: Clone, Resp: Clone> RouterDataConversion<T, Req, Resp> for AccessTokenFlowData {
fn from_old_router_data(
old_router_data: &RouterData<T, Req, Resp>,
) -> CustomResult<RouterDataV2<T, Self, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let resource_common_data = Self {};
Ok(RouterDataV2 {
flow: std::marker::PhantomData,
tenant_id: old_router_data.tenant_id.clone(),
resource_common_data,
connector_auth_type: old_router_data.connector_auth_type.clone(),
request: old_router_data.request.clone(),
response: old_router_data.response.clone(),
})
}
fn to_old_router_data(
new_router_data: RouterDataV2<T, Self, Req, Resp>,
) -> CustomResult<RouterData<T, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let Self {} = new_router_data.resource_common_data;
let request = new_router_data.request.clone();
let response = new_router_data.response.clone();
let router_data = get_default_router_data(
new_router_data.tenant_id.clone(),
"access token",
request,
response,
);
Ok(router_data)
}
}
impl<T, Req: Clone, Resp: Clone> RouterDataConversion<T, Req, Resp> for PaymentFlowData {
fn from_old_router_data(
old_router_data: &RouterData<T, Req, Resp>,
) -> CustomResult<RouterDataV2<T, Self, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let resource_common_data = Self {
merchant_id: old_router_data.merchant_id.clone(),
customer_id: old_router_data.customer_id.clone(),
connector_customer: old_router_data.connector_customer.clone(),
payment_id: old_router_data.payment_id.clone(),
attempt_id: old_router_data.attempt_id.clone(),
status: old_router_data.status,
payment_method: old_router_data.payment_method,
description: old_router_data.description.clone(),
address: old_router_data.address.clone(),
auth_type: old_router_data.auth_type,
connector_meta_data: old_router_data.connector_meta_data.clone(),
amount_captured: old_router_data.amount_captured,
minor_amount_captured: old_router_data.minor_amount_captured,
access_token: old_router_data.access_token.clone(),
session_token: old_router_data.session_token.clone(),
reference_id: old_router_data.reference_id.clone(),
payment_method_token: old_router_data.payment_method_token.clone(),
recurring_mandate_payment_data: old_router_data.recurring_mandate_payment_data.clone(),
preprocessing_id: old_router_data.preprocessing_id.clone(),
payment_method_balance: old_router_data.payment_method_balance.clone(),
connector_api_version: old_router_data.connector_api_version.clone(),
connector_request_reference_id: old_router_data.connector_request_reference_id.clone(),
test_mode: old_router_data.test_mode,
connector_http_status_code: old_router_data.connector_http_status_code,
external_latency: old_router_data.external_latency,
apple_pay_flow: old_router_data.apple_pay_flow.clone(),
connector_response: old_router_data.connector_response.clone(),
payment_method_status: old_router_data.payment_method_status,
};
Ok(RouterDataV2 {
flow: std::marker::PhantomData,
tenant_id: old_router_data.tenant_id.clone(),
resource_common_data,
connector_auth_type: old_router_data.connector_auth_type.clone(),
request: old_router_data.request.clone(),
response: old_router_data.response.clone(),
})
}
fn to_old_router_data(
new_router_data: RouterDataV2<T, Self, Req, Resp>,
) -> CustomResult<RouterData<T, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let Self {
merchant_id,
customer_id,
connector_customer,
payment_id,
attempt_id,
status,
payment_method,
description,
address,
auth_type,
connector_meta_data,
amount_captured,
minor_amount_captured,
access_token,
session_token,
reference_id,
payment_method_token,
recurring_mandate_payment_data,
preprocessing_id,
payment_method_balance,
connector_api_version,
connector_request_reference_id,
test_mode,
connector_http_status_code,
external_latency,
apple_pay_flow,
connector_response,
payment_method_status,
} = new_router_data.resource_common_data;
let mut router_data = get_default_router_data(
new_router_data.tenant_id.clone(),
"payment",
new_router_data.request,
new_router_data.response,
);
router_data.merchant_id = merchant_id;
router_data.customer_id = customer_id;
router_data.connector_customer = connector_customer;
router_data.payment_id = payment_id;
router_data.attempt_id = attempt_id;
router_data.status = status;
router_data.payment_method = payment_method;
router_data.description = description;
router_data.address = address;
router_data.auth_type = auth_type;
router_data.connector_meta_data = connector_meta_data;
router_data.amount_captured = amount_captured;
router_data.minor_amount_captured = minor_amount_captured;
router_data.access_token = access_token;
router_data.session_token = session_token;
router_data.reference_id = reference_id;
router_data.payment_method_token = payment_method_token;
router_data.recurring_mandate_payment_data = recurring_mandate_payment_data;
router_data.preprocessing_id = preprocessing_id;
router_data.payment_method_balance = payment_method_balance;
router_data.connector_api_version = connector_api_version;
router_data.connector_request_reference_id = connector_request_reference_id;
router_data.test_mode = test_mode;
router_data.connector_http_status_code = connector_http_status_code;
router_data.external_latency = external_latency;
router_data.apple_pay_flow = apple_pay_flow;
router_data.connector_response = connector_response;
router_data.payment_method_status = payment_method_status;
Ok(router_data)
}
}
impl<T, Req: Clone, Resp: Clone> RouterDataConversion<T, Req, Resp> for RefundFlowData {
fn from_old_router_data(
old_router_data: &RouterData<T, Req, Resp>,
) -> CustomResult<RouterDataV2<T, Self, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let resource_common_data = Self {
merchant_id: old_router_data.merchant_id.clone(),
customer_id: old_router_data.customer_id.clone(),
payment_id: old_router_data.payment_id.clone(),
attempt_id: old_router_data.attempt_id.clone(),
status: old_router_data.status,
payment_method: old_router_data.payment_method,
connector_meta_data: old_router_data.connector_meta_data.clone(),
amount_captured: old_router_data.amount_captured,
minor_amount_captured: old_router_data.minor_amount_captured,
connector_request_reference_id: old_router_data.connector_request_reference_id.clone(),
refund_id: old_router_data.refund_id.clone().ok_or(
ConnectorError::MissingRequiredField {
field_name: "refund_id",
},
)?,
};
Ok(RouterDataV2 {
flow: std::marker::PhantomData,
tenant_id: old_router_data.tenant_id.clone(),
resource_common_data,
connector_auth_type: old_router_data.connector_auth_type.clone(),
request: old_router_data.request.clone(),
response: old_router_data.response.clone(),
})
}
fn to_old_router_data(
new_router_data: RouterDataV2<T, Self, Req, Resp>,
) -> CustomResult<RouterData<T, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let Self {
merchant_id,
customer_id,
payment_id,
attempt_id,
status,
payment_method,
connector_meta_data,
amount_captured,
minor_amount_captured,
connector_request_reference_id,
refund_id,
} = new_router_data.resource_common_data;
let mut router_data = get_default_router_data(
new_router_data.tenant_id.clone(),
"refund",
new_router_data.request,
new_router_data.response,
);
router_data.merchant_id = merchant_id;
router_data.customer_id = customer_id;
router_data.payment_id = payment_id;
router_data.attempt_id = attempt_id;
router_data.status = status;
router_data.payment_method = payment_method;
router_data.connector_meta_data = connector_meta_data;
router_data.amount_captured = amount_captured;
router_data.minor_amount_captured = minor_amount_captured;
router_data.connector_request_reference_id = connector_request_reference_id;
router_data.refund_id = Some(refund_id);
Ok(router_data)
}
}
impl<T, Req: Clone, Resp: Clone> RouterDataConversion<T, Req, Resp> for DisputesFlowData {
fn from_old_router_data(
old_router_data: &RouterData<T, Req, Resp>,
) -> CustomResult<RouterDataV2<T, Self, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let resource_common_data = Self {
merchant_id: old_router_data.merchant_id.clone(),
payment_id: old_router_data.payment_id.clone(),
attempt_id: old_router_data.attempt_id.clone(),
payment_method: old_router_data.payment_method,
connector_meta_data: old_router_data.connector_meta_data.clone(),
amount_captured: old_router_data.amount_captured,
minor_amount_captured: old_router_data.minor_amount_captured,
connector_request_reference_id: old_router_data.connector_request_reference_id.clone(),
dispute_id: old_router_data.dispute_id.clone().ok_or(
ConnectorError::MissingRequiredField {
field_name: "dispute_id",
},
)?,
};
Ok(RouterDataV2 {
flow: std::marker::PhantomData,
tenant_id: old_router_data.tenant_id.clone(),
resource_common_data,
connector_auth_type: old_router_data.connector_auth_type.clone(),
request: old_router_data.request.clone(),
response: old_router_data.response.clone(),
})
}
fn to_old_router_data(
new_router_data: RouterDataV2<T, Self, Req, Resp>,
) -> CustomResult<RouterData<T, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let Self {
merchant_id,
payment_id,
attempt_id,
payment_method,
connector_meta_data,
amount_captured,
minor_amount_captured,
connector_request_reference_id,
dispute_id,
} = new_router_data.resource_common_data;
let mut router_data = get_default_router_data(
new_router_data.tenant_id.clone(),
"Disputes",
new_router_data.request,
new_router_data.response,
);
router_data.merchant_id = merchant_id;
router_data.payment_id = payment_id;
router_data.attempt_id = attempt_id;
router_data.payment_method = payment_method;
router_data.connector_meta_data = connector_meta_data;
router_data.amount_captured = amount_captured;
router_data.minor_amount_captured = minor_amount_captured;
router_data.connector_request_reference_id = connector_request_reference_id;
router_data.dispute_id = Some(dispute_id);
Ok(router_data)
}
}
#[cfg(feature = "frm")]
impl<T, Req: Clone, Resp: Clone> RouterDataConversion<T, Req, Resp> for FrmFlowData {
fn from_old_router_data(
old_router_data: &RouterData<T, Req, Resp>,
) -> CustomResult<RouterDataV2<T, Self, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let resource_common_data = Self {
merchant_id: old_router_data.merchant_id.clone(),
payment_id: old_router_data.payment_id.clone(),
attempt_id: old_router_data.attempt_id.clone(),
payment_method: old_router_data.payment_method,
connector_request_reference_id: old_router_data.connector_request_reference_id.clone(),
auth_type: old_router_data.auth_type,
connector_wallets_details: old_router_data.connector_wallets_details.clone(),
connector_meta_data: old_router_data.connector_meta_data.clone(),
amount_captured: old_router_data.amount_captured,
minor_amount_captured: old_router_data.minor_amount_captured,
};
Ok(RouterDataV2 {
tenant_id: old_router_data.tenant_id.clone(),
flow: std::marker::PhantomData,
resource_common_data,
connector_auth_type: old_router_data.connector_auth_type.clone(),
request: old_router_data.request.clone(),
response: old_router_data.response.clone(),
})
}
fn to_old_router_data(
new_router_data: RouterDataV2<T, Self, Req, Resp>,
) -> CustomResult<RouterData<T, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let Self {
merchant_id,
payment_id,
attempt_id,
payment_method,
connector_request_reference_id,
auth_type,
connector_wallets_details,
connector_meta_data,
amount_captured,
minor_amount_captured,
} = new_router_data.resource_common_data;
let mut router_data = get_default_router_data(
new_router_data.tenant_id.clone(),
"frm",
new_router_data.request,
new_router_data.response,
);
router_data.merchant_id = merchant_id;
router_data.payment_id = payment_id;
router_data.attempt_id = attempt_id;
router_data.payment_method = payment_method;
router_data.connector_request_reference_id = connector_request_reference_id;
router_data.auth_type = auth_type;
router_data.connector_wallets_details = connector_wallets_details;
router_data.connector_meta_data = connector_meta_data;
router_data.amount_captured = amount_captured;
router_data.minor_amount_captured = minor_amount_captured;
Ok(router_data)
}
}
impl<T, Req: Clone, Resp: Clone> RouterDataConversion<T, Req, Resp> for FilesFlowData {
fn from_old_router_data(
old_router_data: &RouterData<T, Req, Resp>,
) -> CustomResult<RouterDataV2<T, Self, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let resource_common_data = Self {
merchant_id: old_router_data.merchant_id.clone(),
payment_id: old_router_data.payment_id.clone(),
attempt_id: old_router_data.attempt_id.clone(),
connector_meta_data: old_router_data.connector_meta_data.clone(),
connector_request_reference_id: old_router_data.connector_request_reference_id.clone(),
};
Ok(RouterDataV2 {
flow: std::marker::PhantomData,
tenant_id: old_router_data.tenant_id.clone(),
resource_common_data,
connector_auth_type: old_router_data.connector_auth_type.clone(),
request: old_router_data.request.clone(),
response: old_router_data.response.clone(),
})
}
fn to_old_router_data(
new_router_data: RouterDataV2<T, Self, Req, Resp>,
) -> CustomResult<RouterData<T, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let Self {
merchant_id,
payment_id,
attempt_id,
connector_meta_data,
connector_request_reference_id,
} = new_router_data.resource_common_data;
let mut router_data = get_default_router_data(
new_router_data.tenant_id.clone(),
"files",
new_router_data.request,
new_router_data.response,
);
router_data.merchant_id = merchant_id;
router_data.payment_id = payment_id;
router_data.attempt_id = attempt_id;
router_data.connector_meta_data = connector_meta_data;
router_data.connector_request_reference_id = connector_request_reference_id;
Ok(router_data)
}
}
impl<T, Req: Clone, Resp: Clone> RouterDataConversion<T, Req, Resp> for WebhookSourceVerifyData {
fn from_old_router_data(
old_router_data: &RouterData<T, Req, Resp>,
) -> CustomResult<RouterDataV2<T, Self, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let resource_common_data = Self {
merchant_id: old_router_data.merchant_id.clone(),
};
Ok(RouterDataV2 {
tenant_id: old_router_data.tenant_id.clone(),
flow: std::marker::PhantomData,
resource_common_data,
connector_auth_type: old_router_data.connector_auth_type.clone(),
request: old_router_data.request.clone(),
response: old_router_data.response.clone(),
})
}
fn to_old_router_data(
new_router_data: RouterDataV2<T, Self, Req, Resp>,
) -> CustomResult<RouterData<T, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let Self { merchant_id } = new_router_data.resource_common_data;
let mut router_data = get_default_router_data(
new_router_data.tenant_id.clone(),
"webhook source verify",
new_router_data.request,
new_router_data.response,
);
router_data.merchant_id = merchant_id;
Ok(router_data)
}
}
impl<T, Req: Clone, Resp: Clone> RouterDataConversion<T, Req, Resp> for MandateRevokeFlowData {
fn from_old_router_data(
old_router_data: &RouterData<T, Req, Resp>,
) -> CustomResult<RouterDataV2<T, Self, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let resource_common_data = Self {
merchant_id: old_router_data.merchant_id.clone(),
customer_id: old_router_data.customer_id.clone().ok_or(
ConnectorError::MissingRequiredField {
field_name: "customer_id",
},
)?,
payment_id: Some(old_router_data.payment_id.clone()),
};
Ok(RouterDataV2 {
flow: std::marker::PhantomData,
tenant_id: old_router_data.tenant_id.clone(),
resource_common_data,
connector_auth_type: old_router_data.connector_auth_type.clone(),
request: old_router_data.request.clone(),
response: old_router_data.response.clone(),
})
}
fn to_old_router_data(
new_router_data: RouterDataV2<T, Self, Req, Resp>,
) -> CustomResult<RouterData<T, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let Self {
merchant_id,
customer_id,
payment_id,
} = new_router_data.resource_common_data;
let mut router_data = get_default_router_data(
new_router_data.tenant_id.clone(),
"mandate revoke",
new_router_data.request,
new_router_data.response,
);
router_data.merchant_id = merchant_id;
router_data.customer_id = Some(customer_id);
router_data.payment_id = payment_id
.unwrap_or_else(|| {
id_type::PaymentId::get_irrelevant_id("mandate revoke")
.get_string_repr()
.to_owned()
})
.to_owned();
Ok(router_data)
}
}
#[cfg(feature = "payouts")]
impl<T, Req: Clone, Resp: Clone> RouterDataConversion<T, Req, Resp> for PayoutFlowData {
fn from_old_router_data(
old_router_data: &RouterData<T, Req, Resp>,
) -> CustomResult<RouterDataV2<T, Self, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let resource_common_data = Self {
merchant_id: old_router_data.merchant_id.clone(),
customer_id: old_router_data.customer_id.clone(),
connector_customer: old_router_data.connector_customer.clone(),
address: old_router_data.address.clone(),
connector_meta_data: old_router_data.connector_meta_data.clone(),
connector_wallets_details: old_router_data.connector_wallets_details.clone(),
connector_request_reference_id: old_router_data.connector_request_reference_id.clone(),
payout_method_data: old_router_data.payout_method_data.clone(),
quote_id: old_router_data.quote_id.clone(),
};
Ok(RouterDataV2 {
tenant_id: old_router_data.tenant_id.clone(),
flow: std::marker::PhantomData,
resource_common_data,
connector_auth_type: old_router_data.connector_auth_type.clone(),
request: old_router_data.request.clone(),
response: old_router_data.response.clone(),
})
}
fn to_old_router_data(
new_router_data: RouterDataV2<T, Self, Req, Resp>,
) -> CustomResult<RouterData<T, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let Self {
merchant_id,
customer_id,
connector_customer,
address,
connector_meta_data,
connector_wallets_details,
connector_request_reference_id,
payout_method_data,
quote_id,
} = new_router_data.resource_common_data;
let mut router_data = get_default_router_data(
new_router_data.tenant_id.clone(),
"payout",
new_router_data.request,
new_router_data.response,
);
router_data.merchant_id = merchant_id;
router_data.customer_id = customer_id;
router_data.connector_customer = connector_customer;
router_data.address = address;
router_data.connector_meta_data = connector_meta_data;
router_data.connector_wallets_details = connector_wallets_details;
router_data.connector_request_reference_id = connector_request_reference_id;
router_data.payout_method_data = payout_method_data;
router_data.quote_id = quote_id;
Ok(router_data)
}
}
impl<T, Req: Clone, Resp: Clone> RouterDataConversion<T, Req, Resp>
for ExternalAuthenticationFlowData
{
fn from_old_router_data(
old_router_data: &RouterData<T, Req, Resp>,
) -> CustomResult<RouterDataV2<T, Self, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let resource_common_data = Self {
merchant_id: old_router_data.merchant_id.clone(),
connector_meta_data: old_router_data.connector_meta_data.clone(),
address: old_router_data.address.clone(),
};
Ok(RouterDataV2 {
tenant_id: old_router_data.tenant_id.clone(),
flow: std::marker::PhantomData,
resource_common_data,
connector_auth_type: old_router_data.connector_auth_type.clone(),
request: old_router_data.request.clone(),
response: old_router_data.response.clone(),
})
}
fn to_old_router_data(
new_router_data: RouterDataV2<T, Self, Req, Resp>,
) -> CustomResult<RouterData<T, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let Self {
merchant_id,
connector_meta_data,
address,
} = new_router_data.resource_common_data;
let mut router_data = get_default_router_data(
new_router_data.tenant_id.clone(),
"external authentication",
new_router_data.request,
new_router_data.response,
);
router_data.merchant_id = merchant_id;
router_data.connector_meta_data = connector_meta_data;
router_data.address = address;
Ok(router_data)
}
}
impl<T, Req: Clone, Resp: Clone> RouterDataConversion<T, Req, Resp>
for RevenueRecoveryRecordBackData
{
fn from_old_router_data(
old_router_data: &RouterData<T, Req, Resp>,
) -> CustomResult<RouterDataV2<T, Self, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let resource_common_data = Self {};
Ok(RouterDataV2 {
flow: std::marker::PhantomData,
tenant_id: old_router_data.tenant_id.clone(),
resource_common_data,
connector_auth_type: old_router_data.connector_auth_type.clone(),
request: old_router_data.request.clone(),
response: old_router_data.response.clone(),
})
}
fn to_old_router_data(
new_router_data: RouterDataV2<T, Self, Req, Resp>,
) -> CustomResult<RouterData<T, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let router_data = get_default_router_data(
new_router_data.tenant_id.clone(),
"recovery_record_back",
new_router_data.request,
new_router_data.response,
);
Ok(router_data)
}
}
impl<T, Req: Clone, Resp: Clone> RouterDataConversion<T, Req, Resp> for UasFlowData {
fn from_old_router_data(
old_router_data: &RouterData<T, Req, Resp>,
) -> CustomResult<RouterDataV2<T, Self, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let resource_common_data = Self {
authenticate_by: old_router_data.connector.clone(),
source_authentication_id: old_router_data
.authentication_id
.clone()
.ok_or(ConnectorError::MissingRequiredField {
field_name: "source_authentication_id",
})
.attach_printable("missing authentication id for uas")?,
};
Ok(RouterDataV2 {
flow: std::marker::PhantomData,
tenant_id: old_router_data.tenant_id.clone(),
resource_common_data,
connector_auth_type: old_router_data.connector_auth_type.clone(),
request: old_router_data.request.clone(),
response: old_router_data.response.clone(),
})
}
fn to_old_router_data(
new_router_data: RouterDataV2<T, Self, Req, Resp>,
) -> CustomResult<RouterData<T, Req, Resp>, ConnectorError>
where
Self: Sized,
{
let Self {
authenticate_by,
source_authentication_id,
} = new_router_data.resource_common_data;
let mut router_data = get_default_router_data(
new_router_data.tenant_id.clone(),
"uas",
new_router_data.request,
new_router_data.response,
);
router_data.connector = authenticate_by;
router_data.authentication_id = Some(source_authentication_id);
Ok(router_data)
}
}

View File

@ -3,10 +3,16 @@
pub mod api;
pub mod authentication;
/// Configuration related functionalities
pub mod configs;
/// Connector integration interface module
pub mod connector_integration_interface;
/// definition of the new connector integration trait
pub mod connector_integration_v2;
/// Constants used throughout the application
pub mod consts;
/// Conversion implementations
pub mod conversion_impls;
pub mod disputes;
pub mod encryption_interface;
pub mod errors;