mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-10-31 18:17:13 +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,12 +159,8 @@ 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, |  | ||||||
|         &connector_id, |  | ||||||
|         request, |  | ||||||
|     ) |  | ||||||
|             .await?; |             .await?; | ||||||
|  |  | ||||||
|     match mca_response { |     match mca_response { | ||||||
|  | |||||||
| @ -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
	 Mani Chandra
					Mani Chandra