feat(core): Connector specific validation for Payment Sync (#2005)

This commit is contained in:
Sakil Mostak
2023-08-31 12:46:09 +05:30
committed by GitHub
parent eeee0ed5dc
commit 098dc89d0c
10 changed files with 137 additions and 39 deletions

View File

@ -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()?
))
}

View File

@ -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> {

View File

@ -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<

View File

@ -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<

View File

@ -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>

View File

@ -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,

View File

@ -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,

View File

@ -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]

View File

@ -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},
};

View File

@ -211,6 +211,7 @@ pub trait PaymentsPreProcessing:
pub trait Payment:
api_types::ConnectorCommon
+ api_types::ConnectorValidation
+ PaymentAuthorize
+ PaymentsCompleteAuthorize
+ PaymentSync