feat(router): add new payment methods for Bank redirects, BNPL and wallet (#864)

This commit is contained in:
Arjun Karthik
2023-04-21 02:50:29 +05:30
committed by GitHub
parent e4d0dd0a38
commit 304081cbad
11 changed files with 954 additions and 423 deletions

View File

@ -191,6 +191,8 @@ impl
}
}
/// Payment Sync can be useful only incase of Redirect flow.
/// For payments which doesn't involve redrection we have to rely on webhooks.
impl
services::ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>
for Adyen

File diff suppressed because it is too large Load Diff

View File

@ -19,13 +19,15 @@ use crate::{
types::{self, api, storage::enums, ErrorResponse},
};
type Error = error_stack::Report<errors::ConnectorError>;
#[derive(Debug, Serialize, Deserialize)]
pub struct GlobalPayMeta {
account_name: String,
}
impl TryFrom<&types::PaymentsAuthorizeRouterData> for GlobalpayPaymentsRequest {
type Error = error_stack::Report<errors::ConnectorError>;
type Error = Error;
fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
let metadata: GlobalPayMeta =
utils::to_connector_meta_from_secret(item.connector_meta_data.clone())?;
@ -84,7 +86,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for GlobalpayPaymentsRequest {
}
impl TryFrom<&types::PaymentsCaptureRouterData> for requests::GlobalpayCaptureRequest {
type Error = error_stack::Report<errors::ConnectorError>;
type Error = Error;
fn try_from(value: &types::PaymentsCaptureRouterData) -> Result<Self, Self::Error> {
Ok(Self {
amount: Some(value.request.amount_to_capture.to_string()),
@ -93,7 +95,7 @@ impl TryFrom<&types::PaymentsCaptureRouterData> for requests::GlobalpayCaptureRe
}
impl TryFrom<&types::PaymentsCancelRouterData> for requests::GlobalpayCancelRequest {
type Error = error_stack::Report<errors::ConnectorError>;
type Error = Error;
fn try_from(value: &types::PaymentsCancelRouterData) -> Result<Self, Self::Error> {
Ok(Self {
amount: value.request.amount.map(|amount| amount.to_string()),
@ -107,7 +109,7 @@ pub struct GlobalpayAuthType {
}
impl TryFrom<&types::ConnectorAuthType> for GlobalpayAuthType {
type Error = error_stack::Report<errors::ConnectorError>;
type Error = Error;
fn try_from(auth_type: &types::ConnectorAuthType) -> Result<Self, Self::Error> {
match auth_type {
types::ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self {
@ -131,7 +133,7 @@ impl TryFrom<GlobalpayRefreshTokenResponse> for types::AccessToken {
}
impl TryFrom<&types::RefreshTokenRouterData> for GlobalpayRefreshTokenRequest {
type Error = error_stack::Report<errors::ConnectorError>;
type Error = Error;
fn try_from(item: &types::RefreshTokenRouterData) -> Result<Self, Self::Error> {
let globalpay_auth = GlobalpayAuthType::try_from(&item.connector_auth_type)
@ -220,7 +222,7 @@ impl<F, T>
TryFrom<types::ResponseRouterData<F, GlobalpayPaymentsResponse, T, types::PaymentsResponseData>>
for types::RouterData<F, T, types::PaymentsResponseData>
{
type Error = error_stack::Report<errors::ConnectorError>;
type Error = Error;
fn try_from(
item: types::ResponseRouterData<
F,
@ -276,7 +278,7 @@ impl<F, T>
}
impl<F> TryFrom<&types::RefundsRouterData<F>> for requests::GlobalpayRefundRequest {
type Error = error_stack::Report<errors::ConnectorError>;
type Error = Error;
fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> {
Ok(Self {
amount: item.request.refund_amount.to_string(),
@ -287,7 +289,7 @@ impl<F> TryFrom<&types::RefundsRouterData<F>> for requests::GlobalpayRefundReque
impl TryFrom<types::RefundsResponseRouterData<api::Execute, GlobalpayPaymentsResponse>>
for types::RefundExecuteRouterData
{
type Error = error_stack::Report<errors::ConnectorError>;
type Error = Error;
fn try_from(
item: types::RefundsResponseRouterData<api::Execute, GlobalpayPaymentsResponse>,
) -> Result<Self, Self::Error> {
@ -304,7 +306,7 @@ impl TryFrom<types::RefundsResponseRouterData<api::Execute, GlobalpayPaymentsRes
impl TryFrom<types::RefundsResponseRouterData<api::RSync, GlobalpayPaymentsResponse>>
for types::RefundsRouterData<api::RSync>
{
type Error = error_stack::Report<errors::ConnectorError>;
type Error = Error;
fn try_from(
item: types::RefundsResponseRouterData<api::RSync, GlobalpayPaymentsResponse>,
) -> Result<Self, Self::Error> {
@ -328,7 +330,7 @@ pub struct GlobalpayErrorResponse {
fn get_payment_method_data(
item: &types::PaymentsAuthorizeRouterData,
brand_reference: Option<String>,
) -> Result<PaymentMethodData, error_stack::Report<errors::ConnectorError>> {
) -> Result<PaymentMethodData, Error> {
match &item.request.payment_method_data {
api::PaymentMethodData::Card(ccard) => Ok(PaymentMethodData::Card(requests::Card {
number: ccard.card_number.clone(),
@ -348,7 +350,7 @@ fn get_payment_method_data(
})),
api::PaymentMethodData::Wallet(wallet_data) => get_wallet_data(wallet_data),
api::PaymentMethodData::BankRedirect(bank_redirect) => {
get_bank_redirect_data(bank_redirect)
PaymentMethodData::try_from(bank_redirect)
}
_ => Err(errors::ConnectorError::NotImplemented(
"Payment methods".to_string(),
@ -366,9 +368,7 @@ fn get_return_url(item: &types::PaymentsAuthorizeRouterData) -> Option<String> {
}
type MandateDetails = (Option<Initiator>, Option<StoredCredential>, Option<String>);
fn get_mandate_details(
item: &types::PaymentsAuthorizeRouterData,
) -> Result<MandateDetails, error_stack::Report<errors::ConnectorError>> {
fn get_mandate_details(item: &types::PaymentsAuthorizeRouterData) -> Result<MandateDetails, Error> {
Ok(if item.request.is_mandate_payment() {
let connector_mandate_id = item
.request
@ -396,7 +396,7 @@ fn get_mandate_details(
fn get_wallet_data(
wallet_data: &api_models::payments::WalletData,
) -> Result<PaymentMethodData, error_stack::Report<errors::ConnectorError>> {
) -> Result<PaymentMethodData, Error> {
match wallet_data {
api_models::payments::WalletData::PaypalRedirect(_) => {
Ok(PaymentMethodData::Apm(requests::Apm {
@ -410,34 +410,33 @@ fn get_wallet_data(
}))
}
_ => Err(errors::ConnectorError::NotImplemented(
"Payment methods".to_string(),
"Payment method".to_string(),
))?,
}
}
fn get_bank_redirect_data(
bank_redirect: &api_models::payments::BankRedirectData,
) -> Result<PaymentMethodData, error_stack::Report<errors::ConnectorError>> {
match bank_redirect {
api_models::payments::BankRedirectData::Eps { .. } => {
Ok(PaymentMethodData::Apm(requests::Apm {
impl TryFrom<&api_models::payments::BankRedirectData> for PaymentMethodData {
type Error = Error;
fn try_from(value: &api_models::payments::BankRedirectData) -> Result<Self, Self::Error> {
match value {
api_models::payments::BankRedirectData::Eps { .. } => Ok(Self::Apm(requests::Apm {
provider: Some(ApmProvider::Eps),
}))
}
api_models::payments::BankRedirectData::Giropay { .. } => {
Ok(PaymentMethodData::Apm(requests::Apm {
provider: Some(ApmProvider::Giropay),
}))
}
api_models::payments::BankRedirectData::Ideal { .. } => {
Ok(PaymentMethodData::Apm(requests::Apm {
})),
api_models::payments::BankRedirectData::Giropay { .. } => {
Ok(Self::Apm(requests::Apm {
provider: Some(ApmProvider::Giropay),
}))
}
api_models::payments::BankRedirectData::Ideal { .. } => Ok(Self::Apm(requests::Apm {
provider: Some(ApmProvider::Ideal),
}))
}
api_models::payments::BankRedirectData::Sofort { .. } => {
Ok(PaymentMethodData::Apm(requests::Apm {
})),
api_models::payments::BankRedirectData::Sofort { .. } => Ok(Self::Apm(requests::Apm {
provider: Some(ApmProvider::Sofort),
}))
})),
_ => Err(errors::ConnectorError::NotImplemented(
"Payment method".to_string(),
))
.into_report(),
}
}
}

View File

@ -98,7 +98,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for MolliePaymentsRequest {
let payment_method_data = match item.request.capture_method.unwrap_or_default() {
enums::CaptureMethod::Automatic => match item.request.payment_method_data {
api_models::payments::PaymentMethodData::BankRedirect(ref redirect_data) => {
get_payment_method_for_bank_redirect(item, redirect_data)
PaymentMethodData::try_from(redirect_data)
}
api_models::payments::PaymentMethodData::Wallet(ref wallet_data) => {
get_payment_method_for_wallet(item, wallet_data)
@ -135,22 +135,22 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for MolliePaymentsRequest {
}
}
fn get_payment_method_for_bank_redirect(
_item: &types::PaymentsAuthorizeRouterData,
redirect_data: &api_models::payments::BankRedirectData,
) -> Result<PaymentMethodData, Error> {
let payment_method_data = match redirect_data {
api_models::payments::BankRedirectData::Eps { .. } => PaymentMethodData::Eps,
api_models::payments::BankRedirectData::Giropay { .. } => PaymentMethodData::Giropay,
api_models::payments::BankRedirectData::Ideal { .. } => {
PaymentMethodData::Ideal(Box::new(IdealMethodData {
// To do if possible this should be from the payment request
issuer: None,
}))
impl TryFrom<&api_models::payments::BankRedirectData> for PaymentMethodData {
type Error = Error;
fn try_from(value: &api_models::payments::BankRedirectData) -> Result<Self, Self::Error> {
match value {
api_models::payments::BankRedirectData::Eps { .. } => Ok(Self::Eps),
api_models::payments::BankRedirectData::Giropay { .. } => Ok(Self::Giropay),
api_models::payments::BankRedirectData::Ideal { .. } => {
Ok(Self::Ideal(Box::new(IdealMethodData {
// To do if possible this should be from the payment request
issuer: None,
})))
}
api_models::payments::BankRedirectData::Sofort { .. } => Ok(Self::Sofort),
_ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()),
}
api_models::payments::BankRedirectData::Sofort { .. } => PaymentMethodData::Sofort,
};
Ok(payment_method_data)
}
}
fn get_payment_method_for_wallet(

View File

@ -198,7 +198,7 @@ fn get_bank_redirect_request<T>(
redirect_data: &payments::BankRedirectData,
) -> Result<Shift4PaymentsRequest, Error> {
let submit_for_settlement = item.request.is_auto_capture()?;
let method_type = PaymentMethodType::from(redirect_data);
let method_type = PaymentMethodType::try_from(redirect_data)?;
let billing = get_billing(item)?;
let payment_method = Some(PaymentMethod {
method_type,
@ -218,13 +218,15 @@ fn get_bank_redirect_request<T>(
)))
}
impl From<&payments::BankRedirectData> for PaymentMethodType {
fn from(value: &payments::BankRedirectData) -> Self {
impl TryFrom<&payments::BankRedirectData> for PaymentMethodType {
type Error = Error;
fn try_from(value: &payments::BankRedirectData) -> Result<Self, Self::Error> {
match value {
payments::BankRedirectData::Eps { .. } => Self::Eps,
payments::BankRedirectData::Giropay { .. } => Self::Giropay,
payments::BankRedirectData::Ideal { .. } => Self::Ideal,
payments::BankRedirectData::Sofort { .. } => Self::Sofort,
payments::BankRedirectData::Eps { .. } => Ok(Self::Eps),
payments::BankRedirectData::Giropay { .. } => Ok(Self::Giropay),
payments::BankRedirectData::Ideal { .. } => Ok(Self::Ideal),
payments::BankRedirectData::Sofort { .. } => Ok(Self::Sofort),
_ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()),
}
}
}

View File

@ -18,6 +18,8 @@ use crate::{
types::{self, api, storage::enums, BrowserInformation},
};
type Error = error_stack::Report<errors::ConnectorError>;
pub struct TrustpayAuthType {
pub(super) api_key: String,
pub(super) project_id: String,
@ -25,7 +27,7 @@ pub struct TrustpayAuthType {
}
impl TryFrom<&types::ConnectorAuthType> for TrustpayAuthType {
type Error = error_stack::Report<errors::ConnectorError>;
type Error = Error;
fn try_from(auth_type: &types::ConnectorAuthType) -> Result<Self, Self::Error> {
if let types::ConnectorAuthType::SignatureKey {
api_key,
@ -181,18 +183,22 @@ pub struct TrustpayMandatoryParams {
pub billing_postcode: Secret<String>,
}
fn get_trustpay_payment_method(bank_redirection_data: &BankRedirectData) -> TrustpayPaymentMethod {
match bank_redirection_data {
api_models::payments::BankRedirectData::Giropay { .. } => TrustpayPaymentMethod::Giropay,
api_models::payments::BankRedirectData::Eps { .. } => TrustpayPaymentMethod::Eps,
api_models::payments::BankRedirectData::Ideal { .. } => TrustpayPaymentMethod::IDeal,
api_models::payments::BankRedirectData::Sofort { .. } => TrustpayPaymentMethod::Sofort,
impl TryFrom<&BankRedirectData> for TrustpayPaymentMethod {
type Error = Error;
fn try_from(value: &BankRedirectData) -> Result<Self, Self::Error> {
match value {
api_models::payments::BankRedirectData::Giropay { .. } => Ok(Self::Giropay),
api_models::payments::BankRedirectData::Eps { .. } => Ok(Self::Eps),
api_models::payments::BankRedirectData::Ideal { .. } => Ok(Self::IDeal),
api_models::payments::BankRedirectData::Sofort { .. } => Ok(Self::Sofort),
_ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()),
}
}
}
fn get_mandatory_fields(
item: &types::PaymentsAuthorizeRouterData,
) -> Result<TrustpayMandatoryParams, error_stack::Report<errors::ConnectorError>> {
) -> Result<TrustpayMandatoryParams, Error> {
let billing_address = item
.get_billing()?
.address
@ -248,33 +254,35 @@ fn get_bank_redirection_request_data(
item: &types::PaymentsAuthorizeRouterData,
bank_redirection_data: &BankRedirectData,
amount: String,
return_url: String,
auth: TrustpayAuthType,
) -> TrustpayPaymentsRequest {
TrustpayPaymentsRequest::BankRedirectPaymentRequest(Box::new(PaymentRequestBankRedirect {
payment_method: get_trustpay_payment_method(bank_redirection_data),
merchant_identification: MerchantIdentification {
project_id: auth.project_id,
},
payment_information: BankPaymentInformation {
amount: Amount {
amount,
currency: item.request.currency.to_string(),
) -> Result<TrustpayPaymentsRequest, error_stack::Report<errors::ConnectorError>> {
let return_url = item.request.get_return_url()?;
let payment_request =
TrustpayPaymentsRequest::BankRedirectPaymentRequest(Box::new(PaymentRequestBankRedirect {
payment_method: TrustpayPaymentMethod::try_from(bank_redirection_data)?,
merchant_identification: MerchantIdentification {
project_id: auth.project_id,
},
references: References {
merchant_reference: item.attempt_id.clone(),
payment_information: BankPaymentInformation {
amount: Amount {
amount,
currency: item.request.currency.to_string(),
},
references: References {
merchant_reference: item.attempt_id.clone(),
},
},
},
callback_urls: CallbackURLs {
success: format!("{return_url}?status=SuccessOk"),
cancel: return_url.clone(),
error: return_url,
},
}))
callback_urls: CallbackURLs {
success: format!("{return_url}?status=SuccessOk"),
cancel: return_url.clone(),
error: return_url,
},
}));
Ok(payment_request)
}
impl TryFrom<&types::PaymentsAuthorizeRouterData> for TrustpayPaymentsRequest {
type Error = error_stack::Report<errors::ConnectorError>;
type Error = Error;
fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
let default_browser_info = BrowserInformation {
color_depth: 24,
@ -303,7 +311,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for TrustpayPaymentsRequest {
);
let auth = TrustpayAuthType::try_from(&item.connector_auth_type)
.change_context(errors::ConnectorError::FailedToObtainAuthType)?;
Ok(match item.request.payment_method_data {
match item.request.payment_method_data {
api::PaymentMethodData::Card(ref ccard) => Ok(get_card_request_data(
item,
browser_info,
@ -313,19 +321,10 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for TrustpayPaymentsRequest {
item.request.get_return_url()?,
)),
api::PaymentMethodData::BankRedirect(ref bank_redirection_data) => {
Ok(get_bank_redirection_request_data(
item,
bank_redirection_data,
amount,
item.request.get_return_url()?,
auth,
))
get_bank_redirection_request_data(item, bank_redirection_data, amount, auth)
}
_ => Err(errors::ConnectorError::NotImplemented(format!(
"Current Payment Method - {:?}",
item.request.payment_method_data
))),
}?)
_ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()),
}
}
}
@ -524,7 +523,7 @@ impl<F, T>
TryFrom<types::ResponseRouterData<F, TrustpayPaymentsResponse, T, types::PaymentsResponseData>>
for types::RouterData<F, T, types::PaymentsResponseData>
{
type Error = error_stack::Report<errors::ConnectorError>;
type Error = Error;
fn try_from(
item: types::ResponseRouterData<
F,
@ -733,7 +732,7 @@ pub struct TrustpayAuthUpdateRequest {
}
impl TryFrom<&types::RefreshTokenRouterData> for TrustpayAuthUpdateRequest {
type Error = error_stack::Report<errors::ConnectorError>;
type Error = Error;
fn try_from(_item: &types::RefreshTokenRouterData) -> Result<Self, Self::Error> {
Ok(Self {
grant_type: "client_credentials".to_string(),
@ -767,7 +766,7 @@ pub struct TrustpayAccessTokenErrorResponse {
impl<F, T> TryFrom<types::ResponseRouterData<F, TrustpayAuthUpdateResponse, T, types::AccessToken>>
for types::RouterData<F, T, types::AccessToken>
{
type Error = error_stack::Report<errors::ConnectorError>;
type Error = Error;
fn try_from(
item: types::ResponseRouterData<F, TrustpayAuthUpdateResponse, T, types::AccessToken>,
) -> Result<Self, Self::Error> {
@ -820,7 +819,7 @@ pub enum TrustpayRefundRequest {
}
impl<F> TryFrom<&types::RefundsRouterData<F>> for TrustpayRefundRequest {
type Error = error_stack::Report<errors::ConnectorError>;
type Error = Error;
fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> {
let amount = format!(
"{:.2}",
@ -1000,7 +999,7 @@ fn handle_bank_redirects_refund_sync_error_response(
impl<F> TryFrom<types::RefundsResponseRouterData<F, RefundResponse>>
for types::RefundsRouterData<F>
{
type Error = error_stack::Report<errors::ConnectorError>;
type Error = Error;
fn try_from(
item: types::RefundsResponseRouterData<F, RefundResponse>,
) -> Result<Self, Self::Error> {