diff --git a/.typos.toml b/.typos.toml index 983ead3f75d6..67f819c2c52c 100644 --- a/.typos.toml +++ b/.typos.toml @@ -60,6 +60,7 @@ nin = "nin" # National identification number, a field used by PayU connector requestor = "requestor" #Used in external 3ds flows substituters = "substituters" # Present in `flake.nix` unsuccess = "unsuccess" # Used in cryptopay request +authetication = "authetication" #UAS pre-authentication URL [files] extend-exclude = [ diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index ee5654cfb6b1..4725e0552f00 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -3488,7 +3488,9 @@ "enum": [ "threedsecureio", "netcetera", - "gpayments" + "gpayments", + "ctp_mastercard", + "unified_authentication_service" ] }, "AuthenticationStatus": { @@ -6430,6 +6432,7 @@ "checkout", "coinbase", "cryptopay", + "ctp_mastercard", "cybersource", "datatrans", "deutschebank", diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index d7b86b05a194..0c8736ce85e3 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -5925,7 +5925,9 @@ "enum": [ "threedsecureio", "netcetera", - "gpayments" + "gpayments", + "ctp_mastercard", + "unified_authentication_service" ] }, "AuthenticationStatus": { @@ -8792,6 +8794,7 @@ "checkout", "coinbase", "cryptopay", + "ctp_mastercard", "cybersource", "datatrans", "deutschebank", diff --git a/crates/api_models/src/connector_enums.rs b/crates/api_models/src/connector_enums.rs index c70c54f47920..0989614c8a04 100644 --- a/crates/api_models/src/connector_enums.rs +++ b/crates/api_models/src/connector_enums.rs @@ -68,6 +68,7 @@ pub enum Connector { Checkout, Coinbase, Cryptopay, + CtpMastercard, Cybersource, Datatrans, Deutschebank, @@ -278,6 +279,7 @@ impl Connector { | Self::Threedsecureio | Self::Datatrans | Self::Netcetera + | Self::CtpMastercard | Self::Noon | Self::Stripe => false, Self::Checkout | Self::Nmi | Self::Cybersource => true, diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index e3b11ffaa97b..5aac1a07457b 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -2591,12 +2591,17 @@ pub enum AuthenticationConnectors { Threedsecureio, Netcetera, Gpayments, + CtpMastercard, + UnifiedAuthenticationService, } impl AuthenticationConnectors { pub fn is_separate_version_call_required(self) -> bool { match self { - Self::Threedsecureio | Self::Netcetera => false, + Self::Threedsecureio + | Self::Netcetera + | Self::CtpMastercard + | Self::UnifiedAuthenticationService => false, Self::Gpayments => true, } } diff --git a/crates/connector_configs/src/connector.rs b/crates/connector_configs/src/connector.rs index c1f7cfc366c7..7e893a6415e3 100644 --- a/crates/connector_configs/src/connector.rs +++ b/crates/connector_configs/src/connector.rs @@ -242,6 +242,8 @@ pub struct ConnectorConfig { pub zen: Option, pub zsl: Option, pub taxjar: Option, + pub ctp_mastercard: Option, + pub unified_authentication_service: Option, } impl ConnectorConfig { @@ -296,6 +298,10 @@ impl ConnectorConfig { AuthenticationConnectors::Threedsecureio => Ok(connector_data.threedsecureio), AuthenticationConnectors::Netcetera => Ok(connector_data.netcetera), AuthenticationConnectors::Gpayments => Ok(connector_data.gpayments), + AuthenticationConnectors::CtpMastercard => Ok(connector_data.ctp_mastercard), + AuthenticationConnectors::UnifiedAuthenticationService => { + Ok(connector_data.unified_authentication_service) + } } } @@ -412,6 +418,7 @@ impl ConnectorConfig { #[cfg(feature = "dummy_connector")] Connector::DummyConnector7 => Ok(connector_data.paypal_test), Connector::Netcetera => Ok(connector_data.netcetera), + Connector::CtpMastercard => Ok(connector_data.ctp_mastercard), } } } diff --git a/crates/hyperswitch_connectors/src/connectors.rs b/crates/hyperswitch_connectors/src/connectors.rs index 391d9446cbc6..d5a695fe01d7 100644 --- a/crates/hyperswitch_connectors/src/connectors.rs +++ b/crates/hyperswitch_connectors/src/connectors.rs @@ -9,6 +9,7 @@ pub mod boku; pub mod cashtocode; pub mod coinbase; pub mod cryptopay; +pub mod ctp_mastercard; pub mod datatrans; pub mod deutschebank; pub mod digitalvirgo; @@ -55,10 +56,10 @@ pub mod zsl; pub use self::{ airwallex::Airwallex, amazonpay::Amazonpay, bambora::Bambora, bamboraapac::Bamboraapac, billwerk::Billwerk, bitpay::Bitpay, bluesnap::Bluesnap, boku::Boku, cashtocode::Cashtocode, - coinbase::Coinbase, cryptopay::Cryptopay, datatrans::Datatrans, deutschebank::Deutschebank, - digitalvirgo::Digitalvirgo, dlocal::Dlocal, elavon::Elavon, fiserv::Fiserv, - fiservemea::Fiservemea, fiuu::Fiuu, forte::Forte, globepay::Globepay, gocardless::Gocardless, - helcim::Helcim, inespay::Inespay, jpmorgan::Jpmorgan, mollie::Mollie, + coinbase::Coinbase, cryptopay::Cryptopay, ctp_mastercard::CtpMastercard, datatrans::Datatrans, + deutschebank::Deutschebank, digitalvirgo::Digitalvirgo, dlocal::Dlocal, elavon::Elavon, + fiserv::Fiserv, fiservemea::Fiservemea, fiuu::Fiuu, forte::Forte, globepay::Globepay, + gocardless::Gocardless, helcim::Helcim, inespay::Inespay, jpmorgan::Jpmorgan, mollie::Mollie, multisafepay::Multisafepay, nexinets::Nexinets, nexixpay::Nexixpay, nomupay::Nomupay, novalnet::Novalnet, paybox::Paybox, payeezy::Payeezy, payu::Payu, placetopay::Placetopay, powertranz::Powertranz, prophetpay::Prophetpay, rapyd::Rapyd, razorpay::Razorpay, diff --git a/crates/hyperswitch_connectors/src/connectors/ctp_mastercard.rs b/crates/hyperswitch_connectors/src/connectors/ctp_mastercard.rs new file mode 100644 index 000000000000..1d82b98af8af --- /dev/null +++ b/crates/hyperswitch_connectors/src/connectors/ctp_mastercard.rs @@ -0,0 +1,124 @@ +use common_utils::errors::CustomResult; +use error_stack::report; +use hyperswitch_domain_models::{ + router_data::{AccessToken, RouterData}, + router_flow_types::{ + access_token_auth::AccessTokenAuth, + payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void}, + refunds::{Execute, RSync}, + }, + router_request_types::{ + AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData, + PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData, + RefundsData, SetupMandateRequestData, + }, + router_response_types::{PaymentsResponseData, RefundsResponseData}, +}; +use hyperswitch_interfaces::{ + api::{self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorValidation}, + configs::Connectors, + errors, webhooks, +}; + +use crate::constants::headers; + +#[derive(Clone)] +pub struct CtpMastercard; + +impl api::Payment for CtpMastercard {} +impl api::PaymentSession for CtpMastercard {} +impl api::ConnectorAccessToken for CtpMastercard {} +impl api::MandateSetup for CtpMastercard {} +impl api::PaymentAuthorize for CtpMastercard {} +impl api::PaymentSync for CtpMastercard {} +impl api::PaymentCapture for CtpMastercard {} +impl api::PaymentVoid for CtpMastercard {} +impl api::Refund for CtpMastercard {} +impl api::RefundExecute for CtpMastercard {} +impl api::RefundSync for CtpMastercard {} +impl api::PaymentToken for CtpMastercard {} + +impl ConnectorIntegration + for CtpMastercard +{ + // Not Implemented (R) +} + +impl ConnectorCommonExt for CtpMastercard +where + Self: ConnectorIntegration, +{ + fn build_headers( + &self, + req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { + let mut header = vec![( + headers::CONTENT_TYPE.to_string(), + self.get_content_type().to_string().into(), + )]; + let mut api_key = self.get_auth_header(&req.connector_auth_type)?; + header.append(&mut api_key); + Ok(header) + } +} + +impl ConnectorCommon for CtpMastercard { + fn id(&self) -> &'static str { + "ctp_mastercard" + } + + fn base_url<'a>(&self, _connectors: &'a Connectors) -> &'a str { + "" + } +} + +impl ConnectorValidation for CtpMastercard {} + +impl ConnectorIntegration for CtpMastercard {} + +impl ConnectorIntegration for CtpMastercard {} + +impl ConnectorIntegration + for CtpMastercard +{ +} + +impl ConnectorIntegration + for CtpMastercard +{ +} + +impl ConnectorIntegration for CtpMastercard {} + +impl ConnectorIntegration for CtpMastercard {} + +impl ConnectorIntegration for CtpMastercard {} + +impl ConnectorIntegration for CtpMastercard {} + +impl ConnectorIntegration for CtpMastercard {} + +#[async_trait::async_trait] +impl webhooks::IncomingWebhook for CtpMastercard { + fn get_webhook_object_reference_id( + &self, + _request: &webhooks::IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { + Err(report!(errors::ConnectorError::WebhooksNotImplemented)) + } + + fn get_webhook_event_type( + &self, + _request: &webhooks::IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { + Err(report!(errors::ConnectorError::WebhooksNotImplemented)) + } + + fn get_webhook_resource_object( + &self, + _request: &webhooks::IncomingWebhookRequestDetails<'_>, + ) -> CustomResult, errors::ConnectorError> { + Err(report!(errors::ConnectorError::WebhooksNotImplemented)) + } +} diff --git a/crates/hyperswitch_connectors/src/connectors/unified_authentication_service.rs b/crates/hyperswitch_connectors/src/connectors/unified_authentication_service.rs index e85fe5dd7de7..e820a07b350c 100644 --- a/crates/hyperswitch_connectors/src/connectors/unified_authentication_service.rs +++ b/crates/hyperswitch_connectors/src/connectors/unified_authentication_service.rs @@ -4,49 +4,51 @@ use common_utils::{ errors::CustomResult, ext_traits::BytesExt, request::{Method, Request, RequestBuilder, RequestContent}, - types::{AmountConvertor, StringMinorUnit, StringMinorUnitForConnector}, + types::{AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector}, }; use error_stack::{report, ResultExt}; use hyperswitch_domain_models::{ - router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData}, + router_data::{AccessToken, ErrorResponse, RouterData}, router_flow_types::{ access_token_auth::AccessTokenAuth, payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void}, refunds::{Execute, RSync}, + PostAuthenticate, PreAuthenticate, }, router_request_types::{ + unified_authentication_service::{ + UasAuthenticationResponseData, UasPostAuthenticationRequestData, + UasPreAuthenticationRequestData, + }, AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData, PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData, RefundsData, SetupMandateRequestData, }, router_response_types::{PaymentsResponseData, RefundsResponseData}, - types::{ - PaymentsAuthorizeRouterData, PaymentsCaptureRouterData, PaymentsSyncRouterData, - RefundSyncRouterData, RefundsRouterData, - }, + types::{UasPostAuthenticationRouterData, UasPreAuthenticationRouterData}, }; use hyperswitch_interfaces::{ api::{self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorValidation}, configs::Connectors, + consts::NO_ERROR_MESSAGE, errors, events::connector_api_logs::ConnectorEvent, types::{self, Response}, webhooks, }; -use masking::{ExposeInterface, Mask}; use transformers as unified_authentication_service; use crate::{constants::headers, types::ResponseRouterData, utils}; #[derive(Clone)] pub struct UnifiedAuthenticationService { - amount_converter: &'static (dyn AmountConvertor + Sync), + amount_converter: &'static (dyn AmountConvertor + Sync), } impl UnifiedAuthenticationService { pub fn new() -> &'static Self { &Self { - amount_converter: &StringMinorUnitForConnector, + amount_converter: &FloatMajorUnitForConnector, } } } @@ -63,11 +65,18 @@ impl api::Refund for UnifiedAuthenticationService {} impl api::RefundExecute for UnifiedAuthenticationService {} impl api::RefundSync for UnifiedAuthenticationService {} impl api::PaymentToken for UnifiedAuthenticationService {} +impl api::UnifiedAuthenticationService for UnifiedAuthenticationService {} +impl api::UasPreAuthentication for UnifiedAuthenticationService {} +impl api::UasPostAuthentication for UnifiedAuthenticationService {} impl ConnectorIntegration for UnifiedAuthenticationService { - // Not Implemented (R) +} + +impl ConnectorIntegration + for UnifiedAuthenticationService +{ } impl ConnectorCommonExt @@ -77,15 +86,19 @@ where { fn build_headers( &self, - req: &RouterData, + _req: &RouterData, _connectors: &Connectors, ) -> CustomResult)>, errors::ConnectorError> { - let mut header = vec![( - headers::CONTENT_TYPE.to_string(), - self.get_content_type().to_string().into(), - )]; - let mut api_key = self.get_auth_header(&req.connector_auth_type)?; - header.append(&mut api_key); + let header = vec![ + ( + headers::CONTENT_TYPE.to_string(), + self.get_content_type().to_string().into(), + ), + ( + headers::SOURCE.to_string(), + self.get_content_type().to_string().into(), + ), + ]; Ok(header) } } @@ -97,9 +110,6 @@ impl ConnectorCommon for UnifiedAuthenticationService { fn get_currency_unit(&self) -> api::CurrencyUnit { api::CurrencyUnit::Base - // TODO! Check connector documentation, on which unit they are processing the currency. - // If the connector accepts amount in lower unit ( i.e cents for USD) then return api::CurrencyUnit::Minor, - // if connector accepts amount in base unit (i.e dollars for USD) then return api::CurrencyUnit::Base } fn common_get_content_type(&self) -> &'static str { @@ -110,20 +120,6 @@ impl ConnectorCommon for UnifiedAuthenticationService { connectors.unified_authentication_service.base_url.as_ref() } - fn get_auth_header( - &self, - auth_type: &ConnectorAuthType, - ) -> CustomResult)>, errors::ConnectorError> { - let auth = unified_authentication_service::UnifiedAuthenticationServiceAuthType::try_from( - auth_type, - ) - .change_context(errors::ConnectorError::FailedToObtainAuthType)?; - Ok(vec![( - headers::AUTHORIZATION.to_string(), - auth.api_key.expose().into_masked(), - )]) - } - fn build_error_response( &self, res: Response, @@ -139,9 +135,9 @@ impl ConnectorCommon for UnifiedAuthenticationService { Ok(ErrorResponse { status_code: res.status_code, - code: response.code, - message: response.message, - reason: response.reason, + code: response.error.clone(), + message: NO_ERROR_MESSAGE.to_owned(), + reason: Some(response.error), attempt_status: None, connector_transaction_id: None, }) @@ -168,12 +164,16 @@ impl ConnectorIntegration - for UnifiedAuthenticationService +impl + ConnectorIntegration< + PreAuthenticate, + UasPreAuthenticationRequestData, + UasAuthenticationResponseData, + > for UnifiedAuthenticationService { fn get_headers( &self, - req: &PaymentsAuthorizeRouterData, + req: &UasPreAuthenticationRouterData, connectors: &Connectors, ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) @@ -185,21 +185,29 @@ impl ConnectorIntegration CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + Ok(format!( + "{}pre_authetication_processing", + self.base_url(connectors) + )) } fn get_request_body( &self, - req: &PaymentsAuthorizeRouterData, + req: &UasPreAuthenticationRouterData, _connectors: &Connectors, ) -> CustomResult { + let transaction_details = req.request.transaction_details.clone().ok_or( + errors::ConnectorError::MissingRequiredField { + field_name: "transaction_details", + }, + )?; let amount = utils::convert_amount( self.amount_converter, - req.request.minor_amount, - req.request.currency, + transaction_details.amount, + transaction_details.currency, )?; let connector_router_data = @@ -207,7 +215,7 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { Ok(Some( RequestBuilder::new() .method(Method::Post) - .url(&types::PaymentsAuthorizeType::get_url( + .url(&types::UasPreAuthenticationType::get_url( self, req, connectors, )?) .attach_default_headers() - .headers(types::PaymentsAuthorizeType::get_headers( + .headers(types::UasPreAuthenticationType::get_headers( self, req, connectors, )?) - .set_body(types::PaymentsAuthorizeType::get_request_body( + .set_body(types::UasPreAuthenticationType::get_request_body( self, req, connectors, )?) .build(), @@ -237,13 +245,13 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { - let response: unified_authentication_service::UnifiedAuthenticationServicePaymentsResponse = + ) -> CustomResult { + let response: unified_authentication_service::UnifiedAuthenticationServicePreAuthenticateResponse = res.response - .parse_struct("UnifiedAuthenticationService PaymentsAuthorizeResponse") + .parse_struct("UnifiedAuthenticationService UnifiedAuthenticationServicePreAuthenticateResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); @@ -263,12 +271,16 @@ impl ConnectorIntegration - for UnifiedAuthenticationService +impl + ConnectorIntegration< + PostAuthenticate, + UasPostAuthenticationRequestData, + UasAuthenticationResponseData, + > for UnifiedAuthenticationService { fn get_headers( &self, - req: &PaymentsSyncRouterData, + req: &UasPostAuthenticationRouterData, connectors: &Connectors, ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) @@ -280,100 +292,43 @@ impl ConnectorIntegration fn get_url( &self, - _req: &PaymentsSyncRouterData, - _connectors: &Connectors, - ) -> CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) - } - - fn build_request( - &self, - req: &PaymentsSyncRouterData, - connectors: &Connectors, - ) -> CustomResult, errors::ConnectorError> { - Ok(Some( - RequestBuilder::new() - .method(Method::Get) - .url(&types::PaymentsSyncType::get_url(self, req, connectors)?) - .attach_default_headers() - .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?) - .build(), - )) - } - - fn handle_response( - &self, - data: &PaymentsSyncRouterData, - event_builder: Option<&mut ConnectorEvent>, - res: Response, - ) -> CustomResult { - let response: unified_authentication_service::UnifiedAuthenticationServicePaymentsResponse = - res.response - .parse_struct("unified_authentication_service PaymentsSyncResponse") - .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; - event_builder.map(|i| i.set_response_body(&response)); - router_env::logger::info!(connector_response=?response); - RouterData::try_from(ResponseRouterData { - response, - data: data.clone(), - http_code: res.status_code, - }) - } - - fn get_error_response( - &self, - res: Response, - event_builder: Option<&mut ConnectorEvent>, - ) -> CustomResult { - self.build_error_response(res, event_builder) - } -} - -impl ConnectorIntegration - for UnifiedAuthenticationService -{ - fn get_headers( - &self, - req: &PaymentsCaptureRouterData, + _req: &UasPostAuthenticationRouterData, connectors: &Connectors, - ) -> CustomResult)>, errors::ConnectorError> { - self.build_headers(req, connectors) - } - - fn get_content_type(&self) -> &'static str { - self.common_get_content_type() - } - - fn get_url( - &self, - _req: &PaymentsCaptureRouterData, - _connectors: &Connectors, ) -> CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) + Ok(format!( + "{}post_authentication_sync", + self.base_url(connectors) + )) } fn get_request_body( &self, - _req: &PaymentsCaptureRouterData, + req: &UasPostAuthenticationRouterData, _connectors: &Connectors, ) -> CustomResult { - Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into()) + let connector_req = + unified_authentication_service::UnifiedAuthenticationServicePostAuthenticateRequest::try_from( + req, + )?; + Ok(RequestContent::Json(Box::new(connector_req))) } fn build_request( &self, - req: &PaymentsCaptureRouterData, + req: &UasPostAuthenticationRouterData, connectors: &Connectors, ) -> CustomResult, errors::ConnectorError> { Ok(Some( RequestBuilder::new() .method(Method::Post) - .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?) + .url(&types::UasPostAuthenticationType::get_url( + self, req, connectors, + )?) .attach_default_headers() - .headers(types::PaymentsCaptureType::get_headers( + .headers(types::UasPostAuthenticationType::get_headers( self, req, connectors, )?) - .set_body(types::PaymentsCaptureType::get_request_body( + .set_body(types::UasPostAuthenticationType::get_request_body( self, req, connectors, )?) .build(), @@ -382,13 +337,13 @@ impl ConnectorIntegration fn handle_response( &self, - data: &PaymentsCaptureRouterData, + data: &UasPostAuthenticationRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult { - let response: unified_authentication_service::UnifiedAuthenticationServicePaymentsResponse = + ) -> CustomResult { + let response: unified_authentication_service::UnifiedAuthenticationServicePostAuthenticateResponse = res.response - .parse_struct("UnifiedAuthenticationService PaymentsCaptureResponse") + .parse_struct("UnifiedAuthenticationService UnifiedAuthenticationServicePostAuthenticateResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); @@ -408,171 +363,29 @@ impl ConnectorIntegration } } -impl ConnectorIntegration +impl ConnectorIntegration for UnifiedAuthenticationService { } -impl ConnectorIntegration +impl ConnectorIntegration for UnifiedAuthenticationService { - fn get_headers( - &self, - req: &RefundsRouterData, - connectors: &Connectors, - ) -> CustomResult)>, errors::ConnectorError> { - self.build_headers(req, connectors) - } - - fn get_content_type(&self) -> &'static str { - self.common_get_content_type() - } - - fn get_url( - &self, - _req: &RefundsRouterData, - _connectors: &Connectors, - ) -> CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) - } - - fn get_request_body( - &self, - req: &RefundsRouterData, - _connectors: &Connectors, - ) -> CustomResult { - let refund_amount = utils::convert_amount( - self.amount_converter, - req.request.minor_refund_amount, - req.request.currency, - )?; - - let connector_router_data = - unified_authentication_service::UnifiedAuthenticationServiceRouterData::from(( - refund_amount, - req, - )); - let connector_req = - unified_authentication_service::UnifiedAuthenticationServiceRefundRequest::try_from( - &connector_router_data, - )?; - Ok(RequestContent::Json(Box::new(connector_req))) - } - - fn build_request( - &self, - req: &RefundsRouterData, - connectors: &Connectors, - ) -> CustomResult, errors::ConnectorError> { - let request = RequestBuilder::new() - .method(Method::Post) - .url(&types::RefundExecuteType::get_url(self, req, connectors)?) - .attach_default_headers() - .headers(types::RefundExecuteType::get_headers( - self, req, connectors, - )?) - .set_body(types::RefundExecuteType::get_request_body( - self, req, connectors, - )?) - .build(); - Ok(Some(request)) - } +} - fn handle_response( - &self, - data: &RefundsRouterData, - event_builder: Option<&mut ConnectorEvent>, - res: Response, - ) -> CustomResult, errors::ConnectorError> { - let response: unified_authentication_service::RefundResponse = res - .response - .parse_struct("UnifiedAuthenticationService RefundResponse") - .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; - event_builder.map(|i| i.set_response_body(&response)); - router_env::logger::info!(connector_response=?response); - RouterData::try_from(ResponseRouterData { - response, - data: data.clone(), - http_code: res.status_code, - }) - } +impl ConnectorIntegration + for UnifiedAuthenticationService +{ +} - fn get_error_response( - &self, - res: Response, - event_builder: Option<&mut ConnectorEvent>, - ) -> CustomResult { - self.build_error_response(res, event_builder) - } +impl ConnectorIntegration + for UnifiedAuthenticationService +{ } impl ConnectorIntegration for UnifiedAuthenticationService { - fn get_headers( - &self, - req: &RefundSyncRouterData, - connectors: &Connectors, - ) -> CustomResult)>, errors::ConnectorError> { - self.build_headers(req, connectors) - } - - fn get_content_type(&self) -> &'static str { - self.common_get_content_type() - } - - fn get_url( - &self, - _req: &RefundSyncRouterData, - _connectors: &Connectors, - ) -> CustomResult { - Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into()) - } - - fn build_request( - &self, - req: &RefundSyncRouterData, - connectors: &Connectors, - ) -> CustomResult, errors::ConnectorError> { - Ok(Some( - RequestBuilder::new() - .method(Method::Get) - .url(&types::RefundSyncType::get_url(self, req, connectors)?) - .attach_default_headers() - .headers(types::RefundSyncType::get_headers(self, req, connectors)?) - .set_body(types::RefundSyncType::get_request_body( - self, req, connectors, - )?) - .build(), - )) - } - - fn handle_response( - &self, - data: &RefundSyncRouterData, - event_builder: Option<&mut ConnectorEvent>, - res: Response, - ) -> CustomResult { - let response: unified_authentication_service::RefundResponse = res - .response - .parse_struct("UnifiedAuthenticationService RefundSyncResponse") - .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; - event_builder.map(|i| i.set_response_body(&response)); - router_env::logger::info!(connector_response=?response); - RouterData::try_from(ResponseRouterData { - response, - data: data.clone(), - http_code: res.status_code, - }) - } - - fn get_error_response( - &self, - res: Response, - event_builder: Option<&mut ConnectorEvent>, - ) -> CustomResult { - self.build_error_response(res, event_builder) - } } #[async_trait::async_trait] diff --git a/crates/hyperswitch_connectors/src/connectors/unified_authentication_service/transformers.rs b/crates/hyperswitch_connectors/src/connectors/unified_authentication_service/transformers.rs index 6a9347dbeed7..9af21164d064 100644 --- a/crates/hyperswitch_connectors/src/connectors/unified_authentication_service/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/unified_authentication_service/transformers.rs @@ -1,30 +1,29 @@ use common_enums::enums; -use common_utils::types::StringMinorUnit; +use common_utils::types::FloatMajorUnit; use hyperswitch_domain_models::{ - payment_method_data::PaymentMethodData, router_data::{ConnectorAuthType, RouterData}, - router_flow_types::refunds::{Execute, RSync}, - router_request_types::ResponseId, - router_response_types::{PaymentsResponseData, RefundsResponseData}, - types::{PaymentsAuthorizeRouterData, RefundsRouterData}, + router_request_types::unified_authentication_service::{ + DynamicData, PostAuthenticationDetails, TokenDetails, UasAuthenticationResponseData, + }, + types::{UasPostAuthenticationRouterData, UasPreAuthenticationRouterData}, }; use hyperswitch_interfaces::errors; use masking::Secret; use serde::{Deserialize, Serialize}; +use time::PrimitiveDateTime; -use crate::{ - types::{RefundsResponseRouterData, ResponseRouterData}, - utils::PaymentsAuthorizeRequestData, -}; +use crate::types::ResponseRouterData; + +const CTP_MASTERCARD: &str = "ctp_mastercard"; //TODO: Fill the struct with respective fields pub struct UnifiedAuthenticationServiceRouterData { - pub amount: StringMinorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc. + pub amount: FloatMajorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc. pub router_data: T, } -impl From<(StringMinorUnit, T)> for UnifiedAuthenticationServiceRouterData { - fn from((amount, item): (StringMinorUnit, T)) -> Self { +impl From<(FloatMajorUnit, T)> for UnifiedAuthenticationServiceRouterData { + fn from((amount, item): (FloatMajorUnit, T)) -> Self { //Todo : use utils to convert the amount to the type of amount that a connector accepts Self { amount, @@ -33,11 +32,143 @@ impl From<(StringMinorUnit, T)> for UnifiedAuthenticationServiceRouterData } } -//TODO: Fill the struct with respective fields +#[derive(Debug, Serialize, PartialEq)] +pub struct UnifiedAuthenticationServicePreAuthenticateRequest { + pub authenticate_by: String, + pub session_id: String, + pub source_authentication_id: String, + pub authentication_info: Option, + pub service_details: Option, + pub customer_details: Option, + pub pmt_details: Option, + pub auth_creds: AuthType, + pub transaction_details: Option, +} + +#[derive(Debug, Serialize, PartialEq)] +#[serde(tag = "auth_type")] +pub enum AuthType { + HeaderKey { api_key: Secret }, +} + +#[derive(Default, Debug, Serialize, PartialEq)] +pub struct PaymentDetails { + pub pan: cards::CardNumber, + pub digital_card_id: Option, + pub payment_data_type: Option, + pub encrypted_src_card_details: Option, + pub card_expiry_date: Secret, + pub cardholder_name: Secret, + pub card_token_number: Secret, + pub account_type: u8, +} + +#[derive(Default, Debug, Serialize, PartialEq)] +pub struct TransactionDetails { + pub amount: FloatMajorUnit, + pub currency: enums::Currency, + pub date: Option, + pub pan_source: Option, + pub protection_type: Option, + pub entry_mode: Option, + pub transaction_type: Option, + pub otp_value: Option, + pub three_ds_data: Option, +} + +#[derive(Default, Debug, Serialize, PartialEq)] +pub struct ThreeDSData { + pub browser: BrowserInfo, + pub acquirer: Acquirer, +} + +#[derive(Default, Debug, Serialize, PartialEq)] +pub struct Acquirer { + pub merchant_id: String, + pub bin: u32, +} + #[derive(Default, Debug, Serialize, PartialEq)] -pub struct UnifiedAuthenticationServicePaymentsRequest { - amount: StringMinorUnit, - card: UnifiedAuthenticationServiceCard, +pub struct BrowserInfo { + pub accept_header: String, + pub screen_width: u32, + pub screen_height: u32, + pub java_enabled: bool, + pub javascript_enabled: bool, + pub language: String, + pub user_agent: String, + pub color_depth: u32, + pub ip: String, + pub tz: i32, + pub time_zone: i8, + pub challenge_window_size: String, +} + +#[derive(Default, Debug, Serialize, PartialEq)] +pub struct AuthenticationInfo { + pub authentication_type: Option, + pub authentication_reasons: Option>, + pub consent_received: bool, + pub is_authenticated: bool, + pub locale: Option, + pub supported_card_brands: Option, +} + +#[derive(Default, Debug, Serialize, PartialEq)] +pub struct CtpServiceDetails { + pub service_session_ids: Option, + pub merchant_details: Option, +} + +#[derive(Default, Debug, Serialize, PartialEq)] +pub struct ServiceSessionIds { + pub client_id: Option, + pub service_id: Option, + pub correlation_id: Option, + pub client_reference_id: Option, + pub merchant_transaction_id: Option, + pub x_src_flow_id: Option, +} + +#[derive(Default, Debug, Serialize, PartialEq)] +pub struct MerchantDetails { + pub merchant_id: String, + pub merchant_name: String, + pub mcc: String, + pub country_code: String, + pub name: String, + pub requestor_id: String, + pub requestor_name: String, + pub configuration_id: String, + pub merchant_country: String, + pub merchant_category_code: u32, +} + +#[derive(Default, Debug, Serialize, PartialEq)] +pub struct Address { + pub city: String, + pub country: String, + pub line1: Secret, + pub line2: Secret, + pub line3: Option>, + pub post_code: Secret, + pub state: Secret, +} + +#[derive(Default, Debug, Serialize, PartialEq)] +pub struct CustomerDetails { + pub name: Secret, + pub email: Option>, + pub phone_number: Option>, + pub customer_id: String, + #[serde(rename = "type")] + pub customer_type: Option, + pub billing_address: Address, + pub shipping_address: Address, + pub wallet_account_id: Secret, + pub email_hash: Secret, + pub country_code: String, + pub national_identifier: String, } #[derive(Default, Debug, Serialize, Eq, PartialEq)] @@ -49,29 +180,74 @@ pub struct UnifiedAuthenticationServiceCard { complete: bool, } -impl TryFrom<&UnifiedAuthenticationServiceRouterData<&PaymentsAuthorizeRouterData>> - for UnifiedAuthenticationServicePaymentsRequest +impl TryFrom<&UnifiedAuthenticationServiceRouterData<&UasPreAuthenticationRouterData>> + for UnifiedAuthenticationServicePreAuthenticateRequest { type Error = error_stack::Report; fn try_from( - item: &UnifiedAuthenticationServiceRouterData<&PaymentsAuthorizeRouterData>, + item: &UnifiedAuthenticationServiceRouterData<&UasPreAuthenticationRouterData>, ) -> Result { - match item.router_data.request.payment_method_data.clone() { - PaymentMethodData::Card(req_card) => { - let card = UnifiedAuthenticationServiceCard { - number: req_card.card_number, - expiry_month: req_card.card_exp_month, - expiry_year: req_card.card_exp_year, - cvc: req_card.card_cvc, - complete: item.router_data.request.is_auto_capture()?, - }; - Ok(Self { - amount: item.amount.clone(), - card, - }) - } - _ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()), - } + let auth_type = + UnifiedAuthenticationServiceAuthType::try_from(&item.router_data.connector_auth_type)?; + let authentication_id = item.router_data.authentication_id.clone().ok_or( + errors::ConnectorError::MissingRequiredField { + field_name: "authentication_id", + }, + )?; + Ok(Self { + authenticate_by: item.router_data.connector.clone(), + session_id: authentication_id.clone(), + source_authentication_id: authentication_id, + authentication_info: None, + service_details: Some(CtpServiceDetails { + service_session_ids: item.router_data.request.service_details.clone().map( + |service_details| ServiceSessionIds { + client_id: None, + service_id: None, + correlation_id: service_details + .service_session_ids + .clone() + .and_then(|service_session_ids| service_session_ids.correlation_id), + client_reference_id: None, + merchant_transaction_id: service_details + .service_session_ids + .clone() + .and_then(|service_session_ids| { + service_session_ids.merchant_transaction_id + }), + x_src_flow_id: service_details + .service_session_ids + .clone() + .and_then(|service_session_ids| service_session_ids.x_src_flow_id), + }, + ), + merchant_details: None, + }), + customer_details: None, + pmt_details: None, + auth_creds: AuthType::HeaderKey { + api_key: auth_type.api_key, + }, + transaction_details: Some(TransactionDetails { + amount: item.amount, + currency: item + .router_data + .request + .transaction_details + .clone() + .ok_or(errors::ConnectorError::MissingRequiredField { + field_name: "transaction_details", + })? + .currency, + date: None, + pan_source: None, + protection_type: None, + entry_mode: None, + transaction_type: None, + otp_value: None, + three_ds_data: None, + }), + }) } } @@ -92,144 +268,154 @@ impl TryFrom<&ConnectorAuthType> for UnifiedAuthenticationServiceAuthType { } } } -// PaymentsResponse -//TODO: Append the remaining status flags -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -#[serde(rename_all = "lowercase")] -pub enum UnifiedAuthenticationServicePaymentStatus { - Succeeded, - Failed, - #[default] - Processing, -} - -impl From for common_enums::AttemptStatus { - fn from(item: UnifiedAuthenticationServicePaymentStatus) -> Self { - match item { - UnifiedAuthenticationServicePaymentStatus::Succeeded => Self::Charged, - UnifiedAuthenticationServicePaymentStatus::Failed => Self::Failure, - UnifiedAuthenticationServicePaymentStatus::Processing => Self::Authorizing, - } - } + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum UnifiedAuthenticationServicePreAuthenticateStatus { + ACKSUCCESS, + ACKFAILURE, } -//TODO: Fill the struct with respective fields -#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct UnifiedAuthenticationServicePaymentsResponse { - status: UnifiedAuthenticationServicePaymentStatus, - id: String, +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct UnifiedAuthenticationServicePreAuthenticateResponse { + status: UnifiedAuthenticationServicePreAuthenticateStatus, } impl TryFrom< ResponseRouterData< F, - UnifiedAuthenticationServicePaymentsResponse, + UnifiedAuthenticationServicePreAuthenticateResponse, T, - PaymentsResponseData, + UasAuthenticationResponseData, >, - > for RouterData + > for RouterData { type Error = error_stack::Report; fn try_from( item: ResponseRouterData< F, - UnifiedAuthenticationServicePaymentsResponse, + UnifiedAuthenticationServicePreAuthenticateResponse, T, - PaymentsResponseData, + UasAuthenticationResponseData, >, ) -> Result { Ok(Self { - status: common_enums::AttemptStatus::from(item.response.status), - response: Ok(PaymentsResponseData::TransactionResponse { - resource_id: ResponseId::ConnectorTransactionId(item.response.id), - redirection_data: Box::new(None), - mandate_reference: Box::new(None), - connector_metadata: None, - network_txn_id: None, - connector_response_reference_id: None, - incremental_authorization_allowed: None, - charge_id: None, - }), + response: Ok(UasAuthenticationResponseData::PreAuthentication {}), ..item.data }) } } -//TODO: Fill the struct with respective fields -// REFUND : -// Type definition for RefundRequest -#[derive(Default, Debug, Serialize)] -pub struct UnifiedAuthenticationServiceRefundRequest { - pub amount: StringMinorUnit, +#[derive(Debug, Serialize, PartialEq)] +pub struct UnifiedAuthenticationServicePostAuthenticateRequest { + pub authenticate_by: String, + pub source_authentication_id: String, + pub auth_creds: AuthType, } -impl TryFrom<&UnifiedAuthenticationServiceRouterData<&RefundsRouterData>> - for UnifiedAuthenticationServiceRefundRequest -{ - type Error = error_stack::Report; - fn try_from( - item: &UnifiedAuthenticationServiceRouterData<&RefundsRouterData>, - ) -> Result { - Ok(Self { - amount: item.amount.to_owned(), - }) - } +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct UnifiedAuthenticationServicePostAuthenticateResponse { + pub authentication_details: AuthenticationDetails, } -// Type definition for Refund Response - -#[allow(dead_code)] -#[derive(Debug, Serialize, Default, Deserialize, Clone)] -pub enum RefundStatus { - Succeeded, - Failed, - #[default] - Processing, +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct AuthenticationDetails { + pub eci: Option, + pub token_details: UasTokenDetails, + pub dynamic_data_details: Option, } -impl From for enums::RefundStatus { - fn from(item: RefundStatus) -> Self { - match item { - RefundStatus::Succeeded => Self::Success, - RefundStatus::Failed => Self::Failure, - RefundStatus::Processing => Self::Pending, - //TODO: Review mapping - } - } +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct UasTokenDetails { + pub payment_token: cards::CardNumber, + pub payment_account_reference: String, + pub token_expiration_month: Secret, + pub token_expiration_year: Secret, } -//TODO: Fill the struct with respective fields -#[derive(Default, Debug, Clone, Serialize, Deserialize)] -pub struct RefundResponse { - id: String, - status: RefundStatus, +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct UasDynamicData { + pub dynamic_data_value: Option>, + pub dynamic_data_type: String, + pub ds_trans_id: Option, } -impl TryFrom> for RefundsRouterData { +impl TryFrom<&UasPostAuthenticationRouterData> + for UnifiedAuthenticationServicePostAuthenticateRequest +{ type Error = error_stack::Report; - fn try_from( - item: RefundsResponseRouterData, - ) -> Result { + fn try_from(item: &UasPostAuthenticationRouterData) -> Result { + let auth_type = UnifiedAuthenticationServiceAuthType::try_from(&item.connector_auth_type)?; Ok(Self { - response: Ok(RefundsResponseData { - connector_refund_id: item.response.id.to_string(), - refund_status: enums::RefundStatus::from(item.response.status), - }), - ..item.data + authenticate_by: CTP_MASTERCARD.to_owned(), + source_authentication_id: item.authentication_id.clone().ok_or( + errors::ConnectorError::MissingRequiredField { + field_name: "authentication_id", + }, + )?, + auth_creds: AuthType::HeaderKey { + api_key: auth_type.api_key, + }, }) } } -impl TryFrom> for RefundsRouterData { +impl + TryFrom< + ResponseRouterData< + F, + UnifiedAuthenticationServicePostAuthenticateResponse, + T, + UasAuthenticationResponseData, + >, + > for RouterData +{ type Error = error_stack::Report; fn try_from( - item: RefundsResponseRouterData, + item: ResponseRouterData< + F, + UnifiedAuthenticationServicePostAuthenticateResponse, + T, + UasAuthenticationResponseData, + >, ) -> Result { Ok(Self { - response: Ok(RefundsResponseData { - connector_refund_id: item.response.id.to_string(), - refund_status: enums::RefundStatus::from(item.response.status), + response: Ok(UasAuthenticationResponseData::PostAuthentication { + authentication_details: PostAuthenticationDetails { + eci: item.response.authentication_details.eci, + token_details: TokenDetails { + payment_token: item + .response + .authentication_details + .token_details + .payment_token, + payment_account_reference: item + .response + .authentication_details + .token_details + .payment_account_reference, + token_expiration_month: item + .response + .authentication_details + .token_details + .token_expiration_month, + token_expiration_year: item + .response + .authentication_details + .token_details + .token_expiration_year, + }, + dynamic_data_details: item + .response + .authentication_details + .dynamic_data_details + .map(|dynamic_data| DynamicData { + dynamic_data_value: dynamic_data.dynamic_data_value, + dynamic_data_type: dynamic_data.dynamic_data_type, + ds_trans_id: dynamic_data.ds_trans_id, + }), + }, }), ..item.data }) @@ -239,8 +425,5 @@ impl TryFrom> for RefundsRouter //TODO: Fill the struct with respective fields #[derive(Default, Debug, Serialize, Deserialize, PartialEq)] pub struct UnifiedAuthenticationServiceErrorResponse { - pub status_code: u16, - pub code: String, - pub message: String, - pub reason: Option, + pub error: String, } diff --git a/crates/hyperswitch_connectors/src/constants.rs b/crates/hyperswitch_connectors/src/constants.rs index 48a32c180474..9ca4ee9591fb 100644 --- a/crates/hyperswitch_connectors/src/constants.rs +++ b/crates/hyperswitch_connectors/src/constants.rs @@ -26,6 +26,7 @@ pub(crate) mod headers { pub(crate) const X_API_KEY: &str = "X-Api-Key"; pub(crate) const CORRELATION_ID: &str = "Correlation-Id"; pub(crate) const WP_API_VERSION: &str = "WP-Api-Version"; + pub(crate) const SOURCE: &str = "Source"; } /// Unsupported response type error message diff --git a/crates/hyperswitch_connectors/src/default_implementations.rs b/crates/hyperswitch_connectors/src/default_implementations.rs index 041e519acdc6..703b0bb2ac7e 100644 --- a/crates/hyperswitch_connectors/src/default_implementations.rs +++ b/crates/hyperswitch_connectors/src/default_implementations.rs @@ -33,8 +33,13 @@ use hyperswitch_domain_models::{ PreProcessing, Reject, SdkSessionUpdate, }, webhooks::VerifyWebhookSource, + PostAuthenticate, PreAuthenticate, }, router_request_types::{ + unified_authentication_service::{ + UasAuthenticationResponseData, UasPostAuthenticationRequestData, + UasPreAuthenticationRequestData, + }, AcceptDisputeRequestData, AuthorizeSessionTokenData, CompleteAuthorizeData, ConnectorCustomerData, DefendDisputeRequestData, MandateRevokeRequestData, PaymentsApproveData, PaymentsIncrementalAuthorizationData, PaymentsPostProcessingData, @@ -70,6 +75,7 @@ use hyperswitch_interfaces::{ PaymentsPreProcessing, TaxCalculation, }, ConnectorIntegration, ConnectorMandateRevoke, ConnectorRedirectResponse, + UasPostAuthentication, UasPreAuthentication, UnifiedAuthenticationService, }, errors::ConnectorError, }; @@ -140,7 +146,8 @@ default_imp_for_authorize_session_token!( connectors::Worldpay, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); macro_rules! default_imp_for_calculate_tax { @@ -209,7 +216,8 @@ default_imp_for_calculate_tax!( connectors::Worldpay, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); macro_rules! default_imp_for_session_update { @@ -279,7 +287,8 @@ default_imp_for_session_update!( connectors::Thunes, connectors::Tsys, connectors::Deutschebank, - connectors::Volt + connectors::Volt, + connectors::CtpMastercard ); macro_rules! default_imp_for_post_session_tokens { @@ -349,7 +358,8 @@ default_imp_for_post_session_tokens!( connectors::Deutschebank, connectors::Volt, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); use crate::connectors; @@ -409,7 +419,8 @@ default_imp_for_complete_authorize!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); macro_rules! default_imp_for_incremental_authorization { @@ -480,7 +491,8 @@ default_imp_for_incremental_authorization!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); macro_rules! default_imp_for_create_customer { @@ -549,7 +561,8 @@ default_imp_for_create_customer!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); macro_rules! default_imp_for_connector_redirect_response { @@ -613,7 +626,8 @@ default_imp_for_connector_redirect_response!( connectors::Worldline, connectors::Volt, connectors::Xendit, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); macro_rules! default_imp_for_pre_processing_steps{ @@ -680,7 +694,8 @@ default_imp_for_pre_processing_steps!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); macro_rules! default_imp_for_post_processing_steps{ @@ -751,7 +766,8 @@ default_imp_for_post_processing_steps!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); macro_rules! default_imp_for_approve { @@ -822,7 +838,8 @@ default_imp_for_approve!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); macro_rules! default_imp_for_reject { @@ -893,7 +910,8 @@ default_imp_for_reject!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); macro_rules! default_imp_for_webhook_source_verification { @@ -964,7 +982,8 @@ default_imp_for_webhook_source_verification!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); macro_rules! default_imp_for_accept_dispute { @@ -1036,7 +1055,8 @@ default_imp_for_accept_dispute!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); macro_rules! default_imp_for_submit_evidence { @@ -1107,7 +1127,8 @@ default_imp_for_submit_evidence!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); macro_rules! default_imp_for_defend_dispute { @@ -1178,7 +1199,8 @@ default_imp_for_defend_dispute!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); macro_rules! default_imp_for_file_upload { @@ -1258,7 +1280,8 @@ default_imp_for_file_upload!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); macro_rules! default_imp_for_payouts { @@ -1321,7 +1344,8 @@ default_imp_for_payouts!( connectors::Worldpay, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); #[cfg(feature = "payouts")] @@ -1394,7 +1418,8 @@ default_imp_for_payouts_create!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); #[cfg(feature = "payouts")] @@ -1467,7 +1492,8 @@ default_imp_for_payouts_retrieve!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); #[cfg(feature = "payouts")] @@ -1540,7 +1566,8 @@ default_imp_for_payouts_eligibility!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); #[cfg(feature = "payouts")] @@ -1613,7 +1640,8 @@ default_imp_for_payouts_fulfill!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); #[cfg(feature = "payouts")] @@ -1686,7 +1714,8 @@ default_imp_for_payouts_cancel!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); #[cfg(feature = "payouts")] @@ -1759,7 +1788,8 @@ default_imp_for_payouts_quote!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); #[cfg(feature = "payouts")] @@ -1832,7 +1862,8 @@ default_imp_for_payouts_recipient!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); #[cfg(feature = "payouts")] @@ -1905,7 +1936,8 @@ default_imp_for_payouts_recipient_account!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); #[cfg(feature = "frm")] @@ -1978,7 +2010,8 @@ default_imp_for_frm_sale!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); #[cfg(feature = "frm")] @@ -2051,7 +2084,8 @@ default_imp_for_frm_checkout!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); #[cfg(feature = "frm")] @@ -2124,7 +2158,8 @@ default_imp_for_frm_transaction!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); #[cfg(feature = "frm")] @@ -2197,7 +2232,8 @@ default_imp_for_frm_fulfillment!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); #[cfg(feature = "frm")] @@ -2270,7 +2306,8 @@ default_imp_for_frm_record_return!( connectors::Volt, connectors::Xendit, connectors::Zen, - connectors::Zsl + connectors::Zsl, + connectors::CtpMastercard ); macro_rules! default_imp_for_revoking_mandates { @@ -2340,5 +2377,147 @@ default_imp_for_revoking_mandates!( connectors::Volt, connectors::Xendit, connectors::Zen, + connectors::Zsl, + connectors::CtpMastercard +); + +macro_rules! default_imp_for_uas_pre_authentication { + ($($path:ident::$connector:ident),*) => { + $( impl UnifiedAuthenticationService for $path::$connector {} + impl UasPreAuthentication for $path::$connector {} + impl + ConnectorIntegration< + PreAuthenticate, + UasPreAuthenticationRequestData, + UasAuthenticationResponseData + > for $path::$connector + {} + )* + }; +} + +default_imp_for_uas_pre_authentication!( + connectors::Airwallex, + connectors::Amazonpay, + connectors::Bambora, + connectors::Bamboraapac, + connectors::Billwerk, + connectors::Bluesnap, + connectors::Bitpay, + connectors::Boku, + connectors::Cashtocode, + connectors::Coinbase, + connectors::Cryptopay, + connectors::CtpMastercard, + connectors::Datatrans, + connectors::Deutschebank, + connectors::Digitalvirgo, + connectors::Dlocal, + connectors::Elavon, + connectors::Fiserv, + connectors::Fiservemea, + connectors::Fiuu, + connectors::Forte, + connectors::Globepay, + connectors::Gocardless, + connectors::Helcim, + connectors::Inespay, + connectors::Jpmorgan, + connectors::Nomupay, + connectors::Novalnet, + connectors::Nexinets, + connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, + connectors::Powertranz, + connectors::Prophetpay, + connectors::Mollie, + connectors::Multisafepay, + connectors::Paybox, + connectors::Placetopay, + connectors::Rapyd, + connectors::Razorpay, + connectors::Redsys, + connectors::Shift4, + connectors::Stax, + connectors::Square, + connectors::Taxjar, + connectors::Thunes, + connectors::Tsys, + connectors::Worldline, + connectors::Worldpay, + connectors::Volt, + connectors::Xendit, + connectors::Zen, + connectors::Zsl +); + +macro_rules! default_imp_for_uas_post_authentication { + ($($path:ident::$connector:ident),*) => { + $( impl UasPostAuthentication for $path::$connector {} + impl + ConnectorIntegration< + PostAuthenticate, + UasPostAuthenticationRequestData, + UasAuthenticationResponseData + > for $path::$connector + {} + )* + }; +} + +default_imp_for_uas_post_authentication!( + connectors::Airwallex, + connectors::Amazonpay, + connectors::Bambora, + connectors::Bamboraapac, + connectors::Billwerk, + connectors::Bitpay, + connectors::Bluesnap, + connectors::Boku, + connectors::Cashtocode, + connectors::Coinbase, + connectors::Cryptopay, + connectors::CtpMastercard, + connectors::Datatrans, + connectors::Deutschebank, + connectors::Digitalvirgo, + connectors::Dlocal, + connectors::Elavon, + connectors::Fiserv, + connectors::Fiservemea, + connectors::Fiuu, + connectors::Forte, + connectors::Globepay, + connectors::Gocardless, + connectors::Helcim, + connectors::Inespay, + connectors::Jpmorgan, + connectors::Nomupay, + connectors::Novalnet, + connectors::Nexinets, + connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, + connectors::Powertranz, + connectors::Prophetpay, + connectors::Mollie, + connectors::Multisafepay, + connectors::Paybox, + connectors::Placetopay, + connectors::Rapyd, + connectors::Razorpay, + connectors::Redsys, + connectors::Shift4, + connectors::Stax, + connectors::Square, + connectors::Taxjar, + connectors::Thunes, + connectors::Tsys, + connectors::Worldline, + connectors::Worldpay, + connectors::Volt, + connectors::Xendit, + connectors::Zen, connectors::Zsl ); diff --git a/crates/hyperswitch_connectors/src/default_implementations_v2.rs b/crates/hyperswitch_connectors/src/default_implementations_v2.rs index 33c45a542257..4161b36f906e 100644 --- a/crates/hyperswitch_connectors/src/default_implementations_v2.rs +++ b/crates/hyperswitch_connectors/src/default_implementations_v2.rs @@ -216,6 +216,7 @@ default_imp_for_new_connector_integration_payment!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -288,6 +289,7 @@ default_imp_for_new_connector_integration_refund!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -355,6 +357,7 @@ default_imp_for_new_connector_integration_connector_access_token!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -428,6 +431,7 @@ default_imp_for_new_connector_integration_accept_dispute!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -500,6 +504,7 @@ default_imp_for_new_connector_integration_submit_evidence!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -572,6 +577,7 @@ default_imp_for_new_connector_integration_defend_dispute!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -654,6 +660,7 @@ default_imp_for_new_connector_integration_file_upload!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -728,6 +735,7 @@ default_imp_for_new_connector_integration_payouts_create!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -802,6 +810,7 @@ default_imp_for_new_connector_integration_payouts_eligibility!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -876,6 +885,7 @@ default_imp_for_new_connector_integration_payouts_fulfill!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -950,6 +960,7 @@ default_imp_for_new_connector_integration_payouts_cancel!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -1024,6 +1035,7 @@ default_imp_for_new_connector_integration_payouts_quote!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -1098,6 +1110,7 @@ default_imp_for_new_connector_integration_payouts_recipient!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -1172,6 +1185,7 @@ default_imp_for_new_connector_integration_payouts_sync!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -1246,6 +1260,7 @@ default_imp_for_new_connector_integration_payouts_recipient_account!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -1318,6 +1333,7 @@ default_imp_for_new_connector_integration_webhook_source_verification!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -1392,6 +1408,7 @@ default_imp_for_new_connector_integration_frm_sale!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -1466,6 +1483,7 @@ default_imp_for_new_connector_integration_frm_checkout!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -1540,6 +1558,7 @@ default_imp_for_new_connector_integration_frm_transaction!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -1614,6 +1633,7 @@ default_imp_for_new_connector_integration_frm_fulfillment!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -1688,6 +1708,7 @@ default_imp_for_new_connector_integration_frm_record_return!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, @@ -1759,6 +1780,7 @@ default_imp_for_new_connector_integration_revoking_mandates!( connectors::Cashtocode, connectors::Coinbase, connectors::Cryptopay, + connectors::CtpMastercard, connectors::Datatrans, connectors::Deutschebank, connectors::Digitalvirgo, diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs index db35766f33ae..169719cb5dad 100644 --- a/crates/hyperswitch_domain_models/src/payment_method_data.rs +++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs @@ -596,6 +596,7 @@ pub struct NetworkTokenData { pub card_issuing_country: Option, pub bank_code: Option, pub nick_name: Option>, + pub eci: Option, } #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] diff --git a/crates/hyperswitch_domain_models/src/router_flow_types.rs b/crates/hyperswitch_domain_models/src/router_flow_types.rs index 6cdde87772b0..bdd7691b681a 100644 --- a/crates/hyperswitch_domain_models/src/router_flow_types.rs +++ b/crates/hyperswitch_domain_models/src/router_flow_types.rs @@ -6,6 +6,7 @@ pub mod mandate_revoke; pub mod payments; pub mod payouts; pub mod refunds; +pub mod unified_authentication_service; pub mod webhooks; pub use access_token_auth::*; @@ -15,4 +16,5 @@ pub use fraud_check::*; pub use payments::*; pub use payouts::*; pub use refunds::*; +pub use unified_authentication_service::*; pub use webhooks::*; diff --git a/crates/hyperswitch_domain_models/src/router_flow_types/unified_authentication_service.rs b/crates/hyperswitch_domain_models/src/router_flow_types/unified_authentication_service.rs new file mode 100644 index 000000000000..329c18b741ed --- /dev/null +++ b/crates/hyperswitch_domain_models/src/router_flow_types/unified_authentication_service.rs @@ -0,0 +1,5 @@ +#[derive(Debug, Clone)] +pub struct PreAuthenticate; + +#[derive(Debug, Clone)] +pub struct PostAuthenticate; diff --git a/crates/hyperswitch_domain_models/src/router_request_types/unified_authentication_service.rs b/crates/hyperswitch_domain_models/src/router_request_types/unified_authentication_service.rs index 6dd899cd5b38..af2a940cb51b 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types/unified_authentication_service.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types/unified_authentication_service.rs @@ -25,7 +25,7 @@ pub struct TransactionDetails { } #[derive(Clone, Debug)] -pub struct UasPostAuthenticationRequestData; +pub struct UasPostAuthenticationRequestData {} #[derive(Debug, Clone)] pub enum UasAuthenticationResponseData { diff --git a/crates/hyperswitch_domain_models/src/types.rs b/crates/hyperswitch_domain_models/src/types.rs index 201a073dd3e3..2dd38d88b6d9 100644 --- a/crates/hyperswitch_domain_models/src/types.rs +++ b/crates/hyperswitch_domain_models/src/types.rs @@ -5,9 +5,14 @@ use crate::{ router_flow_types::{ AccessTokenAuth, Authorize, AuthorizeSessionToken, CalculateTax, Capture, CompleteAuthorize, CreateConnectorCustomer, Execute, PSync, PaymentMethodToken, - PostSessionTokens, PreProcessing, RSync, Session, SetupMandate, Void, + PostAuthenticate, PostSessionTokens, PreAuthenticate, PreProcessing, RSync, Session, + SetupMandate, Void, }, router_request_types::{ + unified_authentication_service::{ + UasAuthenticationResponseData, UasPostAuthenticationRequestData, + UasPreAuthenticationRequestData, + }, AccessTokenRequestData, AuthorizeSessionTokenData, CompleteAuthorizeData, ConnectorCustomerData, PaymentMethodTokenizationData, PaymentsAuthorizeData, PaymentsCancelData, PaymentsCaptureData, PaymentsPostSessionTokensData, @@ -45,3 +50,9 @@ pub type RefreshTokenRouterData = RouterData; pub type PaymentsSessionRouterData = RouterData; + +pub type UasPostAuthenticationRouterData = + RouterData; + +pub type UasPreAuthenticationRouterData = + RouterData; diff --git a/crates/hyperswitch_interfaces/src/api.rs b/crates/hyperswitch_interfaces/src/api.rs index 617832f191df..bb6b2a4e4f5b 100644 --- a/crates/hyperswitch_interfaces/src/api.rs +++ b/crates/hyperswitch_interfaces/src/api.rs @@ -27,9 +27,17 @@ use hyperswitch_domain_models::{ router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData}, router_data_v2::{ flow_common_types::WebhookSourceVerifyData, AccessTokenFlowData, MandateRevokeFlowData, + UasFlowData, + }, + router_flow_types::{ + mandate_revoke::MandateRevoke, AccessTokenAuth, PostAuthenticate, PreAuthenticate, + VerifyWebhookSource, }, - router_flow_types::{mandate_revoke::MandateRevoke, AccessTokenAuth, VerifyWebhookSource}, router_request_types::{ + unified_authentication_service::{ + UasAuthenticationResponseData, UasPostAuthenticationRequestData, + UasPreAuthenticationRequestData, + }, AccessTokenRequestData, MandateRevokeRequestData, VerifyWebhookSourceRequestData, }, router_response_types::{MandateRevokeResponseData, VerifyWebhookSourceResponseData}, @@ -336,6 +344,60 @@ pub trait ConnectorVerifyWebhookSourceV2: { } +/// trait UnifiedAuthenticationService +pub trait UnifiedAuthenticationService: + ConnectorCommon + UasPreAuthentication + UasPostAuthentication +{ +} + +/// trait UasPreAuthentication +pub trait UasPreAuthentication: + ConnectorIntegration< + PreAuthenticate, + UasPreAuthenticationRequestData, + UasAuthenticationResponseData, +> +{ +} + +/// trait UasPostAuthentication +pub trait UasPostAuthentication: + ConnectorIntegration< + PostAuthenticate, + UasPostAuthenticationRequestData, + UasAuthenticationResponseData, +> +{ +} + +/// trait UnifiedAuthenticationServiceV2 +pub trait UnifiedAuthenticationServiceV2: + ConnectorCommon + UasPreAuthenticationV2 + UasPostAuthenticationV2 +{ +} + +///trait UasPreAuthenticationV2 +pub trait UasPreAuthenticationV2: + ConnectorIntegrationV2< + PreAuthenticate, + UasFlowData, + UasPreAuthenticationRequestData, + UasAuthenticationResponseData, +> +{ +} + +/// trait UasPostAuthenticationV2 +pub trait UasPostAuthenticationV2: + ConnectorIntegrationV2< + PostAuthenticate, + UasFlowData, + UasPostAuthenticationRequestData, + UasAuthenticationResponseData, +> +{ +} + /// trait ConnectorValidation pub trait ConnectorValidation: ConnectorCommon { /// fn validate_capture_method diff --git a/crates/hyperswitch_interfaces/src/configs.rs b/crates/hyperswitch_interfaces/src/configs.rs index e7e59d2d0637..4a3b99636dc3 100644 --- a/crates/hyperswitch_interfaces/src/configs.rs +++ b/crates/hyperswitch_interfaces/src/configs.rs @@ -3,7 +3,6 @@ use common_enums::ApplicationError; use masking::Secret; use router_derive; use serde::Deserialize; - // struct Connectors #[allow(missing_docs, missing_debug_implementations)] #[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)] @@ -28,6 +27,7 @@ pub struct Connectors { pub checkout: ConnectorParams, pub coinbase: ConnectorParams, pub cryptopay: ConnectorParams, + pub ctp_mastercard: NoParams, pub cybersource: ConnectorParams, pub datatrans: ConnectorParams, pub deutschebank: ConnectorParams, @@ -110,6 +110,17 @@ pub struct ConnectorParams { pub secondary_base_url: Option, } +///struct No Param for connectors with no params +#[derive(Debug, Deserialize, Clone, Default)] +pub struct NoParams; + +impl NoParams { + /// function to satisfy connector param validation macro + pub fn validate(&self, _parent_field: &str) -> Result<(), ApplicationError> { + Ok(()) + } +} + /// struct ConnectorParamsWithKeys #[derive(Debug, Deserialize, Clone, Default, router_derive::ConfigValidate)] #[serde(default)] diff --git a/crates/hyperswitch_interfaces/src/types.rs b/crates/hyperswitch_interfaces/src/types.rs index 41a1b1ba83c9..dd344edf9da2 100644 --- a/crates/hyperswitch_interfaces/src/types.rs +++ b/crates/hyperswitch_interfaces/src/types.rs @@ -13,9 +13,14 @@ use hyperswitch_domain_models::{ Session, SetupMandate, Void, }, refunds::{Execute, RSync}, + unified_authentication_service::{PostAuthenticate, PreAuthenticate}, webhooks::VerifyWebhookSource, }, router_request_types::{ + unified_authentication_service::{ + UasAuthenticationResponseData, UasPostAuthenticationRequestData, + UasPreAuthenticationRequestData, + }, AcceptDisputeRequestData, AccessTokenRequestData, AuthorizeSessionTokenData, CompleteAuthorizeData, ConnectorCustomerData, DefendDisputeRequestData, MandateRevokeRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData, @@ -185,3 +190,17 @@ pub type RetrieveFileType = /// Type alias for `ConnectorIntegration` pub type DefendDisputeType = dyn ConnectorIntegration; + +/// Type alias for `ConnectorIntegration` +pub type UasPreAuthenticationType = dyn ConnectorIntegration< + PreAuthenticate, + UasPreAuthenticationRequestData, + UasAuthenticationResponseData, +>; + +/// Type alias for `ConnectorIntegration` +pub type UasPostAuthenticationType = dyn ConnectorIntegration< + PostAuthenticate, + UasPostAuthenticationRequestData, + UasAuthenticationResponseData, +>; diff --git a/crates/router/src/connector.rs b/crates/router/src/connector.rs index 3d3c42d07961..0da0e711fbca 100644 --- a/crates/router/src/connector.rs +++ b/crates/router/src/connector.rs @@ -39,15 +39,16 @@ pub use hyperswitch_connectors::connectors::{ airwallex, airwallex::Airwallex, amazonpay, amazonpay::Amazonpay, bambora, bambora::Bambora, bamboraapac, bamboraapac::Bamboraapac, billwerk, billwerk::Billwerk, bitpay, bitpay::Bitpay, bluesnap, bluesnap::Bluesnap, boku, boku::Boku, cashtocode, cashtocode::Cashtocode, coinbase, - coinbase::Coinbase, cryptopay, cryptopay::Cryptopay, datatrans, datatrans::Datatrans, - deutschebank, deutschebank::Deutschebank, digitalvirgo, digitalvirgo::Digitalvirgo, dlocal, - dlocal::Dlocal, elavon, elavon::Elavon, fiserv, fiserv::Fiserv, fiservemea, - fiservemea::Fiservemea, fiuu, fiuu::Fiuu, forte, forte::Forte, globepay, globepay::Globepay, - gocardless, gocardless::Gocardless, helcim, helcim::Helcim, inespay, inespay::Inespay, - jpmorgan, jpmorgan::Jpmorgan, mollie, mollie::Mollie, multisafepay, multisafepay::Multisafepay, - nexinets, nexinets::Nexinets, nexixpay, nexixpay::Nexixpay, nomupay, nomupay::Nomupay, - novalnet, novalnet::Novalnet, paybox, paybox::Paybox, payeezy, payeezy::Payeezy, payu, - payu::Payu, placetopay, placetopay::Placetopay, powertranz, powertranz::Powertranz, prophetpay, + coinbase::Coinbase, cryptopay, cryptopay::Cryptopay, ctp_mastercard, + ctp_mastercard::CtpMastercard, datatrans, datatrans::Datatrans, deutschebank, + deutschebank::Deutschebank, digitalvirgo, digitalvirgo::Digitalvirgo, dlocal, dlocal::Dlocal, + elavon, elavon::Elavon, fiserv, fiserv::Fiserv, fiservemea, fiservemea::Fiservemea, fiuu, + fiuu::Fiuu, forte, forte::Forte, globepay, globepay::Globepay, gocardless, + gocardless::Gocardless, helcim, helcim::Helcim, inespay, inespay::Inespay, jpmorgan, + jpmorgan::Jpmorgan, mollie, mollie::Mollie, multisafepay, multisafepay::Multisafepay, nexinets, + nexinets::Nexinets, nexixpay, nexixpay::Nexixpay, nomupay, nomupay::Nomupay, novalnet, + novalnet::Novalnet, paybox, paybox::Paybox, payeezy, payeezy::Payeezy, payu, payu::Payu, + placetopay, placetopay::Placetopay, powertranz, powertranz::Powertranz, prophetpay, prophetpay::Prophetpay, rapyd, rapyd::Rapyd, razorpay, razorpay::Razorpay, redsys, redsys::Redsys, shift4, shift4::Shift4, square, square::Square, stax, stax::Stax, taxjar, taxjar::Taxjar, thunes, thunes::Thunes, tsys, tsys::Tsys, unified_authentication_service, diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index 7aaf9b5e2bb2..6f9fd33ef1c6 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -15,7 +15,7 @@ use crate::{connector::utils::PayoutsData, types::api::payouts, utils::OptionExt use crate::{ connector::utils::{ self, missing_field_err, AddressDetailsData, BrowserInformationData, CardData, - PaymentsAuthorizeRequestData, PhoneDetailsData, RouterData, + NetworkTokenData, PaymentsAuthorizeRequestData, PhoneDetailsData, RouterData, }, consts, core::errors, @@ -618,6 +618,7 @@ pub enum AdyenPaymentMethod<'a> { #[serde(rename = "econtext_stores")] PayEasy(Box), Pix(Box), + NetworkToken(Box), } #[derive(Debug, Clone, Serialize)] @@ -731,7 +732,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for JCSVoucherData { Ok(Self { first_name: item.get_billing_first_name()?, last_name: item.get_optional_billing_last_name(), - shopper_email: item.get_billing_email().or(item.request.get_email())?, + shopper_email: item.get_billing_email()?, telephone_number: item.get_billing_phone_number()?, }) } @@ -1217,6 +1218,19 @@ pub struct AdyenApplePay { } #[serde_with::skip_serializing_none] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AdyenNetworkTokenData { + #[serde(rename = "type")] + payment_type: PaymentType, + number: CardNumber, + expiry_month: Secret, + expiry_year: Secret, + holder_name: Option>, + brand: Option, //Mandatory for mandate using network_txns_id + network_payment_reference: Option>, +} + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct DokuBankData { @@ -1598,6 +1612,9 @@ impl TryFrom<&AdyenRouterData<&types::PaymentsAuthorizeRouterData>> for AdyenPay domain::PaymentMethodData::GiftCard(ref gift_card_data) => { AdyenPaymentRequest::try_from((item, gift_card_data.as_ref())) } + domain::PaymentMethodData::NetworkToken(ref token_data) => { + AdyenPaymentRequest::try_from((item, token_data)) + } domain::PaymentMethodData::Crypto(_) | domain::PaymentMethodData::MandatePayment | domain::PaymentMethodData::Reward @@ -1606,7 +1623,6 @@ impl TryFrom<&AdyenRouterData<&types::PaymentsAuthorizeRouterData>> for AdyenPay | domain::PaymentMethodData::Upi(_) | domain::PaymentMethodData::OpenBanking(_) | domain::PaymentMethodData::CardToken(_) - | domain::PaymentMethodData::NetworkToken(_) | domain::PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("Adyen"), @@ -2567,18 +2583,11 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for DokuBankData { Ok(Self { first_name: item.get_billing_first_name()?, last_name: item.get_optional_billing_last_name(), - shopper_email: item.get_billing_email().or(item.request.get_email())?, + shopper_email: item.get_billing_email()?, }) } } -fn get_optional_shopper_email(item: &types::PaymentsAuthorizeRouterData) -> Option { - match item.get_billing_email() { - Ok(email) => Some(email), - Err(_) => item.request.get_optional_email(), - } -} - impl TryFrom<&domain::payments::CardRedirectData> for AdyenPaymentMethod<'_> { type Error = Error; fn try_from( @@ -2615,7 +2624,6 @@ impl let amount = get_amount_data(item); let auth_type = AdyenAuthType::try_from(&item.router_data.connector_auth_type)?; let shopper_interaction = AdyenShopperInteraction::from(item.router_data); - let shopper_email = get_optional_shopper_email(item.router_data); let (recurring_processing_model, store_payment_method, shopper_reference) = get_recurring_processing_model(item.router_data)?; let browser_info = None; @@ -2697,12 +2705,53 @@ impl } } } - payments::MandateReferenceId::NetworkTokenWithNTI(_) => { - Err(errors::ConnectorError::NotSupported { - message: "Network tokenization for payment method".to_string(), - connector: "Adyen", - })? - } + payments::MandateReferenceId::NetworkTokenWithNTI(network_mandate_id) => { + match item.router_data.request.payment_method_data { + domain::PaymentMethodData::NetworkToken(ref token_data) => { + let card_issuer = token_data.get_card_issuer()?; + let brand = CardBrand::try_from(&card_issuer)?; + let card_holder_name = item.router_data.get_optional_billing_full_name(); + let adyen_network_token = AdyenNetworkTokenData { + payment_type: PaymentType::NetworkToken, + number: token_data.token_number.clone(), + expiry_month: token_data.token_exp_month.clone(), + expiry_year: token_data.get_expiry_year_4_digit(), + holder_name: card_holder_name, + brand: Some(brand), // FIXME: Remove hardcoding + network_payment_reference: Some(Secret::new( + network_mandate_id.network_transaction_id, + )), + }; + Ok(AdyenPaymentMethod::NetworkToken(Box::new( + adyen_network_token, + ))) + } + + 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::RealTimePayment(_) + | domain::PaymentMethodData::Upi(_) + | domain::PaymentMethodData::Voucher(_) + | domain::PaymentMethodData::GiftCard(_) + | domain::PaymentMethodData::OpenBanking(_) + | domain::PaymentMethodData::CardToken(_) + | domain::PaymentMethodData::MobilePayment(_) + | domain::PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { + Err(errors::ConnectorError::NotSupported { + message: "Network tokenization for payment method".to_string(), + connector: "Adyen", + })? + } + } + } // }?; Ok(AdyenPaymentRequest { amount, @@ -2717,7 +2766,7 @@ impl mpi_data: None, telephone_number: None, shopper_name: None, - shopper_email, + shopper_email: None, shopper_locale: None, social_security_number: None, billing_address: None, @@ -2765,7 +2814,7 @@ impl let return_url = item.router_data.request.get_return_url()?; let card_holder_name = item.router_data.get_optional_billing_full_name(); let payment_method = AdyenPaymentMethod::try_from((card_data, card_holder_name))?; - let shopper_email = get_optional_shopper_email(item.router_data); + let shopper_email = item.router_data.get_optional_billing_email(); let shopper_name = get_shopper_name(item.router_data.get_optional_billing()); Ok(AdyenPaymentRequest { @@ -2824,7 +2873,6 @@ impl let return_url = item.router_data.request.get_return_url()?; let payment_method = AdyenPaymentMethod::try_from((bank_debit_data, item.router_data))?; let country_code = get_country_code(item.router_data.get_optional_billing()); - let shopper_email = get_optional_shopper_email(item.router_data); let request = AdyenPaymentRequest { amount, merchant_account: auth_type.merchant_account, @@ -2838,7 +2886,7 @@ impl mpi_data: None, shopper_name: None, shopper_locale: None, - shopper_email, + shopper_email: item.router_data.get_optional_billing_email(), social_security_number: None, telephone_number: None, billing_address: None, @@ -2884,7 +2932,6 @@ impl let billing_address = get_address_info(item.router_data.get_optional_billing()).and_then(Result::ok); let shopper_name = get_shopper_name(item.router_data.get_optional_billing()); - let shopper_email = get_optional_shopper_email(item.router_data); let request = AdyenPaymentRequest { amount, @@ -2898,7 +2945,7 @@ impl additional_data, shopper_name, shopper_locale: None, - shopper_email, + shopper_email: item.router_data.get_optional_billing_email(), social_security_number, mpi_data: None, telephone_number: None, @@ -2938,7 +2985,6 @@ impl let shopper_interaction = AdyenShopperInteraction::from(item.router_data); let payment_method = AdyenPaymentMethod::try_from((bank_transfer_data, item.router_data))?; let return_url = item.router_data.request.get_return_url()?; - let shopper_email = get_optional_shopper_email(item.router_data); let request = AdyenPaymentRequest { amount, merchant_account: auth_type.merchant_account, @@ -2952,7 +2998,7 @@ impl mpi_data: None, shopper_name: None, shopper_locale: None, - shopper_email, + shopper_email: item.router_data.get_optional_billing_email(), social_security_number: None, telephone_number: None, billing_address: None, @@ -2991,7 +3037,6 @@ impl let shopper_interaction = AdyenShopperInteraction::from(item.router_data); let return_url = item.router_data.request.get_router_return_url()?; let payment_method = AdyenPaymentMethod::try_from(gift_card_data)?; - let shopper_email = get_optional_shopper_email(item.router_data); let request = AdyenPaymentRequest { amount, merchant_account: auth_type.merchant_account, @@ -3005,7 +3050,7 @@ impl mpi_data: None, shopper_name: None, shopper_locale: None, - shopper_email, + shopper_email: item.router_data.get_optional_billing_email(), telephone_number: None, billing_address: None, delivery_address: None, @@ -3055,7 +3100,6 @@ impl let line_items = Some(get_line_items(item)); let billing_address = get_address_info(item.router_data.get_optional_billing()).and_then(Result::ok); - let shopper_email = get_optional_shopper_email(item.router_data); Ok(AdyenPaymentRequest { amount, @@ -3070,7 +3114,7 @@ impl mpi_data: None, telephone_number: None, shopper_name: None, - shopper_email, + shopper_email: item.router_data.get_optional_billing_email(), shopper_locale, social_security_number: None, billing_address, @@ -3122,13 +3166,11 @@ fn get_shopper_email( .as_ref() .ok_or(errors::ConnectorError::MissingPaymentMethodType)?; match payment_method_type { - storage_enums::PaymentMethodType::Paypal => { - Ok(Some(item.get_billing_email().or(item.request.get_email())?)) - } - _ => Ok(get_optional_shopper_email(item)), + storage_enums::PaymentMethodType::Paypal => Ok(Some(item.get_billing_email()?)), + _ => Ok(item.get_optional_billing_email()), } } else { - Ok(get_optional_shopper_email(item)) + Ok(item.get_optional_billing_email()) } } @@ -3235,7 +3277,7 @@ impl get_recurring_processing_model(item.router_data)?; let return_url = item.router_data.request.get_return_url()?; let shopper_name = get_shopper_name(item.router_data.get_optional_billing()); - let shopper_email = get_optional_shopper_email(item.router_data); + let shopper_email = item.router_data.get_optional_billing_email(); let billing_address = get_address_info(item.router_data.get_optional_billing()).and_then(Result::ok); let delivery_address = @@ -3303,7 +3345,7 @@ impl let shopper_interaction = AdyenShopperInteraction::from(item.router_data); let return_url = item.router_data.request.get_return_url()?; let shopper_name = get_shopper_name(item.router_data.get_optional_billing()); - let shopper_email = get_optional_shopper_email(item.router_data); + let shopper_email = item.router_data.get_optional_billing_email(); let telephone_number = item .router_data .get_billing_phone() @@ -4881,7 +4923,8 @@ impl TryFrom<&AdyenRouterData<&types::PayoutsRouterData>> for AdyenPayoutC })?, }; let bank_data = PayoutBankData { bank: bank_details }; - let address = item.router_data.get_billing_address()?; + let address: &hyperswitch_domain_models::address::AddressDetails = + item.router_data.get_billing_address()?; Ok(Self { amount: Amount { value: item.amount.to_owned(), @@ -4923,7 +4966,8 @@ impl TryFrom<&AdyenRouterData<&types::PayoutsRouterData>> for AdyenPayoutC })? } }; - let address = item.router_data.get_billing_address()?; + let address: &hyperswitch_domain_models::address::AddressDetails = + item.router_data.get_billing_address()?; let payout_wallet = PayoutWalletData { selected_brand: PayoutBrand::Paypal, additional_data, @@ -5350,3 +5394,97 @@ impl ForeignTryFrom<(&Self, AdyenDisputeResponse)> for types::DefendDisputeRoute } } } + +impl TryFrom<(&domain::NetworkTokenData, Option>)> for AdyenPaymentMethod<'_> { + type Error = Error; + fn try_from( + (token_data, card_holder_name): (&domain::NetworkTokenData, Option>), + ) -> Result { + let adyen_network_token = AdyenNetworkTokenData { + payment_type: PaymentType::NetworkToken, + number: token_data.token_number.clone(), + expiry_month: token_data.token_exp_month.clone(), + expiry_year: token_data.get_expiry_year_4_digit(), + holder_name: card_holder_name, + brand: None, // FIXME: Remove hardcoding + network_payment_reference: None, + }; + Ok(AdyenPaymentMethod::NetworkToken(Box::new( + adyen_network_token, + ))) + } +} + +impl + TryFrom<( + &AdyenRouterData<&types::PaymentsAuthorizeRouterData>, + &domain::NetworkTokenData, + )> for AdyenPaymentRequest<'_> +{ + type Error = Error; + fn try_from( + value: ( + &AdyenRouterData<&types::PaymentsAuthorizeRouterData>, + &domain::NetworkTokenData, + ), + ) -> Result { + let (item, token_data) = value; + let amount = get_amount_data(item); + let auth_type = AdyenAuthType::try_from(&item.router_data.connector_auth_type)?; + let shopper_interaction = AdyenShopperInteraction::from(item.router_data); + let shopper_reference = build_shopper_reference( + &item.router_data.customer_id, + item.router_data.merchant_id.clone(), + ); + let (recurring_processing_model, store_payment_method, _) = + get_recurring_processing_model(item.router_data)?; + let browser_info = get_browser_info(item.router_data)?; + let billing_address = + get_address_info(item.router_data.get_optional_billing()).transpose()?; + let country_code = get_country_code(item.router_data.get_optional_billing()); + let additional_data = get_additional_data(item.router_data); + let return_url = item.router_data.request.get_return_url()?; + let card_holder_name = item.router_data.get_optional_billing_full_name(); + let payment_method = AdyenPaymentMethod::try_from((token_data, card_holder_name))?; + let shopper_email = item.router_data.request.email.clone(); + let shopper_name = get_shopper_name(item.router_data.get_optional_billing()); + let mpi_data = AdyenMpiData { + directory_response: "Y".to_string(), + authentication_response: "Y".to_string(), + token_authentication_verification_value: token_data + .token_cryptogram + .clone() + .unwrap_or_default(), + eci: Some("02".to_string()), + }; + + Ok(AdyenPaymentRequest { + amount, + merchant_account: auth_type.merchant_account, + payment_method, + reference: item.router_data.connector_request_reference_id.clone(), + return_url, + shopper_interaction, + recurring_processing_model, + browser_info, + additional_data, + telephone_number: None, + shopper_name, + shopper_email, + shopper_locale: None, + social_security_number: None, + billing_address, + delivery_address: None, + country_code, + line_items: None, + shopper_reference, + store_payment_method, + channel: None, + shopper_statement: item.router_data.request.statement_descriptor.clone(), + shopper_ip: item.router_data.request.get_ip_address_as_optional(), + metadata: item.router_data.request.metadata.clone().map(Into::into), + merchant_order_reference: item.router_data.request.merchant_order_reference_id.clone(), + mpi_data: Some(mpi_data), + }) + } +} diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index 6cca6e9001e9..8e6d74c83753 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -1319,6 +1319,7 @@ impl ConnectorAuthTypeAndMetadataValidation<'_> { cryptopay::transformers::CryptopayAuthType::try_from(self.auth_type)?; Ok(()) } + api_enums::Connector::CtpMastercard => Ok(()), api_enums::Connector::Cybersource => { cybersource::transformers::CybersourceAuthType::try_from(self.auth_type)?; cybersource::transformers::CybersourceConnectorMetadataObject::try_from( diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index 041fb52091ba..2d9a71a2584d 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -100,7 +100,6 @@ pub async fn retrieve_payment_method_core( business_profile, ) .await?; - Ok((pm_opt.to_owned(), payment_token)) } pm_opt @ Some(pm @ domain::PaymentMethodData::BankDebit(_)) => { @@ -127,6 +126,7 @@ pub async fn retrieve_payment_method_core( pm @ Some(domain::PaymentMethodData::GiftCard(_)) => Ok((pm.to_owned(), None)), pm @ Some(domain::PaymentMethodData::OpenBanking(_)) => Ok((pm.to_owned(), None)), pm @ Some(domain::PaymentMethodData::MobilePayment(_)) => Ok((pm.to_owned(), None)), + pm @ Some(domain::PaymentMethodData::NetworkToken(_)) => Ok((pm.to_owned(), None)), pm_opt @ Some(pm @ domain::PaymentMethodData::BankTransfer(_)) => { let payment_token = payment_helpers::store_payment_method_data_in_vault( state, diff --git a/crates/router/src/core/payment_methods/network_tokenization.rs b/crates/router/src/core/payment_methods/network_tokenization.rs index de4524104788..cab515d9bad2 100644 --- a/crates/router/src/core/payment_methods/network_tokenization.rs +++ b/crates/router/src/core/payment_methods/network_tokenization.rs @@ -436,6 +436,7 @@ pub async fn get_token_from_tokenization_service( card_type: None, card_issuing_country: None, bank_code: None, + eci: None, }; Ok(network_token_data) } diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index e8a591437de9..58490271079f 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -386,6 +386,17 @@ where mandate_type, ) .await?; + operation + .to_domain()? + .call_unified_authentication_service_if_eligible( + state, + &mut payment_data, + &mut should_continue_transaction, + &connector_details, + &business_profile, + &key_store, + ) + .await?; operation .to_domain()? diff --git a/crates/router/src/core/payments/connector_integration_v2_impls.rs b/crates/router/src/core/payments/connector_integration_v2_impls.rs index c9da7bb1fd95..c96b8f915b59 100644 --- a/crates/router/src/core/payments/connector_integration_v2_impls.rs +++ b/crates/router/src/core/payments/connector_integration_v2_impls.rs @@ -1,3 +1,8 @@ +use hyperswitch_domain_models::router_flow_types::{PostAuthenticate, PreAuthenticate}; +use hyperswitch_interfaces::api::{ + UasPostAuthenticationV2, UasPreAuthenticationV2, UnifiedAuthenticationServiceV2, +}; + #[cfg(feature = "frm")] use crate::types::fraud_check as frm_types; use crate::{ @@ -1050,8 +1055,6 @@ default_imp_for_new_connector_integration_payouts!( connector::Airwallex, connector::Amazonpay, connector::Authorizedotnet, - connector::Bambora, - connector::Bamboraapac, connector::Bankofamerica, connector::Billwerk, connector::Bitpay, @@ -1122,7 +1125,8 @@ default_imp_for_new_connector_integration_payouts!( connector::Worldline, connector::Worldpay, connector::Zen, - connector::Plaid + connector::Plaid, + connector::CtpMastercard ); #[cfg(feature = "payouts")] @@ -1687,7 +1691,8 @@ default_imp_for_new_connector_integration_frm!( connector::Worldline, connector::Worldpay, connector::Zen, - connector::Plaid + connector::Plaid, + connector::CtpMastercard ); #[cfg(feature = "frm")] @@ -2052,8 +2057,6 @@ default_imp_for_new_connector_integration_connector_authentication!( connector::Aci, connector::Adyen, connector::Adyenplatform, - connector::Airwallex, - connector::Amazonpay, connector::Authorizedotnet, connector::Bambora, connector::Bamboraapac, @@ -2137,12 +2140,12 @@ default_imp_for_new_connector_integration_connector_authentication!( macro_rules! default_imp_for_new_connector_integration_uas { ($($path:ident::$connector:ident),*) => { - $( impl api::UnifiedAuthenticationServiceV2 for $path::$connector {} - impl api::UasPreAuthenticationV2 for $path::$connector {} - impl api::UasPostAuthenticationV2 for $path::$connector {} + $( impl UnifiedAuthenticationServiceV2 for $path::$connector {} + impl UasPreAuthenticationV2 for $path::$connector {} + impl UasPostAuthenticationV2 for $path::$connector {} impl services::ConnectorIntegrationV2< - api::PreAuthenticate, + PreAuthenticate, types::UasFlowData, types::UasPreAuthenticationRequestData, types::UasAuthenticationResponseData, @@ -2150,7 +2153,7 @@ macro_rules! default_imp_for_new_connector_integration_uas { {} impl services::ConnectorIntegrationV2< - api::PostAuthenticate, + PostAuthenticate, types::UasFlowData, types::UasPostAuthenticationRequestData, types::UasAuthenticationResponseData, @@ -2161,87 +2164,37 @@ macro_rules! default_imp_for_new_connector_integration_uas { } default_imp_for_new_connector_integration_uas!( + connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Adyenplatform, - connector::Airwallex, - connector::Amazonpay, connector::Authorizedotnet, - connector::Bambora, - connector::Bamboraapac, connector::Bankofamerica, - connector::Billwerk, - connector::Bitpay, - connector::Bluesnap, - connector::Boku, connector::Braintree, - connector::Cashtocode, connector::Checkout, - connector::Cryptopay, - connector::Coinbase, connector::Cybersource, - connector::Datatrans, - connector::Deutschebank, - connector::Digitalvirgo, - connector::Dlocal, connector::Ebanx, - connector::Elavon, - connector::Fiserv, - connector::Fiservemea, - connector::Forte, - connector::Fiuu, connector::Globalpay, - connector::Globepay, - connector::Gocardless, connector::Gpayments, - connector::Helcim, connector::Iatapay, - connector::Inespay, connector::Itaubank, - connector::Jpmorgan, connector::Klarna, connector::Mifinity, - connector::Mollie, - connector::Multisafepay, connector::Netcetera, - connector::Nexinets, - connector::Nexixpay, connector::Nmi, - connector::Nomupay, connector::Noon, - connector::Novalnet, connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, - connector::Placetopay, - connector::Powertranz, - connector::Prophetpay, - connector::Rapyd, - connector::Razorpay, - connector::Redsys, + connector::Plaid, connector::Riskified, connector::Signifyd, - connector::Square, - connector::Stax, connector::Stripe, - connector::Shift4, - connector::Taxjar, - connector::Trustpay, connector::Threedsecureio, - connector::Thunes, - connector::Tsys, - connector::Volt, + connector::Trustpay, connector::Wellsfargo, - connector::Wise, - connector::Worldline, - connector::Worldpay, - connector::Zen, - connector::Zsl, - connector::Plaid + connector::Wellsfargopayout, + connector::Wise ); diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index ba1964435b80..9c9d0a454b3e 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -13,9 +13,13 @@ pub mod setup_mandate_flow; use async_trait::async_trait; use hyperswitch_domain_models::{ - mandates::CustomerAcceptance, router_request_types::PaymentsCaptureData, + mandates::CustomerAcceptance, + router_flow_types::{PostAuthenticate, PreAuthenticate}, + router_request_types::PaymentsCaptureData, +}; +use hyperswitch_interfaces::api::{ + payouts::Payouts, UasPostAuthentication, UasPreAuthentication, UnifiedAuthenticationService, }; -use hyperswitch_interfaces::api::payouts::Payouts; #[cfg(feature = "frm")] use crate::types::fraud_check as frm_types; @@ -504,7 +508,8 @@ default_imp_for_connector_request_id!( connector::Worldline, connector::Worldpay, connector::Zen, - connector::Zsl + connector::Zsl, + connector::CtpMastercard ); macro_rules! default_imp_for_accept_dispute { @@ -1640,7 +1645,8 @@ default_imp_for_fraud_check!( connector::Worldline, connector::Worldpay, connector::Zen, - connector::Zsl + connector::Zsl, + connector::CtpMastercard ); #[cfg(feature = "frm")] @@ -2243,7 +2249,8 @@ default_imp_for_connector_authentication!( connector::Worldline, connector::Worldpay, connector::Zen, - connector::Zsl + connector::Zsl, + connector::CtpMastercard ); macro_rules! default_imp_for_authorize_session_token { @@ -2488,11 +2495,11 @@ default_imp_for_post_session_tokens!( macro_rules! default_imp_for_uas_pre_authentication { ($($path:ident::$connector:ident),*) => { - $( impl api::UnifiedAuthenticationService for $path::$connector {} - impl api::UasPreAuthentication for $path::$connector {} + $( impl UnifiedAuthenticationService for $path::$connector {} + impl UasPreAuthentication for $path::$connector {} impl services::ConnectorIntegration< - api::PreAuthenticate, + PreAuthenticate, types::UasPreAuthenticationRequestData, types::UasAuthenticationResponseData > for $path::$connector @@ -2501,13 +2508,13 @@ macro_rules! default_imp_for_uas_pre_authentication { }; } #[cfg(feature = "dummy_connector")] -impl api::UasPreAuthentication for connector::DummyConnector {} +impl UasPreAuthentication for connector::DummyConnector {} #[cfg(feature = "dummy_connector")] -impl api::UnifiedAuthenticationService for connector::DummyConnector {} +impl UnifiedAuthenticationService for connector::DummyConnector {} #[cfg(feature = "dummy_connector")] impl services::ConnectorIntegration< - api::PreAuthenticate, + PreAuthenticate, types::UasPreAuthenticationRequestData, types::UasAuthenticationResponseData, > for connector::DummyConnector @@ -2518,95 +2525,44 @@ default_imp_for_uas_pre_authentication!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, - connector::Amazonpay, connector::Authorizedotnet, - connector::Bambora, - connector::Bamboraapac, connector::Bankofamerica, - connector::Billwerk, - connector::Bitpay, - connector::Bluesnap, - connector::Boku, connector::Braintree, - connector::Cashtocode, connector::Checkout, - connector::Cryptopay, - connector::Coinbase, connector::Cybersource, - connector::Datatrans, - connector::Deutschebank, - connector::Digitalvirgo, - connector::Dlocal, connector::Ebanx, - connector::Elavon, - connector::Fiserv, - connector::Fiservemea, - connector::Fiuu, - connector::Forte, connector::Globalpay, - connector::Globepay, - connector::Gocardless, connector::Gpayments, - connector::Helcim, connector::Iatapay, connector::Itaubank, - connector::Jpmorgan, connector::Klarna, connector::Mifinity, connector::Netcetera, - connector::Mollie, - connector::Multisafepay, - connector::Nexinets, - connector::Nexixpay, connector::Nmi, - connector::Nomupay, connector::Noon, - connector::Novalnet, connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, - connector::Placetopay, connector::Plaid, - connector::Powertranz, - connector::Prophetpay, - connector::Rapyd, - connector::Razorpay, connector::Riskified, - connector::Shift4, connector::Signifyd, - connector::Square, - connector::Stax, connector::Stripe, connector::Threedsecureio, - connector::Taxjar, connector::Trustpay, - connector::Tsys, - connector::Volt, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldline, - connector::Worldpay, - connector::Zen, - connector::Zsl, - connector::Inespay, - connector::Redsys, - connector::UnifiedAuthenticationService + connector::Wise ); macro_rules! default_imp_for_uas_post_authentication { ($($path:ident::$connector:ident),*) => { - $( impl api::UasPostAuthentication for $path::$connector {} + $( impl UasPostAuthentication for $path::$connector {} impl services::ConnectorIntegration< - api::PostAuthenticate, + PostAuthenticate, types::UasPostAuthenticationRequestData, types::UasAuthenticationResponseData > for $path::$connector @@ -2615,11 +2571,11 @@ macro_rules! default_imp_for_uas_post_authentication { }; } #[cfg(feature = "dummy_connector")] -impl api::UasPostAuthentication for connector::DummyConnector {} +impl UasPostAuthentication for connector::DummyConnector {} #[cfg(feature = "dummy_connector")] impl services::ConnectorIntegration< - api::PostAuthenticate, + PostAuthenticate, types::UasPostAuthenticationRequestData, types::UasAuthenticationResponseData, > for connector::DummyConnector @@ -2630,87 +2586,36 @@ default_imp_for_uas_post_authentication!( connector::Adyenplatform, connector::Aci, connector::Adyen, - connector::Airwallex, - connector::Amazonpay, connector::Authorizedotnet, - connector::Bambora, - connector::Bamboraapac, connector::Bankofamerica, - connector::Billwerk, - connector::Bitpay, - connector::Bluesnap, - connector::Boku, connector::Braintree, - connector::Cashtocode, connector::Checkout, - connector::Cryptopay, - connector::Coinbase, connector::Cybersource, - connector::Datatrans, - connector::Deutschebank, - connector::Digitalvirgo, - connector::Dlocal, connector::Ebanx, - connector::Elavon, - connector::Fiserv, - connector::Fiservemea, - connector::Fiuu, - connector::Forte, connector::Globalpay, - connector::Globepay, connector::Gpayments, - connector::Gocardless, - connector::Helcim, connector::Iatapay, connector::Itaubank, - connector::Jpmorgan, connector::Klarna, connector::Mifinity, connector::Netcetera, - connector::Mollie, - connector::Multisafepay, - connector::Nexinets, - connector::Nexixpay, connector::Nmi, - connector::Nomupay, connector::Noon, - connector::Novalnet, connector::Nuvei, connector::Opayo, connector::Opennode, - connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, - connector::Placetopay, connector::Plaid, - connector::Powertranz, - connector::Prophetpay, - connector::Rapyd, - connector::Razorpay, connector::Riskified, - connector::Shift4, connector::Signifyd, - connector::Square, - connector::Stax, connector::Stripe, connector::Threedsecureio, - connector::Taxjar, connector::Trustpay, - connector::Tsys, - connector::Volt, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Wise, - connector::Worldline, - connector::Worldpay, - connector::Zen, - connector::Zsl, - connector::Inespay, - connector::Redsys, - connector::UnifiedAuthenticationService + connector::Wise ); /// Determines whether a capture API call should be made for a payment attempt /// This function evaluates whether an authorized payment should proceed with a capture API call diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index ba14457e023c..84256f1b296d 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -2088,6 +2088,7 @@ pub async fn retrieve_card_with_permanent_token( card_type: None, card_issuing_country: None, bank_code: None, + eci: None, }; Ok(domain::PaymentMethodData::NetworkToken(network_token_data)) } else { @@ -2648,13 +2649,15 @@ pub(crate) fn validate_payment_method_fields_present( req.payment_method.is_some() && payment_method_data.is_none() && req.payment_token.is_none() - && req.recurring_details.is_none(), + && req.recurring_details.is_none() + && req.ctp_service_details.is_none(), || { Err(errors::ApiErrorResponse::MissingRequiredField { field_name: "payment_method_data", }) }, )?; + utils::when( req.payment_method.is_some() && req.payment_method_type.is_some(), || { @@ -3313,6 +3316,7 @@ pub(crate) fn validate_pm_or_token_given( payment_method_type: &Option, mandate_type: &Option, token: &Option, + ctp_service_details: &Option, ) -> Result<(), errors::ApiErrorResponse> { utils::when( !matches!( @@ -3322,10 +3326,13 @@ pub(crate) fn validate_pm_or_token_given( mandate_type, Some(api::MandateTransactionType::RecurringMandateTransaction) ) && token.is_none() - && (payment_method_data.is_none() || payment_method.is_none()), + && (payment_method_data.is_none() || payment_method.is_none()) + && ctp_service_details.is_none(), || { Err(errors::ApiErrorResponse::InvalidRequestData { - message: "A payment token or payment method data is required".to_string(), + message: + "A payment token or payment method data or ctp service details is required" + .to_string(), }) }, ) diff --git a/crates/router/src/core/payments/operations/payment_complete_authorize.rs b/crates/router/src/core/payments/operations/payment_complete_authorize.rs index 09e806755ff0..914ddf251efe 100644 --- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs +++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs @@ -171,6 +171,7 @@ impl GetTracker, api::PaymentsRequest> &request.payment_method_type, &mandate_type, &token, + &request.ctp_service_details, )?; } } diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index 58217ef3f41a..aa551ce6fff6 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -16,6 +16,7 @@ use error_stack::{report, ResultExt}; use futures::FutureExt; #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] use hyperswitch_domain_models::payments::payment_intent::PaymentIntentUpdateFields; +use hyperswitch_domain_models::router_request_types::unified_authentication_service; use masking::{ExposeInterface, PeekInterface}; use router_derive::PaymentOperation; use router_env::{instrument, logger, tracing}; @@ -39,7 +40,7 @@ use crate::{ PaymentData, }, unified_authentication_service::{ - self, + self as uas_utils, types::{ClickToPay, UnifiedAuthenticationService, CTP_MASTERCARD}, }, utils as core_utils, @@ -597,6 +598,7 @@ impl GetTracker, api::PaymentsRequest> &request.payment_method_type, &mandate_type, &token, + &request.ctp_service_details, )?; let (token_data, payment_method_info) = if let Some(token) = token.clone() { @@ -778,6 +780,7 @@ impl GetTracker, api::PaymentsRequest> )), // connector_mandate_request_reference_id )), ); + let payment_data = PaymentData { flow: PhantomData, payment_intent, @@ -818,7 +821,7 @@ impl GetTracker, api::PaymentsRequest> poll_config: None, tax_data: None, session_id: None, - service_details: None, + service_details: request.ctp_service_details.clone(), }; let get_trackers_response = operations::GetTrackerResponse { @@ -883,7 +886,6 @@ impl Domain> for business_profile, )) .await?; - utils::when(payment_method_data.is_none(), || { Err(errors::ApiErrorResponse::PaymentMethodNotFound) })?; @@ -1044,10 +1046,10 @@ impl Domain> for business_profile: &domain::Profile, key_store: &domain::MerchantKeyStore, ) -> CustomResult<(), errors::ApiErrorResponse> { - let is_click_to_pay_enabled = true; // fetch from business profile - if let Some(payment_method) = payment_data.payment_attempt.payment_method { - if payment_method == storage_enums::PaymentMethod::Card && is_click_to_pay_enabled { + if payment_method == storage_enums::PaymentMethod::Card + && business_profile.is_click_to_pay_enabled + { let connector_name = CTP_MASTERCARD; // since the above checks satisfies the connector should be click to pay hence hardcoded the connector name let connector_mca = helpers::get_merchant_connector_account( state, @@ -1091,7 +1093,7 @@ impl Domain> for payment_data.payment_attempt.authentication_id = Some(authentication_id.clone()); - let network_token = ClickToPay::post_authentication( + let response = ClickToPay::post_authentication( state, key_store, business_profile, @@ -1102,10 +1104,43 @@ impl Domain> for ) .await?; - payment_data.payment_method_data = - network_token.map(domain::PaymentMethodData::NetworkToken); + let (network_token, authentication_status) = match response.response.clone() { + Ok(unified_authentication_service::UasAuthenticationResponseData::PostAuthentication { + authentication_details, + }) => { + (Some( + hyperswitch_domain_models::payment_method_data::NetworkTokenData { + token_number: authentication_details.token_details.payment_token, + token_exp_month: authentication_details + .token_details + .token_expiration_month, + token_exp_year: authentication_details + .token_details + .token_expiration_year, + token_cryptogram: authentication_details + .dynamic_data_details + .and_then(|data| data.dynamic_data_value), + card_issuer: None, + card_network: None, + card_type: None, + card_issuing_country: None, + bank_code: None, + nick_name: None, + eci: authentication_details.eci, + }),common_enums::AuthenticationStatus::Success) + }, + Ok(unified_authentication_service::UasAuthenticationResponseData::PreAuthentication {}) => (None, common_enums::AuthenticationStatus::Started), + Err(_) => (None, common_enums::AuthenticationStatus::Failed) + }; + + payment_data.payment_attempt.payment_method = + Some(common_enums::PaymentMethod::Card); + + payment_data.payment_method_data = network_token + .clone() + .map(domain::PaymentMethodData::NetworkToken); - unified_authentication_service::create_new_authentication( + uas_utils::create_new_authentication( state, payment_data.payment_attempt.merchant_id.clone(), connector_name.to_string(), @@ -1113,6 +1148,8 @@ impl Domain> for Some(payment_data.payment_intent.get_id().clone()), connector_transaction_id, &authentication_id, + payment_data.service_details.clone(), + authentication_status, ) .await?; } diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 6a676af47b72..a316d6edc372 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -1012,6 +1012,7 @@ impl ValidateRequest GetTracker, api::PaymentsRequest> &request.payment_method_type, &mandate_type, &token, + &request.ctp_service_details, )?; } diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 92486320cdee..4f24ec98881f 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -2589,6 +2589,7 @@ impl TryFrom> for types::PaymentsAuthoriz None } }); + let amount = payment_data.payment_attempt.get_total_amount(); let customer_name = additional_data diff --git a/crates/router/src/core/unified_authentication_service.rs b/crates/router/src/core/unified_authentication_service.rs index 63375419cf75..5ed1b63d721f 100644 --- a/crates/router/src/core/unified_authentication_service.rs +++ b/crates/router/src/core/unified_authentication_service.rs @@ -2,13 +2,13 @@ pub mod transformers; pub mod types; pub mod utils; +use api_models::payments::CtpServiceDetails; use diesel_models::authentication::{Authentication, AuthenticationNew}; use error_stack::ResultExt; use hyperswitch_domain_models::{ errors::api_error_response::ApiErrorResponse, router_request_types::unified_authentication_service::{ - UasAuthenticationResponseData, UasPostAuthenticationRequestData, - UasPreAuthenticationRequestData, + UasPostAuthenticationRequestData, UasPreAuthenticationRequestData, }, }; @@ -23,7 +23,6 @@ use crate::{ }, db::domain, routes::SessionState, - types::api, }; #[cfg(feature = "v1")] @@ -42,7 +41,8 @@ impl UnifiedAuthenticationService for ClickToPay { let pre_authentication_data = UasPreAuthenticationRequestData::try_from(payment_data.clone())?; - let pre_auth_router_data: api::unified_authentication_service::UasPreAuthenticationRouterData = utils::construct_uas_router_data( + let pre_auth_router_data: hyperswitch_domain_models::types::UasPreAuthenticationRouterData = + utils::construct_uas_router_data( connector_name.to_string(), payment_method, payment_data.payment_attempt.merchant_id.clone(), @@ -70,9 +70,7 @@ impl UnifiedAuthenticationService for ClickToPay { merchant_connector_account: &MerchantConnectorAccountType, connector_name: &str, payment_method: common_enums::PaymentMethod, - ) -> RouterResult> - { - let post_authentication_data = UasPostAuthenticationRequestData; + ) -> RouterResult { let authentication_id = payment_data .payment_attempt .authentication_id @@ -80,7 +78,9 @@ impl UnifiedAuthenticationService for ClickToPay { .ok_or(ApiErrorResponse::InternalServerError) .attach_printable("Missing authentication id in payment attempt")?; - let post_auth_router_data: api::unified_authentication_service::UasPostAuthenticationRouterData = utils::construct_uas_router_data( + let post_authentication_data = UasPostAuthenticationRequestData {}; + + let post_auth_router_data: hyperswitch_domain_models::types::UasPostAuthenticationRouterData = utils::construct_uas_router_data( connector_name.to_string(), payment_method, payment_data.payment_attempt.merchant_id.clone(), @@ -97,27 +97,7 @@ impl UnifiedAuthenticationService for ClickToPay { ) .await?; - let network_token = match response.response.clone() { - Ok(UasAuthenticationResponseData::PostAuthentication { - authentication_details, - }) => Some( - hyperswitch_domain_models::payment_method_data::NetworkTokenData { - token_number: authentication_details.token_details.payment_token, - token_exp_month: authentication_details.token_details.token_expiration_month, - token_exp_year: authentication_details.token_details.token_expiration_year, - token_cryptogram: None, - card_issuer: None, - card_network: None, - card_type: None, - card_issuing_country: None, - bank_code: None, - nick_name: None, - }, - ), - _ => None, - }; - - Ok(network_token) + Ok(response) } fn confirmation( @@ -130,6 +110,7 @@ impl UnifiedAuthenticationService for ClickToPay { } } +#[allow(clippy::too_many_arguments)] pub async fn create_new_authentication( state: &SessionState, merchant_id: common_utils::id_type::MerchantId, @@ -138,7 +119,16 @@ pub async fn create_new_authentication( payment_id: Option, merchant_connector_id: common_utils::id_type::MerchantConnectorAccountId, authentication_id: &str, + service_details: Option, + authentication_status: common_enums::AuthenticationStatus, ) -> RouterResult { + let service_details_value = service_details + .map(serde_json::to_value) + .transpose() + .change_context(ApiErrorResponse::InternalServerError) + .attach_printable( + "unable to parse service details into json value while inserting to DB", + )?; let new_authorization = AuthenticationNew { authentication_id: authentication_id.to_owned(), merchant_id, @@ -146,7 +136,7 @@ pub async fn create_new_authentication( connector_authentication_id: None, payment_method_id: "".to_string(), authentication_type: None, - authentication_status: common_enums::AuthenticationStatus::Started, + authentication_status, authentication_lifecycle_status: common_enums::AuthenticationLifecycleStatus::Unused, error_message: None, error_code: None, @@ -173,7 +163,7 @@ pub async fn create_new_authentication( ds_trans_id: None, directory_server_id: None, acquirer_country_code: None, - service_details: None, + service_details: service_details_value, }; state .store diff --git a/crates/router/src/core/unified_authentication_service/transformers.rs b/crates/router/src/core/unified_authentication_service/transformers.rs index 0dd59fc81c76..36b4ad7e4203 100644 --- a/crates/router/src/core/unified_authentication_service/transformers.rs +++ b/crates/router/src/core/unified_authentication_service/transformers.rs @@ -14,9 +14,18 @@ impl TryFrom> for UasPreAuthenticationRequestDat fn try_from(payment_data: PaymentData) -> Result { let service_details = CtpServiceDetails { service_session_ids: Some(ServiceSessionIds { - merchant_transaction_id: None, - correlation_id: None, - x_src_flow_id: None, + merchant_transaction_id: payment_data + .service_details + .as_ref() + .and_then(|details| details.merchant_transaction_id.clone()), + correlation_id: payment_data + .service_details + .as_ref() + .and_then(|details| details.correlation_id.clone()), + x_src_flow_id: payment_data + .service_details + .as_ref() + .and_then(|details| details.x_src_flow_id.clone()), }), }; let currency = payment_data.payment_attempt.currency.ok_or( diff --git a/crates/router/src/core/unified_authentication_service/types.rs b/crates/router/src/core/unified_authentication_service/types.rs index 6fc73ec6cd2b..db0251768cf0 100644 --- a/crates/router/src/core/unified_authentication_service/types.rs +++ b/crates/router/src/core/unified_authentication_service/types.rs @@ -41,7 +41,7 @@ pub trait UnifiedAuthenticationService { _merchant_connector_account: &MerchantConnectorAccountType, _connector_name: &str, _payment_method: common_enums::PaymentMethod, - ) -> RouterResult>; + ) -> RouterResult; fn confirmation( _state: &SessionState, diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index f542eece81f0..c39ead5fbce8 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -36,9 +36,6 @@ pub mod payments_v2; pub mod payouts_v2; pub mod refunds_v2; -pub mod unified_authentication_service; -pub mod unified_authentication_service_v2; - use std::{fmt::Debug, str::FromStr}; use api_models::routing::{self as api_routing, RoutableConnectorChoice}; @@ -53,6 +50,7 @@ pub use hyperswitch_interfaces::api::{ ConnectorMandateRevoke, ConnectorMandateRevokeV2, ConnectorVerifyWebhookSource, ConnectorVerifyWebhookSourceV2, CurrencyUnit, }; +use hyperswitch_interfaces::api::{UnifiedAuthenticationService, UnifiedAuthenticationServiceV2}; #[cfg(feature = "frm")] pub use self::fraud_check::*; @@ -61,7 +59,7 @@ pub use self::payouts::*; pub use self::{ admin::*, api_keys::*, authentication::*, configs::*, customers::*, disputes::*, files::*, payment_link::*, payment_methods::*, payments::*, poll::*, refunds::*, refunds_v2::*, - unified_authentication_service::*, webhooks::*, + webhooks::*, }; use super::transformers::ForeignTryFrom; use crate::{ @@ -373,6 +371,9 @@ impl ConnectorData { enums::Connector::Cryptopay => { Ok(ConnectorEnum::Old(Box::new(connector::Cryptopay::new()))) } + enums::Connector::CtpMastercard => { + Ok(ConnectorEnum::Old(Box::new(&connector::CtpMastercard))) + } enums::Connector::Cybersource => { Ok(ConnectorEnum::Old(Box::new(connector::Cybersource::new()))) } diff --git a/crates/router/src/types/api/authentication.rs b/crates/router/src/types/api/authentication.rs index 7d35943dd793..e82ee116709c 100644 --- a/crates/router/src/types/api/authentication.rs +++ b/crates/router/src/types/api/authentication.rs @@ -150,6 +150,12 @@ impl AuthenticationConnectorData { enums::AuthenticationConnectors::Gpayments => { Ok(ConnectorEnum::Old(Box::new(connector::Gpayments::new()))) } + enums::AuthenticationConnectors::CtpMastercard => { + Ok(ConnectorEnum::Old(Box::new(&connector::CtpMastercard))) + } + enums::AuthenticationConnectors::UnifiedAuthenticationService => Ok( + ConnectorEnum::Old(Box::new(connector::UnifiedAuthenticationService::new())), + ), } } } diff --git a/crates/router/src/types/api/unified_authentication_service.rs b/crates/router/src/types/api/unified_authentication_service.rs deleted file mode 100644 index 97f698856fcc..000000000000 --- a/crates/router/src/types/api/unified_authentication_service.rs +++ /dev/null @@ -1,59 +0,0 @@ -use hyperswitch_domain_models::{ - router_data::RouterData, - router_request_types::unified_authentication_service::{ - UasAuthenticationResponseData, UasPostAuthenticationRequestData, - UasPreAuthenticationRequestData, - }, -}; - -pub use super::unified_authentication_service_v2::{ - UasPostAuthenticationV2, UasPreAuthenticationV2, UnifiedAuthenticationServiceV2, -}; -use crate::services; - -#[derive(Debug, Clone)] -pub struct PreAuthenticate; - -pub trait UnifiedAuthenticationService: - super::ConnectorCommon + UasPreAuthentication + UasPostAuthentication -{ -} - -#[derive(Debug, Clone)] -pub struct PostAuthenticate; - -pub trait UasPreAuthentication: - services::ConnectorIntegration< - PreAuthenticate, - UasPreAuthenticationRequestData, - UasAuthenticationResponseData, -> -{ -} - -pub trait UasPostAuthentication: - services::ConnectorIntegration< - PostAuthenticate, - UasPostAuthenticationRequestData, - UasAuthenticationResponseData, -> -{ -} - -pub type UasPostAuthenticationRouterData = - RouterData; - -pub type UasPostAuthenticationType = dyn services::ConnectorIntegration< - PostAuthenticate, - UasPostAuthenticationRequestData, - UasAuthenticationResponseData, ->; - -pub type UasPreAuthenticationRouterData = - RouterData; - -pub type UasPreAuthenticationType = dyn services::ConnectorIntegration< - PreAuthenticate, - UasPreAuthenticationRequestData, - UasAuthenticationResponseData, ->; diff --git a/crates/router/src/types/api/unified_authentication_service_v2.rs b/crates/router/src/types/api/unified_authentication_service_v2.rs deleted file mode 100644 index 3de12b0bb9e5..000000000000 --- a/crates/router/src/types/api/unified_authentication_service_v2.rs +++ /dev/null @@ -1,35 +0,0 @@ -use hyperswitch_domain_models::{ - router_data_v2::UasFlowData, - router_request_types::unified_authentication_service::{ - UasAuthenticationResponseData, UasPostAuthenticationRequestData, - UasPreAuthenticationRequestData, - }, -}; - -use super::unified_authentication_service::{PostAuthenticate, PreAuthenticate}; -use crate::services; - -pub trait UnifiedAuthenticationServiceV2: - super::ConnectorCommon + UasPreAuthenticationV2 + UasPostAuthenticationV2 -{ -} - -pub trait UasPreAuthenticationV2: - services::ConnectorIntegrationV2< - PreAuthenticate, - UasFlowData, - UasPreAuthenticationRequestData, - UasAuthenticationResponseData, -> -{ -} - -pub trait UasPostAuthenticationV2: - services::ConnectorIntegrationV2< - PostAuthenticate, - UasFlowData, - UasPostAuthenticationRequestData, - UasAuthenticationResponseData, -> -{ -} diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index 269eb831fc69..d4cd57754362 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -228,6 +228,11 @@ impl ForeignTryFrom for common_enums::RoutableConnectors { api_enums::Connector::Checkout => Self::Checkout, api_enums::Connector::Coinbase => Self::Coinbase, api_enums::Connector::Cryptopay => Self::Cryptopay, + api_enums::Connector::CtpMastercard => { + Err(common_utils::errors::ValidationError::InvalidValue { + message: "ctp mastercard is not a routable connector".to_string(), + })? + } api_enums::Connector::Cybersource => Self::Cybersource, api_enums::Connector::Datatrans => Self::Datatrans, api_enums::Connector::Deutschebank => Self::Deutschebank, diff --git a/cypress-tests-v2/cypress/e2e/configs/Payment/Commons.js b/cypress-tests-v2/cypress/e2e/configs/Payment/Commons.js index d445dbd26cd9..228dfd2cfdda 100644 --- a/cypress-tests-v2/cypress/e2e/configs/Payment/Commons.js +++ b/cypress-tests-v2/cypress/e2e/configs/Payment/Commons.js @@ -1199,7 +1199,7 @@ export const connectorDetails = { body: { error: { type: "invalid_request", - message: "A payment token or payment method data is required", + message: "A payment token or payment method data or ctp service details is required", code: "IR_06", }, }, diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Commons.js b/cypress-tests/cypress/e2e/PaymentUtils/Commons.js index 961762f2ddff..86e41c076391 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Commons.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Commons.js @@ -1392,7 +1392,8 @@ export const connectorDetails = { body: { error: { type: "invalid_request", - message: "A payment token or payment method data is required", + message: + "A payment token or payment method data or ctp service details is required", code: "IR_06", }, }, diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Paybox.js b/cypress-tests/cypress/e2e/PaymentUtils/Paybox.js index 7a4a47f9c312..2b85b7e5cd99 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Paybox.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Paybox.js @@ -856,7 +856,8 @@ export const connectorDetails = { body: { error: { type: "invalid_request", - message: "A payment token or payment method data is required", + message: + "A payment token or payment method data or ctp service details is required", code: "IR_06", }, }, diff --git a/postman/collection-dir/checkout/Flow Testcases/Variation Cases/Scenario2-Confirming the payment without PMD/Payments - Confirm/event.test.js b/postman/collection-dir/checkout/Flow Testcases/Variation Cases/Scenario2-Confirming the payment without PMD/Payments - Confirm/event.test.js index e03c186a82e3..6ca7b398c74c 100644 --- a/postman/collection-dir/checkout/Flow Testcases/Variation Cases/Scenario2-Confirming the payment without PMD/Payments - Confirm/event.test.js +++ b/postman/collection-dir/checkout/Flow Testcases/Variation Cases/Scenario2-Confirming the payment without PMD/Payments - Confirm/event.test.js @@ -81,13 +81,13 @@ if (jsonData?.error?.type) { ); } -// Response body should have value "A payment token or payment method data is required" for "message" +// Response body should have value "A payment token or payment method data or ctp service details is required" for "message" if (jsonData?.error?.message) { pm.test( "[POST]::/payments - Content check if value for 'error.message' matches 'connector_error'", function () { pm.expect(jsonData.error.message).to.eql( - "A payment token or payment method data is required", + "A payment token or payment method data or ctp service details is required", ); }, ); diff --git a/postman/collection-dir/paypal/Flow Testcases/Variation Cases/Scenario2-Confirming the payment without PMD/Payments - Confirm/event.test.js b/postman/collection-dir/paypal/Flow Testcases/Variation Cases/Scenario2-Confirming the payment without PMD/Payments - Confirm/event.test.js index e03c186a82e3..6ca7b398c74c 100644 --- a/postman/collection-dir/paypal/Flow Testcases/Variation Cases/Scenario2-Confirming the payment without PMD/Payments - Confirm/event.test.js +++ b/postman/collection-dir/paypal/Flow Testcases/Variation Cases/Scenario2-Confirming the payment without PMD/Payments - Confirm/event.test.js @@ -81,13 +81,13 @@ if (jsonData?.error?.type) { ); } -// Response body should have value "A payment token or payment method data is required" for "message" +// Response body should have value "A payment token or payment method data or ctp service details is required" for "message" if (jsonData?.error?.message) { pm.test( "[POST]::/payments - Content check if value for 'error.message' matches 'connector_error'", function () { pm.expect(jsonData.error.message).to.eql( - "A payment token or payment method data is required", + "A payment token or payment method data or ctp service details is required", ); }, ); diff --git a/postman/collection-json/checkout.postman_collection.json b/postman/collection-json/checkout.postman_collection.json index f01d5d2fe758..33bfcef8aa90 100644 --- a/postman/collection-json/checkout.postman_collection.json +++ b/postman/collection-json/checkout.postman_collection.json @@ -12186,13 +12186,13 @@ " );", "}", "", - "// Response body should have value \"A payment token or payment method data is required\" for \"message\"", + "// Response body should have value \"A payment token or payment method data or ctp service details is required\" for \"message\"", "if (jsonData?.error?.message) {", " pm.test(", " \"[POST]::/payments - Content check if value for 'error.message' matches 'connector_error'\",", " function () {", " pm.expect(jsonData.error.message).to.eql(", - " \"A payment token or payment method data is required\",", + " \"A payment token or payment method data or ctp service details is required\",", " );", " },", " );", diff --git a/postman/collection-json/paypal.postman_collection.json b/postman/collection-json/paypal.postman_collection.json index b4309b2b4a00..50abbd7dd8f2 100644 --- a/postman/collection-json/paypal.postman_collection.json +++ b/postman/collection-json/paypal.postman_collection.json @@ -6137,13 +6137,13 @@ " );", "}", "", - "// Response body should have value \"A payment token or payment method data is required\" for \"message\"", + "// Response body should have value \"A payment token or payment method data or ctp service details is required\" for \"message\"", "if (jsonData?.error?.message) {", " pm.test(", " \"[POST]::/payments - Content check if value for 'error.message' matches 'connector_error'\",", " function () {", " pm.expect(jsonData.error.message).to.eql(", - " \"A payment token or payment method data is required\",", + " \"A payment token or payment method data or ctp service details is required\",", " );", " },", " );",