refactor(connector): [NMI] Include mandatory fields for card 3DS (#3203)

This commit is contained in:
Sakil Mostak
2023-12-26 17:36:33 +05:30
committed by GitHub
parent c7e15aee9d
commit a46b8a7b05
6 changed files with 80 additions and 7 deletions

View File

@ -357,6 +357,7 @@ stripe = { payment_method = "bank_transfer" }
nuvei = { payment_method = "card" } nuvei = { payment_method = "card" }
shift4 = { payment_method = "card" } shift4 = { payment_method = "card" }
bluesnap = { payment_method = "card" } bluesnap = { payment_method = "card" }
nmi = {payment_method = "card"}
[dummy_connector] [dummy_connector]
enabled = true # Whether dummy connector is enabled or not enabled = true # Whether dummy connector is enabled or not

View File

@ -434,6 +434,7 @@ stripe = {payment_method = "bank_transfer"}
nuvei = {payment_method = "card"} nuvei = {payment_method = "card"}
shift4 = {payment_method = "card"} shift4 = {payment_method = "card"}
bluesnap = {payment_method = "card"} bluesnap = {payment_method = "card"}
nmi = {payment_method = "card"}
[connector_customer] [connector_customer]
connector_list = "gocardless,stax,stripe" connector_list = "gocardless,stax,stripe"

View File

@ -247,6 +247,7 @@ stripe = {payment_method = "bank_transfer"}
nuvei = {payment_method = "card"} nuvei = {payment_method = "card"}
shift4 = {payment_method = "card"} shift4 = {payment_method = "card"}
bluesnap = {payment_method = "card"} bluesnap = {payment_method = "card"}
nmi = {payment_method = "card"}
[dummy_connector] [dummy_connector]
enabled = true enabled = true

View File

@ -1450,7 +1450,25 @@ impl Default for super::settings::RequiredFields {
field_type: enums::FieldType::UserCardCvc, field_type: enums::FieldType::UserCardCvc,
value: None, value: None,
} }
) ),
(
"billing.address.first_name".to_string(),
RequiredFieldInfo {
required_field: "billing.address.first_name".to_string(),
display_name: "billing_first_name".to_string(),
field_type: enums::FieldType::UserBillingName,
value: None,
}
),
(
"billing.address.last_name".to_string(),
RequiredFieldInfo {
required_field: "billing.address.last_name".to_string(),
display_name: "billing_last_name".to_string(),
field_type: enums::FieldType::UserBillingName,
value: None,
}
),
] ]
), ),
common: HashMap::new(), common: HashMap::new(),
@ -3481,7 +3499,25 @@ impl Default for super::settings::RequiredFields {
field_type: enums::FieldType::UserCardCvc, field_type: enums::FieldType::UserCardCvc,
value: None, value: None,
} }
) ),
(
"billing.address.first_name".to_string(),
RequiredFieldInfo {
required_field: "billing.address.first_name".to_string(),
display_name: "billing_first_name".to_string(),
field_type: enums::FieldType::UserBillingName,
value: None,
}
),
(
"billing.address.last_name".to_string(),
RequiredFieldInfo {
required_field: "billing.address.last_name".to_string(),
display_name: "billing_last_name".to_string(),
field_type: enums::FieldType::UserBillingName,
value: None,
}
),
] ]
), ),
common: HashMap::new(), common: HashMap::new(),

View File

