Skip to content

Commit

Permalink
feat(connector_onboarding): Add Connector onboarding APIs (#3050)
Browse files Browse the repository at this point in the history
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
  • Loading branch information
ThisIsMani and hyperswitch-bot[bot] authored Dec 5, 2023
1 parent 53df543 commit 7bd6e05
Show file tree
Hide file tree
Showing 25 changed files with 876 additions and 6 deletions.
6 changes: 6 additions & 0 deletions config/config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -477,3 +477,9 @@ connection_timeout = 10 # Timeout for database connection in seconds
[kv_config]
# TTL for KV in seconds
ttl = 900

[paypal_onboarding]
client_id = "paypal_client_id" # Client ID for PayPal onboarding
client_secret = "paypal_secret_key" # Secret key for PayPal onboarding
partner_id = "paypal_partner_id" # Partner ID for PayPal onboarding
enabled = true # Switch to enable or disable PayPal onboarding
8 changes: 7 additions & 1 deletion config/development.toml
Original file line number Diff line number Diff line change
Expand Up @@ -504,4 +504,10 @@ port = 5432
dbname = "hyperswitch_db"
pool_size = 5
connection_timeout = 10
queue_strategy = "Fifo"
queue_strategy = "Fifo"

[connector_onboarding.paypal]
client_id = ""
client_secret = ""
partner_id = ""
enabled = true
6 changes: 6 additions & 0 deletions config/docker_compose.toml
Original file line number Diff line number Diff line change
Expand Up @@ -362,3 +362,9 @@ queue_strategy = "Fifo"

[kv_config]
ttl = 900 # 15 * 60 seconds

[connector_onboarding.paypal]
client_id = ""
client_secret = ""
partner_id = ""
enabled = true
54 changes: 54 additions & 0 deletions crates/api_models/src/connector_onboarding.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use super::{admin, enums};

#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)]
pub struct ActionUrlRequest {
pub connector: enums::Connector,
pub connector_id: String,
pub return_url: String,
}

#[derive(serde::Serialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub enum ActionUrlResponse {
PayPal(PayPalActionUrlResponse),
}

#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)]
pub struct OnboardingSyncRequest {
pub profile_id: String,
pub connector_id: String,
pub connector: enums::Connector,
}

#[derive(serde::Serialize, Debug, Clone)]
pub struct PayPalActionUrlResponse {
pub action_url: String,
}

#[derive(serde::Serialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub enum OnboardingStatus {
PayPal(PayPalOnboardingStatus),
}

#[derive(serde::Serialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
pub enum PayPalOnboardingStatus {
AccountNotFound,
PaymentsNotReceivable,
PpcpCustomDenied,
MorePermissionsNeeded,
EmailNotVerified,
Success(PayPalOnboardingDone),
ConnectorIntegrated(admin::MerchantConnectorResponse),
}

#[derive(serde::Serialize, Debug, Clone)]
pub struct PayPalOnboardingDone {
pub payer_id: String,
}

#[derive(serde::Serialize, Debug, Clone)]
pub struct PayPalIntegrationDone {
pub connector_id: String,
}
1 change: 1 addition & 0 deletions crates/api_models/src/events.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod connector_onboarding;
pub mod customer;
pub mod gsm;
mod locker_migration;
Expand Down
12 changes: 12 additions & 0 deletions crates/api_models/src/events/connector_onboarding.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use common_utils::events::{ApiEventMetric, ApiEventsType};

use crate::connector_onboarding::{
ActionUrlRequest, ActionUrlResponse, OnboardingStatus, OnboardingSyncRequest,
};

common_utils::impl_misc_api_event_type!(
ActionUrlRequest,
ActionUrlResponse,
OnboardingSyncRequest,
OnboardingStatus
);
1 change: 1 addition & 0 deletions crates/api_models/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod api_keys;
pub mod bank_accounts;
pub mod cards_info;
pub mod conditional_configs;
pub mod connector_onboarding;
pub mod currency;
pub mod customers;
pub mod disputes;
Expand Down
33 changes: 33 additions & 0 deletions crates/router/src/configs/kms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,36 @@ impl KmsDecrypt for settings::Database {
})
}
}

#[cfg(feature = "olap")]
#[async_trait::async_trait]
impl KmsDecrypt for settings::PayPalOnboarding {
type Output = Self;

async fn decrypt_inner(
mut self,
kms_client: &KmsClient,
) -> CustomResult<Self::Output, KmsError> {
self.client_id = kms_client.decrypt(self.client_id.expose()).await?.into();
self.client_secret = kms_client
.decrypt(self.client_secret.expose())
.await?
.into();
self.partner_id = kms_client.decrypt(self.partner_id.expose()).await?.into();
Ok(self)
}
}

