diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index bd2cadfa8f..a76dee4ff2 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -952,6 +952,7 @@ pub enum BankTransferData { /// The billing details for Multibanco billing_details: MultibancoBillingDetails, }, + Pix {}, } #[derive(serde::Deserialize, serde::Serialize, Debug, Clone, ToSchema, Eq, PartialEq)] @@ -1331,8 +1332,12 @@ pub enum NextActionData { ThirdPartySdkSessionToken { session_token: Option }, /// Contains url for Qr code image, this qr code has to be shown in sdk QrCodeInformation { + /// Hyperswitch generated image data source url #[schema(value_type = String)] - image_data_url: Url, + image_data_url: Option, + /// The url for Qr code given by the connector + #[schema(value_type = String)] + qr_code_url: Option, }, } @@ -1347,7 +1352,10 @@ pub struct BankTransferNextStepsData { #[derive(Clone, Debug, serde::Deserialize)] pub struct QrCodeNextStepsInstruction { - pub image_data_url: Url, + /// Hyperswitch generated image data source url + pub image_data_url: Option, + /// The url for Qr code given by the connector + pub qr_code_url: Option, } #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)] diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 21badc9b80..d64d7b4991 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -813,6 +813,7 @@ pub enum PaymentMethodType { OnlineBankingSlovakia, PayBright, Paypal, + Pix, Przelewy24, SamsungPay, Sepa, diff --git a/crates/common_enums/src/transformers.rs b/crates/common_enums/src/transformers.rs index 4ca4fadfe4..a1546e635a 100644 --- a/crates/common_enums/src/transformers.rs +++ b/crates/common_enums/src/transformers.rs @@ -1572,6 +1572,7 @@ impl From for PaymentMethod { PaymentMethodType::OnlineBankingThailand => Self::BankRedirect, PaymentMethodType::OnlineBankingPoland => Self::BankRedirect, PaymentMethodType::OnlineBankingSlovakia => Self::BankRedirect, + PaymentMethodType::Pix => Self::BankTransfer, PaymentMethodType::PayBright => Self::PayLater, PaymentMethodType::Paypal => Self::Wallet, PaymentMethodType::Przelewy24 => Self::BankRedirect, diff --git a/crates/router/src/compatibility/stripe/payment_intents/types.rs b/crates/router/src/compatibility/stripe/payment_intents/types.rs index cdbb6bffdf..09e8902e20 100644 --- a/crates/router/src/compatibility/stripe/payment_intents/types.rs +++ b/crates/router/src/compatibility/stripe/payment_intents/types.rs @@ -768,7 +768,10 @@ pub enum StripeNextAction { session_token: Option, }, QrCodeInformation { - image_data_url: url::Url, + /// Hyperswitch generated image data source url + image_data_url: Option, + /// The url for Qr code given by the connector + qr_code_url: Option, }, } @@ -793,9 +796,13 @@ pub(crate) fn into_stripe_next_action( payments::NextActionData::ThirdPartySdkSessionToken { session_token } => { StripeNextAction::ThirdPartySdkSessionToken { session_token } } - payments::NextActionData::QrCodeInformation { image_data_url } => { - StripeNextAction::QrCodeInformation { image_data_url } - } + payments::NextActionData::QrCodeInformation { + image_data_url, + qr_code_url, + } => StripeNextAction::QrCodeInformation { + image_data_url, + qr_code_url, + }, }) } diff --git a/crates/router/src/compatibility/stripe/setup_intents/types.rs b/crates/router/src/compatibility/stripe/setup_intents/types.rs index 8901683979..1b91bacd63 100644 --- a/crates/router/src/compatibility/stripe/setup_intents/types.rs +++ b/crates/router/src/compatibility/stripe/setup_intents/types.rs @@ -369,7 +369,10 @@ pub enum StripeNextAction { session_token: Option, }, QrCodeInformation { - image_data_url: url::Url, + /// Hyperswitch generated image data source url + image_data_url: Option, + /// The url for Qr code given by the connector + qr_code_url: Option, }, } @@ -394,9 +397,13 @@ pub(crate) fn into_stripe_next_action( payments::NextActionData::ThirdPartySdkSessionToken { session_token } => { StripeNextAction::ThirdPartySdkSessionToken { session_token } } - payments::NextActionData::QrCodeInformation { image_data_url } => { - StripeNextAction::QrCodeInformation { image_data_url } - } + payments::NextActionData::QrCodeInformation { + image_data_url, + qr_code_url, + } => StripeNextAction::QrCodeInformation { + image_data_url, + qr_code_url, + }, }) } diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index 62e4bac31a..7ac4773fa8 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -2,6 +2,7 @@ use api_models::payouts::PayoutMethodData; use api_models::{enums, payments, webhooks}; use cards::CardNumber; +use error_stack::ResultExt; use masking::PeekInterface; use reqwest::Url; use serde::{Deserialize, Serialize}; @@ -27,6 +28,7 @@ use crate::{ transformers::ForeignFrom, PaymentsAuthorizeData, }, + utils as crate_utils, }; type Error = error_stack::Report; @@ -234,7 +236,7 @@ pub struct AdyenThreeDS { #[serde(untagged)] pub enum AdyenPaymentResponse { Response(Response), - RedirectResponse(RedirectionResponse), + AdyenNextActionResponse(AdyenNextActionResponse), RedirectionErrorResponse(RedirectionErrorResponse), } @@ -259,16 +261,16 @@ pub struct RedirectionErrorResponse { #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct RedirectionResponse { +pub struct AdyenNextActionResponse { result_code: AdyenStatus, - action: AdyenRedirectionAction, + action: AdyenNextAction, refusal_reason: Option, refusal_reason_code: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct AdyenRedirectionAction { +pub struct AdyenNextAction { payment_method_type: String, url: Option, method: Option, @@ -276,6 +278,7 @@ pub struct AdyenRedirectionAction { type_of_response: ActionType, data: Option>, payment_data: Option, + qr_code_data: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -283,6 +286,8 @@ pub struct AdyenRedirectionAction { pub enum ActionType { Redirect, Await, + #[serde(rename = "qrCode")] + QrCode, } #[derive(Default, Debug, Clone, Serialize, Deserialize)] @@ -294,26 +299,26 @@ pub struct Amount { #[derive(Debug, Clone, Serialize)] #[serde(tag = "type")] pub enum AdyenPaymentMethod<'a> { - AdyenAffirm(Box), + AdyenAffirm(Box), AdyenCard(Box), - AdyenKlarna(Box), - AdyenPaypal(Box), - AfterPay(Box), - AlmaPayLater(Box), - AliPay(Box), - AliPayHk(Box), + AdyenKlarna(Box), + AdyenPaypal(Box), + AfterPay(Box), + AlmaPayLater(Box), + AliPay(Box), + AliPayHk(Box), ApplePay(Box), #[serde(rename = "atome")] Atome(Box), BancontactCard(Box), - Bizum(Box), + Bizum(Box), Blik(Box), - ClearPay(Box), - Dana(Box), + ClearPay(Box), + Dana(Box), Eps(Box>), #[serde(rename = "gcash")] Gcash(Box), - Giropay(Box), + Giropay(Box), Gpay(Box), #[serde(rename = "gopay_wallet")] GoPay(Box), @@ -322,31 +327,32 @@ pub enum AdyenPaymentMethod<'a> { Kakaopay(Box), Mandate(Box), Mbway(Box), - MobilePay(Box), + MobilePay(Box), #[serde(rename = "momo_wallet")] Momo(Box), #[serde(rename = "touchngo")] TouchNGo(Box), OnlineBankingCzechRepublic(Box), - OnlineBankingFinland(Box), + OnlineBankingFinland(Box), OnlineBankingPoland(Box), OnlineBankingSlovakia(Box), #[serde(rename = "molpay_ebanking_fpx_MY")] OnlineBankingFpx(Box), #[serde(rename = "molpay_ebanking_TH")] OnlineBankingThailand(Box), - PayBright(Box), - Sofort(Box), - Trustly(Box), - Walley(Box), - WeChatPayWeb(Box), + PayBright(Box), + Sofort(Box), + Trustly(Box), + Walley(Box), + WeChatPayWeb(Box), AchDirectDebit(Box), #[serde(rename = "sepadirectdebit")] SepaDirectDebit(Box), BacsDirectDebit(Box), SamsungPay(Box), - Twint(Box), - Vipps(Box), + Twint(Box), + Vipps(Box), + Pix(Box), } #[derive(Debug, Clone, Serialize)] @@ -386,11 +392,8 @@ pub struct MandateData { stored_payment_method_id: String, } -#[derive(Debug, Clone, Serialize)] -pub struct WeChatPayWebData { - #[serde(rename = "type")] - payment_type: PaymentType, -} +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AtomeData {} #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "camelCase")] @@ -404,11 +407,6 @@ pub struct BancontactCardData { holder_name: Secret, } -#[derive(Debug, Clone, Serialize)] -pub struct MobilePayData { - #[serde(rename = "type")] - payment_type: PaymentType, -} #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "camelCase")] pub struct MbwayData { @@ -417,12 +415,6 @@ pub struct MbwayData { telephone_number: Secret, } -#[derive(Debug, Clone, Serialize)] -pub struct WalleyData { - #[serde(rename = "type")] - payment_type: PaymentType, -} - #[derive(Debug, Clone, Serialize)] pub struct SamsungPayPmData { #[serde(rename = "type")] @@ -432,16 +424,11 @@ pub struct SamsungPayPmData { } #[derive(Debug, Clone, Serialize)] -pub struct PayBrightData { +pub struct PmdForPaymentType { #[serde(rename = "type")] payment_type: PaymentType, } -#[derive(Debug, Clone, Serialize)] -pub struct OnlineBankingFinlandData { - #[serde(rename = "type")] - payment_type: PaymentType, -} #[derive(Debug, Clone, Serialize)] pub struct OnlineBankingCzechRepublicData { #[serde(rename = "type")] @@ -659,13 +646,6 @@ pub struct BlikRedirectionData { blik_code: String, } -#[derive(Debug, Clone, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct BankRedirectionPMData { - #[serde(rename = "type")] - payment_type: PaymentType, -} - #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "camelCase")] pub struct BankRedirectionWithIssuer<'a> { @@ -724,23 +704,6 @@ pub enum CancelStatus { #[default] Processing, } -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct AdyenPaypal { - #[serde(rename = "type")] - payment_type: PaymentType, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct AliPayData { - #[serde(rename = "type")] - payment_type: PaymentType, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct AliPayHkData { - #[serde(rename = "type")] - payment_type: PaymentType, -} #[derive(Debug, Clone, Serialize, Deserialize)] pub struct GoPayData {} @@ -772,33 +735,6 @@ pub struct AdyenApplePay { apple_pay_token: Secret, } -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct DanaWalletData { - #[serde(rename = "type")] - payment_type: PaymentType, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TwintWalletData { - #[serde(rename = "type")] - payment_type: PaymentType, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct VippsWalletData { - #[serde(rename = "type")] - payment_type: PaymentType, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct AtomeData {} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct AdyenPayLaterData { - #[serde(rename = "type")] - payment_type: PaymentType, -} - // Refunds Request and Response #[derive(Default, Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -819,6 +755,12 @@ pub struct AdyenRefundResponse { status: String, } +#[derive(Clone, Debug, Serialize)] +pub struct QrCodeNextInstructions { + pub image_data_url: Option, + pub qr_code_url: Option, +} + pub struct AdyenAuthType { pub(super) api_key: String, pub(super) merchant_account: String, @@ -885,6 +827,7 @@ pub enum PaymentType { #[serde(rename = "directdebit_GB")] BacsDirectDebit, Samsungpay, + Pix, Twint, Vipps, } @@ -1039,6 +982,9 @@ impl<'a> TryFrom<&types::PaymentsAuthorizeRouterData> for AdyenPaymentRequest<'a api_models::payments::PaymentMethodData::BankDebit(ref bank_debit) => { AdyenPaymentRequest::try_from((item, bank_debit)) } + api_models::payments::PaymentMethodData::BankTransfer(ref bank_transfer) => { + AdyenPaymentRequest::try_from((item, bank_transfer.as_ref())) + } _ => Err(errors::ConnectorError::NotSupported { message: format!("{:?}", item.request.payment_method_type), connector: "Adyen", @@ -1370,19 +1316,19 @@ impl<'a> TryFrom<&api::WalletData> for AdyenPaymentMethod<'a> { Ok(AdyenPaymentMethod::ApplePay(Box::new(apple_pay_data))) } api_models::payments::WalletData::PaypalRedirect(_) => { - let wallet = AdyenPaypal { + let wallet = PmdForPaymentType { payment_type: PaymentType::Paypal, }; Ok(AdyenPaymentMethod::AdyenPaypal(Box::new(wallet))) } api_models::payments::WalletData::AliPayRedirect(_) => { - let alipay_data = AliPayData { + let alipay_data = PmdForPaymentType { payment_type: PaymentType::Alipay, }; Ok(AdyenPaymentMethod::AliPay(Box::new(alipay_data))) } api_models::payments::WalletData::AliPayHkRedirect(_) => { - let alipay_hk_data = AliPayHkData { + let alipay_hk_data = PmdForPaymentType { payment_type: PaymentType::AlipayHk, }; Ok(AdyenPaymentMethod::AliPayHk(Box::new(alipay_hk_data))) @@ -1415,13 +1361,13 @@ impl<'a> TryFrom<&api::WalletData> for AdyenPaymentMethod<'a> { Ok(AdyenPaymentMethod::Mbway(Box::new(mbway_data))) } api_models::payments::WalletData::MobilePayRedirect(_) => { - let data = MobilePayData { + let data = PmdForPaymentType { payment_type: PaymentType::MobilePay, }; Ok(AdyenPaymentMethod::MobilePay(Box::new(data))) } api_models::payments::WalletData::WeChatPayRedirect(_) => { - let data = WeChatPayWebData { + let data = PmdForPaymentType { payment_type: PaymentType::WeChatPayWeb, }; Ok(AdyenPaymentMethod::WeChatPayWeb(Box::new(data))) @@ -1434,19 +1380,19 @@ impl<'a> TryFrom<&api::WalletData> for AdyenPaymentMethod<'a> { Ok(AdyenPaymentMethod::SamsungPay(Box::new(data))) } api_models::payments::WalletData::TwintRedirect { .. } => { - let data = TwintWalletData { + let data = PmdForPaymentType { payment_type: PaymentType::Twint, }; Ok(AdyenPaymentMethod::Twint(Box::new(data))) } api_models::payments::WalletData::VippsRedirect { .. } => { - let data = VippsWalletData { + let data = PmdForPaymentType { payment_type: PaymentType::Vipps, }; Ok(AdyenPaymentMethod::Vipps(Box::new(data))) } api_models::payments::WalletData::DanaRedirect { .. } => { - let data = DanaWalletData { + let data = PmdForPaymentType { payment_type: PaymentType::Dana, }; Ok(AdyenPaymentMethod::Dana(Box::new(data))) @@ -1466,13 +1412,13 @@ impl<'a> TryFrom<(&api::PayLaterData, Option)> let (pay_later_data, country_code) = value; match pay_later_data { api_models::payments::PayLaterData::KlarnaRedirect { .. } => { - let klarna = AdyenPayLaterData { + let klarna = PmdForPaymentType { payment_type: PaymentType::Klarna, }; Ok(AdyenPaymentMethod::AdyenKlarna(Box::new(klarna))) } api_models::payments::PayLaterData::AffirmRedirect { .. } => Ok( - AdyenPaymentMethod::AdyenAffirm(Box::new(AdyenPayLaterData { + AdyenPaymentMethod::AdyenAffirm(Box::new(PmdForPaymentType { payment_type: PaymentType::Affirm, })), ), @@ -1483,11 +1429,11 @@ impl<'a> TryFrom<(&api::PayLaterData, Option)> | api_enums::CountryAlpha2::FR | api_enums::CountryAlpha2::ES | api_enums::CountryAlpha2::GB => { - Ok(AdyenPaymentMethod::ClearPay(Box::new(AdyenPayLaterData { + Ok(AdyenPaymentMethod::ClearPay(Box::new(PmdForPaymentType { payment_type: PaymentType::ClearPay, }))) } - _ => Ok(AdyenPaymentMethod::AfterPay(Box::new(AdyenPayLaterData { + _ => Ok(AdyenPaymentMethod::AfterPay(Box::new(PmdForPaymentType { payment_type: PaymentType::Afterpaytouch, }))), } @@ -1498,17 +1444,17 @@ impl<'a> TryFrom<(&api::PayLaterData, Option)> } } api_models::payments::PayLaterData::PayBrightRedirect { .. } => { - Ok(AdyenPaymentMethod::PayBright(Box::new(PayBrightData { + Ok(AdyenPaymentMethod::PayBright(Box::new(PmdForPaymentType { payment_type: PaymentType::PayBright, }))) } api_models::payments::PayLaterData::WalleyRedirect { .. } => { - Ok(AdyenPaymentMethod::Walley(Box::new(WalleyData { + Ok(AdyenPaymentMethod::Walley(Box::new(PmdForPaymentType { payment_type: PaymentType::Walley, }))) } api_models::payments::PayLaterData::AlmaRedirect { .. } => Ok( - AdyenPaymentMethod::AlmaPayLater(Box::new(AdyenPayLaterData { + AdyenPaymentMethod::AlmaPayLater(Box::new(PmdForPaymentType { payment_type: PaymentType::Alma, })), ), @@ -1563,7 +1509,7 @@ impl<'a> TryFrom<&api_models::payments::BankRedirectData> for AdyenPaymentMethod }, ))), api_models::payments::BankRedirectData::Bizum { .. } => { - Ok(AdyenPaymentMethod::Bizum(Box::new(BankRedirectionPMData { + Ok(AdyenPaymentMethod::Bizum(Box::new(PmdForPaymentType { payment_type: PaymentType::Bizum, }))) } @@ -1582,11 +1528,11 @@ impl<'a> TryFrom<&api_models::payments::BankRedirectData> for AdyenPaymentMethod .map(|adyen_bank_name| adyen_bank_name.0), })), ), - api_models::payments::BankRedirectData::Giropay { .. } => Ok( - AdyenPaymentMethod::Giropay(Box::new(BankRedirectionPMData { + api_models::payments::BankRedirectData::Giropay { .. } => { + Ok(AdyenPaymentMethod::Giropay(Box::new(PmdForPaymentType { payment_type: PaymentType::Giropay, - })), - ), + }))) + } api_models::payments::BankRedirectData::Ideal { bank_name, .. } => Ok( AdyenPaymentMethod::Ideal(Box::new(BankRedirectionWithIssuer { payment_type: PaymentType::Ideal, @@ -1605,7 +1551,7 @@ impl<'a> TryFrom<&api_models::payments::BankRedirectData> for AdyenPaymentMethod ))) } api_models::payments::BankRedirectData::OnlineBankingFinland { .. } => Ok( - AdyenPaymentMethod::OnlineBankingFinland(Box::new(OnlineBankingFinlandData { + AdyenPaymentMethod::OnlineBankingFinland(Box::new(PmdForPaymentType { payment_type: PaymentType::OnlineBankingFinland, })), ), @@ -1631,21 +1577,42 @@ impl<'a> TryFrom<&api_models::payments::BankRedirectData> for AdyenPaymentMethod issuer: OnlineBankingThailandIssuer::try_from(issuer)?, })), ), - api_models::payments::BankRedirectData::Sofort { .. } => Ok( - AdyenPaymentMethod::Sofort(Box::new(BankRedirectionPMData { + api_models::payments::BankRedirectData::Sofort { .. } => { + Ok(AdyenPaymentMethod::Sofort(Box::new(PmdForPaymentType { payment_type: PaymentType::Sofort, - })), - ), - api_models::payments::BankRedirectData::Trustly { .. } => Ok( - AdyenPaymentMethod::Trustly(Box::new(BankRedirectionPMData { + }))) + } + api_models::payments::BankRedirectData::Trustly { .. } => { + Ok(AdyenPaymentMethod::Trustly(Box::new(PmdForPaymentType { payment_type: PaymentType::Trustly, - })), - ), + }))) + } _ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()), } } } +impl<'a> TryFrom<&api_models::payments::BankTransferData> for AdyenPaymentMethod<'a> { + type Error = Error; + fn try_from( + bank_transfer_data: &api_models::payments::BankTransferData, + ) -> Result { + match bank_transfer_data { + api_models::payments::BankTransferData::Pix {} => { + Ok(AdyenPaymentMethod::Pix(Box::new(PmdForPaymentType { + payment_type: PaymentType::Pix, + }))) + } + api_models::payments::BankTransferData::AchBankTransfer { .. } + | api_models::payments::BankTransferData::SepaBankTransfer { .. } + | api_models::payments::BankTransferData::BacsBankTransfer { .. } + | api_models::payments::BankTransferData::MultibancoBankTransfer { .. } => { + Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()) + } + } + } +} + impl<'a> TryFrom<( &types::PaymentsAuthorizeRouterData, @@ -1822,6 +1789,52 @@ impl<'a> } } +impl<'a> + TryFrom<( + &types::PaymentsAuthorizeRouterData, + &api_models::payments::BankTransferData, + )> for AdyenPaymentRequest<'a> +{ + type Error = Error; + + fn try_from( + value: ( + &types::PaymentsAuthorizeRouterData, + &api_models::payments::BankTransferData, + ), + ) -> Result { + let (item, bank_transfer_data) = value; + let amount = get_amount_data(item); + let auth_type = AdyenAuthType::try_from(&item.connector_auth_type)?; + let shopper_interaction = AdyenShopperInteraction::from(item); + let return_url = item.request.get_return_url()?; + let payment_method = AdyenPaymentMethod::try_from(bank_transfer_data)?; + let request = AdyenPaymentRequest { + amount, + merchant_account: auth_type.merchant_account, + payment_method, + reference: item.payment_id.to_string(), + return_url, + browser_info: None, + shopper_interaction, + recurring_processing_model: None, + additional_data: None, + shopper_name: None, + shopper_locale: None, + shopper_email: item.request.email.clone(), + telephone_number: None, + billing_address: None, + delivery_address: None, + country_code: None, + line_items: None, + shopper_reference: None, + store_payment_method: None, + channel: None, + }; + Ok(request) + } +} + impl<'a> TryFrom<( &types::PaymentsAuthorizeRouterData, @@ -2101,8 +2114,8 @@ pub fn get_adyen_response( Ok((status, error, payments_response_data)) } -pub fn get_redirection_response( - response: RedirectionResponse, +pub fn get_next_action_response( + response: AdyenNextActionResponse, is_manual_capture: bool, status_code: u16, ) -> errors::CustomResult< @@ -2113,15 +2126,19 @@ pub fn get_redirection_response( ), errors::ConnectorError, > { - let status = - storage_enums::AttemptStatus::foreign_from((is_manual_capture, response.result_code)); + let status = storage_enums::AttemptStatus::foreign_from(( + is_manual_capture, + response.result_code.to_owned(), + )); let error = if response.refusal_reason.is_some() || response.refusal_reason_code.is_some() { Some(types::ErrorResponse { code: response .refusal_reason_code + .to_owned() .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()), message: response .refusal_reason + .to_owned() .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()), reason: None, status_code, @@ -2130,29 +2147,27 @@ pub fn get_redirection_response( None }; - let redirection_data = response.action.url.map(|url| { - let form_fields = response.action.data.unwrap_or_else(|| { - std::collections::HashMap::from_iter( - url.query_pairs() - .map(|(key, value)| (key.to_string(), value.to_string())), - ) - }); - services::RedirectForm::Form { - endpoint: url.to_string(), - method: response.action.method.unwrap_or(services::Method::Get), - form_fields, - } - }); + let redirection_data = match response.action.type_of_response { + ActionType::QrCode => None, + _ => response + .action + .url + .to_owned() + .map(|url| services::RedirectForm::from((url, services::Method::Get))), + }; + + let connector_metadata = get_connector_metadata(response)?; // We don't get connector transaction id for redirections in Adyen. let payments_response_data = types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, redirection_data, mandate_reference: None, - connector_metadata: None, + connector_metadata, network_txn_id: None, connector_response_reference_id: None, }; + Ok((status, error, payments_response_data)) } @@ -2188,6 +2203,46 @@ pub fn get_redirection_error_response( Ok((status, error, payments_response_data)) } +pub fn get_connector_metadata( + response: AdyenNextActionResponse, +) -> errors::CustomResult, errors::ConnectorError> { + let connector_metadata = match response.action.type_of_response { + ActionType::QrCode => { + let metadata = get_qr_code_metadata(response); + Some(metadata) + } + _ => None, + } + .transpose() + .change_context(errors::ConnectorError::ResponseHandlingFailed)?; + + Ok(connector_metadata) +} + +pub fn get_qr_code_metadata( + response: AdyenNextActionResponse, +) -> errors::CustomResult { + let image_data = response + .action + .qr_code_data + .map(crate_utils::QrImage::new_from_data) + .transpose() + .change_context(errors::ConnectorError::ResponseHandlingFailed)?; + + let image_data_url = + image_data.and_then(|image_data| Url::parse(image_data.data.as_str()).ok()); + + let qr_code_instructions = QrCodeNextInstructions { + image_data_url, + qr_code_url: response.action.url, + }; + + common_utils::ext_traits::Encode::::encode_to_value( + &qr_code_instructions, + ) + .change_context(errors::ConnectorError::ResponseHandlingFailed) +} + impl TryFrom<( types::ResponseRouterData, @@ -2207,8 +2262,8 @@ impl AdyenPaymentResponse::Response(response) => { get_adyen_response(response, is_manual_capture, item.http_code)? } - AdyenPaymentResponse::RedirectResponse(response) => { - get_redirection_response(response, is_manual_capture, item.http_code)? + AdyenPaymentResponse::AdyenNextActionResponse(response) => { + get_next_action_response(response, is_manual_capture, item.http_code)? } AdyenPaymentResponse::RedirectionErrorResponse(response) => { get_redirection_error_response(response, is_manual_capture, item.http_code)? diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 9d9906f0a2..245ee39918 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -1232,12 +1232,13 @@ fn create_stripe_payment_method( billing_details, )) } + payments::BankTransferData::Pix {} => Err(errors::ConnectorError::NotImplemented( + "this payment method".to_string(), + ) + .into()), } } - _ => Err(errors::ConnectorError::NotImplemented( - "this payment method for stripe".to_string(), - ) - .into()), + _ => Err(errors::ConnectorError::NotImplemented("payment method".to_string()).into()), } } @@ -1660,7 +1661,6 @@ pub struct SepaAndBacsBankTransferInstructions { pub receiver: SepaAndBacsReceiver, } -#[serde_with::skip_serializing_none] #[derive(Clone, Debug, Serialize)] pub struct WechatPayNextInstructions { pub image_data_url: Url, @@ -2900,6 +2900,9 @@ impl payment_method_type: StripePaymentMethodType::CustomerBalance, })), )), + payments::BankTransferData::Pix {} => Err( + errors::ConnectorError::NotImplemented("payment method".to_string()).into(), + ), } } api::PaymentMethodData::MandatePayment diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 54c2e1f947..b4447c8524 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -376,6 +376,7 @@ where if payment_intent.status == enums::IntentStatus::RequiresCustomerAction || bank_transfer_next_steps.is_some() + || next_action_containing_qr_code.is_some() { next_action_response = bank_transfer_next_steps .map(|bank_transfer| { @@ -386,6 +387,7 @@ where .or(next_action_containing_qr_code.map(|qr_code_data| { api_models::payments::NextActionData::QrCodeInformation { image_data_url: qr_code_data.image_data_url, + qr_code_url: qr_code_data.qr_code_url, } })) .or(redirection_data.map(|_| { @@ -661,24 +663,19 @@ impl ForeignFrom for api::ephemeral_key::EphemeralK pub fn bank_transfer_next_steps_check( payment_attempt: storage::PaymentAttempt, ) -> RouterResult> { - let bank_transfer_next_step = if let Some(diesel_models::enums::PaymentMethod::BankTransfer) = - payment_attempt.payment_method - { - let bank_transfer_next_steps: Option = - payment_attempt - .connector_metadata - .map(|metadata| { - metadata - .parse_value("NextStepsRequirements") - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed to parse the Value to NextRequirements struct") - }) - .transpose()?; - bank_transfer_next_steps - } else { - None - }; - Ok(bank_transfer_next_step) + let bank_transfer_next_steps: Result< + Option, + _, + > = payment_attempt + .connector_metadata + .map(|metadata| { + metadata + .parse_value("BankTransferNextStepsData") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to parse the Value to NextRequirements struct") + }) + .transpose(); + Ok(bank_transfer_next_steps.ok().flatten()) } pub fn change_order_details_to_new_type( diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index 6d3fa897af..b1aa46472b 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -218,7 +218,9 @@ impl ForeignFrom for api_enums::PaymentMethod { } api_enums::PaymentMethodType::Evoucher | api_enums::PaymentMethodType::ClassicReward => Self::Reward, - api_enums::PaymentMethodType::Multibanco => Self::BankTransfer, + api_enums::PaymentMethodType::Multibanco | api_enums::PaymentMethodType::Pix => { + Self::BankTransfer + } } } } diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 11ef305ffa..dcffea6c7e 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -3197,6 +3197,17 @@ } } } + }, + { + "type": "object", + "required": [ + "pix" + ], + "properties": { + "pix": { + "type": "object" + } + } } ] }, @@ -6249,11 +6260,17 @@ "description": "Contains url for Qr code image, this qr code has to be shown in sdk", "required": [ "image_data_url", + "qr_code_url", "type" ], "properties": { "image_data_url": { - "type": "string" + "type": "string", + "description": "Hyperswitch generated image data source url" + }, + "qr_code_url": { + "type": "string", + "description": "The url for Qr code given by the connector" }, "type": { "type": "string", @@ -7232,6 +7249,7 @@ "online_banking_slovakia", "pay_bright", "paypal", + "pix", "przelewy24", "samsung_pay", "sepa",