diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 5f9618738b2..cd405e3ca98 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -1664,7 +1664,10 @@ impl GetPaymentMethodType for CryptoData { impl GetPaymentMethodType for UpiData { fn get_payment_method_type(&self) -> api_enums::PaymentMethodType { - api_enums::PaymentMethodType::UpiCollect + match self { + Self::UpiCollect(_) => api_enums::PaymentMethodType::UpiCollect, + Self::UpiIntent(_) => api_enums::PaymentMethodType::UpiIntent, + } } } impl GetPaymentMethodType for VoucherData { @@ -2119,11 +2122,21 @@ pub struct CryptoData { #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize, ToSchema)] #[serde(rename_all = "snake_case")] -pub struct UpiData { +pub enum UpiData { + UpiCollect(UpiCollectData), + UpiIntent(UpiIntentData), +} + +#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub struct UpiCollectData { #[schema(value_type = Option, example = "successtest@iata")] pub vpa_id: Option>, } +#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize, ToSchema)] +pub struct UpiIntentData {} + #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize, ToSchema)] pub struct SofortBilling { /// The country associated with the billing @@ -2960,6 +2973,11 @@ pub enum NextActionData { /// The url for Qr code given by the connector qr_code_url: Option, }, + /// Contains url to fetch Qr code data + FetchQrCodeInformation { + #[schema(value_type = String)] + qr_code_fetch_url: Url, + }, /// Contains the download url and the reference number for transaction DisplayVoucherInformation { #[schema(value_type = String)] @@ -3045,6 +3063,11 @@ pub struct SdkNextActionData { pub next_action: NextActionCall, } +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)] +pub struct FetchQrCodeInformation { + pub qr_code_fetch_url: Url, +} + #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)] pub struct BankTransferNextStepsData { /// The instructions for performing a bank transfer diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index dc4ca6b2cb3..3df291d5681 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -1430,6 +1430,7 @@ pub enum PaymentMethodType { Trustly, Twint, UpiCollect, + UpiIntent, Vipps, Venmo, Walley, diff --git a/crates/common_enums/src/transformers.rs b/crates/common_enums/src/transformers.rs index faca2579c0a..cb37180c987 100644 --- a/crates/common_enums/src/transformers.rs +++ b/crates/common_enums/src/transformers.rs @@ -1854,6 +1854,7 @@ impl From for PaymentMethod { PaymentMethodType::Trustly => Self::BankRedirect, PaymentMethodType::Twint => Self::Wallet, PaymentMethodType::UpiCollect => Self::Upi, + PaymentMethodType::UpiIntent => Self::Upi, PaymentMethodType::Vipps => Self::Wallet, PaymentMethodType::Venmo => Self::Wallet, PaymentMethodType::Walley => Self::PayLater, diff --git a/crates/euclid/src/frontend/dir/enums.rs b/crates/euclid/src/frontend/dir/enums.rs index c5f864bf770..133fee18c0d 100644 --- a/crates/euclid/src/frontend/dir/enums.rs +++ b/crates/euclid/src/frontend/dir/enums.rs @@ -268,6 +268,7 @@ pub enum CryptoType { #[strum(serialize_all = "snake_case")] pub enum UpiType { UpiCollect, + UpiIntent, } #[derive( diff --git a/crates/euclid/src/frontend/dir/lowering.rs b/crates/euclid/src/frontend/dir/lowering.rs index f6b156bf909..cc4c9be2a2d 100644 --- a/crates/euclid/src/frontend/dir/lowering.rs +++ b/crates/euclid/src/frontend/dir/lowering.rs @@ -75,6 +75,7 @@ impl From for global_enums::PaymentMethodType { fn from(value: enums::UpiType) -> Self { match value { enums::UpiType::UpiCollect => Self::UpiCollect, + enums::UpiType::UpiIntent => Self::UpiIntent, } } } diff --git a/crates/euclid/src/frontend/dir/transformers.rs b/crates/euclid/src/frontend/dir/transformers.rs index bcc951b0057..052561b5aab 100644 --- a/crates/euclid/src/frontend/dir/transformers.rs +++ b/crates/euclid/src/frontend/dir/transformers.rs @@ -109,6 +109,7 @@ impl IntoDirValue for (global_enums::PaymentMethodType, global_enums::PaymentMet } global_enums::PaymentMethodType::Evoucher => Ok(dirval!(RewardType = Evoucher)), global_enums::PaymentMethodType::UpiCollect => Ok(dirval!(UpiType = UpiCollect)), + global_enums::PaymentMethodType::UpiIntent => Ok(dirval!(UpiType = UpiIntent)), global_enums::PaymentMethodType::SamsungPay => Ok(dirval!(WalletType = SamsungPay)), global_enums::PaymentMethodType::GoPay => Ok(dirval!(WalletType = GoPay)), global_enums::PaymentMethodType::KakaoPay => Ok(dirval!(WalletType = KakaoPay)), diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs index 9dc85c103e9..7517918ed95 100644 --- a/crates/hyperswitch_domain_models/src/payment_method_data.rs +++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs @@ -289,10 +289,20 @@ pub struct CryptoData { #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "snake_case")] -pub struct UpiData { +pub enum UpiData { + UpiCollect(UpiCollectData), + UpiIntent(UpiIntentData), +} + +#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "snake_case")] +pub struct UpiCollectData { pub vpa_id: Option>, } +#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)] +pub struct UpiIntentData {} + #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "snake_case")] pub enum VoucherData { @@ -690,8 +700,12 @@ impl From for CryptoData { impl From for UpiData { fn from(value: api_models::payments::UpiData) -> Self { - let api_models::payments::UpiData { vpa_id } = value; - Self { vpa_id } + match value { + api_models::payments::UpiData::UpiCollect(upi) => { + Self::UpiCollect(UpiCollectData { vpa_id: upi.vpa_id }) + } + api_models::payments::UpiData::UpiIntent(_) => Self::UpiIntent(UpiIntentData {}), + } } } diff --git a/crates/kgraph_utils/src/mca.rs b/crates/kgraph_utils/src/mca.rs index b32c8c23bd9..76c7381bf22 100644 --- a/crates/kgraph_utils/src/mca.rs +++ b/crates/kgraph_utils/src/mca.rs @@ -77,7 +77,6 @@ fn get_dir_value_payment_method( api_enums::PaymentMethodType::ClassicReward => Ok(dirval!(RewardType = ClassicReward)), api_enums::PaymentMethodType::Evoucher => Ok(dirval!(RewardType = Evoucher)), - api_enums::PaymentMethodType::UpiCollect => Ok(dirval!(UpiType = UpiCollect)), api_enums::PaymentMethodType::SamsungPay => Ok(dirval!(WalletType = SamsungPay)), api_enums::PaymentMethodType::GoPay => Ok(dirval!(WalletType = GoPay)), api_enums::PaymentMethodType::KakaoPay => Ok(dirval!(WalletType = KakaoPay)), @@ -133,6 +132,8 @@ fn get_dir_value_payment_method( api_enums::PaymentMethodType::Oxxo => Ok(dirval!(VoucherType = Oxxo)), api_enums::PaymentMethodType::CardRedirect => Ok(dirval!(CardRedirectType = CardRedirect)), api_enums::PaymentMethodType::Venmo => Ok(dirval!(WalletType = Venmo)), + api_enums::PaymentMethodType::UpiIntent => Ok(dirval!(UpiType = UpiIntent)), + api_enums::PaymentMethodType::UpiCollect => Ok(dirval!(UpiType = UpiCollect)), } } diff --git a/crates/kgraph_utils/src/transformers.rs b/crates/kgraph_utils/src/transformers.rs index 3e43a4324f9..1bff0eac0d7 100644 --- a/crates/kgraph_utils/src/transformers.rs +++ b/crates/kgraph_utils/src/transformers.rs @@ -230,6 +230,7 @@ impl IntoDirValue for (api_enums::PaymentMethodType, api_enums::PaymentMethod) { api_enums::PaymentMethodType::ClassicReward => Ok(dirval!(RewardType = ClassicReward)), api_enums::PaymentMethodType::Evoucher => Ok(dirval!(RewardType = Evoucher)), api_enums::PaymentMethodType::UpiCollect => Ok(dirval!(UpiType = UpiCollect)), + api_enums::PaymentMethodType::UpiIntent => Ok(dirval!(UpiType = UpiIntent)), api_enums::PaymentMethodType::SamsungPay => Ok(dirval!(WalletType = SamsungPay)), api_enums::PaymentMethodType::GoPay => Ok(dirval!(WalletType = GoPay)), api_enums::PaymentMethodType::KakaoPay => Ok(dirval!(WalletType = KakaoPay)), diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index c67ea2d2746..fd0688ed293 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -291,6 +291,8 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::CryptoData, api_models::payments::RewardData, api_models::payments::UpiData, + api_models::payments::UpiCollectData, + api_models::payments::UpiIntentData, api_models::payments::VoucherData, api_models::payments::BoletoVoucherData, api_models::payments::AlfamartVoucherData, diff --git a/crates/router/src/compatibility/stripe/payment_intents/types.rs b/crates/router/src/compatibility/stripe/payment_intents/types.rs index 5e8c9ea08c0..0526eacb2e8 100644 --- a/crates/router/src/compatibility/stripe/payment_intents/types.rs +++ b/crates/router/src/compatibility/stripe/payment_intents/types.rs @@ -141,10 +141,10 @@ impl From for payments::WalletData { } impl From for payments::UpiData { - fn from(upi: StripeUpi) -> Self { - Self { - vpa_id: Some(upi.vpa_id), - } + fn from(upi_data: StripeUpi) -> Self { + Self::UpiCollect(payments::UpiCollectData { + vpa_id: Some(upi_data.vpa_id), + }) } } @@ -315,6 +315,18 @@ impl TryFrom for payments::PaymentsRequest { let amount = item.amount.map(|amount| MinorUnit::new(amount).into()); + let payment_method_data = item.payment_method_data.as_ref().map(|pmd| { + let payment_method_data = match pmd.payment_method_details.as_ref() { + Some(spmd) => Some(payments::PaymentMethodData::from(spmd.to_owned())), + None => get_pmd_based_on_payment_method_type(item.payment_method_types), + }; + + payments::PaymentMethodDataRequest { + payment_method_data, + billing: pmd.billing_details.clone().map(payments::Address::from), + } + }); + let request = Ok(Self { payment_id: item.id.map(payments::PaymentIdType::PaymentIntentId), amount, @@ -334,16 +346,7 @@ impl TryFrom for payments::PaymentsRequest { phone: item.shipping.as_ref().and_then(|s| s.phone.clone()), description: item.description, return_url: item.return_url, - payment_method_data: item.payment_method_data.as_ref().and_then(|pmd| { - pmd.payment_method_details - .as_ref() - .map(|spmd| payments::PaymentMethodDataRequest { - payment_method_data: Some(payments::PaymentMethodData::from( - spmd.to_owned(), - )), - billing: pmd.billing_details.clone().map(payments::Address::from), - }) - }), + payment_method_data, payment_method: item .payment_method_data .as_ref() @@ -816,6 +819,9 @@ pub enum StripeNextAction { display_to_timestamp: Option, qr_code_url: Option, }, + FetchQrCodeInformation { + qr_code_fetch_url: url::Url, + }, DisplayVoucherInformation { voucher_details: payments::VoucherNextStepData, }, @@ -858,6 +864,9 @@ pub(crate) fn into_stripe_next_action( display_to_timestamp, qr_code_url, }, + payments::NextActionData::FetchQrCodeInformation { qr_code_fetch_url } => { + StripeNextAction::FetchQrCodeInformation { qr_code_fetch_url } + } payments::NextActionData::DisplayVoucherInformation { voucher_details } => { StripeNextAction::DisplayVoucherInformation { voucher_details } } @@ -884,3 +893,15 @@ pub(crate) fn into_stripe_next_action( pub struct StripePaymentRetrieveBody { pub client_secret: Option, } + +//To handle payment types that have empty payment method data +fn get_pmd_based_on_payment_method_type( + payment_method_type: Option, +) -> Option { + match payment_method_type { + Some(api_enums::PaymentMethodType::UpiIntent) => Some(payments::PaymentMethodData::Upi( + payments::UpiData::UpiIntent(payments::UpiIntentData {}), + )), + _ => None, + } +} diff --git a/crates/router/src/compatibility/stripe/setup_intents/types.rs b/crates/router/src/compatibility/stripe/setup_intents/types.rs index bbcafb65e9f..9a1cf58f11b 100644 --- a/crates/router/src/compatibility/stripe/setup_intents/types.rs +++ b/crates/router/src/compatibility/stripe/setup_intents/types.rs @@ -382,6 +382,9 @@ pub enum StripeNextAction { display_to_timestamp: Option, qr_code_url: Option, }, + FetchQrCodeInformation { + qr_code_fetch_url: url::Url, + }, DisplayVoucherInformation { voucher_details: payments::VoucherNextStepData, }, @@ -424,6 +427,9 @@ pub(crate) fn into_stripe_next_action( display_to_timestamp, qr_code_url, }, + payments::NextActionData::FetchQrCodeInformation { qr_code_fetch_url } => { + StripeNextAction::FetchQrCodeInformation { qr_code_fetch_url } + } payments::NextActionData::DisplayVoucherInformation { voucher_details } => { StripeNextAction::DisplayVoucherInformation { voucher_details } } diff --git a/crates/router/src/connector/adyen.rs b/crates/router/src/connector/adyen.rs index e2effb2e325..1a63dc50c9e 100644 --- a/crates/router/src/connector/adyen.rs +++ b/crates/router/src/connector/adyen.rs @@ -214,7 +214,8 @@ impl ConnectorValidation for Adyen { | PaymentMethodType::SamsungPay | PaymentMethodType::Evoucher | PaymentMethodType::Cashapp - | PaymentMethodType::UpiCollect => { + | PaymentMethodType::UpiCollect + | PaymentMethodType::UpiIntent => { capture_method_not_supported!(connector, capture_method, payment_method_type) } }, diff --git a/crates/router/src/connector/iatapay/transformers.rs b/crates/router/src/connector/iatapay/transformers.rs index 5daa33ab944..b36792e90ca 100644 --- a/crates/router/src/connector/iatapay/transformers.rs +++ b/crates/router/src/connector/iatapay/transformers.rs @@ -1,7 +1,8 @@ use std::collections::HashMap; use api_models::enums::PaymentMethod; -use common_utils::errors::CustomResult; +use common_utils::{errors::CustomResult, ext_traits::Encode}; +use error_stack::ResultExt; use masking::{Secret, SwitchStrategy}; use serde::{Deserialize, Serialize}; @@ -84,6 +85,13 @@ pub struct PayerInfo { token_id: Secret, } +#[derive(Debug, Serialize)] +#[serde(rename_all = "UPPERCASE")] +pub enum PreferredCheckoutMethod { + Vpa, + Qr, +} + #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct IatapayPaymentsRequest { @@ -95,7 +103,9 @@ pub struct IatapayPaymentsRequest { locale: String, redirect_urls: RedirectUrls, notification_url: String, + #[serde(skip_serializing_if = "Option::is_none")] payer_info: Option, + preferred_checkout_method: Option, } impl @@ -136,24 +146,31 @@ impl | PaymentMethod::GiftCard => item.router_data.get_billing_country()?.to_string(), }; let return_url = item.router_data.get_return_url()?; - let payer_info = match item.router_data.request.payment_method_data.clone() { - domain::PaymentMethodData::Upi(upi_data) => upi_data.vpa_id.map(|id| PayerInfo { - token_id: id.switch_strategy(), - }), - domain::PaymentMethodData::Card(_) - | domain::PaymentMethodData::CardRedirect(_) - | domain::PaymentMethodData::Wallet(_) - | domain::PaymentMethodData::PayLater(_) - | domain::PaymentMethodData::BankRedirect(_) - | domain::PaymentMethodData::BankDebit(_) - | domain::PaymentMethodData::BankTransfer(_) - | domain::PaymentMethodData::Crypto(_) - | domain::PaymentMethodData::MandatePayment - | domain::PaymentMethodData::Reward - | domain::PaymentMethodData::Voucher(_) - | domain::PaymentMethodData::GiftCard(_) - | domain::PaymentMethodData::CardToken(_) => None, - }; + let (payer_info, preferred_checkout_method) = + match item.router_data.request.payment_method_data.clone() { + domain::PaymentMethodData::Upi(upi_type) => match upi_type { + domain::UpiData::UpiCollect(upi_data) => ( + upi_data.vpa_id.map(|id| PayerInfo { + token_id: id.switch_strategy(), + }), + Some(PreferredCheckoutMethod::Vpa), + ), + domain::UpiData::UpiIntent(_) => (None, Some(PreferredCheckoutMethod::Qr)), + }, + domain::PaymentMethodData::Card(_) + | domain::PaymentMethodData::CardRedirect(_) + | domain::PaymentMethodData::Wallet(_) + | domain::PaymentMethodData::PayLater(_) + | domain::PaymentMethodData::BankRedirect(_) + | domain::PaymentMethodData::BankDebit(_) + | domain::PaymentMethodData::BankTransfer(_) + | domain::PaymentMethodData::Crypto(_) + | domain::PaymentMethodData::MandatePayment + | domain::PaymentMethodData::Reward + | domain::PaymentMethodData::Voucher(_) + | domain::PaymentMethodData::GiftCard(_) + | domain::PaymentMethodData::CardToken(_) => (None, None), + }; let payload = Self { merchant_id: IatapayAuthType::try_from(&item.router_data.connector_auth_type)? .merchant_id, @@ -165,6 +182,7 @@ impl redirect_urls: get_redirect_url(return_url), payer_info, notification_url: item.router_data.request.get_webhook_url()?, + preferred_checkout_method, }; Ok(payload) } @@ -291,8 +309,46 @@ fn get_iatpay_response( }; let connector_response_reference_id = response.merchant_payment_id.or(response.iata_payment_id); - let payment_response_data = response.checkout_methods.map_or( - types::PaymentsResponseData::TransactionResponse { + let payment_response_data = match response.checkout_methods { + Some(checkout_methods) => { + let (connector_metadata, redirection_data) = + match checkout_methods.redirect.redirect_url.ends_with("qr") { + true => { + let qr_code_info = api_models::payments::FetchQrCodeInformation { + qr_code_fetch_url: url::Url::parse( + &checkout_methods.redirect.redirect_url, + ) + .change_context(errors::ConnectorError::ResponseHandlingFailed)?, + }; + ( + Some(qr_code_info.encode_to_value()) + .transpose() + .change_context(errors::ConnectorError::ResponseHandlingFailed)?, + None, + ) + } + false => ( + None, + Some(services::RedirectForm::Form { + endpoint: checkout_methods.redirect.redirect_url, + method: services::Method::Get, + form_fields, + }), + ), + }; + + types::PaymentsResponseData::TransactionResponse { + resource_id: id, + redirection_data, + mandate_reference: None, + connector_metadata, + network_txn_id: None, + connector_response_reference_id: connector_response_reference_id.clone(), + incremental_authorization_allowed: None, + charge_id: None, + } + } + None => types::PaymentsResponseData::TransactionResponse { resource_id: id.clone(), redirection_data: None, mandate_reference: None, @@ -302,21 +358,8 @@ fn get_iatpay_response( incremental_authorization_allowed: None, charge_id: None, }, - |checkout_methods| types::PaymentsResponseData::TransactionResponse { - resource_id: id, - redirection_data: Some(services::RedirectForm::Form { - endpoint: checkout_methods.redirect.redirect_url, - method: services::Method::Get, - form_fields, - }), - mandate_reference: None, - connector_metadata: None, - network_txn_id: None, - connector_response_reference_id: connector_response_reference_id.clone(), - incremental_authorization_allowed: None, - charge_id: None, - }, - ); + }; + Ok((status, error, payment_response_data)) } diff --git a/crates/router/src/connector/klarna.rs b/crates/router/src/connector/klarna.rs index 5c174c69e3b..48b6616a64e 100644 --- a/crates/router/src/connector/klarna.rs +++ b/crates/router/src/connector/klarna.rs @@ -398,6 +398,7 @@ impl | common_enums::PaymentMethodType::Trustly | common_enums::PaymentMethodType::Twint | common_enums::PaymentMethodType::UpiCollect + | common_enums::PaymentMethodType::UpiIntent | common_enums::PaymentMethodType::Venmo | common_enums::PaymentMethodType::Vipps | common_enums::PaymentMethodType::Walley diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 55b0d7f4675..83bca39626f 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -675,6 +675,7 @@ impl TryFrom for StripePaymentMethodType { | enums::PaymentMethodType::Paypal | enums::PaymentMethodType::Pix | enums::PaymentMethodType::UpiCollect + | enums::PaymentMethodType::UpiIntent | enums::PaymentMethodType::Cashapp | enums::PaymentMethodType::Oxxo => Err(errors::ConnectorError::NotImplemented( connector_util::get_unimplemented_payment_method_error_message("stripe"), diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index a39f0deb3ca..db99ff590cd 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -1009,6 +1009,7 @@ impl PaymentRedirectFlow for PaymentRedirectCompleteAuthorize { api_models::payments::NextActionData::DisplayBankTransferInformation { .. } => None, api_models::payments::NextActionData::ThirdPartySdkSessionToken { .. } => None, api_models::payments::NextActionData::QrCodeInformation{..} => None, + api_models::payments::NextActionData::FetchQrCodeInformation{..} => None, api_models::payments::NextActionData::DisplayVoucherInformation{ .. } => None, api_models::payments::NextActionData::WaitScreenInformation{..} => None, api_models::payments::NextActionData::ThreeDsInvoke{..} => None, diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 973ca4b2266..6e3f6a9bf6e 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -2338,7 +2338,7 @@ pub fn validate_payment_method_type_against_payment_method( ), api_enums::PaymentMethod::Upi => matches!( payment_method_type, - api_enums::PaymentMethodType::UpiCollect + api_enums::PaymentMethodType::UpiCollect | api_enums::PaymentMethodType::UpiIntent ), api_enums::PaymentMethod::Voucher => matches!( payment_method_type, @@ -4252,9 +4252,9 @@ pub fn get_key_params_for_surcharge_details( )), api_models::payments::PaymentMethodData::MandatePayment => None, api_models::payments::PaymentMethodData::Reward => None, - api_models::payments::PaymentMethodData::Upi(_) => Some(( + api_models::payments::PaymentMethodData::Upi(upi_data) => Some(( common_enums::PaymentMethod::Upi, - common_enums::PaymentMethodType::UpiCollect, + upi_data.get_payment_method_type(), None, )), api_models::payments::PaymentMethodData::Voucher(voucher) => Some(( diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 7f6b0cc1f61..8f6af2f89bc 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -541,6 +541,9 @@ where let papal_sdk_next_action = paypal_sdk_next_steps_check(payment_attempt.clone())?; + let next_action_containing_fetch_qr_code_url = + fetch_qr_code_url_next_steps_check(payment_attempt.clone())?; + let next_action_containing_wait_screen = wait_screen_next_steps_check(payment_attempt.clone())?; @@ -550,6 +553,7 @@ where || next_action_containing_qr_code_url.is_some() || next_action_containing_wait_screen.is_some() || papal_sdk_next_action.is_some() + || next_action_containing_fetch_qr_code_url.is_some() || payment_data.authentication.is_some() { next_action_response = bank_transfer_next_steps @@ -566,6 +570,11 @@ where .or(next_action_containing_qr_code_url.map(|qr_code_data| { api_models::payments::NextActionData::foreign_from(qr_code_data) })) + .or(next_action_containing_fetch_qr_code_url.map(|fetch_qr_code_data| { + api_models::payments::NextActionData::FetchQrCodeInformation { + qr_code_fetch_url: fetch_qr_code_data.qr_code_fetch_url + } + })) .or(papal_sdk_next_action.map(|paypal_next_action_data| { api_models::payments::NextActionData::InvokeSdkClient{ next_action_data: paypal_next_action_data @@ -899,6 +908,18 @@ pub fn paypal_sdk_next_steps_check( Ok(paypal_next_steps) } +pub fn fetch_qr_code_url_next_steps_check( + payment_attempt: storage::PaymentAttempt, +) -> RouterResult> { + let qr_code_steps: Option> = + payment_attempt + .connector_metadata + .map(|metadata| metadata.parse_value("FetchQrCodeInformation")); + + let qr_code_fetch_url = qr_code_steps.transpose().ok().flatten(); + Ok(qr_code_fetch_url) +} + pub fn wait_screen_next_steps_check( payment_attempt: storage::PaymentAttempt, ) -> RouterResult> { @@ -1108,8 +1129,8 @@ impl ForeignFrom for api_models::paymen display_to_timestamp, } => Self::QrCodeInformation { qr_code_url: Some(qr_code_url), - display_to_timestamp, image_data_url: None, + display_to_timestamp, }, } } diff --git a/crates/router/src/types/domain/payments.rs b/crates/router/src/types/domain/payments.rs index 7b1f3365490..51d3210a70f 100644 --- a/crates/router/src/types/domain/payments.rs +++ b/crates/router/src/types/domain/payments.rs @@ -5,6 +5,6 @@ pub use hyperswitch_domain_models::payment_method_data::{ GooglePayPaymentMethodInfo, GooglePayRedirectData, GooglePayThirdPartySdkData, GooglePayWalletData, GpayTokenizationData, IndomaretVoucherData, KakaoPayRedirection, MbWayRedirection, PayLaterData, PaymentMethodData, SamsungPayWalletData, - SepaAndBacsBillingDetails, SwishQrData, TouchNGoRedirection, VoucherData, WalletData, - WeChatPayQr, + SepaAndBacsBillingDetails, SwishQrData, TouchNGoRedirection, UpiCollectData, UpiData, + UpiIntentData, VoucherData, WalletData, WeChatPayQr, }; diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index da8e8c621b7..59ec42abfd2 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -461,7 +461,9 @@ impl ForeignFrom for api_enums::PaymentMethod { | api_enums::PaymentMethodType::Trustly | api_enums::PaymentMethodType::Bizum | api_enums::PaymentMethodType::Interac => Self::BankRedirect, - api_enums::PaymentMethodType::UpiCollect => Self::Upi, + api_enums::PaymentMethodType::UpiCollect | api_enums::PaymentMethodType::UpiIntent => { + Self::Upi + } api_enums::PaymentMethodType::CryptoCurrency => Self::Crypto, api_enums::PaymentMethodType::Ach | api_enums::PaymentMethodType::Sepa diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index b87b516de28..30bd356cd45 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -11757,6 +11757,25 @@ } } }, + { + "type": "object", + "description": "Contains url to fetch Qr code data", + "required": [ + "qr_code_fetch_url", + "type" + ], + "properties": { + "qr_code_fetch_url": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "fetch_qr_code_information" + ] + } + } + }, { "type": "object", "description": "Contains the download url and the reference number for transaction", @@ -13529,6 +13548,7 @@ "trustly", "twint", "upi_collect", + "upi_intent", "vipps", "venmo", "walley", @@ -18692,7 +18712,7 @@ }, "additionalProperties": false }, - "UpiData": { + "UpiCollectData": { "type": "object", "properties": { "vpa_id": { @@ -18702,6 +18722,35 @@ } } }, + "UpiData": { + "oneOf": [ + { + "type": "object", + "required": [ + "upi_collect" + ], + "properties": { + "upi_collect": { + "$ref": "#/components/schemas/UpiCollectData" + } + } + }, + { + "type": "object", + "required": [ + "upi_intent" + ], + "properties": { + "upi_intent": { + "$ref": "#/components/schemas/UpiIntentData" + } + } + } + ] + }, + "UpiIntentData": { + "type": "object" + }, "ValueType": { "oneOf": [ {