mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 09:07:09 +08:00
fix(connector_onboarding): Check if connector exists for the merchant account and add reset tracking id API (#3229)
This commit is contained in:
@ -52,3 +52,9 @@ pub struct PayPalOnboardingDone {
|
||||
pub struct PayPalIntegrationDone {
|
||||
pub connector_id: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)]
|
||||
pub struct ResetTrackingIdRequest {
|
||||
pub connector_id: String,
|
||||
pub connector: enums::Connector,
|
||||
}
|
||||
|
||||
@ -2,11 +2,13 @@ use common_utils::events::{ApiEventMetric, ApiEventsType};
|
||||
|
||||
use crate::connector_onboarding::{
|
||||
ActionUrlRequest, ActionUrlResponse, OnboardingStatus, OnboardingSyncRequest,
|
||||
ResetTrackingIdRequest,
|
||||
};
|
||||
|
||||
common_utils::impl_misc_api_event_type!(
|
||||
ActionUrlRequest,
|
||||
ActionUrlResponse,
|
||||
OnboardingSyncRequest,
|
||||
OnboardingStatus
|
||||
OnboardingStatus,
|
||||
ResetTrackingIdRequest
|
||||
);
|
||||
|
||||
@ -77,6 +77,9 @@ pub const VERIFY_CONNECTOR_ID_PREFIX: &str = "conn_verify";
|
||||
#[cfg(feature = "olap")]
|
||||
pub const VERIFY_CONNECTOR_MERCHANT_ID: &str = "test_merchant";
|
||||
|
||||
#[cfg(feature = "olap")]
|
||||
pub const CONNECTOR_ONBOARDING_CONFIG_PREFIX: &str = "onboarding";
|
||||
|
||||
/// Max payment session expiry
|
||||
pub const MAX_SESSION_EXPIRY: u32 = 7890000;
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
use api_models::{connector_onboarding as api, enums};
|
||||
use error_stack::ResultExt;
|
||||
use masking::Secret;
|
||||
|
||||
use crate::{
|
||||
@ -19,16 +18,23 @@ pub trait AccessToken {
|
||||
|
||||
pub async fn get_action_url(
|
||||
state: AppState,
|
||||
user_from_token: auth::UserFromToken,
|
||||
request: api::ActionUrlRequest,
|
||||
) -> RouterResponse<api::ActionUrlResponse> {
|
||||
utils::check_if_connector_exists(&state, &request.connector_id, &user_from_token.merchant_id)
|
||||
.await?;
|
||||
|
||||
let connector_onboarding_conf = state.conf.connector_onboarding.clone();
|
||||
let is_enabled = utils::is_enabled(request.connector, &connector_onboarding_conf);
|
||||
let tracking_id =
|
||||
utils::get_tracking_id_from_configs(&state, &request.connector_id, request.connector)
|
||||
.await?;
|
||||
|
||||
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,
|
||||
tracking_id,
|
||||
request.return_url,
|
||||
))
|
||||
.await?;
|
||||
@ -49,40 +55,42 @@ pub async fn sync_onboarding_status(
|
||||
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)?;
|
||||
utils::check_if_connector_exists(&state, &request.connector_id, &user_from_token.merchant_id)
|
||||
.await?;
|
||||
|
||||
let connector_onboarding_conf = state.conf.connector_onboarding.clone();
|
||||
let is_enabled = utils::is_enabled(request.connector, &connector_onboarding_conf);
|
||||
let tracking_id =
|
||||
utils::get_tracking_id_from_configs(&state, &request.connector_id, request.connector)
|
||||
.await?;
|
||||
|
||||
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(),
|
||||
tracking_id,
|
||||
))
|
||||
.await?;
|
||||
if let api::OnboardingStatus::PayPal(api::PayPalOnboardingStatus::Success(
|
||||
ref inner_data,
|
||||
ref paypal_onboarding_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()),
|
||||
api_secret: Secret::new(paypal_onboarding_data.payer_id.clone()),
|
||||
};
|
||||
let some_data = paypal::update_mca(
|
||||
let update_mca_data = paypal::update_mca(
|
||||
&state,
|
||||
&merchant_account,
|
||||
user_from_token.merchant_id,
|
||||
request.connector_id.to_owned(),
|
||||
auth_details,
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Ok(ApplicationResponse::Json(api::OnboardingStatus::PayPal(
|
||||
api::PayPalOnboardingStatus::ConnectorIntegrated(some_data),
|
||||
api::PayPalOnboardingStatus::ConnectorIntegrated(update_mca_data),
|
||||
)));
|
||||
}
|
||||
Ok(ApplicationResponse::Json(status))
|
||||
@ -94,3 +102,15 @@ pub async fn sync_onboarding_status(
|
||||
.into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn reset_tracking_id(
|
||||
state: AppState,
|
||||
user_from_token: auth::UserFromToken,
|
||||
request: api::ResetTrackingIdRequest,
|
||||
) -> RouterResponse<()> {
|
||||
utils::check_if_connector_exists(&state, &request.connector_id, &user_from_token.merchant_id)
|
||||
.await?;
|
||||
utils::set_tracking_id_in_configs(&state, &request.connector_id, request.connector).await?;
|
||||
|
||||
Ok(ApplicationResponse::StatusOk)
|
||||
}
|
||||
|
||||
@ -23,11 +23,11 @@ fn build_referral_url(state: AppState) -> String {
|
||||
|
||||
async fn build_referral_request(
|
||||
state: AppState,
|
||||
connector_id: String,
|
||||
tracking_id: String,
|
||||
return_url: String,
|
||||
) -> RouterResult<Request> {
|
||||
let access_token = utils::paypal::generate_access_token(state.clone()).await?;
|
||||
let request_body = types::paypal::PartnerReferralRequest::new(connector_id, return_url);
|
||||
let request_body = types::paypal::PartnerReferralRequest::new(tracking_id, return_url);
|
||||
|
||||
utils::paypal::build_paypal_post_request(
|
||||
build_referral_url(state),
|
||||
@ -38,12 +38,12 @@ async fn build_referral_request(
|
||||
|
||||
pub async fn get_action_url_from_paypal(
|
||||
state: AppState,
|
||||
connector_id: String,
|
||||
tracking_id: String,
|
||||
return_url: String,
|
||||
) -> RouterResult<String> {
|
||||
let referral_request = Box::pin(build_referral_request(
|
||||
state.clone(),
|
||||
connector_id,
|
||||
tracking_id,
|
||||
return_url,
|
||||
))
|
||||
.await?;
|
||||
@ -137,7 +137,7 @@ async fn find_paypal_merchant_by_tracking_id(
|
||||
|
||||
pub async fn update_mca(
|
||||
state: &AppState,
|
||||
merchant_account: &oss_types::domain::MerchantAccount,
|
||||
merchant_id: String,
|
||||
connector_id: String,
|
||||
auth_details: oss_types::ConnectorAuthType,
|
||||
) -> RouterResult<oss_api_types::MerchantConnectorResponse> {
|
||||
@ -159,13 +159,9 @@ pub async fn update_mca(
|
||||
connector_webhook_details: None,
|
||||
pm_auth_config: None,
|
||||
};
|
||||
let mca_response = admin::update_payment_connector(
|
||||
state.clone(),
|
||||
&merchant_account.merchant_id,
|
||||
&connector_id,
|
||||
request,
|
||||
)
|
||||
.await?;
|
||||
let mca_response =
|
||||
admin::update_payment_connector(state.clone(), &merchant_id, &connector_id, request)
|
||||
.await?;
|
||||
|
||||
match mca_response {
|
||||
ApplicationResponse::Json(mca_data) => Ok(mca_data),
|
||||
|
||||
@ -961,5 +961,6 @@ impl ConnectorOnboarding {
|
||||
.app_data(web::Data::new(state))
|
||||
.service(web::resource("/action_url").route(web::post().to(get_action_url)))
|
||||
.service(web::resource("/sync").route(web::post().to(sync_onboarding_status)))
|
||||
.service(web::resource("/reset_tracking_id").route(web::post().to(reset_tracking_id)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ pub async fn get_action_url(
|
||||
state,
|
||||
&http_req,
|
||||
req_payload.clone(),
|
||||
|state, _: auth::UserFromToken, req| core::get_action_url(state, req),
|
||||
core::get_action_url,
|
||||
&auth::JWTAuth(Permission::MerchantAccountWrite),
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
@ -45,3 +45,22 @@ pub async fn sync_onboarding_status(
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn reset_tracking_id(
|
||||
state: web::Data<AppState>,
|
||||
http_req: HttpRequest,
|
||||
json_payload: web::Json<api_types::ResetTrackingIdRequest>,
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::ResetTrackingId;
|
||||
let req_payload = json_payload.into_inner();
|
||||
Box::pin(api::server_wrap(
|
||||
flow.clone(),
|
||||
state,
|
||||
&http_req,
|
||||
req_payload.clone(),
|
||||
core::reset_tracking_id,
|
||||
&auth::JWTAuth(Permission::MerchantAccountWrite),
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
@ -183,7 +183,9 @@ impl From<Flow> for ApiIdentifier {
|
||||
Self::UserRole
|
||||
}
|
||||
|
||||
Flow::GetActionUrl | Flow::SyncOnboardingStatus => Self::ConnectorOnboarding,
|
||||
Flow::GetActionUrl | Flow::SyncOnboardingStatus | Flow::ResetTrackingId => {
|
||||
Self::ConnectorOnboarding
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
use diesel_models::{ConfigNew, ConfigUpdate};
|
||||
use error_stack::ResultExt;
|
||||
|
||||
use super::errors::StorageErrorExt;
|
||||
use crate::{
|
||||
consts,
|
||||
core::errors::{api_error_response::NotImplementedMessage, ApiErrorResponse, RouterResult},
|
||||
routes::app::settings,
|
||||
routes::{app::settings, AppState},
|
||||
types::{self, api::enums},
|
||||
};
|
||||
|
||||
@ -34,3 +39,105 @@ pub fn is_enabled(
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn check_if_connector_exists(
|
||||
state: &AppState,
|
||||
connector_id: &str,
|
||||
merchant_id: &str,
|
||||
) -> RouterResult<()> {
|
||||
let key_store = state
|
||||
.store
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
merchant_id,
|
||||
&state.store.get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
|
||||
let _connector = state
|
||||
.store
|
||||
.find_by_merchant_connector_account_merchant_id_merchant_connector_id(
|
||||
merchant_id,
|
||||
connector_id,
|
||||
&key_store,
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(ApiErrorResponse::MerchantConnectorAccountNotFound {
|
||||
id: connector_id.to_string(),
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_tracking_id_in_configs(
|
||||
state: &AppState,
|
||||
connector_id: &str,
|
||||
connector: enums::Connector,
|
||||
) -> RouterResult<()> {
|
||||
let timestamp = common_utils::date_time::now_unix_timestamp().to_string();
|
||||
let find_config = state
|
||||
.store
|
||||
.find_config_by_key(&build_key(connector_id, connector))
|
||||
.await;
|
||||
|
||||
if find_config.is_ok() {
|
||||
state
|
||||
.store
|
||||
.update_config_by_key(
|
||||
&build_key(connector_id, connector),
|
||||
ConfigUpdate::Update {
|
||||
config: Some(timestamp),
|
||||
},
|
||||
)
|
||||
.await
|
||||
.change_context(ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Error updating data in configs table")?;
|
||||
} else if find_config
|
||||
.as_ref()
|
||||
.map_err(|e| e.current_context().is_db_not_found())
|
||||
.err()
|
||||
.unwrap_or(false)
|
||||
{
|
||||
state
|
||||
.store
|
||||
.insert_config(ConfigNew {
|
||||
key: build_key(connector_id, connector),
|
||||
config: timestamp,
|
||||
})
|
||||
.await
|
||||
.change_context(ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Error inserting data in configs table")?;
|
||||
} else {
|
||||
find_config.change_context(ApiErrorResponse::InternalServerError)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_tracking_id_from_configs(
|
||||
state: &AppState,
|
||||
connector_id: &str,
|
||||
connector: enums::Connector,
|
||||
) -> RouterResult<String> {
|
||||
let timestamp = state
|
||||
.store
|
||||
.find_config_by_key_unwrap_or(
|
||||
&build_key(connector_id, connector),
|
||||
Some(common_utils::date_time::now_unix_timestamp().to_string()),
|
||||
)
|
||||
.await
|
||||
.change_context(ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Error getting data from configs table")?
|
||||
.config;
|
||||
|
||||
Ok(format!("{}_{}", connector_id, timestamp))
|
||||
}
|
||||
|
||||
fn build_key(connector_id: &str, connector: enums::Connector) -> String {
|
||||
format!(
|
||||
"{}_{}_{}",
|
||||
consts::CONNECTOR_ONBOARDING_CONFIG_PREFIX,
|
||||
connector,
|
||||
connector_id,
|
||||
)
|
||||
}
|
||||
|
||||
@ -317,6 +317,8 @@ pub enum Flow {
|
||||
GetActionUrl,
|
||||
/// Sync connector onboarding status
|
||||
SyncOnboardingStatus,
|
||||
/// Reset tracking id
|
||||
ResetTrackingId,
|
||||
/// Verify email Token
|
||||
VerifyEmail,
|
||||
/// Send verify email
|
||||
|
||||
Reference in New Issue
Block a user