diff --git a/crates/router/src/connector/adyen.rs b/crates/router/src/connector/adyen.rs index a7762862f2..79acad0b0b 100644 --- a/crates/router/src/connector/adyen.rs +++ b/crates/router/src/connector/adyen.rs @@ -363,9 +363,10 @@ impl req: &types::PaymentsAuthorizeRouterData, ) -> CustomResult, errors::ConnectorError> { let connector_req = adyen::AdyenPaymentRequest::try_from(req)?; - let adyen_req = - utils::Encode::::encode_to_string_of_json(&connector_req) - .change_context(errors::ConnectorError::RequestEncodingFailed)?; + let adyen_req = utils::Encode::>::encode_to_string_of_json( + &connector_req, + ) + .change_context(errors::ConnectorError::RequestEncodingFailed)?; Ok(Some(adyen_req)) } diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index fe3603be07..4eff65179f 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -1,5 +1,5 @@ use base64::Engine; -use error_stack::{IntoReport, ResultExt}; +use error_stack::ResultExt; use masking::PeekInterface; use reqwest::Url; use serde::{Deserialize, Serialize}; @@ -10,7 +10,11 @@ use crate::{ core::errors, pii::{self, Email, Secret}, services, - types::{self, api, storage::enums as storage_enums}, + types::{ + self, + api::{self, enums as api_enums}, + storage::enums as storage_enums, + }, }; // Adyen Types Definition @@ -75,10 +79,10 @@ pub struct LineItem { #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] -pub struct AdyenPaymentRequest { +pub struct AdyenPaymentRequest<'a> { amount: Amount, merchant_account: String, - payment_method: AdyenPaymentMethod, + payment_method: AdyenPaymentMethod<'a>, reference: String, return_url: String, browser_info: Option, @@ -87,6 +91,7 @@ pub struct AdyenPaymentRequest { recurring_processing_model: Option, additional_data: Option, shopper_name: Option, + shopper_locale: Option, shopper_email: Option>, telephone_number: Option>, billing_address: Option
, @@ -203,9 +208,9 @@ pub struct Amount { value: i64, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize)] #[serde(tag = "type")] -pub enum AdyenPaymentMethod { +pub enum AdyenPaymentMethod<'a> { AdyenCard(AdyenCard), AdyenPaypal(AdyenPaypal), Gpay(AdyenGPay), @@ -213,6 +218,23 @@ pub enum AdyenPaymentMethod { AfterPay(AdyenPayLaterData), AdyenKlarna(AdyenPayLaterData), AdyenAffirm(AdyenPayLaterData), + Eps(BankRedirectionWithIssuer<'a>), + Ideal(BankRedirectionWithIssuer<'a>), + Giropay(BankRedirectionPMData), + Sofort(BankRedirectionPMData), +} + +#[derive(Debug, Clone, Serialize)] +pub struct BankRedirectionPMData { + #[serde(rename = "type")] + payment_type: PaymentType, +} + +#[derive(Debug, Clone, Serialize)] +pub struct BankRedirectionWithIssuer<'a> { + #[serde(rename = "type")] + payment_type: PaymentType, + issuer: &'a str, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -311,6 +333,74 @@ pub enum PaymentType { Klarna, Affirm, Afterpaytouch, + Eps, + Ideal, + Giropay, + #[serde(rename = "directEbanking")] + Sofort, +} + +pub struct AdyenTestBankNames<'a>(&'a str); + +impl<'a> TryFrom<&api_enums::BankNames> for AdyenTestBankNames<'a> { + type Error = error_stack::Report; + fn try_from(bank: &api_enums::BankNames) -> Result { + Ok(match bank { + api_models::enums::BankNames::AbnAmro => Self("1121"), + api_models::enums::BankNames::AsnBank => Self("1151"), + api_models::enums::BankNames::Bunq => Self("1152"), + api_models::enums::BankNames::Handelsbanken => Self("1153"), + api_models::enums::BankNames::Ing => Self("1154"), + api_models::enums::BankNames::Knab => Self("1155"), + api_models::enums::BankNames::Moneyou => Self("1156"), + api_models::enums::BankNames::Rabobank => Self("1157"), + api_models::enums::BankNames::Regiobank => Self("1158"), + api_models::enums::BankNames::Revolut => Self("1159"), + api_models::enums::BankNames::SnsBank => Self("1159"), + api_models::enums::BankNames::TriodosBank => Self("1159"), + api_models::enums::BankNames::VanLanschot => Self("1159"), + api_models::enums::BankNames::BankAustria => { + Self("e6819e7a-f663-414b-92ec-cf7c82d2f4e5") + } + api_models::enums::BankNames::BawagPskAg => { + Self("ba7199cc-f057-42f2-9856-2378abf21638") + } + api_models::enums::BankNames::Dolomitenbank => { + Self("d5d5b133-1c0d-4c08-b2be-3c9b116dc326") + } + api_models::enums::BankNames::EasybankAg => { + Self("eff103e6-843d-48b7-a6e6-fbd88f511b11") + } + api_models::enums::BankNames::ErsteBankUndSparkassen => { + Self("3fdc41fc-3d3d-4ee3-a1fe-cd79cfd58ea3") + } + api_models::enums::BankNames::HypoTirolBankAg => { + Self("6765e225-a0dc-4481-9666-e26303d4f221") + } + api_models::enums::BankNames::PosojilnicaBankEGen => { + Self("65ef4682-4944-499f-828f-5d74ad288376") + } + api_models::enums::BankNames::RaiffeisenBankengruppeOsterreich => { + Self("ee9fc487-ebe0-486c-8101-17dce5141a67") + } + api_models::enums::BankNames::SchoellerbankAg => { + Self("1190c4d1-b37a-487e-9355-e0a067f54a9f") + } + api_models::enums::BankNames::SpardaBankWien => { + Self("8b0bfeea-fbb0-4337-b3a1-0e25c0f060fc") + } + api_models::enums::BankNames::VolksbankGruppe => { + Self("e2e97aaa-de4c-4e18-9431-d99790773433") + } + api_models::enums::BankNames::VolkskreditbankAg => { + Self("4a0a975b-0594-4b40-9068-39f77b3a91f9") + } + _ => Err(errors::ConnectorError::NotSupported { + payment_method: String::from("BankRedirect"), + connector: "Adyen", + })?, + }) + } } impl TryFrom<&types::ConnectorAuthType> for AdyenAuthType { @@ -328,7 +418,7 @@ impl TryFrom<&types::ConnectorAuthType> for AdyenAuthType { } // Payment Request Transform -impl TryFrom<&types::PaymentsAuthorizeRouterData> for AdyenPaymentRequest { +impl<'a> TryFrom<&types::PaymentsAuthorizeRouterData> for AdyenPaymentRequest<'a> { type Error = error_stack::Report; fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result { match item.payment_method { @@ -337,11 +427,9 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for AdyenPaymentRequest { get_paylater_specific_payment_data(item) } storage_models::enums::PaymentMethod::Wallet => get_wallet_specific_payment_data(item), - _ => Err(errors::ConnectorError::NotSupported { - payment_method: item.payment_method.to_string(), - connector: "adyen", - }) - .into_report()?, + storage_models::enums::PaymentMethod::BankRedirect => { + get_bank_redirect_specific_payment_data(item) + } } } } @@ -468,9 +556,9 @@ fn get_country_code(item: &types::PaymentsAuthorizeRouterData) -> Option address.and_then(|address| address.country.clone()) } -fn get_payment_method_data( +fn get_payment_method_data<'a>( item: &types::PaymentsAuthorizeRouterData, -) -> Result> { +) -> Result, error_stack::Report> { match item.request.payment_method_data { api::PaymentMethodData::Card(ref card) => { let adyen_card = AdyenCard { @@ -539,13 +627,39 @@ fn get_payment_method_data( ), } } - _ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()), + api_models::payments::PaymentMethodData::BankRedirect(ref bank_redirect_data) => { + match bank_redirect_data { + api_models::payments::BankRedirectData::Eps { bank_name, .. } => { + Ok(AdyenPaymentMethod::Eps(BankRedirectionWithIssuer { + payment_type: PaymentType::Eps, + issuer: AdyenTestBankNames::try_from(bank_name)?.0, + })) + } + api_models::payments::BankRedirectData::Ideal { bank_name, .. } => { + Ok(AdyenPaymentMethod::Ideal(BankRedirectionWithIssuer { + payment_type: PaymentType::Ideal, + issuer: AdyenTestBankNames::try_from(bank_name)?.0, + })) + } + + api_models::payments::BankRedirectData::Giropay { .. } => { + Ok(AdyenPaymentMethod::Giropay(BankRedirectionPMData { + payment_type: PaymentType::Giropay, + })) + } + api_models::payments::BankRedirectData::Sofort { .. } => { + Ok(AdyenPaymentMethod::Sofort(BankRedirectionPMData { + payment_type: PaymentType::Sofort, + })) + } + } + } } } -fn get_card_specific_payment_data( +fn get_card_specific_payment_data<'a>( item: &types::PaymentsAuthorizeRouterData, -) -> Result> { +) -> Result, error_stack::Report> { let amount = get_amount_data(item); let auth_type = AdyenAuthType::try_from(&item.connector_auth_type)?; let shopper_interaction = AdyenShopperInteraction::from(item); @@ -567,6 +681,7 @@ fn get_card_specific_payment_data( telephone_number: None, shopper_name: None, shopper_email: None, + shopper_locale: None, billing_address: None, delivery_address: None, country_code: None, @@ -574,9 +689,64 @@ fn get_card_specific_payment_data( }) } -fn get_wallet_specific_payment_data( +fn get_sofort_extra_details( item: &types::PaymentsAuthorizeRouterData, -) -> Result> { +) -> (Option, Option) { + match item.request.payment_method_data { + api_models::payments::PaymentMethodData::BankRedirect(ref b) => { + if let api_models::payments::BankRedirectData::Sofort { + country, + preferred_language, + } = b + { + ( + Some(preferred_language.to_string()), + Some(country.to_string()), + ) + } else { + (None, None) + } + } + _ => (None, None), + } +} +fn get_bank_redirect_specific_payment_data<'a>( + item: &types::PaymentsAuthorizeRouterData, +) -> Result, error_stack::Report> { + let amount = get_amount_data(item); + let auth_type = AdyenAuthType::try_from(&item.connector_auth_type)?; + let shopper_interaction = AdyenShopperInteraction::from(item); + let recurring_processing_model = get_recurring_processing_model(item); + let browser_info = get_browser_info(item); + let additional_data = get_additional_data(item); + let return_url = item.get_return_url()?; + let payment_method = get_payment_method_data(item)?; + let (shopper_locale, country) = get_sofort_extra_details(item); + + Ok(AdyenPaymentRequest { + amount, + merchant_account: auth_type.merchant_account, + payment_method, + reference: item.payment_id.to_string(), + return_url, + shopper_interaction, + recurring_processing_model, + browser_info, + additional_data, + telephone_number: None, + shopper_name: None, + shopper_email: None, + shopper_locale, + billing_address: None, + delivery_address: None, + country_code: country, + line_items: None, + }) +} + +fn get_wallet_specific_payment_data<'a>( + item: &types::PaymentsAuthorizeRouterData, +) -> Result, error_stack::Report> { let amount = get_amount_data(item); let auth_type = AdyenAuthType::try_from(&item.connector_auth_type)?; let browser_info = get_browser_info(item); @@ -598,6 +768,7 @@ fn get_wallet_specific_payment_data( telephone_number: None, shopper_name: None, shopper_email: None, + shopper_locale: None, billing_address: None, delivery_address: None, country_code: None, @@ -605,9 +776,9 @@ fn get_wallet_specific_payment_data( }) } -fn get_paylater_specific_payment_data( +fn get_paylater_specific_payment_data<'a>( item: &types::PaymentsAuthorizeRouterData, -) -> Result> { +) -> Result, error_stack::Report> { let amount = get_amount_data(item); let auth_type = AdyenAuthType::try_from(&item.connector_auth_type)?; let browser_info = get_browser_info(item); @@ -636,6 +807,7 @@ fn get_paylater_specific_payment_data( telephone_number, shopper_name, shopper_email, + shopper_locale: None, billing_address, delivery_address, country_code, diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index a23f4af796..d31dadc985 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -136,11 +136,11 @@ pub struct StripePayLaterData { pub enum StripeBankName { Eps { #[serde(rename = "payment_method_data[eps][bank]")] - bank_name: api_models::enums::BankNames, + bank_name: StripeBankNames, }, Ideal { #[serde(rename = "payment_method_data[ideal][bank]")] - ideal_bank_name: api_models::enums::BankNames, + ideal_bank_name: StripeBankNames, }, } @@ -162,15 +162,15 @@ fn get_bank_name( match (stripe_pm_type, bank_redirect_data) { ( StripePaymentMethodType::Eps, - api_models::payments::BankRedirectData::Eps { bank_name, .. }, + api_models::payments::BankRedirectData::Eps { ref bank_name, .. }, ) => Ok(Some(StripeBankName::Eps { - bank_name: bank_name.to_owned(), + bank_name: StripeBankNames::try_from(bank_name)?, })), ( StripePaymentMethodType::Ideal, api_models::payments::BankRedirectData::Ideal { bank_name, .. }, ) => Ok(Some(StripeBankName::Ideal { - ideal_bank_name: bank_name.to_owned(), + ideal_bank_name: StripeBankNames::try_from(bank_name)?, })), (StripePaymentMethodType::Sofort | StripePaymentMethodType::Giropay, _) => Ok(None), _ => Err(errors::ConnectorError::MismatchedPaymentData), @@ -211,6 +211,117 @@ pub enum StripePaymentMethodType { Sofort, } +#[derive(Debug, Eq, PartialEq, Serialize, Clone)] +#[serde(rename_all = "snake_case")] +pub enum StripeBankNames { + AbnAmro, + ArzteUndApothekerBank, + AsnBank, + AustrianAnadiBankAg, + BankAustria, + BankhausCarlSpangler, + BankhausSchelhammerUndSchatteraAg, + BawagPskAg, + BksBankAg, + BrullKallmusBankAg, + BtvVierLanderBank, + Bunq, + CapitalBankGraweGruppeAg, + Dolomitenbank, + EasybankAg, + ErsteBankUndSparkassen, + Handelsbanken, + HypoAlpeadriabankInternationalAg, + HypoNoeLbFurNiederosterreichUWien, + HypoOberosterreichSalzburgSteiermark, + HypoTirolBankAg, + HypoVorarlbergBankAg, + HypoBankBurgenlandAktiengesellschaft, + Ing, + Knab, + MarchfelderBank, + OberbankAg, + RaiffeisenBankengruppeOsterreich, + SchoellerbankAg, + SpardaBankWien, + VolksbankGruppe, + VolkskreditbankAg, + VrBankBraunau, + Moneyou, + Rabobank, + Regiobank, + Revolut, + SnsBank, + TriodosBank, + VanLanschot, +} + +impl TryFrom<&api_models::enums::BankNames> for StripeBankNames { + type Error = errors::ConnectorError; + fn try_from(bank: &api_models::enums::BankNames) -> Result { + Ok(match bank { + api_models::enums::BankNames::AbnAmro => Self::AbnAmro, + api_models::enums::BankNames::ArzteUndApothekerBank => Self::ArzteUndApothekerBank, + api_models::enums::BankNames::AsnBank => Self::AsnBank, + api_models::enums::BankNames::AustrianAnadiBankAg => Self::AustrianAnadiBankAg, + api_models::enums::BankNames::BankAustria => Self::BankAustria, + api_models::enums::BankNames::BankhausCarlSpangler => Self::BankhausCarlSpangler, + api_models::enums::BankNames::BankhausSchelhammerUndSchatteraAg => { + Self::BankhausSchelhammerUndSchatteraAg + } + api_models::enums::BankNames::BawagPskAg => Self::BawagPskAg, + api_models::enums::BankNames::BksBankAg => Self::BksBankAg, + api_models::enums::BankNames::BrullKallmusBankAg => Self::BrullKallmusBankAg, + api_models::enums::BankNames::BtvVierLanderBank => Self::BtvVierLanderBank, + api_models::enums::BankNames::Bunq => Self::Bunq, + api_models::enums::BankNames::CapitalBankGraweGruppeAg => { + Self::CapitalBankGraweGruppeAg + } + api_models::enums::BankNames::Dolomitenbank => Self::Dolomitenbank, + api_models::enums::BankNames::EasybankAg => Self::EasybankAg, + api_models::enums::BankNames::ErsteBankUndSparkassen => Self::ErsteBankUndSparkassen, + api_models::enums::BankNames::Handelsbanken => Self::Handelsbanken, + api_models::enums::BankNames::HypoAlpeadriabankInternationalAg => { + Self::HypoAlpeadriabankInternationalAg + } + api_models::enums::BankNames::HypoNoeLbFurNiederosterreichUWien => { + Self::HypoNoeLbFurNiederosterreichUWien + } + api_models::enums::BankNames::HypoOberosterreichSalzburgSteiermark => { + Self::HypoOberosterreichSalzburgSteiermark + } + api_models::enums::BankNames::HypoTirolBankAg => Self::HypoTirolBankAg, + api_models::enums::BankNames::HypoVorarlbergBankAg => Self::HypoVorarlbergBankAg, + api_models::enums::BankNames::HypoBankBurgenlandAktiengesellschaft => { + Self::HypoBankBurgenlandAktiengesellschaft + } + api_models::enums::BankNames::Ing => Self::Ing, + api_models::enums::BankNames::Knab => Self::Knab, + api_models::enums::BankNames::MarchfelderBank => Self::MarchfelderBank, + api_models::enums::BankNames::OberbankAg => Self::OberbankAg, + api_models::enums::BankNames::RaiffeisenBankengruppeOsterreich => { + Self::RaiffeisenBankengruppeOsterreich + } + api_models::enums::BankNames::Rabobank => Self::Rabobank, + api_models::enums::BankNames::Regiobank => Self::Regiobank, + api_models::enums::BankNames::Revolut => Self::Revolut, + api_models::enums::BankNames::SnsBank => Self::SnsBank, + api_models::enums::BankNames::TriodosBank => Self::TriodosBank, + api_models::enums::BankNames::VanLanschot => Self::VanLanschot, + api_models::enums::BankNames::Moneyou => Self::Moneyou, + api_models::enums::BankNames::SchoellerbankAg => Self::SchoellerbankAg, + api_models::enums::BankNames::SpardaBankWien => Self::SpardaBankWien, + api_models::enums::BankNames::VolksbankGruppe => Self::VolksbankGruppe, + api_models::enums::BankNames::VolkskreditbankAg => Self::VolkskreditbankAg, + api_models::enums::BankNames::VrBankBraunau => Self::VrBankBraunau, + _ => Err(errors::ConnectorError::NotSupported { + payment_method: String::from("BankRedirect"), + connector: "Stripe", + })?, + }) + } +} + fn validate_shipping_address_against_payment_method( shipping_address: &StripeShippingAddress, payment_method: &StripePaymentMethodType,