Skip to content

Commit

Permalink
feat(router): [BOA] implement mandates for cards and wallets (#4232)
Browse files Browse the repository at this point in the history
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
  • Loading branch information
AkshayaFoiger and hyperswitch-bot[bot] authored Apr 2, 2024
1 parent 97fbc89 commit 2f304e6
Show file tree
Hide file tree
Showing 10 changed files with 986 additions and 299 deletions.
5 changes: 3 additions & 2 deletions config/config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -383,15 +383,16 @@ slack_invite_url = "https://www.example.com/" # Slack invite url for hyperswit
discord_invite_url = "https://www.example.com/" # Discord invite url for hyperswitch

[mandates.supported_payment_methods]
card.credit = { connector_list = "stripe,adyen,cybersource" } # Mandate supported payment method type and connector for card
card.credit = { connector_list = "stripe,adyen,cybersource,bankofamerica"} # Mandate supported payment method type and connector for card
wallet.paypal = { connector_list = "adyen" } # Mandate supported payment method type and connector for wallets
pay_later.klarna = { connector_list = "adyen" } # Mandate supported payment method type and connector for pay_later
bank_debit.ach = { connector_list = "gocardless" } # Mandate supported payment method type and connector for bank_debit
bank_debit.becs = { connector_list = "gocardless" } # Mandate supported payment method type and connector for bank_debit
bank_debit.sepa = { connector_list = "gocardless" } # Mandate supported payment method type and connector for bank_debit
bank_redirect.ideal = { connector_list = "stripe,adyen,globalpay" } # Mandate supported payment method type and connector for bank_redirect
bank_redirect.sofort = { connector_list = "stripe,adyen,globalpay" }
wallet.apple_pay = { connector_list = "stripe,adyen,cybersource,noon" }
wallet.apple_pay = { connector_list = "stripe,adyen,cybersource,noon,bankofamerica" }
wallet.google_pay = { connector_list = "bankofamerica"}
bank_redirect.giropay = { connector_list = "adyen,globalpay" }


Expand Down
8 changes: 4 additions & 4 deletions config/deployments/integration_test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,11 @@ connectors_with_delayed_session_response = "trustpay,payme"
bank_debit.ach.connector_list = "gocardless"
bank_debit.becs.connector_list = "gocardless"
bank_debit.sepa.connector_list = "gocardless"
card.credit.connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon"
card.debit.connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon"
card.credit.connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon,bankofamerica"
card.debit.connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon,bankofamerica"
pay_later.klarna.connector_list = "adyen"
wallet.apple_pay.connector_list = "stripe,adyen,cybersource,noon"
wallet.google_pay.connector_list = "stripe,adyen,cybersource"
wallet.apple_pay.connector_list = "stripe,adyen,cybersource,noon,bankofamerica"
wallet.google_pay.connector_list = "stripe,adyen,cybersource,bankofamerica"
wallet.paypal.connector_list = "adyen"
bank_redirect.ideal.connector_list = "stripe,adyen,globalpay"
bank_redirect.sofort.connector_list = "stripe,adyen,globalpay"
Expand Down
8 changes: 4 additions & 4 deletions config/deployments/production.toml
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,11 @@ enabled = false
bank_debit.ach.connector_list = "gocardless"
bank_debit.becs.connector_list = "gocardless"
bank_debit.sepa.connector_list = "gocardless"
card.credit.connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon"
card.debit.connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon"
card.credit.connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon,bankofamerica"
card.debit.connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon,bankofamerica"
pay_later.klarna.connector_list = "adyen"
wallet.apple_pay.connector_list = "stripe,adyen,cybersource,noon"
wallet.google_pay.connector_list = "stripe,adyen,cybersource"
wallet.apple_pay.connector_list = "stripe,adyen,cybersource,noon,bankofamerica"
wallet.google_pay.connector_list = "stripe,adyen,cybersource,bankofamerica"
wallet.paypal.connector_list = "adyen"
bank_redirect.ideal.connector_list = "stripe,adyen,globalpay"
bank_redirect.sofort.connector_list = "stripe,adyen,globalpay"
Expand Down
8 changes: 4 additions & 4 deletions config/deployments/sandbox.toml
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,11 @@ enabled = true
bank_debit.ach.connector_list = "gocardless"
bank_debit.becs.connector_list = "gocardless"
bank_debit.sepa.connector_list = "gocardless"
card.credit.connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon"
card.debit.connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon"
card.credit.connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon,bankofamerica"
card.debit.connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon,bankofamerica"
pay_later.klarna.connector_list = "adyen"
wallet.apple_pay.connector_list = "stripe,adyen,cybersource,noon"
wallet.google_pay.connector_list = "stripe,adyen,cybersource"
wallet.apple_pay.connector_list = "stripe,adyen,cybersource,noon,bankofamerica"
wallet.google_pay.connector_list = "stripe,adyen,cybersource,bankofamerica"
wallet.paypal.connector_list = "adyen"
bank_redirect.ideal.connector_list = "stripe,adyen,globalpay"
bank_redirect.sofort.connector_list = "stripe,adyen,globalpay"
Expand Down
8 changes: 4 additions & 4 deletions config/development.toml
Original file line number Diff line number Diff line change
Expand Up @@ -495,11 +495,11 @@ connectors_with_webhook_source_verification_call = "paypal"

[mandates.supported_payment_methods]
pay_later.klarna = { connector_list = "adyen" }
wallet.google_pay = { connector_list = "stripe,adyen,cybersource" }
wallet.apple_pay = { connector_list = "stripe,adyen,cybersource,noon" }
wallet.google_pay = { connector_list = "stripe,adyen,cybersource,bankofamerica" }
wallet.apple_pay = { connector_list = "stripe,adyen,cybersource,noon,bankofamerica" }
wallet.paypal = { connector_list = "adyen" }
card.credit = { connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon" }
card.debit = { connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon" }
card.credit = { connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon,bankofamerica" }
card.debit = { connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon,bankofamerica" }
bank_debit.ach = { connector_list = "gocardless" }
bank_debit.becs = { connector_list = "gocardless" }
bank_debit.sepa = { connector_list = "gocardless" }
Expand Down
8 changes: 4 additions & 4 deletions config/docker_compose.toml
Original file line number Diff line number Diff line change
Expand Up @@ -365,11 +365,11 @@ adyen = { banks = "aib,bank_of_scotland,danske_bank,first_direct,first_trust,hal

[mandates.supported_payment_methods]
pay_later.klarna = { connector_list = "adyen" }
wallet.google_pay = { connector_list = "stripe,adyen" }
wallet.apple_pay = { connector_list = "stripe,adyen,cybersource,noon" }
wallet.google_pay = { connector_list = "stripe,adyen,bankofamerica" }
wallet.apple_pay = { connector_list = "stripe,adyen,cybersource,noon,bankofamerica" }
wallet.paypal = { connector_list = "adyen" }
card.credit = { connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon" }
card.debit = { connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon" }
card.credit = { connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon,bankofamerica" }
card.debit = { connector_list = "stripe,adyen,authorizedotnet,cybersource,globalpay,worldpay,multisafepay,nmi,nexinets,noon,bankofamerica" }
bank_debit.ach = { connector_list = "gocardless" }
bank_debit.becs = { connector_list = "gocardless" }
bank_debit.sepa = { connector_list = "gocardless" }
Expand Down
142 changes: 133 additions & 9 deletions crates/router/src/connector/bankofamerica.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use time::OffsetDateTime;
use transformers as bankofamerica;
use url::Url;

use super::utils::{PaymentsAuthorizeRequestData, RouterData};
use super::utils::{PaymentsAuthorizeRequestData, PaymentsSetupMandateRequestData, RouterData};
use crate::{
configs::settings,
connector::{utils as connector_utils, utils::RefundsRequestData},
Expand Down Expand Up @@ -288,19 +288,141 @@ impl
types::PaymentsResponseData,
> for Bankofamerica
{
fn get_headers(
&self,
req: &types::SetupMandateRouterData,
connectors: &settings::Connectors,
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
self.build_headers(req, connectors)
}
fn get_content_type(&self) -> &'static str {
self.common_get_content_type()
}
fn get_url(
&self,
req: &types::SetupMandateRouterData,
connectors: &settings::Connectors,
) -> CustomResult<String, errors::ConnectorError> {
if req.is_three_ds() && req.request.is_card() {
Ok(format!(
"{}risk/v1/authentication-setups",
self.base_url(connectors)
))
} else {
Ok(format!("{}pts/v2/payments/", self.base_url(connectors)))
}
}
fn get_request_body(
&self,
req: &types::SetupMandateRouterData,
_connectors: &settings::Connectors,
) -> CustomResult<RequestContent, errors::ConnectorError> {
if req.is_three_ds() && req.request.is_card() {
let connector_req = bankofamerica::BankOfAmericaAuthSetupRequest::try_from((
&req.request.payment_method_data,
req.connector_request_reference_id.clone(),
))?;
Ok(RequestContent::Json(Box::new(connector_req)))
} else {
let connector_req = bankofamerica::BankOfAmericaPaymentsRequest::try_from(req)?;
Ok(RequestContent::Json(Box::new(connector_req)))
}
}

fn build_request(
&self,
_req: &types::RouterData<
req: &types::RouterData<
api::SetupMandate,
types::SetupMandateRequestData,
types::PaymentsResponseData,
>,
_connectors: &settings::Connectors,
connectors: &settings::Connectors,
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
Err(errors::ConnectorError::NotImplemented(
"Setup Mandate flow for Bankofamerica".to_string(),
)
.into())
Ok(Some(
services::RequestBuilder::new()
.method(services::Method::Post)
.url(&types::SetupMandateType::get_url(self, req, connectors)?)
.attach_default_headers()
.headers(types::SetupMandateType::get_headers(self, req, connectors)?)
.set_body(types::SetupMandateType::get_request_body(
self, req, connectors,
)?)
.build(),
))
}
fn handle_response(
&self,
data: &types::SetupMandateRouterData,
event_builder: Option<&mut ConnectorEvent>,
res: Response,
) -> CustomResult<types::SetupMandateRouterData, errors::ConnectorError> {
if data.is_three_ds() && data.request.is_card() {
let response: bankofamerica::BankOfAmericaAuthSetupResponse = res
.response
.parse_struct("Bankofamerica AuthSetupResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
event_builder.map(|i| i.set_response_body(&response));
router_env::logger::info!(connector_response=?response);
types::RouterData::try_from(types::ResponseRouterData {
response,
data: data.clone(),
http_code: res.status_code,
})
} else {
let response: bankofamerica::BankOfAmericaSetupMandatesResponse = res
.response
.parse_struct("BankOfAmericaSetupMandatesResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

event_builder.map(|i| i.set_response_body(&response));
router_env::logger::info!(connector_response=?response);

types::RouterData::try_from(types::ResponseRouterData {
response,
data: data.clone(),
http_code: res.status_code,
})
}
}

fn get_error_response(
&self,
res: Response,
event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
self.build_error_response(res, event_builder)
}

fn get_5xx_error_response(
&self,
res: Response,
event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
let response: bankofamerica::BankOfAmericaServerErrorResponse = res
.response
.parse_struct("BankOfAmericaServerErrorResponse")
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

event_builder.map(|event| event.set_response_body(&response));
router_env::logger::info!(error_response=?response);

let attempt_status = match response.reason {
Some(reason) => match reason {
transformers::Reason::SystemError => Some(enums::AttemptStatus::Failure),
transformers::Reason::ServerTimeout | transformers::Reason::ServiceTimeout => None,
},
None => None,
};
Ok(ErrorResponse {
status_code: res.status_code,
reason: response.status.clone(),
code: response.status.unwrap_or(consts::NO_ERROR_CODE.to_string()),
message: response
.message
.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
attempt_status,
connector_transaction_id: None,
})
}
}

Expand Down Expand Up @@ -457,8 +579,10 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P
req,
))?;
if req.is_three_ds() && req.request.is_card() {
let connector_req =
bankofamerica::BankOfAmericaAuthSetupRequest::try_from(&connector_router_data)?;
let connector_req = bankofamerica::BankOfAmericaAuthSetupRequest::try_from((
&req.request.payment_method_data,
req.connector_request_reference_id.clone(),
))?;
Ok(RequestContent::Json(Box::new(connector_req)))
} else {
let connector_req =
Expand Down
Loading

0 comments on commit 2f304e6

Please sign in to comment.