diff --git a/config/config.example.toml b/config/config.example.toml index 775318e7d0..f1f0598117 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -112,7 +112,7 @@ basilisk_host = "" # Basilisk host locker_signing_key_id = "1" # Key_id to sign basilisk hs locker [delayed_session_response] -connectors_with_delayed_session_response = "trustpay" # List of connectors which has delayed session response +connectors_with_delayed_session_response = "trustpay,payme" # List of connectors which has delayed session response [jwekey] # 4 priv/pub key pair locker_key_identifier1 = "" # key identifier for key rotation , should be same as basilisk diff --git a/config/development.toml b/config/development.toml index d568a9d1b7..64502d6e40 100644 --- a/config/development.toml +++ b/config/development.toml @@ -383,7 +383,7 @@ slack_invite_url = "https://join.slack.com/t/hyperswitch-io/shared_invite/zt-1k6 discord_invite_url = "https://discord.gg/wJZ7DVW8mm" [delayed_session_response] -connectors_with_delayed_session_response = "trustpay" +connectors_with_delayed_session_response = "trustpay,payme" [mandates.supported_payment_methods] pay_later.klarna = { connector_list = "adyen" } diff --git a/config/docker_compose.toml b/config/docker_compose.toml index 21490be482..c5cd23a272 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -178,7 +178,7 @@ cards = [ ] [delayed_session_response] -connectors_with_delayed_session_response = "trustpay" +connectors_with_delayed_session_response = "trustpay,payme" [scheduler] diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 276e75ef14..1afe76e4ec 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -2407,6 +2407,10 @@ pub struct ApplepaySessionTokenResponse { pub delayed_session_token: bool, /// The next action for the sdk (ex: calling confirm or sync call) pub sdk_next_action: SdkNextAction, + /// The connector transaction id + pub connector_reference_id: Option, + /// The public key id is to invoke third party sdk + pub connector_sdk_public_key: Option, } #[derive(Debug, Eq, PartialEq, serde::Serialize, Clone, ToSchema)] @@ -2489,9 +2493,9 @@ pub struct ApplePayPaymentRequest { /// Represents the total for the payment. pub total: AmountInfo, /// The list of merchant capabilities(ex: whether capable of 3ds or no-3ds) - pub merchant_capabilities: Vec, + pub merchant_capabilities: Option>, /// The list of supported networks - pub supported_networks: Vec, + pub supported_networks: Option>, pub merchant_identifier: Option, } diff --git a/crates/router/src/connector/bluesnap/transformers.rs b/crates/router/src/connector/bluesnap/transformers.rs index ff4f9cfd8a..3c629d3abf 100644 --- a/crates/router/src/connector/bluesnap/transformers.rs +++ b/crates/router/src/connector/bluesnap/transformers.rs @@ -392,14 +392,18 @@ impl TryFrom 200, + _ => res.status_code, + }; Ok(ErrorResponse { - status_code: res.status_code, - code: response.code, - message: response.message, - reason: response.reason, + status_code, + code: response.status_error_code.to_string(), + message: response.status_error_details.clone(), + reason: Some(format!( + "{}, additional info: {}", + response.status_error_details, response.status_additional_info + )), }) } } @@ -101,26 +104,18 @@ impl ConnectorIntegration - for Payme -{ -} - -impl ConnectorIntegration - for Payme -{ -} +impl api::PaymentsPreProcessing for Payme {} impl ConnectorIntegration< - api::InitPayment, - types::PaymentsAuthorizeData, + api::PreProcessing, + types::PaymentsPreProcessingData, types::PaymentsResponseData, > for Payme { fn get_headers( &self, - req: &types::PaymentsInitRouterData, + req: &types::PaymentsPreProcessingRouterData, connectors: &settings::Connectors, ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) @@ -132,11 +127,7 @@ impl fn get_url( &self, - _req: &types::RouterData< - api::InitPayment, - types::PaymentsAuthorizeData, - types::PaymentsResponseData, - >, + _req: &types::PaymentsPreProcessingRouterData, connectors: &settings::Connectors, ) -> CustomResult { Ok(format!("{}api/generate-sale", self.base_url(connectors))) @@ -144,7 +135,7 @@ impl fn get_request_body( &self, - req: &types::PaymentsInitRouterData, + req: &types::PaymentsPreProcessingRouterData, ) -> CustomResult, errors::ConnectorError> { let req_obj = payme::GenerateSaleRequest::try_from(req)?; let payme_req = types::RequestBody::log_and_get_request_body( @@ -157,37 +148,32 @@ impl fn build_request( &self, - req: &types::PaymentsInitRouterData, + req: &types::PaymentsPreProcessingRouterData, connectors: &settings::Connectors, ) -> CustomResult, errors::ConnectorError> { - Ok(Some( + let req = Some( services::RequestBuilder::new() .method(services::Method::Post) - .url(&types::PaymentsInitType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::PaymentsInitType::get_headers(self, req, connectors)?) - .body(types::PaymentsInitType::get_request_body(self, req)?) + .headers(types::PaymentsPreProcessingType::get_headers( + self, req, connectors, + )?) + .url(&types::PaymentsPreProcessingType::get_url( + self, req, connectors, + )?) + .body(types::PaymentsPreProcessingType::get_request_body( + self, req, + )?) .build(), - )) + ); + Ok(req) } fn handle_response( &self, - data: &types::PaymentsInitRouterData, + data: &types::PaymentsPreProcessingRouterData, res: Response, - ) -> CustomResult< - types::RouterData< - api::InitPayment, - types::PaymentsAuthorizeData, - types::PaymentsResponseData, - >, - errors::ConnectorError, - > - where - api::InitPayment: Clone, - types::PaymentsAuthorizeData: Clone, - types::PaymentsResponseData: Clone, - { + ) -> CustomResult { let response: payme::GenerateSaleResponse = res .response .parse_struct("Payme GenerateSaleResponse") @@ -205,44 +191,29 @@ impl ) -> CustomResult { self.build_error_response(res) } + + fn get_5xx_error_response( + &self, + res: Response, + ) -> CustomResult { + // we are always getting 500 in error scenarios + self.build_error_response(res) + } +} + +impl ConnectorIntegration + for Payme +{ +} + +impl ConnectorIntegration + for Payme +{ } -#[async_trait::async_trait] impl ConnectorIntegration for Payme { - async fn execute_pretasks( - &self, - router_data: &mut types::PaymentsAuthorizeRouterData, - app_state: &routes::AppState, - ) -> CustomResult<(), errors::ConnectorError> { - if router_data.request.mandate_id.is_none() { - let integ: Box< - &(dyn ConnectorIntegration< - api::InitPayment, - types::PaymentsAuthorizeData, - types::PaymentsResponseData, - > + Send - + Sync - + 'static), - > = Box::new(&Self); - let init_data = &types::PaymentsInitRouterData::from(( - &router_data.to_owned(), - router_data.request.clone(), - )); - let init_res = services::execute_connector_processing_step( - app_state, - integ, - init_data, - payments::CallConnectorAction::Trigger, - None, - ) - .await?; - router_data.request.related_transaction_id = init_res.request.related_transaction_id; - } - Ok(()) - } - fn get_headers( &self, req: &types::PaymentsAuthorizeRouterData, @@ -324,6 +295,14 @@ impl ConnectorIntegration CustomResult { self.build_error_response(res) } + + fn get_5xx_error_response( + &self, + res: Response, + ) -> CustomResult { + // we are always getting 500 in error scenarios + self.build_error_response(res) + } } impl ConnectorIntegration @@ -401,6 +380,14 @@ impl ConnectorIntegration CustomResult { + // we are always getting 500 in error scenarios + self.build_error_response(res) + } } impl ConnectorIntegration @@ -479,6 +466,14 @@ impl ConnectorIntegration CustomResult { self.build_error_response(res) } + + fn get_5xx_error_response( + &self, + res: Response, + ) -> CustomResult { + // we are always getting 500 in error scenarios + self.build_error_response(res) + } } impl ConnectorIntegration @@ -570,6 +565,14 @@ impl ConnectorIntegration CustomResult { self.build_error_response(res) } + + fn get_5xx_error_response( + &self, + res: Response, + ) -> CustomResult { + // we are always getting 500 in error scenarios + self.build_error_response(res) + } } impl ConnectorIntegration for Payme { @@ -651,6 +654,14 @@ impl ConnectorIntegration CustomResult { self.build_error_response(res) } + + fn get_5xx_error_response( + &self, + res: Response, + ) -> CustomResult { + // we are always getting 500 in error scenarios + self.build_error_response(res) + } } #[async_trait::async_trait] diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs index 4ad640f275..7c594f7577 100644 --- a/crates/router/src/connector/payme/transformers.rs +++ b/crates/router/src/connector/payme/transformers.rs @@ -6,13 +6,15 @@ use serde::{Deserialize, Serialize}; use crate::{ connector::utils::{ - missing_field_err, AddressDetailsData, CardData, PaymentsAuthorizeRequestData, - PaymentsSyncRequestData, RouterData, + self, missing_field_err, AddressDetailsData, CardData, PaymentsAuthorizeRequestData, + PaymentsPreProcessingData, PaymentsSyncRequestData, RouterData, }, core::errors, types::{self, api, storage::enums, MandateReference}, }; +const LANGUAGE: &str = "en"; + #[derive(Debug, Serialize)] pub struct PayRequest { buyer_name: Secret, @@ -20,6 +22,7 @@ pub struct PayRequest { payme_sale_id: String, #[serde(flatten)] card: PaymeCard, + language: String, } #[derive(Debug, Serialize)] @@ -32,6 +35,7 @@ pub struct MandateRequest { seller_payme_id: Secret, sale_callback_url: String, buyer_key: Secret, + language: String, } #[derive(Debug, Serialize)] @@ -71,6 +75,7 @@ pub struct GenerateSaleRequest { seller_payme_id: Secret, sale_callback_url: String, sale_payment_method: SalePaymentMethod, + language: String, } #[derive(Debug, Deserialize)] @@ -183,11 +188,12 @@ pub enum SaleType { #[serde(rename_all = "kebab-case")] pub enum SalePaymentMethod { CreditCard, + ApplePay, } -impl TryFrom<&types::PaymentsInitRouterData> for GenerateSaleRequest { +impl TryFrom<&types::PaymentsPreProcessingRouterData> for GenerateSaleRequest { type Error = error_stack::Report; - fn try_from(item: &types::PaymentsInitRouterData) -> Result { + fn try_from(item: &types::PaymentsPreProcessingRouterData) -> Result { let sale_type = SaleType::try_from(item)?; let seller_payme_id = PaymeAuthType::try_from(&item.connector_auth_type)?.seller_payme_id; let order_details = item.request.get_order_details()?; @@ -196,44 +202,67 @@ impl TryFrom<&types::PaymentsInitRouterData> for GenerateSaleRequest { .ok_or_else(missing_field_err("order_details"))? .product_name .clone(); + let pmd = item + .request + .payment_method_data + .to_owned() + .ok_or_else(missing_field_err("payment_method_data"))?; Ok(Self { - currency: item.request.currency, - sale_type, - sale_price: item.request.amount, - transaction_id: item.payment_id.clone(), - product_name, - sale_return_url: item.request.get_return_url()?, seller_payme_id, + sale_price: item.request.get_amount()?, + currency: item.request.get_currency()?, + product_name, + sale_payment_method: SalePaymentMethod::try_from(&pmd)?, + sale_type, + transaction_id: item.payment_id.clone(), + sale_return_url: item.request.get_return_url()?, sale_callback_url: item.request.get_webhook_url()?, - sale_payment_method: SalePaymentMethod::try_from(&item.request.payment_method_data)?, + language: LANGUAGE.to_string(), }) } } -impl TryFrom<&types::PaymentsInitRouterData> for SaleType { - type Error = error_stack::Report; - fn try_from(value: &types::PaymentsInitRouterData) -> Result { - let sale_type = if value.request.setup_mandate_details.is_some() { - // First mandate - Self::Token - } else { - // Normal payments - match value.request.is_auto_capture()? { - true => Self::Sale, - false => Self::Authorize, - } - }; - Ok(sale_type) - } -} - impl TryFrom<&PaymentMethodData> for SalePaymentMethod { type Error = error_stack::Report; fn try_from(item: &PaymentMethodData) -> Result { match item { PaymentMethodData::Card(_) => Ok(Self::CreditCard), - PaymentMethodData::Wallet(_) - | PaymentMethodData::PayLater(_) + PaymentMethodData::Wallet(wallet_data) => match wallet_data { + api_models::payments::WalletData::ApplePay(_) => Ok(Self::ApplePay), + api_models::payments::WalletData::AliPayQr(_) + | api_models::payments::WalletData::AliPayRedirect(_) + | api_models::payments::WalletData::AliPayHkRedirect(_) + | api_models::payments::WalletData::MomoRedirect(_) + | api_models::payments::WalletData::KakaoPayRedirect(_) + | api_models::payments::WalletData::GoPayRedirect(_) + | api_models::payments::WalletData::GcashRedirect(_) + | api_models::payments::WalletData::ApplePayRedirect(_) + | api_models::payments::WalletData::ApplePayThirdPartySdk(_) + | api_models::payments::WalletData::DanaRedirect {} + | api_models::payments::WalletData::GooglePay(_) + | api_models::payments::WalletData::GooglePayRedirect(_) + | api_models::payments::WalletData::GooglePayThirdPartySdk(_) + | api_models::payments::WalletData::MbWayRedirect(_) + | api_models::payments::WalletData::MobilePayRedirect(_) + | api_models::payments::WalletData::PaypalRedirect(_) + | api_models::payments::WalletData::PaypalSdk(_) + | api_models::payments::WalletData::SamsungPay(_) + | api_models::payments::WalletData::TwintRedirect {} + | api_models::payments::WalletData::VippsRedirect {} + | api_models::payments::WalletData::TouchNGoRedirect(_) + | api_models::payments::WalletData::WeChatPayRedirect(_) + | api_models::payments::WalletData::WeChatPayQr(_) + | api_models::payments::WalletData::CashappQr(_) + | api_models::payments::WalletData::SwishQr(_) => { + Err(errors::ConnectorError::NotSupported { + message: "Wallet".to_string(), + connector: "payme", + payment_experience: "Redirection".to_string(), + } + .into()) + } + }, + PaymentMethodData::PayLater(_) | PaymentMethodData::BankRedirect(_) | PaymentMethodData::BankDebit(_) | PaymentMethodData::BankTransfer(_) @@ -288,6 +317,81 @@ impl TryFrom<&types::RefundSyncRouterData> for PaymeQueryTransactionRequest { } } +impl + TryFrom< + types::ResponseRouterData< + F, + GenerateSaleResponse, + types::PaymentsPreProcessingData, + types::PaymentsResponseData, + >, + > for types::RouterData +{ + type Error = error_stack::Report; + fn try_from( + item: types::ResponseRouterData< + F, + GenerateSaleResponse, + types::PaymentsPreProcessingData, + types::PaymentsResponseData, + >, + ) -> Result { + let currency_code = item.data.request.get_currency()?; + let amount = item.data.request.get_amount()?; + let amount_in_base_unit = utils::to_currency_base_unit(amount, currency_code)?; + let pmd = item.data.request.payment_method_data.to_owned(); + + let session_token = match pmd { + Some(PaymentMethodData::Wallet( + api_models::payments::WalletData::ApplePayThirdPartySdk(_), + )) => Some(api_models::payments::SessionToken::ApplePay(Box::new( + api_models::payments::ApplepaySessionTokenResponse { + session_token_data: + api_models::payments::ApplePaySessionResponse::NoSessionResponse, + payment_request_data: Some(api_models::payments::ApplePayPaymentRequest { + country_code: item.data.get_billing_country()?, + currency_code, + total: api_models::payments::AmountInfo { + label: "Apple Pay".to_string(), + total_type: None, + amount: amount_in_base_unit, + }, + merchant_capabilities: None, + supported_networks: None, + merchant_identifier: None, + }), + connector: "payme".to_string(), + delayed_session_token: true, + sdk_next_action: api_models::payments::SdkNextAction { + next_action: api_models::payments::NextActionCall::Sync, + }, + connector_reference_id: Some(item.response.payme_sale_id.to_owned()), + connector_sdk_public_key: Some( + PaymeAuthType::try_from(&item.data.connector_auth_type)? + .payme_public_key + .expose(), + ), + }, + ))), + _ => None, + }; + Ok(Self { + // We don't get any status from payme, so defaulting it to pending + status: enums::AttemptStatus::Pending, + preprocessing_id: Some(item.response.payme_sale_id.to_owned()), + response: Ok(types::PaymentsResponseData::PreProcessingResponse { + pre_processing_id: types::PreprocessingResponseId::ConnectorTransactionId( + item.response.payme_sale_id, + ), + connector_metadata: None, + session_token, + connector_response_reference_id: None, + }), + ..item.data + }) + } +} + impl TryFrom<&types::PaymentsAuthorizeRouterData> for MandateRequest { type Error = error_stack::Report; fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result { @@ -307,6 +411,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for MandateRequest { seller_payme_id, sale_callback_url: item.request.get_webhook_url()?, buyer_key: Secret::new(item.request.get_connector_mandate_id()?), + language: LANGUAGE.to_string(), }) } } @@ -324,7 +429,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PayRequest { }; let buyer_email = item.request.get_email()?; let buyer_name = item.get_billing_address()?.get_full_name()?; - let payme_sale_id = item.request.related_transaction_id.clone().ok_or( + let payme_sale_id = item.preprocessing_id.to_owned().ok_or( errors::ConnectorError::MissingConnectorRelatedTransactionID { id: "payme_sale_id".to_string(), }, @@ -334,6 +439,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PayRequest { buyer_email, buyer_name, payme_sale_id, + language: LANGUAGE.to_string(), }) } _ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()), @@ -344,7 +450,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PayRequest { // Auth Struct pub struct PaymeAuthType { #[allow(dead_code)] - pub(super) payme_client_key: Secret, + pub(super) payme_public_key: Secret, pub(super) seller_payme_id: Secret, } @@ -354,13 +460,30 @@ impl TryFrom<&types::ConnectorAuthType> for PaymeAuthType { match auth_type { types::ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self { seller_payme_id: api_key.to_owned(), - payme_client_key: key1.to_owned(), + payme_public_key: key1.to_owned(), }), _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()), } } } +impl TryFrom<&types::PaymentsPreProcessingRouterData> for SaleType { + type Error = error_stack::Report; + fn try_from(value: &types::PaymentsPreProcessingRouterData) -> Result { + let sale_type = if value.request.setup_mandate_details.is_some() { + // First mandate + Self::Token + } else { + // Normal payments + match value.request.is_auto_capture()? { + true => Self::Sale, + false => Self::Authorize, + } + }; + Ok(sale_type) + } +} + #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum SaleStatus { @@ -420,44 +543,6 @@ pub struct PaymeMetadata { payme_transaction_id: String, } -impl - TryFrom< - types::ResponseRouterData< - F, - GenerateSaleResponse, - types::PaymentsAuthorizeData, - types::PaymentsResponseData, - >, - > for types::RouterData -{ - type Error = error_stack::Report; - fn try_from( - item: types::ResponseRouterData< - F, - GenerateSaleResponse, - types::PaymentsAuthorizeData, - types::PaymentsResponseData, - >, - ) -> Result { - Ok(Self { - status: enums::AttemptStatus::Authorizing, - request: types::PaymentsAuthorizeData { - related_transaction_id: Some(item.response.payme_sale_id.clone()), - ..item.data.request - }, - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId(item.response.payme_sale_id), - redirection_data: None, - mandate_reference: None, - connector_metadata: None, - network_txn_id: None, - connector_response_reference_id: None, - }), - ..item.data - }) - } -} - #[derive(Debug, Serialize)] pub struct PaymentCaptureRequest { payme_sale_id: String, @@ -481,6 +566,7 @@ pub struct PaymeRefundRequest { sale_refund_amount: i64, payme_sale_id: String, seller_payme_id: Secret, + language: String, } impl TryFrom<&types::RefundsRouterData> for PaymeRefundRequest { @@ -491,6 +577,7 @@ impl TryFrom<&types::RefundsRouterData> for PaymeRefundRequest { payme_sale_id: item.request.connector_transaction_id.clone(), seller_payme_id: auth_type.seller_payme_id, sale_refund_amount: item.request.refund_amount, + language: LANGUAGE.to_string(), }) } } @@ -579,9 +666,9 @@ impl #[derive(Default, Debug, Serialize, Deserialize, PartialEq)] pub struct PaymeErrorResponse { pub status_code: u16, - pub code: String, - pub message: String, - pub reason: Option, + pub status_error_details: String, + pub status_additional_info: String, + pub status_error_code: u16, } #[derive(Debug, Serialize, Deserialize)] diff --git a/crates/router/src/connector/trustpay/transformers.rs b/crates/router/src/connector/trustpay/transformers.rs index e65c51a2bc..deacf17882 100644 --- a/crates/router/src/connector/trustpay/transformers.rs +++ b/crates/router/src/connector/trustpay/transformers.rs @@ -1048,8 +1048,10 @@ pub fn get_apple_pay_session( payment_request_data: Some(api_models::payments::ApplePayPaymentRequest { country_code: apple_pay_init_result.country_code, currency_code: apple_pay_init_result.currency_code, - supported_networks: apple_pay_init_result.supported_networks.clone(), - merchant_capabilities: apple_pay_init_result.merchant_capabilities.clone(), + supported_networks: Some(apple_pay_init_result.supported_networks.clone()), + merchant_capabilities: Some( + apple_pay_init_result.merchant_capabilities.clone(), + ), total: apple_pay_init_result.total.into(), merchant_identifier: None, }), @@ -1060,6 +1062,8 @@ pub fn get_apple_pay_session( next_action: api_models::payments::NextActionCall::Sync, } }, + connector_reference_id: None, + connector_sdk_public_key: None, }, ))), connector_response_reference_id: None, diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index 877778c504..b64f18bc05 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -193,6 +193,10 @@ pub trait PaymentsPreProcessingData { fn get_payment_method_type(&self) -> Result; fn get_currency(&self) -> Result; fn get_amount(&self) -> Result; + fn is_auto_capture(&self) -> Result; + fn get_order_details(&self) -> Result, Error>; + fn get_webhook_url(&self) -> Result; + fn get_return_url(&self) -> Result; } impl PaymentsPreProcessingData for types::PaymentsPreProcessingData { @@ -210,6 +214,28 @@ impl PaymentsPreProcessingData for types::PaymentsPreProcessingData { fn get_amount(&self) -> Result { self.amount.ok_or_else(missing_field_err("amount")) } + fn is_auto_capture(&self) -> Result { + match self.capture_method { + Some(diesel_models::enums::CaptureMethod::Automatic) | None => Ok(true), + Some(diesel_models::enums::CaptureMethod::Manual) => Ok(false), + Some(_) => Err(errors::ConnectorError::CaptureMethodNotSupported.into()), + } + } + fn get_order_details(&self) -> Result, Error> { + self.order_details + .clone() + .ok_or_else(missing_field_err("order_details")) + } + fn get_webhook_url(&self) -> Result { + self.webhook_url + .clone() + .ok_or_else(missing_field_err("webhook_url")) + } + fn get_return_url(&self) -> Result { + self.router_return_url + .clone() + .ok_or_else(missing_field_err("return_url")) + } } pub trait PaymentsAuthorizeRequestData { diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 65d7bc41f3..52395f768c 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -843,7 +843,7 @@ async fn complete_preprocessing_steps_if_required( state: &AppState, connector: &api::ConnectorData, payment_data: &PaymentData, - router_data: types::RouterData, + mut router_data: types::RouterData, should_continue_payment: bool, ) -> RouterResult<(types::RouterData, bool)> where @@ -871,7 +871,7 @@ where _ => (router_data, should_continue_payment), }, Some(api_models::payments::PaymentMethodData::Wallet(_)) => { - if connector.connector_name.to_string() == *"trustpay" { + if is_preprocessing_required_for_wallets(connector.connector_name.to_string()) { ( router_data.preprocessing_steps(state, connector).await?, false, @@ -880,12 +880,27 @@ where (router_data, should_continue_payment) } } + Some(api_models::payments::PaymentMethodData::Card(_)) => { + if connector.connector_name == types::Connector::Payme { + router_data = router_data.preprocessing_steps(state, connector).await?; + + let is_error_in_response = router_data.response.is_err(); + // If is_error_in_response is true, should_continue_payment should be false, we should throw the error + (router_data, !is_error_in_response) + } else { + (router_data, should_continue_payment) + } + } _ => (router_data, should_continue_payment), }; Ok(router_data_and_should_continue_payment) } +pub fn is_preprocessing_required_for_wallets(connector_name: String) -> bool { + connector_name == *"trustpay" || connector_name == *"payme" +} + fn is_payment_method_tokenization_enabled_for_connector( state: &AppState, connector_name: &str, diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index 51992b9f7a..710468bd4a 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -745,7 +745,6 @@ default_imp_for_pre_processing_steps!( connector::Opennode, connector::Payeezy, connector::Paypal, - connector::Payme, connector::Payu, connector::Powertranz, connector::Rapyd, diff --git a/crates/router/src/core/payments/flows/authorize_flow.rs b/crates/router/src/core/payments/flows/authorize_flow.rs index ddeb474548..3d68ddf1e6 100644 --- a/crates/router/src/core/payments/flows/authorize_flow.rs +++ b/crates/router/src/core/payments/flows/authorize_flow.rs @@ -360,6 +360,11 @@ impl TryFrom for types::PaymentsPreProcessingData email: data.email, currency: Some(data.currency), payment_method_type: data.payment_method_type, + setup_mandate_details: data.setup_mandate_details, + capture_method: data.capture_method, + order_details: data.order_details, + router_return_url: data.router_return_url, + webhook_url: data.webhook_url, }) } } diff --git a/crates/router/src/core/payments/flows/session_flow.rs b/crates/router/src/core/payments/flows/session_flow.rs index 7e348b2c43..2e9a406a2f 100644 --- a/crates/router/src/core/payments/flows/session_flow.rs +++ b/crates/router/src/core/payments/flows/session_flow.rs @@ -192,14 +192,18 @@ async fn create_applepay_session_token( })?, currency_code: router_data.request.currency, total: amount_info, - merchant_capabilities: applepay_metadata - .data - .payment_request_data - .merchant_capabilities, - supported_networks: applepay_metadata - .data - .payment_request_data - .supported_networks, + merchant_capabilities: Some( + applepay_metadata + .data + .payment_request_data + .merchant_capabilities, + ), + supported_networks: Some( + applepay_metadata + .data + .payment_request_data + .supported_networks, + ), merchant_identifier: Some( applepay_metadata .data @@ -267,6 +271,8 @@ fn create_apple_pay_session_response( connector: connector_name, delayed_session_token: delayed_response, sdk_next_action: { payment_types::SdkNextAction { next_action } }, + connector_reference_id: None, + connector_sdk_public_key: None, }, )), }), diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index e4ec1ae74b..c70a53a874 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -2449,7 +2449,7 @@ pub fn router_data_type_conversion( attempt_id: router_data.attempt_id, access_token: router_data.access_token, session_token: router_data.session_token, - reference_id: None, + reference_id: router_data.reference_id, payment_method_token: router_data.payment_method_token, customer_id: router_data.customer_id, connector_customer: router_data.connector_customer, diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 9f34255ae1..51848748cd 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -614,7 +614,9 @@ where payment_attempt .connector .as_ref() - .map(|connector| matches!(connector.as_str(), "trustpay")) + .map(|connector| { + matches!(connector.as_str(), "trustpay") || matches!(connector.as_str(), "payme") + }) .and_then(|is_connector_supports_third_party_sdk| { if is_connector_supports_third_party_sdk { payment_attempt @@ -1100,6 +1102,39 @@ impl TryFrom> for types::PaymentsPreProce fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result { let payment_data = additional_data.payment_data; let payment_method_data = payment_data.payment_method_data; + let router_base_url = &additional_data.router_base_url; + let attempt = &payment_data.payment_attempt; + let connector_name = &additional_data.connector_name; + + let order_details = payment_data + .payment_intent + .order_details + .map(|order_details| { + order_details + .iter() + .map(|data| { + data.to_owned() + .parse_value("OrderDetailsWithAmount") + .change_context(errors::ApiErrorResponse::InvalidDataValue { + field_name: "OrderDetailsWithAmount", + }) + .attach_printable("Unable to parse OrderDetailsWithAmount") + }) + .collect::, _>>() + }) + .transpose()?; + + let webhook_url = Some(helpers::create_webhook_url( + router_base_url, + &attempt.merchant_id, + connector_name, + )); + let router_return_url = Some(helpers::create_redirect_url( + router_base_url, + attempt, + connector_name, + payment_data.creds_identifier.as_deref(), + )); Ok(Self { payment_method_data, @@ -1107,6 +1142,11 @@ impl TryFrom> for types::PaymentsPreProce currency: Some(payment_data.currency), amount: Some(payment_data.amount.into()), payment_method_type: payment_data.payment_attempt.payment_method_type, + setup_mandate_details: payment_data.setup_mandate, + capture_method: payment_data.payment_attempt.capture_method, + order_details, + router_return_url, + webhook_url, }) } } diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 9c1e8b0b6d..c81516ab65 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -364,6 +364,11 @@ pub struct PaymentsPreProcessingData { pub email: Option, pub currency: Option, pub payment_method_type: Option, + pub setup_mandate_details: Option, + pub capture_method: Option, + pub order_details: Option>, + pub router_return_url: Option, + pub webhook_url: Option, } #[derive(Debug, Clone)] diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 39b4bccd2b..209f21e6b4 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -2219,9 +2219,7 @@ "required": [ "country_code", "currency_code", - "total", - "merchant_capabilities", - "supported_networks" + "total" ], "properties": { "country_code": { @@ -2238,14 +2236,16 @@ "items": { "type": "string" }, - "description": "The list of merchant capabilities(ex: whether capable of 3ds or no-3ds)" + "description": "The list of merchant capabilities(ex: whether capable of 3ds or no-3ds)", + "nullable": true }, "supported_networks": { "type": "array", "items": { "type": "string" }, - "description": "The list of supported networks" + "description": "The list of supported networks", + "nullable": true }, "merchant_identifier": { "type": "string", @@ -2360,6 +2360,16 @@ }, "sdk_next_action": { "$ref": "#/components/schemas/SdkNextAction" + }, + "connector_reference_id": { + "type": "string", + "description": "The connector transaction id", + "nullable": true + }, + "connector_sdk_public_key": { + "type": "string", + "description": "The public key id is to invoke third party sdk", + "nullable": true } } },