Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(connectors): fiuu,novalnet,worldpay - extend NTI flows #6946

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,7 @@ check_token_status_url= "" # base url to check token status from token servic
connector_list = "cybersource" # Supported connectors for network tokenization

[network_transaction_id_supported_connectors]
connector_list = "stripe,adyen,cybersource" # Supported connectors for network transaction id
connector_list = "adyen,cybersource,fiuu,novalnet,stripe,worldpay" # Supported connectors for network transaction id

[grpc_client.dynamic_routing_client] # Dynamic Routing Client Configuration
host = "localhost" # Client Host
Expand Down
2 changes: 1 addition & 1 deletion config/deployments/integration_test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ card.credit = { connector_list = "cybersource" } # Update Mandate sup
card.debit = { connector_list = "cybersource" } # Update Mandate supported payment method type and connector for card

[network_transaction_id_supported_connectors]
connector_list = "stripe,adyen,cybersource"
connector_list = "adyen,cybersource,fiuu,novalnet,stripe,worldpay"


[payouts]
Expand Down
2 changes: 1 addition & 1 deletion config/deployments/sandbox.toml
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ card.credit = { connector_list = "cybersource" } # Update Mandate sup
card.debit = { connector_list = "cybersource" } # Update Mandate supported payment method type and connector for card

[network_transaction_id_supported_connectors]
connector_list = "stripe,adyen,cybersource"
connector_list = "adyen,cybersource,fiuu,novalnet,stripe,worldpay"


[payouts]
Expand Down
2 changes: 1 addition & 1 deletion config/development.toml
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ card.credit = { connector_list = "cybersource" }
card.debit = { connector_list = "cybersource" }

[network_transaction_id_supported_connectors]
connector_list = "stripe,adyen,cybersource"
connector_list = "adyen,cybersource,fiuu,novalnet,stripe,worldpay"

[connector_request_reference_id_config]
merchant_ids_send_payment_id_as_connector_request_id = []
Expand Down
2 changes: 1 addition & 1 deletion config/docker_compose.toml
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ card.credit = { connector_list = "cybersource" }
card.debit = { connector_list = "cybersource" }

[network_transaction_id_supported_connectors]
connector_list = "stripe,adyen,cybersource"
connector_list = "adyen,cybersource,fiuu,novalnet,stripe,worldpay"

[connector_customer]
connector_list = "gocardless,stax,stripe"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,8 @@ pub struct FiuuPaymentSyncResponse {
error_desc: String,
#[serde(rename = "miscellaneous")]
miscellaneous: Option<HashMap<String, Secret<String>>>,
#[serde(rename = "SchemeTransactionID")]
scheme_transaction_id: Option<Secret<String>>,
}

