diff --git a/crates/router/src/connector/bluesnap.rs b/crates/router/src/connector/bluesnap.rs index 60a9025ef0..ba6e660185 100644 --- a/crates/router/src/connector/bluesnap.rs +++ b/crates/router/src/connector/bluesnap.rs @@ -152,6 +152,26 @@ impl ConnectorValidation for Bluesnap { ), } } + + fn validate_psync_reference_id( + &self, + data: &types::PaymentsSyncRouterData, + ) -> CustomResult<(), errors::ConnectorError> { + // if connector_transaction_id is present, psync can be made + if data + .request + .connector_transaction_id + .get_connector_transaction_id() + .is_ok() + { + return Ok(()); + } + // if merchant_id is present, psync can be made along with attempt_id + let meta_data: CustomResult = + connector_utils::to_connector_meta_from_secret(data.connector_meta_data.clone()); + + meta_data.map(|_| ()) + } } impl api::Payment for Bluesnap {} @@ -379,17 +399,22 @@ impl ConnectorIntegration CustomResult { - let connector_payment_id = req - .request - .connector_transaction_id - .get_connector_transaction_id() - .change_context(errors::ConnectorError::MissingConnectorTransactionID)?; - Ok(format!( - "{}{}{}", - self.base_url(connectors), - "services/2/transactions/", - connector_payment_id - )) + let meta_data: CustomResult = + connector_utils::to_connector_meta_from_secret(req.connector_meta_data.clone()); + + match meta_data { + // if merchant_id is present, psync can be made using merchant_transaction_id + Ok(data) => get_url_with_merchant_transaction_id( + self.base_url(connectors).to_string(), + data.merchant_id, + req.attempt_id.to_owned(), + ), + // otherwise psync is made using connector_transaction_id + Err(_) => get_psync_url_with_connector_transaction_id( + &req.request.connector_transaction_id, + self.base_url(connectors).to_string(), + ), + } } fn build_request( @@ -919,12 +944,22 @@ impl ConnectorIntegration CustomResult { - Ok(format!( - "{}{}{}", - self.base_url(connectors), - "services/2/transactions/", - req.request.get_connector_refund_id()? - )) + let meta_data: CustomResult = + connector_utils::to_connector_meta_from_secret(req.connector_meta_data.clone()); + + match meta_data { + // if merchant_id is present, rsync can be made using merchant_transaction_id + Ok(data) => get_url_with_merchant_transaction_id( + self.base_url(connectors).to_string(), + data.merchant_id, + req.attempt_id.to_owned(), + ), + // otherwise rsync is made using connector_transaction_id + Err(_) => get_rsync_url_with_connector_transaction_id( + req, + self.base_url(connectors).to_string(), + ), + } } fn build_request( @@ -1241,3 +1276,39 @@ impl ConnectorErrorTypeMapping for Bluesnap { } } } + +fn get_url_with_merchant_transaction_id( + base_url: String, + merchant_id: String, + merchant_transaction_id: String, +) -> CustomResult { + Ok(format!( + "{}{}{},{}", + base_url, "services/2/transactions/", merchant_transaction_id, merchant_id + )) +} + +fn get_psync_url_with_connector_transaction_id( + connector_transaction_id: &types::ResponseId, + base_url: String, +) -> CustomResult { + let connector_transaction_id = connector_transaction_id + .get_connector_transaction_id() + .change_context(errors::ConnectorError::MissingConnectorTransactionID)?; + Ok(format!( + "{}{}{}", + base_url, "services/2/transactions/", connector_transaction_id + )) +} + +fn get_rsync_url_with_connector_transaction_id( + req: &types::RefundSyncRouterData, + base_url: String, +) -> CustomResult { + Ok(format!( + "{}{}{}", + base_url, + "services/2/transactions/", + req.request.get_connector_refund_id()? + )) +} diff --git a/crates/router/src/connector/bluesnap/transformers.rs b/crates/router/src/connector/bluesnap/transformers.rs index a1e494d4b5..67117f06dc 100644 --- a/crates/router/src/connector/bluesnap/transformers.rs +++ b/crates/router/src/connector/bluesnap/transformers.rs @@ -156,6 +156,11 @@ pub struct ApplepayHeader { transaction_id: Secret, } +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct BluesnapConnectorMetaData { + pub merchant_id: String, +} + impl TryFrom<&types::PaymentsAuthorizeRouterData> for BluesnapPaymentsRequest { type Error = error_stack::Report; fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result { diff --git a/crates/router/src/connector/wise.rs b/crates/router/src/connector/wise.rs index b0eee83484..e64e95ed90 100644 --- a/crates/router/src/connector/wise.rs +++ b/crates/router/src/connector/wise.rs @@ -15,6 +15,7 @@ use crate::{ services::{ self, request::{self, Mask}, + ConnectorValidation, }, types::{ self, @@ -121,6 +122,7 @@ impl api::PaymentCapture for Wise {} impl api::PreVerify for Wise {} impl api::ConnectorAccessToken for Wise {} impl api::PaymentToken for Wise {} +impl ConnectorValidation for Wise {} impl services::ConnectorIntegration< diff --git a/crates/router/src/core/payments/flows/psync_flow.rs b/crates/router/src/core/payments/flows/psync_flow.rs index e1646502fc..f72cf897e0 100644 --- a/crates/router/src/core/payments/flows/psync_flow.rs +++ b/crates/router/src/core/payments/flows/psync_flow.rs @@ -113,6 +113,14 @@ impl Feature connector: &api::ConnectorData, call_connector_action: payments::CallConnectorAction, ) -> RouterResult<(Option, bool)> { + if connector + .connector + .validate_psync_reference_id(self) + .is_err() + { + return Ok((None, false)); + } + let request = match call_connector_action { payments::CallConnectorAction::Trigger => { let connector_integration: services::BoxedConnectorIntegration< diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index efea54d0af..d63551bdbf 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1641,10 +1641,7 @@ pub fn validate_payment_method_type_against_payment_method( } } -pub fn check_force_psync_precondition( - status: &storage_enums::AttemptStatus, - connector_transaction_id: &Option, -) -> bool { +pub fn check_force_psync_precondition(status: &storage_enums::AttemptStatus) -> bool { !matches!( status, storage_enums::AttemptStatus::Charged @@ -1653,7 +1650,7 @@ pub fn check_force_psync_precondition( | storage_enums::AttemptStatus::CodInitiated | storage_enums::AttemptStatus::Started | storage_enums::AttemptStatus::Failure - ) && connector_transaction_id.is_some() + ) } pub fn append_option(func: F, option1: Option, option2: Option) -> Option diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs index 6f9f4f470e..044268ea0a 100644 --- a/crates/router/src/core/payments/operations/payment_status.rs +++ b/crates/router/src/core/payments/operations/payment_status.rs @@ -377,10 +377,8 @@ async fn get_tracker_for_sync< payment_method_data: None, force_sync: Some( request.force_sync - && (helpers::check_force_psync_precondition( - &payment_attempt.status, - &payment_attempt.connector_transaction_id, - ) || contains_encoded_data), + && (helpers::check_force_psync_precondition(&payment_attempt.status) + || contains_encoded_data), ), payment_attempt, refunds, diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 3a26b8ee65..3d2a1781f3 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -76,19 +76,24 @@ where .or(payment_data.payment_attempt.payment_method) .get_required_value("payment_method_type")?; - // [#44]: why should response be filled during request - let response = payment_data + let resource_id = match payment_data .payment_attempt .connector_transaction_id - .as_ref() - .map(|id| types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId(id.to_string()), - redirection_data: None, - mandate_reference: None, - connector_metadata: None, - network_txn_id: None, - connector_response_reference_id: None, - }); + .clone() + { + Some(id) => types::ResponseId::ConnectorTransactionId(id), + None => types::ResponseId::NoResponseId, + }; + + // [#44]: why should response be filled during request + let response = Ok(types::PaymentsResponseData::TransactionResponse { + resource_id, + redirection_data: None, + mandate_reference: None, + connector_metadata: None, + network_txn_id: None, + connector_response_reference_id: None, + }); let additional_data = PaymentAdditionalData { router_base_url: state.conf.server.base_url.clone(), @@ -142,7 +147,7 @@ where .unwrap_or_default(), connector_meta_data: merchant_connector_account.get_metadata(), request: T::try_from(additional_data)?, - response: response.map_or_else(|| Err(types::ErrorResponse::default()), Ok), + response, amount_captured: payment_data.payment_intent.amount_captured, access_token: None, session_token: None, diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index 68f5a8419f..aad24b232e 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -74,6 +74,17 @@ pub trait ConnectorValidation: ConnectorCommon { } } } + + fn validate_psync_reference_id( + &self, + data: &types::PaymentsSyncRouterData, + ) -> CustomResult<(), errors::ConnectorError> { + data.request + .connector_transaction_id + .get_connector_transaction_id() + .change_context(errors::ConnectorError::MissingConnectorTransactionID) + .map(|_| ()) + } } #[async_trait::async_trait] diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 546bc3efe6..52882a5d9b 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -26,7 +26,7 @@ use crate::{ configs::settings::Connectors, connector, consts, core::errors::{self, CustomResult}, - services::{request, ConnectorIntegration, ConnectorRedirectResponse}, + services::{request, ConnectorIntegration, ConnectorRedirectResponse, ConnectorValidation}, types::{self, api::enums as api_enums}, }; diff --git a/crates/router/src/types/api/payments.rs b/crates/router/src/types/api/payments.rs index b3448cca2d..935cf76a13 100644 --- a/crates/router/src/types/api/payments.rs +++ b/crates/router/src/types/api/payments.rs @@ -211,6 +211,7 @@ pub trait PaymentsPreProcessing: pub trait Payment: api_types::ConnectorCommon + + api_types::ConnectorValidation + PaymentAuthorize + PaymentsCompleteAuthorize + PaymentSync