mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 01:27:31 +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 struct PayPalIntegrationDone {
|
||||||
pub connector_id: String,
|
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::{
|
use crate::connector_onboarding::{
|
||||||
ActionUrlRequest, ActionUrlResponse, OnboardingStatus, OnboardingSyncRequest,
|
ActionUrlRequest, ActionUrlResponse, OnboardingStatus, OnboardingSyncRequest,
|
||||||
|
ResetTrackingIdRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
common_utils::impl_misc_api_event_type!(
|
common_utils::impl_misc_api_event_type!(
|
||||||
ActionUrlRequest,
|
ActionUrlRequest,
|
||||||
ActionUrlResponse,
|
ActionUrlResponse,
|
||||||
OnboardingSyncRequest,
|
OnboardingSyncRequest,
|
||||||
OnboardingStatus
|
OnboardingStatus,
|
||||||
|
ResetTrackingIdRequest
|
||||||
);
|
);
|
||||||
|
|||||||
@ -77,6 +77,9 @@ pub const VERIFY_CONNECTOR_ID_PREFIX: &str = "conn_verify";
|
|||||||
#[cfg(feature = "olap")]
|
#[cfg(feature = "olap")]
|
||||||
pub const VERIFY_CONNECTOR_MERCHANT_ID: &str = "test_merchant";
|
pub const VERIFY_CONNECTOR_MERCHANT_ID: &str = "test_merchant";
|
||||||
|
|
||||||
|
#[cfg(feature = "olap")]
|
||||||
|
pub const CONNECTOR_ONBOARDING_CONFIG_PREFIX: &str = "onboarding";
|
||||||
|
|
||||||
/// Max payment session expiry
|
/// Max payment session expiry
|
||||||
pub const MAX_SESSION_EXPIRY: u32 = 7890000;
|
pub const MAX_SESSION_EXPIRY: u32 = 7890000;
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
use api_models::{connector_onboarding as api, enums};
|
use api_models::{connector_onboarding as api, enums};
|
||||||
use error_stack::ResultExt;
|
|
||||||
use masking::Secret;
|
use masking::Secret;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -19,16 +18,23 @@ pub trait AccessToken {
|
|||||||
|
|
||||||
pub async fn get_action_url(
|
pub async fn get_action_url(
|
||||||
state: AppState,
|
state: AppState,
|
||||||
|
user_from_token: auth::UserFromToken,
|
||||||
request: api::ActionUrlRequest,
|
request: api::ActionUrlRequest,
|
||||||
) -> RouterResponse<api::ActionUrlResponse> {
|
) -> 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 connector_onboarding_conf = state.conf.connector_onboarding.clone();
|
||||||
let is_enabled = utils::is_enabled(request.connector, &connector_onboarding_conf);
|
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) {
|
match (is_enabled, request.connector) {
|
||||||
(Some(true), enums::Connector::Paypal) => {
|
(Some(true), enums::Connector::Paypal) => {
|
||||||
let action_url = Box::pin(paypal::get_action_url_from_paypal(
|
let action_url = Box::pin(paypal::get_action_url_from_paypal(
|
||||||
state,
|
state,
|
||||||
request.connector_id,
|
tracking_id,
|
||||||
request.return_url,
|
request.return_url,
|
||||||
))
|
))
|
||||||
.await?;
|
.await?;
|
||||||
@ -49,40 +55,42 @@ pub async fn sync_onboarding_status(
|
|||||||
user_from_token: auth::UserFromToken,
|
user_from_token: auth::UserFromToken,
|
||||||
request: api::OnboardingSyncRequest,
|
request: api::OnboardingSyncRequest,
|
||||||
) -> RouterResponse<api::OnboardingStatus> {
|
) -> RouterResponse<api::OnboardingStatus> {
|
||||||
let merchant_account = user_from_token
|
utils::check_if_connector_exists(&state, &request.connector_id, &user_from_token.merchant_id)
|
||||||
.get_merchant_account(state.clone())
|
.await?;
|
||||||
.await
|
|
||||||
.change_context(ApiErrorResponse::MerchantAccountNotFound)?;
|
|
||||||
let connector_onboarding_conf = state.conf.connector_onboarding.clone();
|
let connector_onboarding_conf = state.conf.connector_onboarding.clone();
|
||||||
let is_enabled = utils::is_enabled(request.connector, &connector_onboarding_conf);
|
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) {
|
match (is_enabled, request.connector) {
|
||||||
(Some(true), enums::Connector::Paypal) => {
|
(Some(true), enums::Connector::Paypal) => {
|
||||||
let status = Box::pin(paypal::sync_merchant_onboarding_status(
|
let status = Box::pin(paypal::sync_merchant_onboarding_status(
|
||||||
state.clone(),
|
state.clone(),
|
||||||
request.connector_id.clone(),
|
tracking_id,
|
||||||
))
|
))
|
||||||
.await?;
|
.await?;
|
||||||
if let api::OnboardingStatus::PayPal(api::PayPalOnboardingStatus::Success(
|
if let api::OnboardingStatus::PayPal(api::PayPalOnboardingStatus::Success(
|
||||||
ref inner_data,
|
ref paypal_onboarding_data,
|
||||||
)) = status
|
)) = status
|
||||||
{
|
{
|
||||||
let connector_onboarding_conf = state.conf.connector_onboarding.clone();
|
let connector_onboarding_conf = state.conf.connector_onboarding.clone();
|
||||||
let auth_details = oss_types::ConnectorAuthType::SignatureKey {
|
let auth_details = oss_types::ConnectorAuthType::SignatureKey {
|
||||||
api_key: connector_onboarding_conf.paypal.client_secret,
|
api_key: connector_onboarding_conf.paypal.client_secret,
|
||||||
key1: connector_onboarding_conf.paypal.client_id,
|
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,
|
&state,
|
||||||
&merchant_account,
|
user_from_token.merchant_id,
|
||||||
request.connector_id.to_owned(),
|
request.connector_id.to_owned(),
|
||||||
auth_details,
|
auth_details,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
return Ok(ApplicationResponse::Json(api::OnboardingStatus::PayPal(
|
return Ok(ApplicationResponse::Json(api::OnboardingStatus::PayPal(
|
||||||
api::PayPalOnboardingStatus::ConnectorIntegrated(some_data),
|
api::PayPalOnboardingStatus::ConnectorIntegrated(update_mca_data),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
Ok(ApplicationResponse::Json(status))
|
Ok(ApplicationResponse::Json(status))
|
||||||
@ -94,3 +102,15 @@ pub async fn sync_onboarding_status(
|
|||||||
.into()),
|
.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(
|
async fn build_referral_request(
|
||||||
state: AppState,
|
state: AppState,
|
||||||
connector_id: String,
|
tracking_id: String,
|
||||||
return_url: String,
|
return_url: String,
|
||||||
) -> RouterResult<Request> {
|
) -> RouterResult<Request> {
|
||||||
let access_token = utils::paypal::generate_access_token(state.clone()).await?;
|
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(
|
utils::paypal::build_paypal_post_request(
|
||||||
build_referral_url(state),
|
build_referral_url(state),
|
||||||
@ -38,12 +38,12 @@ async fn build_referral_request(
|
|||||||
|
|
||||||
pub async fn get_action_url_from_paypal(
|
pub async fn get_action_url_from_paypal(
|
||||||
state: AppState,
|
state: AppState,
|
||||||
connector_id: String,
|
tracking_id: String,
|
||||||
return_url: String,
|
return_url: String,
|
||||||
) -> RouterResult<String> {
|
) -> RouterResult<String> {
|
||||||
let referral_request = Box::pin(build_referral_request(
|
let referral_request = Box::pin(build_referral_request(
|
||||||
state.clone(),
|
state.clone(),
|
||||||
connector_id,
|
tracking_id,
|
||||||
return_url,
|
return_url,
|
||||||
))
|
))
|
||||||
.await?;
|
.await?;
|
||||||
@ -137,7 +137,7 @@ async fn find_paypal_merchant_by_tracking_id(
|
|||||||
|
|
||||||
pub async fn update_mca(
|
pub async fn update_mca(
|
||||||
state: &AppState,
|
state: &AppState,
|
||||||
merchant_account: &oss_types::domain::MerchantAccount,
|
merchant_id: String,
|
||||||
connector_id: String,
|
connector_id: String,
|
||||||
auth_details: oss_types::ConnectorAuthType,
|
auth_details: oss_types::ConnectorAuthType,
|
||||||
) -> RouterResult<oss_api_types::MerchantConnectorResponse> {
|
) -> RouterResult<oss_api_types::MerchantConnectorResponse> {
|
||||||
@ -159,13 +159,9 @@ pub async fn update_mca(
|
|||||||
connector_webhook_details: None,
|
connector_webhook_details: None,
|
||||||
pm_auth_config: None,
|
pm_auth_config: None,
|
||||||
};
|
};
|
||||||
let mca_response = admin::update_payment_connector(
|
let mca_response =
|
||||||
state.clone(),
|
admin::update_payment_connector(state.clone(), &merchant_id, &connector_id, request)
|
||||||
&merchant_account.merchant_id,
|
.await?;
|
||||||
&connector_id,
|
|
||||||
request,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
match mca_response {
|
match mca_response {
|
||||||
ApplicationResponse::Json(mca_data) => Ok(mca_data),
|
ApplicationResponse::Json(mca_data) => Ok(mca_data),
|
||||||
|
|||||||
@ -961,5 +961,6 @@ impl ConnectorOnboarding {
|
|||||||
.app_data(web::Data::new(state))
|
.app_data(web::Data::new(state))
|
||||||
.service(web::resource("/action_url").route(web::post().to(get_action_url)))
|
.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("/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,
|
state,
|
||||||
&http_req,
|
&http_req,
|
||||||
req_payload.clone(),
|
req_payload.clone(),
|
||||||
|state, _: auth::UserFromToken, req| core::get_action_url(state, req),
|
core::get_action_url,
|
||||||
&auth::JWTAuth(Permission::MerchantAccountWrite),
|
&auth::JWTAuth(Permission::MerchantAccountWrite),
|
||||||
api_locking::LockAction::NotApplicable,
|
api_locking::LockAction::NotApplicable,
|
||||||
))
|
))
|
||||||
@ -45,3 +45,22 @@ pub async fn sync_onboarding_status(
|
|||||||
))
|
))
|
||||||
.await
|
.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
|
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::{
|
use crate::{
|
||||||
|
consts,
|
||||||
core::errors::{api_error_response::NotImplementedMessage, ApiErrorResponse, RouterResult},
|
core::errors::{api_error_response::NotImplementedMessage, ApiErrorResponse, RouterResult},
|
||||||
routes::app::settings,
|
routes::{app::settings, AppState},
|
||||||
types::{self, api::enums},
|
types::{self, api::enums},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -34,3 +39,105 @@ pub fn is_enabled(
|
|||||||
_ => None,
|
_ => 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,
|
GetActionUrl,
|
||||||
/// Sync connector onboarding status
|
/// Sync connector onboarding status
|
||||||
SyncOnboardingStatus,
|
SyncOnboardingStatus,
|
||||||
|
/// Reset tracking id
|
||||||
|
ResetTrackingId,
|
||||||
/// Verify email Token
|
/// Verify email Token
|
||||||
VerifyEmail,
|
VerifyEmail,
|
||||||
/// Send verify email
|
/// Send verify email
|
||||||
|
|||||||
Reference in New Issue
Block a user