#[cfg(feature = "olap")]
#[async_trait::async_trait]
impl KmsDecrypt for settings::ConnectorOnboarding {
type Output = Self;

async fn decrypt_inner(
mut self,
kms_client: &KmsClient,
) -> CustomResult<Self::Output, KmsError> {
self.paypal = self.paypal.decrypt_inner(kms_client).await?;
Ok(self)
}
}
17 changes: 17 additions & 0 deletions crates/router/src/configs/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ pub struct Settings {
#[cfg(feature = "olap")]
pub report_download_config: ReportConfig,
pub events: EventsConfig,
#[cfg(feature = "olap")]
pub connector_onboarding: ConnectorOnboarding,
}

#[derive(Debug, Deserialize, Clone)]
Expand Down Expand Up @@ -884,3 +886,18 @@ impl<'de> Deserialize<'de> for LockSettings {
})
}
}

#[cfg(feature = "olap")]
#[derive(Debug, Deserialize, Clone, Default)]
pub struct ConnectorOnboarding {
pub paypal: PayPalOnboarding,
}

#[cfg(feature = "olap")]
#[derive(Debug, Deserialize, Clone, Default)]
pub struct PayPalOnboarding {
pub client_id: masking::Secret<String>,
pub client_secret: masking::Secret<String>,
pub partner_id: masking::Secret<String>,
pub enabled: bool,
}
2 changes: 2 additions & 0 deletions crates/router/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ pub mod cache;
pub mod cards_info;
pub mod conditional_config;
pub mod configs;
#[cfg(feature = "olap")]
pub mod connector_onboarding;
#[cfg(any(feature = "olap", feature = "oltp"))]
pub mod currency;
pub mod customers;
Expand Down
96 changes: 96 additions & 0 deletions crates/router/src/core/connector_onboarding.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use api_models::{connector_onboarding as api, enums};
use error_stack::ResultExt;
use masking::Secret;

use crate::{
core::errors::{ApiErrorResponse, RouterResponse, RouterResult},
services::{authentication as auth, ApplicationResponse},
types::{self as oss_types},
utils::connector_onboarding as utils,
AppState,
};

pub mod paypal;

#[async_trait::async_trait]
pub trait AccessToken {
async fn access_token(state: &AppState) -> RouterResult<oss_types::AccessToken>;
}

pub async fn get_action_url(
state: AppState,
request: api::ActionUrlRequest,
) -> RouterResponse<api::ActionUrlResponse> {
let connector_onboarding_conf = state.conf.connector_onboarding.clone();
let is_enabled = utils::is_enabled(request.connector, &connector_onboarding_conf);

match (is_enabled, request.connector) {
(Some(true), enums::Connector::Paypal) => {
let action_url = Box::pin(paypal::get_action_url_from_paypal(
state,
request.connector_id,
request.return_url,
))
.await?;
Ok(ApplicationResponse::Json(api::ActionUrlResponse::PayPal(
api::PayPalActionUrlResponse { action_url },
)))
}
_ => Err(ApiErrorResponse::FlowNotSupported {
flow: "Connector onboarding".to_string(),
connector: request.connector.to_string(),
}
.into()),
}
}

pub async fn sync_onboarding_status(
state: AppState,
user_from_token: auth::UserFromToken,
request: api::OnboardingSyncRequest,
) -> RouterResponse<api::OnboardingStatus> {
let merchant_account = user_from_token
.get_merchant_account(state.clone())
.await
.change_context(ApiErrorResponse::MerchantAccountNotFound)?;
let connector_onboarding_conf = state.conf.connector_onboarding.clone();
let is_enabled = utils::is_enabled(request.connector, &connector_onboarding_conf);

match (is_enabled, request.connector) {
(Some(true), enums::Connector::Paypal) => {
let status = Box::pin(paypal::sync_merchant_onboarding_status(
state.clone(),
request.connector_id.clone(),
))
.await?;
if let api::OnboardingStatus::PayPal(api::PayPalOnboardingStatus::Success(
ref inner_data,
)) = status
{
let connector_onboarding_conf = state.conf.connector_onboarding.clone();
let auth_details = oss_types::ConnectorAuthType::SignatureKey {
api_key: connector_onboarding_conf.paypal.client_secret,
key1: connector_onboarding_conf.paypal.client_id,
api_secret: Secret::new(inner_data.payer_id.clone()),
};
let some_data = paypal::update_mca(
&state,
&merchant_account,
request.connector_id.to_owned(),
auth_details,
)
.await?;

return Ok(ApplicationResponse::Json(api::OnboardingStatus::PayPal(
api::PayPalOnboardingStatus::ConnectorIntegrated(some_data),
)));
}
Ok(ApplicationResponse::Json(status))
}
_ => Err(ApiErrorResponse::FlowNotSupported {
flow: "Connector onboarding".to_string(),
connector: request.connector.to_string(),
}
.into()),
}
}
Loading

0 comments on commit 7bd6e05

Please sign in to comment.