@ -6,7 +6,10 @@ use masking::{ExposeInterface, Secret};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
connector::utils::{self, PaymentsAuthorizeRequestData, PaymentsCompleteAuthorizeRequestData}, connector::utils::{
self, AddressDetailsData, PaymentsAuthorizeRequestData,
PaymentsCompleteAuthorizeRequestData, RouterData,
},
core::errors, core::errors,
services, services,
types::{self, api, storage::enums, transformers::ForeignFrom, ConnectorAuthType}, types::{self, api, storage::enums, transformers::ForeignFrom, ConnectorAuthType},
@ -83,6 +86,9 @@ pub struct NmiVaultRequest {
security_key: Secret<String>, security_key: Secret<String>,
ccnumber: CardNumber, ccnumber: CardNumber,
ccexp: Secret<String>, ccexp: Secret<String>,
cvv: Secret<String>,
first_name: Secret<String>,
last_name: Secret<String>,
customer_vault: CustomerAction, customer_vault: CustomerAction,
} }
@ -97,12 +103,16 @@ impl TryFrom<&types::PaymentsPreProcessingRouterData> for NmiVaultRequest {
type Error = Error; type Error = Error;
fn try_from(item: &types::PaymentsPreProcessingRouterData) -> Result<Self, Self::Error> { fn try_from(item: &types::PaymentsPreProcessingRouterData) -> Result<Self, Self::Error> {
let auth_type: NmiAuthType = (&item.connector_auth_type).try_into()?; let auth_type: NmiAuthType = (&item.connector_auth_type).try_into()?;
let (ccnumber, ccexp) = get_card_details(item.request.payment_method_data.clone())?; let (ccnumber, ccexp, cvv) = get_card_details(item.request.payment_method_data.clone())?;
let billing_details = item.get_billing_address()?;
Ok(Self { Ok(Self {
security_key: auth_type.api_key, security_key: auth_type.api_key,
ccnumber, ccnumber,
ccexp, ccexp,
cvv,
first_name: billing_details.get_first_name()?.to_owned(),
last_name: billing_details.get_last_name()?.to_owned(),
customer_vault: CustomerAction::AddCustomer, customer_vault: CustomerAction::AddCustomer,
}) })
} }
@ -110,7 +120,7 @@ impl TryFrom<&types::PaymentsPreProcessingRouterData> for NmiVaultRequest {
fn get_card_details( fn get_card_details(
payment_method_data: Option<api::PaymentMethodData>, payment_method_data: Option<api::PaymentMethodData>,
) -> CustomResult<(CardNumber, Secret<String>), errors::ConnectorError> { ) -> CustomResult<(CardNumber, Secret<String>, Secret<String>), errors::ConnectorError> {
match payment_method_data { match payment_method_data {
Some(api::PaymentMethodData::Card(ref card_details)) => Ok(( Some(api::PaymentMethodData::Card(ref card_details)) => Ok((
card_details.card_number.clone(), card_details.card_number.clone(),
@ -118,6 +128,7 @@ fn get_card_details(
card_details, card_details,
"".to_string(), "".to_string(),
), ),
card_details.card_cvc.clone(),
)), )),
_ => Err(errors::ConnectorError::NotImplemented( _ => Err(errors::ConnectorError::NotImplemented(
utils::get_unimplemented_payment_method_error_message("Nmi"), utils::get_unimplemented_payment_method_error_message("Nmi"),
@ -189,6 +200,7 @@ impl
config: "public_key", config: "public_key",
}, },
)?, )?,
order_id: item.data.connector_request_reference_id.clone(),
}), }),
mandate_reference: None, mandate_reference: None,
connector_metadata: None, connector_metadata: None,
@ -220,13 +232,17 @@ impl
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct NmiCompleteRequest { pub struct NmiCompleteRequest {
amount: f64,
#[serde(rename = "type")] #[serde(rename = "type")]
transaction_type: TransactionType, transaction_type: TransactionType,
security_key: Secret<String>, security_key: Secret<String>,
orderid: String,
ccnumber: CardNumber,
ccexp: Secret<String>,
cardholder_auth: CardHolderAuthType, cardholder_auth: CardHolderAuthType,
cavv: String, cavv: String,
xid: String, xid: String,
three_ds_version: ThreeDsVersion, three_ds_version: Option<ThreeDsVersion>,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
@ -240,6 +256,8 @@ pub enum CardHolderAuthType {
pub enum ThreeDsVersion { pub enum ThreeDsVersion {
#[serde(rename = "2.0.0")] #[serde(rename = "2.0.0")]
VersionTwo, VersionTwo,
#[serde(rename = "2.1.0")]
VersionTwoPointOne,
#[serde(rename = "2.2.0")] #[serde(rename = "2.2.0")]
VersionTwoPointTwo, VersionTwoPointTwo,
} }
@ -250,7 +268,8 @@ pub struct NmiRedirectResponseData {
cavv: String, cavv: String,
xid: String, xid: String,
card_holder_auth: CardHolderAuthType, card_holder_auth: CardHolderAuthType,
three_ds_version: ThreeDsVersion, three_ds_version: Option<ThreeDsVersion>,
order_id: String,
} }
impl TryFrom<&NmiRouterData<&types::PaymentsCompleteAuthorizeRouterData>> for NmiCompleteRequest { impl TryFrom<&NmiRouterData<&types::PaymentsCompleteAuthorizeRouterData>> for NmiCompleteRequest {
@ -275,9 +294,16 @@ impl TryFrom<&NmiRouterData<&types::PaymentsCompleteAuthorizeRouterData>> for Nm
field_name: "three_ds_data", field_name: "three_ds_data",
})?; })?;
let (ccnumber, ccexp, ..) =
get_card_details(item.router_data.request.payment_method_data.clone())?;
Ok(Self { Ok(Self {
amount: item.amount,
transaction_type, transaction_type,
security_key: auth_type.api_key, security_key: auth_type.api_key,
orderid: three_ds_data.order_id,
ccnumber,
ccexp,
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,

View File

@ -778,6 +778,7 @@ pub enum RedirectForm {
currency: Currency, currency: Currency,
public_key: Secret<String>, public_key: Secret<String>,
customer_vault_id: String, customer_vault_id: String,
order_id: String,
}, },
} }
@ -1507,6 +1508,7 @@ pub fn build_redirection_form(
currency, currency,
public_key, public_key,
customer_vault_id, customer_vault_id,
order_id,
} => { } => {
let public_key_val = public_key.peek(); let public_key_val = public_key.peek();
maud::html! { maud::html! {
@ -1563,6 +1565,12 @@ pub fn build_redirection_form(
item4.value=e.threeDsVersion; item4.value=e.threeDsVersion;
responseForm.appendChild(item4); responseForm.appendChild(item4);
var item5=document.createElement('input');
item4.type='hidden';
item4.name='orderId';
item4.value='{order_id}';
responseForm.appendChild(item5);
document.body.appendChild(responseForm); document.body.appendChild(responseForm);
responseForm.submit(); responseForm.submit();
}}); }});