#[derive(Debug, Serialize, Deserialize, Display, Clone, PartialEq)]
Expand Down Expand Up @@ -1182,7 +1184,10 @@ impl TryFrom<PaymentsSyncResponseRouterData<FiuuPaymentResponse>> for PaymentsSy
redirection_data: Box::new(None),
mandate_reference: Box::new(None),
connector_metadata: None,
network_txn_id: None,
network_txn_id: response
.scheme_transaction_id
.as_ref()
.map(|id| id.clone().expose()),
connector_response_reference_id: None,
incremental_authorization_allowed: None,
charge_id: None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ pub struct NovalnetCard {
card_holder: Secret<String>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct NovalnetRawCardDetails {
card_number: CardNumber,
card_expiry_month: Secret<String>,
card_expiry_year: Secret<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct NovalnetMandate {
token: Secret<String>,
Expand All @@ -107,6 +114,7 @@ pub struct NovalnetApplePay {
#[serde(untagged)]
pub enum NovalNetPaymentData {
Card(NovalnetCard),
RawCardForNTI(NovalnetRawCardDetails),
GooglePay(NovalnetGooglePay),
ApplePay(NovalnetApplePay),
MandatePayment(NovalnetMandate),
Expand All @@ -130,6 +138,7 @@ pub struct NovalnetPaymentsRequestTransaction {
error_return_url: Option<String>,
enforce_3d: Option<i8>, //NOTE: Needed for CREDITCARD, GOOGLEPAY
create_token: Option<i8>,
scheme_tid: Option<Secret<String>>, // Card network's transaction ID
}

#[derive(Debug, Serialize, Clone)]
Expand Down Expand Up @@ -243,6 +252,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
payment_data: Some(novalnet_card),
enforce_3d,
create_token,
scheme_tid: None,
};

Ok(Self {
Expand Down Expand Up @@ -274,6 +284,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
payment_data: Some(novalnet_google_pay),
enforce_3d,
create_token,
scheme_tid: None,
};

Ok(Self {
Expand All @@ -299,6 +310,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
})),
enforce_3d: None,
create_token,
scheme_tid: None,
};

Ok(Self {
Expand Down Expand Up @@ -340,6 +352,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
payment_data: None,
enforce_3d: None,
create_token,
scheme_tid: None,
};
Ok(Self {
merchant,
Expand Down Expand Up @@ -398,6 +411,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
payment_data: Some(novalnet_mandate_data),
enforce_3d,
create_token: None,
scheme_tid: None,
};

Ok(Self {
Expand All @@ -407,6 +421,44 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
custom,
})
}
Some(api_models::payments::MandateReferenceId::NetworkMandateId(
network_transaction_id,
)) => match item.router_data.request.payment_method_data {
PaymentMethodData::CardDetailsForNetworkTransactionId(ref raw_card_details) => {
let novalnet_card =
NovalNetPaymentData::RawCardForNTI(NovalnetRawCardDetails {
card_number: raw_card_details.card_number.clone(),
card_expiry_month: raw_card_details.card_exp_month.clone(),
card_expiry_year: raw_card_details.card_exp_year.clone(),
});

let transaction = NovalnetPaymentsRequestTransaction {
test_mode,
payment_type: NovalNetPaymentTypes::CREDITCARD,
amount: item.amount.clone(),
currency: item.router_data.request.currency,
order_no: item.router_data.connector_request_reference_id.clone(),
hook_url: Some(hook_url),
return_url: Some(return_url.clone()),
error_return_url: Some(return_url.clone()),
payment_data: Some(novalnet_card),
enforce_3d,
create_token,
scheme_tid: Some(network_transaction_id.into()),
};

Ok(Self {
merchant,
transaction,
customer,
custom,
})
}
_ => Err(errors::ConnectorError::NotImplemented(
utils::get_unimplemented_payment_method_error_message("novalnet"),
)
.into()),
},
_ => Err(errors::ConnectorError::NotImplemented(
utils::get_unimplemented_payment_method_error_message("novalnet"),
)
Expand Down
36 changes: 36 additions & 0 deletions crates/hyperswitch_connectors/src/connectors/worldpay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1199,6 +1199,42 @@ impl IncomingWebhook for Worldpay {
let psync_body = WorldpayEventResponse::try_from(body)?;
Ok(Box::new(psync_body))
}

fn get_mandate_details(
&self,
request: &IncomingWebhookRequestDetails<'_>,
) -> CustomResult<
Option<hyperswitch_domain_models::router_flow_types::ConnectorMandateDetails>,
errors::ConnectorError,
> {
let body: WorldpayWebhookTransactionId = request
.body
.parse_struct("WorldpayWebhookTransactionId")
.change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
let mandate_reference = body.event_details.token.map(|mandate_token| {
hyperswitch_domain_models::router_flow_types::ConnectorMandateDetails {
connector_mandate_id: mandate_token.href,
}
});
Ok(mandate_reference)
}

fn get_network_txn_id(
&self,
request: &IncomingWebhookRequestDetails<'_>,
) -> CustomResult<
Option<hyperswitch_domain_models::router_flow_types::ConnectorNetworkTxnId>,
errors::ConnectorError,
> {
let body: WorldpayWebhookTransactionId = request
.body
.parse_struct("WorldpayWebhookTransactionId")
.change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
let optional_network_txn_id = body.event_details.scheme_reference.map(|network_txn_id| {
hyperswitch_domain_models::router_flow_types::ConnectorNetworkTxnId::new(network_txn_id)
});
Ok(optional_network_txn_id)
}
}

impl ConnectorRedirectResponse for Worldpay {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,22 @@ pub enum TokenCreationType {
Worldpay,
}

#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CustomerAgreement {
#[serde(rename = "type")]
pub agreement_type: CustomerAgreementType,
pub stored_card_usage: StoredCardUsageType,
pub stored_card_usage: Option<StoredCardUsageType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub scheme_reference: Option<Secret<String>>,
}

#[derive(Clone, Debug, PartialEq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum CustomerAgreementType {
Subscription,
Unscheduled,
}

#[derive(Clone, Debug, PartialEq, Serialize)]
Expand All @@ -78,22 +82,30 @@ pub enum StoredCardUsageType {
pub enum PaymentInstrument {
Card(CardPayment),
CardToken(CardToken),
RawCardForNTI(RawCardDetails),
Googlepay(WalletPayment),
Applepay(WalletPayment),
}

#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CardPayment {
#[serde(rename = "type")]
pub payment_type: PaymentType,
#[serde(flatten)]
pub raw_card_details: RawCardDetails,
pub cvc: Secret<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub card_holder_name: Option<Secret<String>>,
pub card_number: cards::CardNumber,
pub expiry_date: ExpiryDate,
#[serde(skip_serializing_if = "Option::is_none")]
pub billing_address: Option<BillingAddress>,
pub cvc: Secret<String>,
}

#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RawCardDetails {
#[serde(rename = "type")]
pub payment_type: PaymentType,
pub card_number: cards::CardNumber,
pub expiry_date: ExpiryDate,
}

#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ pub struct AuthorizedResponse {
pub fraud: Option<Fraud>,
/// Mandate's token
pub token: Option<MandateToken>,
/// Network transaction ID
pub scheme_reference: Option<Secret<String>>,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
Expand Down Expand Up @@ -429,9 +431,13 @@ pub struct WorldpayWebhookTransactionId {
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EventDetails {
pub transaction_reference: String,
#[serde(rename = "type")]
pub event_type: EventType,
pub transaction_reference: String,
/// Mandate's token
pub token: Option<MandateToken>,
/// Network transaction ID
pub scheme_reference: Option<Secret<String>>,
}

#[derive(Debug, Serialize, Deserialize)]
Expand Down
Loading
Loading