fix(connector): [NMI] Handle empty response in psync and error response in complete authorize (#3548)

This commit is contained in:
Prasunna Soppa
2024-02-05 17:51:00 +05:30
committed by GitHub
parent a9c0d0c554
commit a0fcef3f04
2 changed files with 55 additions and 50 deletions

View File

@ -2,7 +2,7 @@ use api_models::webhooks;
use cards::CardNumber; use cards::CardNumber;
use common_utils::{errors::CustomResult, ext_traits::XmlExt}; use common_utils::{errors::CustomResult, ext_traits::XmlExt};
use error_stack::{IntoReport, Report, ResultExt}; use error_stack::{IntoReport, Report, ResultExt};
use masking::{ExposeInterface, Secret}; use masking::{ExposeInterface, PeekInterface, Secret};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
@ -141,7 +141,7 @@ fn get_card_details(
pub struct NmiVaultResponse { pub struct NmiVaultResponse {
pub response: Response, pub response: Response,
pub responsetext: String, pub responsetext: String,
pub customer_vault_id: Option<String>, pub customer_vault_id: Option<Secret<String>>,
pub response_code: String, pub response_code: String,
pub transactionid: String, pub transactionid: String,
} }
@ -191,11 +191,14 @@ impl
)? )?
.to_string(), .to_string(),
currency: currency_data, currency: currency_data,
customer_vault_id: item.response.customer_vault_id.ok_or( customer_vault_id: item
errors::ConnectorError::MissingRequiredField { .response
.customer_vault_id
.ok_or(errors::ConnectorError::MissingRequiredField {
field_name: "customer_vault_id", field_name: "customer_vault_id",
}, })?
)?, .peek()
.to_string(),
public_key: auth_type.public_key.ok_or( public_key: auth_type.public_key.ok_or(
errors::ConnectorError::InvalidConnectorConfig { errors::ConnectorError::InvalidConnectorConfig {
config: "public_key", config: "public_key",
@ -237,40 +240,27 @@ pub struct NmiCompleteRequest {
#[serde(rename = "type")] #[serde(rename = "type")]
transaction_type: TransactionType, transaction_type: TransactionType,
security_key: Secret<String>, security_key: Secret<String>,
orderid: String, orderid: Option<String>,
ccnumber: CardNumber, ccnumber: CardNumber,
ccexp: Secret<String>, ccexp: Secret<String>,
cardholder_auth: CardHolderAuthType, cardholder_auth: Option<String>,
cavv: String, cavv: Option<String>,
xid: String, xid: Option<String>,
three_ds_version: Option<ThreeDsVersion>, eci: Option<String>,
} three_ds_version: Option<String>,
directory_server_id: Option<String>,
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum CardHolderAuthType {
Verified,
Attempted,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum ThreeDsVersion {
#[serde(rename = "2.0.0")]
VersionTwo,
#[serde(rename = "2.1.0")]
VersionTwoPointOne,
#[serde(rename = "2.2.0")]
VersionTwoPointTwo,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct NmiRedirectResponseData { pub struct NmiRedirectResponseData {
cavv: String, cavv: Option<String>,
xid: String, xid: Option<String>,
card_holder_auth: CardHolderAuthType, eci: Option<String>,
three_ds_version: Option<ThreeDsVersion>, card_holder_auth: Option<String>,
order_id: String, three_ds_version: Option<String>,
order_id: Option<String>,
directory_server_id: Option<String>,
} }
impl TryFrom<&NmiRouterData<&types::PaymentsCompleteAuthorizeRouterData>> for NmiCompleteRequest { impl TryFrom<&NmiRouterData<&types::PaymentsCompleteAuthorizeRouterData>> for NmiCompleteRequest {
@ -308,7 +298,9 @@ impl TryFrom<&NmiRouterData<&types::PaymentsCompleteAuthorizeRouterData>> for Nm
cardholder_auth: three_ds_data.card_holder_auth, cardholder_auth: three_ds_data.card_holder_auth,
cavv: three_ds_data.cavv, cavv: three_ds_data.cavv,
xid: three_ds_data.xid, xid: three_ds_data.xid,
eci: three_ds_data.eci,
three_ds_version: three_ds_data.three_ds_version, three_ds_version: three_ds_data.three_ds_version,
directory_server_id: three_ds_data.directory_server_id,
}) })
} }
} }
@ -881,21 +873,22 @@ impl TryFrom<types::PaymentsSyncResponseRouterData<types::Response>>
item: types::PaymentsSyncResponseRouterData<types::Response>, item: types::PaymentsSyncResponseRouterData<types::Response>,
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
let response = SyncResponse::try_from(item.response.response.to_vec())?; let response = SyncResponse::try_from(item.response.response.to_vec())?;
Ok(Self { match response.transaction {
status: enums::AttemptStatus::from(NmiStatus::from(response.transaction.condition)), Some(trn) => Ok(Self {
response: Ok(types::PaymentsResponseData::TransactionResponse { status: enums::AttemptStatus::from(NmiStatus::from(trn.condition)),
resource_id: types::ResponseId::ConnectorTransactionId( response: Ok(types::PaymentsResponseData::TransactionResponse {
response.transaction.transaction_id, resource_id: types::ResponseId::ConnectorTransactionId(trn.transaction_id),
), redirection_data: None,
redirection_data: None, mandate_reference: None,
mandate_reference: None, connector_metadata: None,
connector_metadata: None, network_txn_id: None,
network_txn_id: None, connector_response_reference_id: None,
connector_response_reference_id: None, incremental_authorization_allowed: None,
incremental_authorization_allowed: None, }),
..item.data
}), }),
..item.data None => Ok(Self { ..item.data }), //when there is empty connector response i.e. response we get in psync when payment status is in authentication_pending
}) }
} }
} }
@ -1081,7 +1074,7 @@ pub struct SyncTransactionResponse {
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub struct SyncResponse { pub struct SyncResponse {
pub transaction: SyncTransactionResponse, pub transaction: Option<SyncTransactionResponse>,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
@ -1199,10 +1192,10 @@ pub struct NmiWebhookObject {
impl TryFrom<&NmiWebhookBody> for SyncResponse { impl TryFrom<&NmiWebhookBody> for SyncResponse {
type Error = Error; type Error = Error;
fn try_from(item: &NmiWebhookBody) -> Result<Self, Self::Error> { fn try_from(item: &NmiWebhookBody) -> Result<Self, Self::Error> {
let transaction = SyncTransactionResponse { let transaction = Some(SyncTransactionResponse {
transaction_id: item.event_body.transaction_id.to_owned(), transaction_id: item.event_body.transaction_id.to_owned(),
condition: item.event_body.condition.to_owned(), condition: item.event_body.condition.to_owned(),
}; });
Ok(Self { transaction }) Ok(Self { transaction })
} }

View File

@ -1715,6 +1715,18 @@ pub fn build_redirection_form(
item2.value=e.xid; item2.value=e.xid;
responseForm.appendChild(item2); responseForm.appendChild(item2);
var item6=document.createElement('input');
item6.type='hidden';
item6.name='eci';
item6.value=e.eci;
responseForm.appendChild(item6);
var item7=document.createElement('input');
item7.type='hidden';
item7.name='directoryServerId';
item7.value=e.directoryServerId;
responseForm.appendChild(item7);
var item3=document.createElement('input'); var item3=document.createElement('input');
item3.type='hidden'; item3.type='hidden';
item3.name='cardHolderAuth'; item3.name='cardHolderAuth';