mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 12:06:56 +08:00
feat(core): Connector specific validation for Payment Sync (#2005)
This commit is contained in:
@ -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<bluesnap::BluesnapConnectorMetaData, errors::ConnectorError> =
|
||||
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<api::PSync, types::PaymentsSyncData, types::PaymentsRe
|
||||
req: &types::PaymentsSyncRouterData,
|
||||
connectors: &settings::Connectors,
|
||||
) -> CustomResult<String, errors::ConnectorError> {
|
||||
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<bluesnap::BluesnapConnectorMetaData, errors::ConnectorError> =
|
||||
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<api::RSync, types::RefundsData, types::RefundsResponse
|
||||
req: &types::RefundSyncRouterData,
|
||||
connectors: &settings::Connectors,
|
||||
) -> CustomResult<String, errors::ConnectorError> {
|
||||
Ok(format!(
|
||||
"{}{}{}",
|
||||
self.base_url(connectors),
|
||||
"services/2/transactions/",
|
||||
req.request.get_connector_refund_id()?
|
||||
))
|
||||
let meta_data: CustomResult<bluesnap::BluesnapConnectorMetaData, errors::ConnectorError> =
|
||||
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<String, errors::ConnectorError> {
|
||||
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<String, errors::ConnectorError> {
|
||||
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<String, errors::ConnectorError> {
|
||||
Ok(format!(
|
||||
"{}{}{}",
|
||||
base_url,
|
||||
"services/2/transactions/",
|
||||
req.request.get_connector_refund_id()?
|
||||
))
|
||||
}
|
||||
|
||||
@ -156,6 +156,11 @@ pub struct ApplepayHeader {
|
||||
transaction_id: Secret<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct BluesnapConnectorMetaData {
|
||||
pub merchant_id: String,
|
||||
}
|
||||
|
||||
impl TryFrom<&types::PaymentsAuthorizeRouterData> for BluesnapPaymentsRequest {
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
|
||||
|
||||
@ -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<
|
||||
|
||||
@ -113,6 +113,14 @@ impl Feature<api::PSync, types::PaymentsSyncData>
|
||||
connector: &api::ConnectorData,
|
||||
call_connector_action: payments::CallConnectorAction,
|
||||
) -> RouterResult<(Option<services::Request>, 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<
|
||||
|
||||
@ -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<String>,
|
||||
) -> 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<T, U, F, V>(func: F, option1: Option<T>, option2: Option<U>) -> Option<V>
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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},
|
||||
};
|
||||
|
||||
|
||||
@ -211,6 +211,7 @@ pub trait PaymentsPreProcessing:
|
||||
|
||||
pub trait Payment:
|
||||
api_types::ConnectorCommon
|
||||
+ api_types::ConnectorValidation
|
||||
+ PaymentAuthorize
|
||||
+ PaymentsCompleteAuthorize
|
||||
+ PaymentSync
|
||||
|
||||
Reference in New Issue
Block a user